File: winged_edge.h

package info (click to toggle)
regina-normal 4.93-1
  • links: PTS
  • area: main
  • in suites: wheezy
  • size: 28,576 kB
  • sloc: cpp: 86,815; ansic: 13,030; xml: 9,089; perl: 951; sh: 380; python: 273; makefile: 103
file content (708 lines) | stat: -rw-r--r-- 21,367 bytes parent folder | download
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
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
/*
 *	winged_edge.h
 *
 *	This file defines the usual "winged edge" data structure for
 *	representing a convex polyhedron, along with some extra
 *	fields describing the polyhedron's position in the projective
 *	model of hyperbolic 3-space.  (The "projective model" is
 *	the Minkowski space model projected onto the hyperplane
 *	x[0] == 1.)
 *
 *	This file is intended solely for #inclusion in SnapPea.h.
 *	It needs some of the typedefs which occur there.
 */

#ifndef _winged_edge_
#define _winged_edge_

#define INFINITE_RADIUS		1e20
#define INFINITE_DISTANCE	1e20
#define INFINITE_LENGTH		1e20

/*
 *	The values of the following two enums are used to index the
 *	static arrays in make_cube() in Dirichlet_construction.c,
 *	so their values shouldn't be changed.  (They are also toggled in
 *	Dirichlet_extras.c Dirichlet_conversion.c with the "not" operator '!'.)
 */

typedef int WEEdgeEnd;
enum
{
	tail = 0,
	tip  = 1
};

typedef int WEEdgeSide;
enum
{
	left  = 0,
	right = 1
};

/*
 *	The WEEdge structure keeps pointers to Tetrahedra for local use
 *	in Dirichlet_conversion.c.  The internal structure of a Tetrahedron
 *	is private to the kernel, so we must include an "opaque typedef" here.
 *	(Indeed even the existence of the Tetrahedron structure is private to
 *	the kernel, so we are "cheating" a bit even by including the typedef.)
 */
typedef struct Tetrahedron		TetrahedronSneak;


/*
 *	Forward declarations.
 */

typedef struct WEVertex			WEVertex;
typedef struct WEEdge			WEEdge;
typedef struct WEFace			WEFace;

typedef struct WEVertexClass	WEVertexClass;
typedef struct WEEdgeClass		WEEdgeClass;
typedef struct WEFaceClass		WEFaceClass;

typedef struct WEPolyhedron		WEPolyhedron;


struct WEVertex
{
	/*
	 *	The vector x gives the position of the WEVertex in the
	 *	projective model of hyperbolic 3-space.  The projective
	 *	model is viewed as a subset of the Minkowski space model,
	 *	so x is a 4-element vector with x[0] == 1.0.
	 */
	O31Vector		x;

	/*
	 *	The vector xx[] is an extra copy of x[] for local use in
	 *	the user interface.  Even as the polyhedron spins, the UI
	 *	should not modify x[], but should write the coordinates
	 *	of the rotated vertices into xx[] instead.  There are two
	 *	reasons for this:
	 *
	 *	(1)	This scheme avoids cumulative roundoff error in the
	 *		coordinates, which could in principle deform the
	 *		polyhedron.  One can argue that on a 680x0 Mac, which
	 *		has 8-byte mantissas, a polyhedron could spin for a
	 *		million years before enough error would accumulate
	 *		to make a 1-pixel difference on the screen.  However,
	 *		on an Iris, which uses floats instead of doubles, the
	 *		roundoff error is a real issue.  In any case, good
	 *		programming style dictates that a routine for displaying
	 *		a polyhedron should not alter the polyhedron it's
	 *		displaying.
	 *
	 *	(2)	If the user changes the Dehn filling coefficients
	 *		slightly, say from (7,1) to (8,1), the change in the
	 *		polyhedron will be small, and we'd like the new polyhedron
	 *		to appear in roughly the same position as the old one,
	 *		so the continuity is visible.  For this to occur, x[]
	 *		must always contain the polyhedron's initial position,
	 *		not its rotated position.
	 */
/*UNUSED IN OPENGL INTERFACE*/
	O31Vector		xx;

