File: Dirichlet_conversion.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 (320 lines) | stat: -rw-r--r-- 9,282 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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/*
 *	Dirichlet_conversion.c
 *
 *	This file contains the function
 *
 *		Triangulation *Dirichlet_to_triangulation(WEPolyhedron *polyhedron);
 *
 *	which converts a Dirichlet domain to a Triangulation, leaving the
 *	Dirichlet domain unchanged.  For closed manifolds, drills out
 *	an arbitrary curve and expresses the manifold as a Dehn filling.
 *	The polyhedron must be a manifold;  returns NULL for orbifolds.
 */

/*
 *							The Algorithm
 *
 *	When subdividing a Dirichlet domain into tetrahedra, one faces a
 *	tradeoff between the ease of programming and efficiency of the resulting
 *	triangulation.  Plan A is the cleanest to implement, but uses twice
 *	as many tetrahedra as Plan B, and four times as many as plan C.
 *
 *	Plan A
 *
 *	The vertices of each tetrahedron are as follows.
 *
 *	  index	  location
 *		0	at a vertex of the Dirichlet domain
 *		1	at the midpoint of an edge incident to the aforementioned vertex
 *		2	at the  center  of a  face incident to the aforementioned edge
 *		3	at the center of the Dirichlet domain
 *
 *	As a mnemonic, note that vertex i lies at the center of a cell
 *	of dimension i.  Make yourself a sketch of the Dirichlet domain,
 *	and it will be obvious that tetrahedra of the above form triangulate
 *	the manifold.  Moreover, all tet->gluing[]'s are the identity (!)
 *	so the implementation need only be concerned with the tet->neighbor[]'s.
 *
 *	Plan B
 *
 *	Fuse together pairs of tetrahedra from Plan A across their faces
 *	of FaceIndex 0.  This halves the number of tetrahedra required,
 *	but makes the programming more complicated.
 *
 *	Plan C
 *
 *	Fuse together pairs of tetrahedra from Plan B across their faces
 *	of FaceIndex 3 (i.e. across the faces of the original Dirichlet domain).
 *	This halves the number of tetrahedra required, but makes the programming
 *	more complicated.
 *
 *	The Choice
 *
 *	For now I will go with Plan A because it's simplest.
 *	If memory use turns out to be a problem (which I suspect it won't)
 *	I can rewrite the code to use Plan B or C instead.  In any case,
 *	note that the large number of Tetrahedra are required only temporarily,
 *	and don't have TetShapes attached.  The only remaining danger with this
 *	plan is that in the case of a closed manifold, the drilled curve might
 *	not be isotopic to the geodesic in its isotopy class.
 */

#include "kernel.h"

#define DEFAULT_NAME	"no name"
#define MAX_TRIES		16

static Triangulation	*try_Dirichlet_to_triangulation(WEPolyhedron *polyhedron);
static Boolean			singular_set_is_empty(WEPolyhedron *polyhedron);


Triangulation *Dirichlet_to_triangulation(
	WEPolyhedron	*polyhedron)
{
	/*
	 *	When the polyhedron represents a closed manifold,
	 *	try_Dirichlet_to_triangulation() drills out an arbitrary curve
	 *	to express the manifold as a Dehn filling.  Usually the arbitrary
	 *	curve turns out to be isotopic to a geodesic, but not always.
	 *	Here we try several repetitions of try_Dirichlet_to_triangulation(),
	 *	if necessary, to obtain a hyperbolic Dehn filling.
	 *	Fortunately in almost all cases (about 95% in my informal tests)
	 *	try_Dirichlet_to_triangulation() get a geodesic on its first try.
	 */
	
	int				count;
	Triangulation	*triangulation;
	
	triangulation = try_Dirichlet_to_triangulation(polyhedron);
	
	count = MAX_TRIES;
	while (	--count >= 0
		 && triangulation != NULL
		 && triangulation->solution_type[filled] != geometric_solution
		 && triangulation->solution_type[filled] != nongeometric_solution)
	{
		free_triangulation(triangulation);
		triangulation = try_Dirichlet_to_triangulation(polyhedron);
	}

	return triangulation;
}


