void reorient( Triangulation *manifold) { Tetrahedron *tet; for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) reverse_orientation(tet); if (manifold->orientability == oriented_manifold) { /* * The peripheral curves haven't gone anywhere, * but the sheets they are on are now considered * the left_handed sheets rather than the right_handed * sheets. So transfer them to what used to be the * left_handed sheets but are now the right_handed sheets. */ transfer_peripheral_curves(manifold); /* * To adhere to the orientation conventions for peripheral curves * (see the documentation at the top of peripheral_curves.c) * we must reverse the directions of all meridians. * * Note that it was the act of transferring the peripheral curves * from the left_handed to right_handed sheets -- note the reversal * of the Tetrahedra -- that caused the violation of the orientaiton * convention. In particular, curves in nonorientable manifold, even * on (double covers of) Klein bottle cusps, still respect the convention. */ reverse_all_meridians(manifold); /* * Adjust the edge orientations, too. */ make_all_edge_orientations_right_handed(manifold); } /* * The Chern-Simons invariant of the manifold will be negated, * and the fudge factor will be different. */ if (manifold->CS_value_is_known) { manifold->CS_value[ultimate] = - manifold->CS_value[ultimate]; manifold->CS_value[penultimate] = - manifold->CS_value[penultimate]; } compute_CS_fudge_from_value(manifold); }
FuncResult proto_canonize( Triangulation *manifold) { /* * 95/10/12 JRW * I added the needs_polishing flag so that the solution will be * polished iff it needs to be. In the past this was no big deal, * but now we want the cusp neighborhoods module to be able to * maintain a canonical triangulation in real time. If no changes * need to be made and all cusps are complete (so we don't have to * worry about restoring the filled solution), we want to get out * of here as quickly as possible. */ Boolean all_done, needs_polishing; int num_attempts, i; num_attempts = 0; needs_polishing = FALSE; do { /* * First make sure that a hyperbolic structure is present, and * all Tetrahedra are positively oriented. Overwrite the filled * structure with the complete one. */ if (manifold->solution_type[complete] == geometric_solution && all_cusps_are_complete(manifold) == TRUE) { /* * This is the express route. * * No polishing will be required if the triangulation is * already canonical, because the hyperbolic structure won't * change and there is no need to restore the filled solution. */ } else { /* * This is the generic algorithm. * * (validate_hyperbolic_structure() overwrites the filled * solution with the complete solution.) */ if (validate_hyperbolic_structure(manifold) == func_failed) { compute_CS_fudge_from_value(manifold); return func_failed; } needs_polishing = TRUE; } /* * Choose cusp cross sections bounding equal volumes, * and use the Tilt Theorem to compute the tilts. * (See "Convex hulls..." for details.) */ allocate_cross_sections(manifold); compute_cross_sections(manifold); compute_tilts(manifold); /* * Keep going through the following loop as long as we * continue to keep improving the triangulation. * Do not perform any operation (i.e. any two_to_three() * move) that would create negatively oriented Tetrahedra. * * It is possible to get into an infinite loop here, doing an * endless series of 2->3 and 3->2 moves, presumably * do to numerical instability. Thus the total number of * moves is capped. */ for(i = 0; i < MAX_MOVES*manifold->num_tetrahedra; i++) { /* * Cancel pairs of Tetrahedra sharing an EdgeClass * of order two. (Since the Triangulation contains * no negatively oriented Tetrahedra, Tetrahedra sharing * an EdgeClass of order two will be within epsilon of * being flat.) */ if (attempt_cancellation(manifold) == TRUE) { needs_polishing = TRUE; continue; } /* * Perform 3-2 moves whereever necessary. */ if (attempt_three_to_two(manifold) == TRUE) { needs_polishing = TRUE; continue; } /* * Perform 2-3 moves whereever necessary. */ if (attempt_two_to_three(manifold) == TRUE) { needs_polishing = TRUE; continue; } /* * We can't make any more progress. * Break out of the loop, and then check whether we've * really found a subdivision of the canonical cell * decomposition, or whether we've had the misfortune to * get stuck on (potential) negatively oriented Tetrahedra. */ break; } /* * We don't need the VertexCrossSections any more, so * we might as well get rid of them before (possibly) * randomizing the manifold. */ free_cross_sections(manifold); /* * Did we really find a subdivision of the canonical * cell decomposition? * Or did we just get stuck on (potential) negatively * oriented Tetrahedra? */ all_done = validate_canonical_triangulation(manifold); /* * If we got stuck on (potential) negatively oriented * Tetrahedra, randomize the Triangulation and try * again. */ if (all_done == FALSE) randomize_triangulation(manifold); /* * The documentation says that if a hyperbolic structure * with all positively oriented tetrahedra is present, then * proto_canonize() will never fail. And indeed with enough * random retriangulations it should always be able to find * a subdivision of the canonical cell decomposition. But * if a bug shows up somewhere we don't want this loop to run * forever, so if num_attempts exceeds MAX_ATTEMPTS we should * declare a fatal error and quit. */ if (++num_attempts > MAX_ATTEMPTS) uFatalError("proto_canonize", "canonize_part_1"); } while (all_done == FALSE); /* * Clean up. */ if (needs_polishing == TRUE) { /* * polish_hyperbolic_structures() takes responsibility for * the shape_histories. */ tidy_peripheral_curves(manifold); polish_hyperbolic_structures(manifold); /* * If the Chern-Simons invariant is present, update the fudge factor. */ compute_CS_fudge_from_value(manifold); } return func_OK; }