	/*
	 *	The distance from the vertex to the origin.  If the vertex is ideal,
	 *	dist is set to INFINITE_DISTANCE.  Even though just the distance is
	 *	given here, the UI may want to display cosh(dist) as well.
	 */
	double			dist;

	/*
	 *	Is this an ideal vertex?
	 */
	Boolean			ideal;

	/*
	 *	The solid angle at this vertex of the Dirichlet domain.
	 */
	double			solid_angle;

	/*
	 *	The Dirichlet domain's face pairings group the vertices
	 *	into vertex classes.
	 */
	WEVertexClass	*v_class;

	/*
	 *	The visible field is used while displaying the WEPolyhedron to
	 *	keep track of whether the vertex is visible to the user.
	 */
	Boolean			visible;

	/*
	 *	The distance_to_plane field is used locally within
	 *	Dirichlet_construction.c to record the inner product
	 *	of the WEVertex's location x[] with an arbitrary but
	 *	fixed normal vector to the hyperplane currently under
	 *	consideration.  Thus, distance_to_plane is proportional
	 *	to the Euclidean distance in the projective model from
	 *	the point (x[1], x[2], x[3]) to the intersection of the
	 *	hyperplane with the projective model (at x[0] == 1.0).
	 *
	 *	The which_side_of_plane field is +1, 0 or -1 according
	 *	to whether, after accounting for possible roundoff error,
	 *	distance_to_plane is positive, zero or negative, respectively.
	 */
	double			distance_to_plane;
	int				which_side_of_plane;

	/*
	 *	The zero_order field is used locally in check_topology_of_cut()
	 *	to verify that precisely zero or two 0-edges are incident to
	 *	each 0-vertex.
	 */
	int				zero_order;

	/*
	 *	The WEVertices are kept on a doubly-linked list.
	 */
	WEVertex		*prev,
					*next;

};


struct WEEdge
{
/*	2007-12-10  If I had this to do over, I'd use "half-edges" instead
 *	of whole edges.  Half-edges may always be oriented counterclockwise,
 *	which would simply the code.
 */

	/*
	 *	v[tail] and v[tip] are the vertices incident to the
	 *	tail and tip, respectively, of the directed WEEdge.
	 */
	WEVertex		*v[2];

	/*
	 *	e[tail][left]  is the WEEdge incident to both v[tail] and f[left].
	 *	e[tail][right] is the WEEdge incident to both v[tail] and f[right].
	 *	e[tip ][left]  is the WEEdge incident to both v[tip ] and f[left].
	 *	e[tip ][right] is the WEEdge incident to both v[tip ] and f[right].
	 */
	WEEdge			*e[2][2];

	/*
	 *	f[left] and f[right] are the faces incident to the
	 *	left and right sides, respectively, of the directed WEEdge.
	 */
	WEFace			*f[2];

	/*
	 *	The dihedral angle between edge->f[left] and edge->f[right].
	 */
	double			dihedral_angle;

	/*
	 *	dist_line_to_origin is the distance to the origin from the line
	 *		containing the edge.
	 *
	 *	dist_edge_to_origin is the distance to the origin from the edge
	 *		itself.  Usually this will be the same as dist_line_to_origin,
	 *		but occasionally the minimum distance from the line to the origin
	 *		will be realized at a point not on the edge itself.  In the latter
	 *		case the minimum distance from the origin to the edge itself will
	 *		be realized at an endpoint.
	 *
	 *	Note:  The UI may want to display the squared hyperbolic cosines
	 *	of the above distances, as well as the distances themselves.
	 *
	 *	closest_point_on_line and closest_point_on_edge record the points
	 *		at which the above minima are realized.  (At present the Mac UI
	 *		ignores these, but eventually we may want to display them to the
	 *		user upon request.)
	 */
	double			dist_line_to_origin,
					dist_edge_to_origin;
	O31Vector		closest_point_on_line,
					closest_point_on_edge;

