echo x - vsphere.3
cat >vsphere.3 <<'--- END OF FILE ---'
.TH VSPHERE 3 "March 29, 1990" "UCSF Computer Graphics Laboratory"
.SH NAME
vsphere \- virtual sphere transformation
.SH SYNOPSIS
.nf
.B
#include "vsphere.h"
.PP
.B int vsphere(fx, fy, tx, ty, rotmat)
.B float fx, fy;
.B float tx, ty;
.B float rotmat[4][4];
.fi
.SH DESCRIPTION
The virtual sphere algorithm is used for simulating a trackball with
a mouse. A circular region on the screen is designated as the
trackball area, and dragging the mouse in this region corresponds
to rotating the trackball.
.PP
The
.IR vsphere(3)
function is used to compute the transformation matrix which corresponds
to the movement of the mouse from one position to another. The starting
and ending positions are described by normalized x-y coordinates, with
the center of the trackball region designated as the origin, and the
radius of the region as unit length. The resulting matrix is an
orthonormal 4x4 matrix, with the pure rotation matrix in the upper
left 3x3.
.PP
If both starting and ending positions are inside the trackball region,
then the trackball analogy is used to compute the rotation. If both
positions are outside the trackball region,
.I vsphere
computes a rotation about the z-axis based on the angle formed by the
starting position, the center of the trackball region, and the ending
position. If one position is inside the trackball region and the
other outside, or the two positions are identical,
.I vsphere
returns an error and does not fill in the rotation matrix.
.PP
The following pseudo-code fragment shows how the
.I vsphere
function might be used.
.sp
.in +0.5i
.nf
.ft C
if (mouse_in_active_region && button_down) {
mouse_coord = read_mouse();
from_x = normalize(mouse_coord.x);
from_y = normalize(mouse_coord.y);
do {
mouse_coord = read_mouse();
to_x = normalize(mouse_coord.x);
to_y = normalize(mouse_coord.y);
if (vsphere(from_x, from_y, t_x, t_y, rotmat) == 0)
apply_matrix(rotmat);
from_x = to_x;
from_y = to_y;
} while (button_down);
}
.fi
.in -0.5i
.SH DIAGNOSTICS
Normally,
.I vsphere
returns 0 after filling in the rotation matrix. If for some reason,
.I vsphere
cannot compute a matrix, it returns a negative number and does not
fill in the matrix
.IR i.e. ,
it will not be filled with an identity matrix.
A return value of -1 indicates the given positions are identical.
A return value of -2 indicates that the starting position is outside
the trackball region but the ending position is inside.
A return value of -3 indicates that the starting position is inside
the trackball region but the ending position is outside.
.SH "SEE ALSO"
Chen, Michael, Mountford, S. Joy & Sellen, Abigail.
A Study in Interactive 3-D Rotation Using 2-D Control Devices.
Proceedings of SIGGRAPH'88. In
.I Computer Graphics
22, 4 (August 1988), 121-129.
.SH AUTHOR
Conrad Huang, UCSF Computer Graphics Laboratory
--- END OF FILE ---
echo x - vsphere.h
cat >vsphere.h <<'--- END OF FILE ---'
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, San Francisco. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: vsphere.h,v 1.2 89/11/09 15:45:51 conrad Exp $
*/
#ifndef VSPHERE_INCLUDE
#define VSPHERE_INCLUDE
#ifdef __STDC__
extern int vsphere(float, float, float, float, float[4][4]);
#else
extern int vsphere();
#endif
#endif
--- END OF FILE ---
echo x - vsphere.c
cat >vsphere.c <<'--- END OF FILE ---'
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, San Francisco. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* $Id: vsphere.c,v 1.3 89/11/09 15:45:26 conrad Exp $
*/
#include
#include
#include "vsphere.h"
/*
* vsphere:
* Convert X-Y coordinates into a 4x4 rotation matrix
*/
#ifdef __STDC__
int
vsphere(float fx, float fy, float tx, float ty, float rotmat[4][4])
#else
int
vsphere(fx, fy, tx, ty, rotmat)
float fx, fy;
float tx, ty;
float rotmat[4][4];
#endif
{
register int i;
double d1, d2;
float f[3], t[3], a[3], g[3], u[3];
float m1[4][4], m2[4][4];
static void vxv3();
static void normalize();
static void matrix_identity();
static void matrix_multiply();
/*
* First construct the unit vectors and computing
* the normal unit vectors. If we cross from outside
* the sphere to inside the sphere (or vice versa), then
* we ignore the transition because the discontinuity
* tends to make molecules jump.
*/
d1 = fx * fx + fy * fy;
d2 = tx * tx + ty * ty;
if (d1 > 1 && d2 < 1)
return -2;
if (d2 > 1 && d1 < 1)
return -3;
if (d1 < 1) {
f[0] = fx;
f[1] = fy;
f[2] = sqrt(1 - d1);
}
else {
d1 = sqrt(d1);
f[0] = fx / d1;
f[1] = fy / d1;
f[2] = 0;
}
if (d2 < 1) {
t[0] = tx;
t[1] = ty;
t[2] = sqrt(1 - d2);
}
else {
d2 = sqrt(d2);
t[0] = tx / d2;
t[1] = ty / d2;
t[2] = 0;
}
/*
* If the positions normalize to the same place we just punt.
* We don't even bother to put in the identity matrix.
*/
if (f[0] == t[0] && f[1] == t[1] && f[2] == t[2])
return -1;
vxv3(a, f, t);
normalize(a);
vxv3(g, a, f); /* Don't need to normalize these since the */
vxv3(u, a, t); /* cross product of normal unit vectors is */
/* a unit vector */
/*
* Now assemble them into the inverse matrix (to go from
* the from-vector to xyz-space) and the transform matrix
* (to go from xyz-space to to-vector). The product of
* the inverse and transformation matrices is the rotation
* matrix.
*/
matrix_identity(m1);
matrix_identity(m2);
for (i = 0; i < 3; i++) {
m1[i][0] = f[i];
m1[i][1] = a[i];
m1[i][2] = g[i];
m2[0][i] = t[i];
m2[1][i] = a[i];
m2[2][i] = u[i];
}
matrix_multiply(m1, m2, rotmat);
return 0;
}
/*
* matrix_ident:
* Create an identity matrix
*/
static void
matrix_identity(m)
float m[4][4];
{
register int i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++)
m[i][j] = 0;
m[i][i] = 1;
}
}
/*
* matrix_multiply:
* Multiply two matrices
*/
static void
matrix_multiply(m1, m2, result)
float m1[4][4], m2[4][4];
float result[4][4];
{
register int i, j, k;
float tmp;
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++) {
tmp = 0;
for (k = 0; k < 4; k++)
tmp += m1[i][k] * m2[k][j];
result[i][j] = tmp;
}
}
/*
* vxv3:
* Take the cross product of two vectors
*/
static void
vxv3(c, a, b)
float c[3], a[3], b[3];
{
c[0] = a[1] * b[2] - a[2] * b[1];
c[1] = a[2] * b[0] - a[0] * b[2];
c[2] = a[0] * b[1] - a[1] * b[0];
}
/*
* normalize:
* Normalize a vector
*/
static void
normalize(v)
float v[3];
{
float d;
d = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] /= d;
v[1] /= d;
v[2] /= d;
}
--- END OF FILE ---