static Triangulation *try_Dirichlet_to_triangulation(
	WEPolyhedron	*polyhedron)
{
	/*
	 *	Implement Plan A as described above.
	 */
	
	Triangulation	*triangulation;
	WEEdge			*edge,
					*nbr_edge,
					*mate_edge;
	WEEdgeEnd		end;
	WEEdgeSide		side;
	Tetrahedron		*new_tet;
	FaceIndex		f;

	/*
	 *	Don't attempt to triangulate an orbifold.
	 */

	if (singular_set_is_empty(polyhedron) == FALSE)
		return NULL;
	
	/*
	 *	Set up the Triangulation.
	 */

	triangulation = NEW_STRUCT(Triangulation);
	initialize_triangulation(triangulation);

	/*
	 *	Allocate and copy the name.
	 */

	triangulation->name = NEW_ARRAY(strlen(DEFAULT_NAME) + 1, char);
	strcpy(triangulation->name, DEFAULT_NAME);

	/*
	 *	Allocate the Tetrahedra.
	 */

	triangulation->num_tetrahedra = 4 * polyhedron->num_edges;

	for (edge = polyhedron->edge_list_begin.next;
		 edge != &polyhedron->edge_list_end;
		 edge = edge->next)

		for (end = 0; end < 2; end++)	/* = tail, tip */

			for (side = 0; side < 2; side++)	/* = left, right */
			{
				new_tet = NEW_STRUCT(Tetrahedron);
				initialize_tetrahedron(new_tet);
				INSERT_BEFORE(new_tet, &triangulation->tet_list_end);
				edge->tet[end][side] = new_tet;
			}

	/*
	 *	Initialize neighbors.
	 */

	for (edge = polyhedron->edge_list_begin.next;
		 edge != &polyhedron->edge_list_end;
		 edge = edge->next)

		for (end = 0; end < 2; end++)	/* = tail, tip */

			for (side = 0; side < 2; side++)	/* = left, right */
			{
				/*
				 *	Neighbor[0] is associated to this same WEEdge.
				 *	It lies on the same side (left or right), but
				 *	at the opposite end (tail or tip).
				 */
				edge->tet[end][side]->neighbor[0] = edge->tet[!end][side];

				/*
				 *	Neighbor[1] lies on the same face of the Dirichlet
				 *	domain, but at the "next side" of that face.
				 */
				nbr_edge = edge->e[end][side];
				if (nbr_edge->v[!end] == edge->v[end])
					/* edge and nbr_edge point in the same direction */
					edge->tet[end][side]->neighbor[1] = nbr_edge->tet[!end][side];
				else if (nbr_edge->v[end] == edge->v[end])
					/* edge and nbr_edge point in opposite directions */
					edge->tet[end][side]->neighbor[1] = nbr_edge->tet[end][!side];
				else
					uFatalError("Dirichlet_to_triangulation", "Dirichlet_conversion");

				/*
				 *	Neighbor[2] is associated to this same WEEdge.
				 *	It lies at the same end (tail or tip), but
				 *	on the opposite side (left or right).
				 */
				edge->tet[end][side]->neighbor[2] = edge->tet[end][!side];

				/*
				 *	Neighbor[3] lies on this face's "mate" elsewhere
				 *	on the Dirichlet domain.
				 */
				mate_edge = edge->neighbor[side];
				edge->tet[end][side]->neighbor[3] = mate_edge->tet
					[edge->preserves_direction[side] ? end  : !end ]
					[edge->preserves_sides[side]     ? side : !side];
			}

	/*
	 *	Initialize all gluings to the identity.
	 */

	for (edge = polyhedron->edge_list_begin.next;
		 edge != &polyhedron->edge_list_end;
		 edge = edge->next)

		for (end = 0; end < 2; end++)	/* = tail, tip */

			for (side = 0; side < 2; side++)	/* = left, right */

				for (f = 0; f < 4; f++)

					edge->tet[end][side]->gluing[f] = IDENTITY_PERMUTATION;

	/*
	 *	Set up the EdgeClasses.
	 */
	create_edge_classes(triangulation);
	orient_edge_classes(triangulation);

	/*
	 *	Attempt to orient the manifold.
	 */
	orient(triangulation);

	/*
	 *	Set up the Cusps, including "fake cusps" for the finite vertices.
	 *	Then locate and remove the fake cusps.  If the manifold is closed,
	 *	drill out an arbitrary curve to express it as a Dehn filling.
	 *	Finally, determine the topology of each cusp (torus or Klein bottle)
	 *	and count them.
	 */
	create_cusps(triangulation);
	mark_fake_cusps(triangulation);
	peripheral_curves(triangulation);
	remove_finite_vertices(triangulation);
	count_cusps(triangulation);
	
	/*
	 *	Try to compute a hyperbolic structure, first for the unfilled
	 *	manifold, and then for the closed manifold if appropriate.
	 */
	find_complete_hyperbolic_structure(triangulation);
	do_Dehn_filling(triangulation);

	/*
	 *	If the manifold is hyperbolic, install a shortest basis on each cusp.
	 */
	if (	triangulation->solution_type[complete] == geometric_solution
	 	 || triangulation->solution_type[complete] == nongeometric_solution)
		install_shortest_bases(triangulation);

	/*
	 *	All done!
	 */
	return triangulation;
}


static Boolean singular_set_is_empty(
	WEPolyhedron	*polyhedron)
{
	/*
	 *	Check whether the singular set of this orbifold is empty.
	 */

	WEVertexClass	*vertex_class;
	WEEdgeClass		*edge_class;
	WEFaceClass		*face_class;

	for (vertex_class = polyhedron->vertex_class_begin.next;
		 vertex_class != &polyhedron->vertex_class_end;
		 vertex_class = vertex_class->next)

		if (vertex_class->singularity_order >= 2)

			return FALSE;

	/*
	 *	Dirichlet_construction.c subdivides Dirichlet domains for
	 *	orbifolds so that the k-skeleton of the singular set lies
	 *	in the k-skeleton of the Dirichlet domain (k = 0,1,2).
	 *	Thus if there are no singular VertexClasses, there can't be
	 *	any singular EdgeClasses or FaceClasses either.
	 */
	
	for (edge_class = polyhedron->edge_class_begin.next;
		 edge_class != &polyhedron->edge_class_end;
		 edge_class = edge_class->next)

		if (edge_class->singularity_order >= 2)

			uFatalError("singular_set_is_empty", "Dirichlet_conversion");

	for (face_class = polyhedron->face_class_begin.next;
		 face_class != &polyhedron->face_class_end;
		 face_class = face_class->next)

		if (face_class->num_elements != 2)

			uFatalError("singular_set_is_empty", "Dirichlet_conversion");

	/*
	 *	No singularities are present.
	 */

	return TRUE;
}