	/*
	 *	How long is this edge?
	 *	If it's infinite, the length is set to INFINITE_LENGTH.
	 */
	double			length;

	/*
	 *	The Dirichlet domain's face pairings group the edges
	 *	into edge classes.
	 */
	WEEdgeClass		*e_class;

	/*
	 *	The visible field is used while displaying the WEPolyhedron to
	 *	keep track of whether the edge is visible to the user.
	 */
	Boolean			visible;

	/*
	 *	The Dirichlet domain's face identifications determine which sets
	 *	of edges are identified to single edges in the manifold itself.
	 *	For each edge on the Dirichlet domain,
	 *
	 *		edge->neighbor[left] tells the WEEdge to which the given edge
	 *			is mapped by edge->f[left]->group_element,
	 *
	 *		edge->preserves_sides[left] tell whether the left side of the
	 *			given edge maps to the left side of the image,
	 *
	 *		edge->preserves_direction[left] tells whether the mapping
	 *			preserves the direction of the edge, and
	 *
	 *		edge->preserves_orientation[left] tells whether the mapping
	 *			preserves orientation,
	 *
	 *	and similarly for edge->neighbor[right], etc.
	 *
	 *	The preserves_sides, preserves_direction and preserves_orientation
	 *	fields are intentionally redundant.  Any two determine the third.
	 *
	 *	If the singular set is empty or consists of disjoint circles (as will
	 *	always be the case for Dehn fillings on cusped manifolds), then the
	 *	function Dirichlet_bells_and_whistles() will redirect WEEdges as
	 *	necessary so that the preserves_direction[] fields are all TRUE.
	 *	Even for orbifolds with more complicated singular sets, it will
	 *	give consistent directions to the edges whenever possible.
	 */
	WEEdge			*neighbor[2];
	Boolean			preserves_sides[2],
					preserves_direction[2],
					preserves_orientation[2];

	/*
	 *	The tet[][] fields are used locally in Dirichlet_conversion.c
	 *	to construct a Triangulation for the manifold represented by
	 *	the Dirichlet domain.  Otherwise they may be ignored.
	 *	The four Tetrahedra incident to this WEEdge are tet[tail][left],
	 *	tet[tail][right], tet[tip][left], and tet[tip][right].
	 */
	TetrahedronSneak	*tet[2][2];

	/*
	 *	The WEEdges are kept on a doubly-linked list.
	 */
	WEEdge			*prev,
					*next;

};


struct WEFace
{
	/*
	 *	some_edge is an arbitrary WEEdge incident to the given WEFace.
	 */
	WEEdge			*some_edge;

	/*
	 *	mate is the WEFace which is identified to this face under
	 *	the action of the covering transformation group.
	 */
	WEFace			*mate;

	/*
	 *	group_element is the O(3,1) matrix which takes this face's mate
	 *	to this face.  In other words, this face lies in the plane which
	 *	passes orthogonally through the midpoint of the segment connecting
	 *	the origin to its (the origin's) image under the group_element.
	 */
	O31Matrix		*group_element;

	/*
	 *	The distance from the face plane to the origin.  The point of
	 *	closest approach may or may not lie on the face itself.
	 */
	double			dist;
	O31Vector		closest_point;

	/*
	 *	The to_be_removed field is used locally in install_new_face() in
	 *	Dirichlet_construction.c to record which WEFaces are to be removed.
	 */
	Boolean			to_be_removed;

	/*
	 *	The clean field is used locally in check_faces() in
	 *	Dirichlet_construction.c to record which WEFaces are known to be
	 *	subsets of their mates under the action of the group_element.
	 */
	Boolean			clean;

	/*
	 *	The copied field is used locally in rewrite_gen_list() and
	 *	(independently) in poly_to_current_list() in Dirichlet_construction.c
	 *	to record which WEFaces have had their group_elements copied to the
	 *	MatrixPairList.
	 */
	Boolean			copied;

