1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
|
/*
* Dirichlet_rotate.c
*
* This file provides the following functions for the UI, to allow
* convenient Dirichlet domain rotation.
*
* void set_identity_matrix(O31Matrix position);
* void set_poly_velocity(O31Matrix velocity, double theta[3]);
* void update_poly_position(O31Matrix position, O31Matrix velocity);
* void update_poly_vertices(WEPolyhedron *polyhedron,
* O31Matrix position, double scale);
* void update_poly_visibility(WEPolyhedron *polyhedron,
* O31Matrix position, O31Vector direction);
*
* set_identity_matrix() sets a position or velocity matrix to the identity.
*
* set_poly_velocity() takes as input the small rotation angles theta[]
* about each of the coordinate axes, and computes the corresonding
* rotation matrix. set_poly_velocity() may be used to update the
* velocity when the user drags the polyhedron with the mouse.
* For example, say the user interface is using a coordinate system
* in which the x-axis points to the right, the y-axis points down,
* and the z-axis points into the screen, and the user drags the
* mouse a small distance (dx, dy). The dx corresponds to a small
* clockwise rotation about the y-axis. The dy corresponds to a small
* counterclockwise rotation about the x-axis. So we pass the vector
* theta[3] = (dy, -dx, 0) to set_poly_velocity() and get back the
* corresponding velocity matrix.
*
* update_poly_position() updates the position by left-multiplying by the
* velocity. Call it to keep the polyhedron moving.
*
* update_poly_vertices() multiplies the standard vertex coordinates x[]
* by the position matrix to obtain the rotated coordinates xx[].
* It then multiplies the rotated coordinates by the constant "scale";
* this lets the UI scale the rotated coordinates to match the window
* coordinates (if you don't need this feature, pass scale = 1.0).
*
* update_poly_visibility() checks which vertices, edges and faces are
* visible to the user with the polyhedron in its present position,
* and sets their visibility fields accordingly. The direction vector
* points from the center of the polyhedron to the user. Note that
* the direction vector is an O31Vector; just set the 0-th component
* to 0.0.
*/
#include "kernel.h"
static void set_face_visibility(WEPolyhedron *polyhedron, O31Matrix position, O31Vector direction);
static void set_edge_visibility(WEPolyhedron *polyhedron);
static void set_vertex_visibility(WEPolyhedron *polyhedron);
void set_identity_matrix(
O31Matrix m)
{
/*
* This function is just a wrapper around a call to
* o31_copy(position, O31_identity), to avoid giving
* the UI access to the kernel's O(3,1) matrix library.
*/
o31_copy(m, O31_identity);
}
void update_poly_position(
O31Matrix position,
O31Matrix velocity)
{
/*
* Multiply the position by the velocity to get the new position.
*/
o31_product(velocity, position, position);
}
void update_poly_vertices(
WEPolyhedron *polyhedron,
O31Matrix position,
double scale)
{
WEVertex *vertex;
for (vertex = polyhedron->vertex_list_begin.next;
vertex != &polyhedron->vertex_list_end;
vertex = vertex->next)
{
o31_matrix_times_vector(position, vertex->x, vertex->xx);
o31_constant_times_vector(scale, vertex->xx, vertex->xx);
}
}
void update_poly_visibility(
WEPolyhedron *polyhedron,
O31Matrix position,
O31Vector direction)
{
/*
* Check which vertices, edges and faces are visible to the user with
* the polyhedron in its present position, and set their visibility
* fields accordingly. The direction vector points from the center
* of the polyhedron to the user.
*/
/*
* direction[0] is probably zero already, but just in case it's not,
* set it to zero explicitly. (We're using O31Vectors, but we care
* only about the 3-dimensional part.)
*/
direction[0] = 0.0;
/*
* Set the face visibility first.
*/
set_face_visibility(polyhedron, position, direction);
/*
* An edge is visible iff it lies on a visible face.
*/
set_edge_visibility(polyhedron);
/*
* A vertex is visible iff it lies on a visible edge.
*/
set_vertex_visibility(polyhedron);
}
static void set_face_visibility(
WEPolyhedron *polyhedron,
O31Matrix position,
O31Vector direction)
{
WEFace *face;
O31Vector old_normal,
new_normal;
int i;
for (face = polyhedron->face_list_begin.next;
face != &polyhedron->face_list_end;
face = face->next)
{
/*
* The first column of the group_element provides a normal
* vector relative to the polyhedron's original position.
*/
for (i = 0; i < 4; i++)
old_normal[i] = (*face->group_element)[i][0];
/*
* Apply the position matrix to find the normal vector relative
* to the polyhedron's current position.
*/
o31_matrix_times_vector(position, old_normal, new_normal);
/*
* The face will be visible iff the new_normal has a positive
* component in the given direction.
*/
face->visible = (o31_inner_product(direction, new_normal) > 0.0);
}
}
static void set_edge_visibility(
WEPolyhedron *polyhedron)
{
WEEdge *edge;
for (edge = polyhedron->edge_list_begin.next;
edge != &polyhedron->edge_list_end;
edge = edge->next)
edge->visible = (edge->f[left]->visible || edge->f[right]->visible);
}
static void set_vertex_visibility(
WEPolyhedron *polyhedron)
{
WEVertex *vertex;
WEEdge *edge;
/*
* Initialize all vertex visibilities to FALSE.
*/
for (vertex = polyhedron->vertex_list_begin.next;
vertex != &polyhedron->vertex_list_end;
vertex = vertex->next)
vertex->visible = FALSE;
/*
* The endpoints of each visible edge will be visible vertices.
*/
for (edge = polyhedron->edge_list_begin.next;
edge != &polyhedron->edge_list_end;
edge = edge->next)
if (edge->visible)
{
edge->v[tail]->visible = TRUE;
edge->v[tip ]->visible = TRUE;
}
}
|