File: Dirichlet_rotate.c

package info (click to toggle)
snappea 3.0d3-20.1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 5,896 kB
  • ctags: 3,582
  • sloc: ansic: 33,469; sh: 8,293; python: 7,623; makefile: 240
file content (210 lines) | stat: -rw-r--r-- 5,904 bytes parent folder | download | duplicates (8)
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;
		}
}