	/*
	 *	The matched field show that the WEEdges incident to this face have
	 *	been matched with their neighbors incident to face->mate.
	 */
	Boolean			matched;

	/*
	 *	The visible field is used while displaying the WEPolyhedron to
	 *	keep track of whether the face is visible to the user.
	 *	(This field is likely to be irrelevant in a 3D graphics environment
	 * 	like OpenGL.)
	 */
	Boolean			visible;

	/*
	 *	How many sides does this face have?
	 */
	int				num_sides;

	/*
	 *	The face and its mate are assigned to the same WEFaceClass.
	 *	In the case of an orbifold, a face may be its own mate, in which
	 *	case the WEFaceClass will have only one element.
	 */
	WEFaceClass		*f_class;

	/*
	 *	The WEFaces are kept on a doubly-linked list.
	 */
	WEFace			*prev,
					*next;

};


/*
 *	The Dirichlet domain's face pairings identify the WEVertices, WEEdges
 *	and WEFaces into WEVertexClasses, WEEdgeClasses and WEFaceClasses.
 *	Each equivalence class is assigned an index.  (The indices are
 *	assigned consecutively, beginning at zero.)  The index is used
 *	to define a "hue", which is the suggested hue for that cell.
 *	The function index_to_hue() in index_to_hue.c assigns hues in such
 *	a way that the low-numbered cells' hues are all easily distinguishable
 *	from one another.  This is especially important for the WEFaceClasses.
 *	If there are a large number of faces we can't possibly hope that all
 *	the hues will be easily distinguishable, but we do want the hues of
 *	the largest faces (which are closest to the origin and have the lowest
 *	indices) to be easily distinguishable.
 */


struct WEVertexClass
{
	/*
	 *	At present the WEVertexClasses are listed in arbitrary order,
	 *	but if necessary they could easily be sorted to provide
	 *	some control over their hues, as is done for WEFaceClasses.
	 */
	int				index;
	double			hue;

	int				num_elements;

	/*
	 *	The total solid angle surrounding this vertex
	 *	(4pi for a manifold, 4pi/n for an orbifold).
	 */
	double			solid_angle;

	/*
	 *	The "n" in the preceding 4pi/n is recorded as the singularity_order.
	 *	(For ideal vertices, n is set to zero.)
	 */
	int				singularity_order;

	/*
	 *	Is this an ideal vertex class?
	 */
	Boolean			ideal;

	/*
	 *	All the vertices in the vertex class should be the same distance from
	 *	the origin.  Dirichlet_extras.c checks that the distances are indeed
	 *	approximately equal, and records their average here.
	 */
	double			dist;

	/*
	 *	min_dist and max_dist are used locally in vertex_distances()
	 *	in Dirichlet_extras.c to check that the dist values of the
	 *	constituent vertices are consistent.
	 */
	double			min_dist,
					max_dist;

	/*
	 *	belongs_to_region and is_3_ball are used locally in
	 *	compute_spine_radius() in Dirichlet_extras.c.
	 *	belongs_to_region keeps track of how various regions
	 *	have been united.  is_3_ball records which such unified
	 *	regions are topologically 3-balls.
	 */
	WEVertexClass	*belongs_to_region;
	Boolean			is_3_ball;

	/*
	 *	The WEVertexClasses are kept on a doubly-linked list.
	 */
	WEVertexClass	*prev,
					*next;
};


struct WEEdgeClass
{
	/*
	 *	At present the WEEdgeClasses are listed in arbitrary order,
	 *	but if necessary they could easily be sorted to provide
	 *	some control over their hues, as is done for WEFaceClasses.
	 */
	int				index;
	double			hue;

	int				num_elements;

	/*
	 *	The total dihedral angle surrounding this edge
	 *	(2pi for a manifold, 2pi/n for an orbifold).
	 */
	double			dihedral_angle;

	/*
	 *	The "n" in the preceding 2pi/n is recorded as the singularity_order.
	 */
	int				singularity_order;

	/*
	 *	All the edges in the edge class should be the same distance from
	 *	the origin.  Dirichlet_extras.c checks that the distances are indeed
	 *	approximately equal, and records their average here.
	 */
	double			dist_line_to_origin,
					dist_edge_to_origin;

	/*
	 *	How long is the identified edge?
	 *	If it's infinite, the length is set to INFINITE_LENGTH.
	 */
	double			length;

	/*
	 *	Performing the face identifications on the Dirichlet domain gives
	 *	a manifold or orbifold.  The link of the midpoint of an edge will
	 *	be a 2-orbifold.
	 */
	Orbifold2		link;

	/*
	 *	min_line_dist and max_line_dist are used locally in edge_distances()
	 *	in Dirichlet_extras.c to check that the dist_line_to_origin values
	 *	of the constituent edges are consistent.
	 */
	double			min_line_dist,
					max_line_dist;

	/*
	 *	min_length and max_length are used locally in edge_lengths()
	 *	in Dirichlet_extras.c to check that the length values
	 *	of the constituent edges are consistent.
	 */
	double			min_length,
					max_length;

	/*
	 *	removed is used locally in compute_spine_radius() in Dirichlet_extras.c
	 *	to keep track of which 2-cells in the dual spine have been removed.
	 */
	Boolean			removed;

	/*
	 *	The WEEdgeClasses are kept on a doubly-linked list.
	 */
	WEEdgeClass		*prev,
					*next;
};


struct WEFaceClass
{
	/*
	 *	Indices are assigned to face classes in order of increasing
	 *	distance from the origin.  The closest face class gets index 0,
	 *	the next closest gets index 1, etc.  (The distance is actually the
	 *	distance from the origin to the plane containing the face, whether
	 *	or not the face happens to include the point where the plane is
	 *	closest to the origin.)
	 *
	 *	Lemma.  A face and its mate are the same distance from the origin.
	 *
	 *	Proof.  The face plane is midway between the origin and the
	 *	origin's image under the group_element.  d(g^-1(origin), origin)
	 *	= d(origin, g(origin)).  Q.E.D.
	 *
	 *	The function index_to_hue() in index_to_hue.c insures that
	 *	the largest faces have easily distinguishable colors.  For example,
	 *	a (37,1) Dehn surgery on the figure eight knot yields a Dirichlet
	 *	domain with a few large faces and many tiny ones.  We wouldn't want
	 *	to color the large faces with, say, twelve different shades of blue.
	 *	The index-to-hue conversion scheme spreads their hues evenly through
	 *	the spectrum.
	 */

	int				index;
	double			hue;

	/*
	 *	Typically a WEFaceClass will have two elements, but if a face is
	 *	glued to itself (in an orbifold), then the WEFaceClass will have
	 *	only one element.
	 */
	int				num_elements;

	/*
	 *	The distance from the face plane to the origin.  The point of
	 *	closest approach may or may not lie on the face itself.
	 */
	double			dist;

	/*
	 *	Is the gluing orientation_reversing or orientation_preserving?
	 */
	MatrixParity	parity;

	/*
	 *	The WEFaceClasses are kept on a doubly-linked list.
	 */
	WEFaceClass		*prev,
					*next;
};


struct WEPolyhedron
{
	int				num_vertices,
					num_edges,
					num_faces;

	int				num_finite_vertices,
					num_ideal_vertices;

	int				num_vertex_classes,
					num_edge_classes,
					num_face_classes;

	int				num_finite_vertex_classes,
					num_ideal_vertex_classes;

	/*
	 *	Because matrices in O(3,1) tend to accumulate roundoff error, it's
	 *	hard to get a good bound on the accuracy of the computed volume.
	 *	Nevertheless, the kernel computes the best value it can, with the
	 *	hope that it will aid the user in recognizing manifolds defined
	 *	by a set of generators.  (The volume of a manifold defined by
	 *	Dehn filling a Triangulation can be computed directly to great
	 *	accuracy, using the kernel's volume() function.)
	 */
	double			approximate_volume;
	 
	/*
	 *	The inradius is the radius of the largest sphere (centered at the
	 *		basepoint) which can be inscribed in the Dirichlet domain.
	 *	The outradius is the radius of the smallest sphere (centered at the
	 *		basepoint) which can be circumscribed about the Dirichlet domain.
	 *		The outradius will be infinite for cusped manifolds, in which
	 *		case it's set to INFINITE_RADIUS.
	 */
	double			inradius,
					outradius;

	/*
	 *	spine_radius is the infimum of the radii (measured from the origin)
	 *	of all spines dual to the Dirichlet domain.  compute_spine_radius()
	 *	in Dirichlet_extras.c shows that spine_radius equals the maximum
	 *	of dist_edge_to_origin over all edge classes.  The spine_radius
	 *	plays an essential role in the length spectrum routines.
	 *
	 *	Note:  In practice compute_spine_radius() removes selected 2-cells
	 *	from the spine to reduce its radius, and thereby reduce the time
	 *	required to compute length spectra.  Please see compute_spine_radius()
	 *	in Dirichlet_extras.c for details.
	 */
	double			spine_radius;

	/*
	 *	Each face pairing isometry is an element of SO(3,1), so the inner
	 *	products of its i-th column with its j-th column should be -1 (if
	 *	i = j = 0), +1 (if i = j != 0) or 0 (if i != j).  The greatest
	 *	deviation from these values (over all faces) is recorded in the
	 *	deviation field.
	 */
	double			deviation;

	/*
	 *	The geometric Euler characteristic of the quotient orbifold (i.e. the
	 *	orbifold obtained by doing the face identifications) is computed as
	 *
	 *						c[0] - c[1] + c[2] - c[3]
	 *
	 *	where
	 *
	 *		c[0] = the sum of the solid angles at the vertices divided by 4 pi,
	 *
	 *		c[1] = the sum of the dihedral angles at the edges divided by 2 pi,
	 *
	 *		c[2] = half the number of faces of the Dirichlet domain,
	 *
	 *		c[3] = the number of 3-cells, which is always one.
	 *
	 *	This corresponds to the definition of the Euler characteristic of an
	 *	orbifold, as explained in Chapter 5 of the 1991 version of Thurston's
	 *	notes.  It should, in theory, always come out to zero.  But since
	 *	we compute it using floating point approximations to the solid and
	 *	dihedral angles, it provides a measure of the numerical inaccuracies
	 *	in the computation.
	 */
	double			geometric_Euler_characteristic;

	/*
	 *	vertex_epsilon is used in the construction of the Dirichlet domain.
	 *	If the squared distance from a vertex to a hyperplane is within
	 *	vertex_epsilon of zero, the vertex is assumed to lie on the hyperplane.
	 *	If vertex_epsilon is too large, we won't be able to resolve the small
	 *	faces which occur in high order Dehn fillings.  If vertex_epsilon is
	 *	too small, we'll get spurious Dirichlet plane intersections for
	 *	manifolds with simple, symmetrical, non-general-position covering
	 *	transformation groups.
	 */
	double			vertex_epsilon;

	/*
	 *	The following dummy nodes serve as the beginnings and ends of the
	 *	doubly-linked lists of vertices, edges and faces.
	 */
	WEVertex		vertex_list_begin,
					vertex_list_end;
	WEEdge			edge_list_begin,
					edge_list_end;
	WEFace			face_list_begin,
					face_list_end;

	/*
	 *	The following dummy nodes serve as the beginnings and ends of the
	 *	doubly-linked lists of vertex classes, edge classes and face classes.
	 */
	WEVertexClass	vertex_class_begin,
					vertex_class_end;
	WEEdgeClass		edge_class_begin,
					edge_class_end;
	WEFaceClass		face_class_begin,
					face_class_end;

};

#endif