/* Determine whether a side is in check * @param si identifies the check tester * @param side_in_check which side? * @return true iff side_in_check is in check according to slice si */ boolean exctinction_all_piece_observation_tester_is_in_check(slice_index si, Side side_attacked) { boolean result = false; square const *bnp; TraceFunctionEntry(__func__); TraceFunctionParam("%u",si); TraceEnumerator(Side,side_attacked,""); TraceFunctionParamListEnd(); for (bnp = boardnum; *bnp; ++bnp) if (TSTFLAG(being_solved.spec[*bnp],side_attacked)) { replace_observation_target(*bnp); if (is_square_observed(EVALUATE(check))) { result = true; break; } } TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
static Boolean would_create_negatively_oriented_tetrahedra( Tetrahedron *tet0, FaceIndex f0) { Permutation gluing; Tetrahedron *tet1; FaceIndex f1, side0, side1; gluing = tet0->gluing[f0]; tet1 = tet0->neighbor[f0]; f1 = EVALUATE(gluing, f0); /* * tet0 and tet1 meet at a common 2-simplex. For each edge * of that 2-simplex, add the incident dihedral angles of * tet0 and tet1. If any such sum is greater than pi, then * the two_to_three() move would create a negatively oriented * Tetrahedron on that side, and we return TRUE. Otherwise * no negatively oriented Tetrahedra will be created, and we * return FALSE. * * Choose ANGLE_EPSILON to allow the creation of Tetrahedra which * are just barely negatively oriented, but essentially flat. */ for (side0 = 0; side0 < 4; side0++) { if (side0 == f0) continue; side1 = EVALUATE(gluing, side0); if (tet0->shape[complete]->cwl[ultimate][edge3_between_faces[f0][side0]].log.imag + tet1->shape[complete]->cwl[ultimate][edge3_between_faces[f1][side1]].log.imag > PI + ANGLE_EPSILON) return TRUE; } return FALSE; }
static void find_mates( PerimeterPiece *perimeter_anchor) { PerimeterPiece *pp; Tetrahedron *nbr_tet; Permutation gluing; VertexIndex nbr_vertex; FaceIndex nbr_face; /* * First tell the tetrahedra about the PerimeterPieces. */ pp = perimeter_anchor; do { pp->tet->extra[pp->vertex].its_perimeter_piece[pp->face] = pp; pp = pp->next; } while (pp != perimeter_anchor); /* * Now let each PerimeterPiece figure out who its mate is. */ pp = perimeter_anchor; do { nbr_tet = pp->tet->neighbor[pp->face]; gluing = pp->tet->gluing[pp->face]; nbr_vertex = EVALUATE(gluing, pp->vertex); nbr_face = EVALUATE(gluing, pp->face); pp->mate = nbr_tet->extra[nbr_vertex].its_perimeter_piece[nbr_face]; pp->gluing_parity = (pp->orientation == pp->mate->orientation) == (parity[gluing] == orientation_preserving) ? orientation_preserving : orientation_reversing; pp = pp->next; } while (pp != perimeter_anchor); }
static Real sum_of_tilts( Tetrahedron *tet0, FaceIndex f0) { Tetrahedron *tet1; FaceIndex f1; tet1 = tet0->neighbor[f0]; f1 = EVALUATE(tet0->gluing[f0], f0); return ( tet0->tilt[f0] + tet1->tilt[f1] ); }
static boolean is_mover_supported(numecoup n) { boolean result; TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); siblingply(trait[nbply]); push_observation_target(move_generation_stack[n].departure); result = is_square_observed(EVALUATE(observer)); finply(); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
static boolean is_target_unguarded(numecoup n) { boolean result; TraceFunctionEntry(__func__); TraceFunctionParam("%u",n); TraceFunctionParamListEnd(); siblingply(advers(trait[nbply])); push_observation_target(move_generation_stack[n].capture); result = !is_square_observed(EVALUATE(observer)); finply(); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
static boolean is_mover_supported_recursive(void) { boolean result; Flags const mask = BIT(trait[nbply])|BIT(Royal); TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); TraceSquare(move_generation_stack[CURRMOVE_OF_PLY(nbply)].capture); TraceEOL(); if (TSTFULLFLAGMASK(being_solved.spec[move_generation_stack[CURRMOVE_OF_PLY(nbply)].capture],mask)) result = true; else result = is_square_observed(EVALUATE(observation)); TraceFunctionExit(__func__); TraceFunctionResult("%u",result); TraceFunctionResultEnd(); return result; }
static void PushMagicViewsByOnePiece(piece_walk_type pi_magic) { square const *pos_viewed; TraceFunctionEntry(__func__); TraceWalk(pi_magic); TraceFunctionParamListEnd(); for (pos_viewed = boardnum; *pos_viewed; pos_viewed++) if (get_walk_of_piece_on_square(*pos_viewed)>Invalid && !TSTFLAGMASK(being_solved.spec[*pos_viewed],BIT(Magic)|BIT(Royal)) && !is_piece_neutral(being_solved.spec[*pos_viewed])) { replace_observation_target(*pos_viewed); observing_walk[nbply] = pi_magic; /* ignore return value - it's ==false */ fork_is_square_observed_nested_delegate(temporary_hack_is_square_observed_specific[trait[nbply]], EVALUATE(observation)); } TraceFunctionExit(__func__); TraceFunctionResultEnd(); }
static boolean is_attacked_exactly_once(square sq_departure, Side trait_ply) { TraceFunctionEntry(__func__); TraceFunctionParamListEnd(); assert(!are_we_counting); are_we_counting = true; amu_attack_count = 0; single_attacker_departure = initsquare; is_square_observed_general_post_move_iterator_solve(advers(trait_ply), sq_departure, EVALUATE(observation)); are_we_counting = false; TraceFunctionExit(__func__); TraceFunctionResult("%u",amu_attack_count==1); TraceFunctionResultEnd(); return amu_attack_count==1; }
static Boolean is_isometry_plausible( Tetrahedron *initial_tet0, Tetrahedron *initial_tet1, Permutation initial_map) { /* * To check whether an Isometry taking initial_tet0 to * initial_tet1 via initial_map is even plausible, let's * check whether their EdgeClass orders match up. */ int i, j; for (i = 0; i < 4; i++) for (j = i + 1; j < 4; j++) { if (initial_tet0->edge_class[edge_between_vertices[i][j]]->order != initial_tet1->edge_class[edge_between_vertices[EVALUATE(initial_map, i)] [EVALUATE(initial_map, j)]]->order) return FALSE; if (initial_tet0->edge_class[edge_between_vertices[i][j]]->is_singular != initial_tet1->edge_class[edge_between_vertices[EVALUATE(initial_map, i)] [EVALUATE(initial_map, j)]]->is_singular) return FALSE; if (initial_tet0->edge_class[edge_between_vertices[i][j]]->is_singular && initial_tet0->edge_class[edge_between_vertices[i][j]]->singular_order != initial_tet1->edge_class[edge_between_vertices[EVALUATE(initial_map, i)] [EVALUATE(initial_map, j)]]->singular_order) return FALSE; } return TRUE; }
static FuncResult attempt_isometry( Triangulation *manifold0, Tetrahedron *initial_tet0, Tetrahedron *initial_tet1, Permutation initial_map, int *singular_map ) { Tetrahedron *tet0, *tet1, *nbr0, *nbr1, **queue; EdgeClass *edge0, *edge1; int first, last, i, j; FaceIndex face0, face1; Permutation gluing0, gluing1, nbr0_map; /* * initial_tet1 and initial_map are arbitrary, so * the vast majority of calls to attempt_isometry() * will fail. Therefore it's worth including a quick * plausibility check at the beginning, to make the * algorithm run faster. */ if (is_isometry_plausible(initial_tet0, initial_tet1, initial_map) == FALSE) return func_failed; /* * Initialize all the image fields of manifold0 * to NULL to show they haven't been set. */ for ( tet0 = manifold0->tet_list_begin.next; tet0 != &manifold0->tet_list_end; tet0 = tet0->next) tet0->image = NULL; /* * Allocate space for a queue which is large enough * to hold pointers to all the Tetrahedra in manifold0. */ queue = NEW_ARRAY(manifold0->num_tetrahedra, Tetrahedron *); /* * At all times, the Tetrahedra on the queue will be those which * * (1) have set their image and map fields, but * * (2) have not checked their neighbors. */ /* * Set the image and map fields for initial_tet0. */ initial_tet0->image = initial_tet1; initial_tet0->map = initial_map; /* * Put initial_tet0 on the queue. */ first = 0; last = 0; queue[first] = initial_tet0; /* * While there are Tetrahedra on the queue . . . */ while (last >= first) { /* * Pull the first Tetrahedron off the queue and call it tet0. */ tet0 = queue[first++]; /* * tet0 maps to some Tetrahedron tet1 in manifold1. */ tet1 = tet0->image; /* we will keep track on how the singular edges in manifold0 map into manifold1 */ for(i=0;i<4;i++) for(j=i+1;j<4;j++) { edge0 = tet0->edge_class[edge_between_vertices[i][j]]; edge1 = tet1->edge_class[edge_between_vertices[EVALUATE(tet0->map, i)] [EVALUATE(tet0->map, j)]]; if (edge0->order != edge1->order ) { my_free(queue); return func_failed; } if (edge0->is_singular != edge1->is_singular ) { my_free(queue); return func_failed; } if (edge0->is_singular && edge0->singular_order != edge1->singular_order ) { my_free(queue); return func_failed; } if (singular_map != NULL && edge0->is_singular ) singular_map[edge0->singular_index] = edge1->singular_index; } /* * For each face of tet0 . . . */ for (face0 = 0; face0 < 4; face0++) { /* * Let nbr0 be the Tetrahedron which meets tet0 at face0. */ nbr0 = tet0->neighbor[face0]; /* * tet0->map takes face0 of tet0 to face1 of tet1. */ face1 = EVALUATE(tet0->map, face0); /* * Let nbr1 be the Tetrahedron which meets tet1 at face1. */ nbr1 = tet1->neighbor[face1]; /* * Let gluing0 be the gluing which identifies face0 of * tet0 to nbr0, and similarly for gluing1. */ gluing0 = tet0->gluing[face0]; gluing1 = tet1->gluing[face1]; /* * gluing0 * tet0 ------> nbr0 * | | * tet0->map | | nbr0->map * | | * V gluing1 V * tet1 ------> nbr1 * * We want to ensure that tet1 and nbr1 enjoy the same * relationship to each other in manifold1 that tet0 and * nbr0 do in manifold0. The conditions * * nbr0->image == nbr1 * and * nbr0->map == gluing1 o tet0->map o gluing0^-1 * * are necessary and sufficient to insure that we have a * combinatorial equivalence between the Triangulations. * (The proof relies on the fact that we've already checked * (near the beginning of compute_cusped_isometries() above) * that the Triangulations have the same number of Tetrahedra; * otherwise one Triangulation could be a (possibly branched) * covering of the other.) */ /* * Compute the required value for nbr0->map. */ nbr0_map = compose_permutations( compose_permutations( gluing1, tet0->map ), inverse_permutation[gluing0] ); /* * If nbr0->image and nbr0->map have already been set, * check that they satisfy the above conditions. */ if (nbr0->image != NULL) { if (nbr0->image != nbr1 || nbr0->map != nbr0_map) { /* * This isn't an isometry. */ my_free(queue); return func_failed; } } /* * else . . . * nbr0->image and nbr0->map haven't been set. * Set them, and put nbr0 on the queue. */ else { if (!is_isometry_plausible(nbr0,nbr1,nbr0_map)) { my_free(queue); return func_failed; } nbr0->image = nbr1; nbr0->map = nbr0_map; queue[++last] = nbr0; } } } /* * A quick error check. * Is it plausible that each Tetrahedron * has been on the queue exactly once? */ if (first != manifold0->num_tetrahedra || last != manifold0->num_tetrahedra - 1) uFatalError("attempt_isometry", "isometry"); /* * Free the queue, and report success. */ my_free(queue); return func_OK; }
int gss(double a, double b, double *_min, double *_fmin, gss_evaluate_t proc_evaluate, gss_progress_t proc_progress, void* instance, const gss_parameter_t *_param) { double c, d, min = NAN; double fa, fb, fc, fd, fmin = INFINITY; int k = 0; int retval; unsigned short int successful = 1; gss_parameter_t param = _param ? (*_param) : _defparam; gss_i_warning_flag = 0; if (a > b) { c = a; a = b; b = c; } c = a + RESPHI*(b-a); EVALUATE(a, fa); EVALUATE(b, fb); EVALUATE(c, fc); if (fc >= fa || fc >= fb) { if (param.on_error == GSS_ERROR_STOP) { return PLFIT_FAILURE; } else { gss_i_warning_flag = 1; } } while (fabs(a-b) > param.epsilon) { k++; d = c + RESPHI*(b-c); EVALUATE(d, fd); if (fd >= fa || fd >= fb) { if (param.on_error == GSS_ERROR_STOP) { successful = 0; break; } else { gss_i_warning_flag = 1; } } if (fc <= fd) { b = a; a = d; } else { a = c; c = d; fc = fd; } } if (successful) { c = (a+b) / 2.0; k++; EVALUATE(c, fc); TERMINATE; } return successful ? PLFIT_SUCCESS : PLFIT_FAILURE; }
static void renumber_neighbors_and_gluings( Tetrahedron *tet) { Tetrahedron *temp_neighbor; Permutation temp_gluing; int i, j, d[4], temp_digit; Tetrahedron *nbr_tet; /* * Renumbering the neighbors is easy: we simply swap * neighbor[2] and neighbor[3]. */ temp_neighbor = tet->neighbor[2]; tet->neighbor[2] = tet->neighbor[3]; tet->neighbor[3] = temp_neighbor; /* * Renumbering the gluings is trickier, because three * changes are required: * * Change A: Swap gluing[2] and gluing[3]. * * Change B: Within each gluing of tet, swap the image of * vertex 2 and the image of vertex 3, e.g. 0312 -> 3012. * * Change C: For each gluing of a face (typically of a Tetrahedron * other than tet) that glues to tet, interchange * 2 and 3, e.g. 0312 -> 0213. */ /* * Change A: Swap gluing[2] and gluing[3]. */ temp_gluing = tet->gluing[2]; tet->gluing[2] = tet->gluing[3]; tet->gluing[3] = temp_gluing; /* * Changes B and C are carried out for each of the four gluings of tet. */ for (i = 0; i < 4; i++) { /* * Change B: Swap the image of vertex 2 and the image of vertex 3. */ /* * Unpack the digits of the gluing. */ for (j = 0; j < 4; j++) { d[j] = tet->gluing[i] & 0x3; tet->gluing[i] >>= 2; } /* * Swap the digits in positions 2 and 3. */ temp_digit = d[3]; d[3] = d[2]; d[2] = temp_digit; /* * Repack the digits. */ for (j = 4; --j >= 0; ) { tet->gluing[i] <<= 2; tet->gluing[i] += d[j]; } /* * Change C: Fix up the inverse of tet->gluing[i]. * * If tet->neighbor[i] != tet, we simply write the inverse of * tet->gluing[i] into the appropriate gluing field of the neighbor. * * If tet->neighbor[i] == tet, the simple approach doesn't work * because of the messy interaction between Changes B and C. * Instead, we exploit the fact that tet->gluing[i] is the inverse * of some other gluing of tet, and apply Change C directly to * tet->gluing[i] rather than its inverse. */ nbr_tet = tet->neighbor[i]; if (nbr_tet != tet) /* * Write the inverse directly. */ nbr_tet->gluing[EVALUATE(tet->gluing[i],i)] = inverse_permutation[tet->gluing[i]]; else { /* * Perform Change C on tet->gluing[i]. */ /* * Unpack the digits. */ for (j = 0; j < 4; j++) { d[j] = tet->gluing[i] & 0x3; tet->gluing[i] >>= 2; } /* * Swap 2 and 3 in the images. */ for (j = 0; j < 4; j++) switch (d[j]) { case 0: case 1: /* leave d[j] alone */ break; case 2: d[j] = 3; break; case 3: d[j] = 2; break; } /* * Repack the digits. */ for (j = 4; --j >= 0; ) { tet->gluing[i] <<= 2; tet->gluing[i] += d[j]; } } } }
static void visit_tetrahedra( Triangulation *manifold, Boolean compute_corners, Boolean centroid_at_origin) { Tetrahedron **queue, *tet; int queue_first, queue_last; Tetrahedron *nbr_tet; Permutation gluing; FaceIndex face, nbr_face; int i; VertexIndex nbr_i; /* * choose_generators() has already called initialize_flags(). */ /* * Initialize num_generators to zero. */ manifold->num_generators = 0; /* * Allocate space for a queue of pointers to the Tetrahedra. * Each Tetrahedron will appear on the queue exactly once, * so an array of length manifold->num_tetrahedra will be just right. */ queue = NEW_ARRAY(manifold->num_tetrahedra, Tetrahedron *); /* * Initialize the queue. */ queue_first = 0; queue_last = 0; /* * Choose the initial Tetrahedron according to some criterion. * If compute_corners is TRUE, position its corners. * 2000/4/2 The choice of initial tetrahedron is independent * of compute_corners. */ initial_tetrahedron(manifold, &queue[0], compute_corners, centroid_at_origin); /* * Mark the initial Tetrahedron as visited. */ queue[0]->generator_path = -1; queue[0]->flag = right_handed; /* * Start processing the queue. */ do { /* * Pull a Tetrahedron off the front of the queue. */ tet = queue[queue_first++]; /* * Look at the four neighboring Tetrahedra. */ for (face = 0; face < 4; face++) { /* * Note who the neighbor is, and which of * its faces we're glued to. */ nbr_tet = tet->neighbor[face]; gluing = tet->gluing[face]; nbr_face = EVALUATE(gluing, face); /* * If nbr_tet hasn't been visited, set the appropriate * generator_statuses to not_a_generator, and then put * nbr_tet on the back of the queue. */ if (nbr_tet->flag == unknown_orientation) { tet ->generator_status[face] = not_a_generator; nbr_tet->generator_status[nbr_face] = not_a_generator; tet ->generator_index[face] = -1; /* garbage value */ nbr_tet->generator_index[nbr_face] = -1; nbr_tet->generator_path = nbr_face; nbr_tet->flag = (parity[gluing] == orientation_preserving) ? tet->flag : ! tet->flag; if (compute_corners) { for (i = 0; i < 4; i++) { if (i == face) continue; nbr_i = EVALUATE(gluing, i); nbr_tet->corner[nbr_i] = tet->corner[i]; } compute_fourth_corner( nbr_tet->corner, /* array of corner coordinates */ nbr_face, /* the corner to be computed */ nbr_tet->flag, /* nbr_tet's current orientation */ nbr_tet->shape[filled]->cwl[ultimate]); /* shapes */ } queue[++queue_last] = nbr_tet; } /* * If nbr_tet has been visited, check whether a generator * has been assigned to common face, and if not, assign one. */ else if (tet->generator_status[face] == unassigned_generator) { tet ->generator_status[face] = outbound_generator; nbr_tet->generator_status[nbr_face] = inbound_generator; tet ->generator_index[face] = manifold->num_generators; nbr_tet->generator_index[nbr_face] = manifold->num_generators; tet ->generator_parity[face] = nbr_tet->generator_parity[nbr_face] = ((parity[gluing] == orientation_preserving) == (tet->flag == nbr_tet->flag)) ? orientation_preserving : orientation_reversing; manifold->num_generators++; } } } while (queue_first <= queue_last); /* * Free the memory used for the queue. */ my_free(queue); /* * An "unnecessary" (but quick) error check. */ if ( queue_first != manifold->num_tetrahedra || queue_last != manifold->num_tetrahedra - 1) uFatalError("visit_tetrahedra", "choose_generators"); }
static void compute_singular_action( Triangulation *manifold, Isometry *isometry) { Boolean lower_index_is_at_top; EdgeIndex index, image_index; VertexIndex image_v1,image_v2,v1,v2; Tetrahedron *tet, *image_tet; EdgeClass *edge, *image_edge; PositionedTet ptet, ptet0; for( edge = manifold->edge_list_begin.next; edge!=&manifold->edge_list_end; edge = edge->next ) if (edge->is_singular) { if (edge->singular_index<0) uFatalError("compute_singular_action","isometry_cusped"); tet = edge->incident_tet; index = edge->incident_edge_index; v1 = MIN(one_vertex_at_edge[index], other_vertex_at_edge[index]); v2 = MAX(one_vertex_at_edge[index], other_vertex_at_edge[index]); image_tet = tet->image; image_v1 = EVALUATE(tet->map,v1); image_v2 = EVALUATE(tet->map,v2); image_index = edge_between_vertices[image_v1][image_v2]; image_edge = image_tet->edge_class[image_index]; if (image_edge->singular_index<0 || image_edge->singular_order != edge->singular_order ) uFatalError("compute_singular_action","isometry_cusped"); /* i have never kept track of a direction only the singular edges. prehaps this is something i should be doing... * for now, here is how we'll kept track of orientation of these maps from singular edge to singular edge: * each edge has an incident tet and an incident edge index, define an ordering on the ends of the singular * edge by the ordering of the vertex indices of this edge. * * there may be some clever way of doing this with the handedness of the edge classes. i am not sure. */ set_left_edge( image_edge, &ptet0 ); ptet = ptet0; lower_index_is_at_top = ( ptet.bottom_face < ptet.right_face ); isometry->singular_image[edge->singular_index] = 0; do{ if (ptet.tet == image_tet && edge_between_faces[ptet.near_face][ptet.left_face] == image_index) { if (lower_index_is_at_top) { if (image_v1 == ptet.bottom_face) isometry->singular_image[edge->singular_index] = image_edge->singular_index + 1; else isometry->singular_image[edge->singular_index] = -(image_edge->singular_index + 1); } else { if (image_v1 == ptet.bottom_face) isometry->singular_image[edge->singular_index] = -(image_edge->singular_index + 1); else isometry->singular_image[edge->singular_index] = image_edge->singular_index + 1; } break; } veer_left( &ptet ); }while(!same_positioned_tet( &ptet0, &ptet )); if (isometry->singular_image[edge->singular_index] == 0) uFatalError("compute_singular_action","isometry_cusped"); } }
static void expand_perimeter( PerimeterPiece *perimeter_anchor) { int num_unchecked_pieces; PerimeterPiece *pp, *new_piece; Permutation gluing; Tetrahedron *nbr_tet; VertexIndex nbr_vertex; FaceIndex nbr_back_face, nbr_left_face, nbr_right_face; Orientation nbr_orientation; for (num_unchecked_pieces = 3, pp = perimeter_anchor; num_unchecked_pieces; pp = pp->next) if (pp->checked == FALSE) { gluing = pp->tet->gluing[pp->face]; nbr_tet = pp->tet->neighbor[pp->face]; nbr_vertex = EVALUATE(gluing, pp->vertex); if (nbr_tet->extra[nbr_vertex].visited) { pp->checked = TRUE; num_unchecked_pieces--; } else { /* * Extend the tree to the neighboring vertex. */ nbr_back_face = EVALUATE(gluing, pp->face); if (parity[gluing] == orientation_preserving) nbr_orientation = pp->orientation; else nbr_orientation = ! pp->orientation; if (nbr_orientation == right_handed) { nbr_left_face = remaining_face[nbr_vertex][nbr_back_face]; nbr_right_face = remaining_face[nbr_back_face][nbr_vertex]; } else { nbr_left_face = remaining_face[nbr_back_face][nbr_vertex]; nbr_right_face = remaining_face[nbr_vertex][nbr_back_face]; } nbr_tet->extra[nbr_vertex].visited = TRUE; nbr_tet->extra[nbr_vertex].parent_tet = pp->tet; nbr_tet->extra[nbr_vertex].parent_vertex = pp->vertex; nbr_tet->extra[nbr_vertex].this_faces_parent = nbr_back_face; nbr_tet->extra[nbr_vertex].parent_faces_this = pp->face; nbr_tet->extra[nbr_vertex].orientation = nbr_orientation; /* * Extend the perimeter across the neighboring * vertex. The new PerimeterPiece is added on * the right side of the old one, so that the * pp = pp->next step in the loop moves us past * both the old and new perimeter pieces. This * causes the perimeter to expand uniformly in * all directions. */ new_piece = NEW_STRUCT(PerimeterPiece); new_piece->tet = nbr_tet; new_piece->vertex = nbr_vertex; new_piece->face = nbr_right_face; new_piece->orientation = nbr_orientation; new_piece->checked = FALSE; new_piece->next = pp; new_piece->prev = pp->prev; pp->prev->next = new_piece; pp->tet = nbr_tet; pp->vertex = nbr_vertex; pp->face = nbr_left_face; pp->orientation = nbr_orientation; pp->checked = FALSE; /* unchanged */ pp->next = pp->next; /* unchanged */ pp->prev = new_piece; /* * Increment the count of unchecked pieces. */ num_unchecked_pieces++; } } }
static void drill_tube( Triangulation *manifold, Tetrahedron *tet, EdgeIndex e, Boolean creating_new_cusp) { /* * Insert a triangular-pillow-with-tunnel (as described at the top * of this file) so as to connect the boundary component at one * end of the given edge to the boundary component at the other end. * The orientation on the triangular pillow will match the * orientation on tet, so that the orientation on the manifold * (if there is one) will be preserved. Edge orientations are also * respected. */ VertexIndex v0, v1, v2, vv0, vv1, vv2; FaceIndex f, ff; Tetrahedron *nbr_tet, *new_tet0, *new_tet1; Permutation gluing; EdgeClass *edge0, *edge1, *edge2, *new_edge; Orientation edge_orientation0, edge_orientation1, edge_orientation2; PeripheralCurve c; Orientation h; int num_strands, intersection_number[2], the_gcd; Cusp *unique_cusp; MatrixInt22 basis_change[1]; /* * Relative to the orientation of tet, the vertices v0, v1 and v2 * are arranged in counterclockwise order around the face f. */ v0 = one_vertex_at_edge[e]; v1 = other_vertex_at_edge[e]; v2 = remaining_face[v1][v0]; f = remaining_face[v0][v1]; /* * Note the matching face and its vertices. */ nbr_tet = tet->neighbor[f]; gluing = tet->gluing[f]; ff = EVALUATE(gluing, f); vv0 = EVALUATE(gluing, v0); vv1 = EVALUATE(gluing, v1); vv2 = EVALUATE(gluing, v2); /* * Note the incident EdgeClasses (which may or may not be distinct). */ edge0 = tet->edge_class[e]; edge1 = tet->edge_class[edge_between_vertices[v1][v2]]; edge2 = tet->edge_class[edge_between_vertices[v2][v0]]; /* * Construct the triangular-pillow-with-tunnel, as described * at the top of this file. */ new_tet0 = NEW_STRUCT(Tetrahedron); new_tet1 = NEW_STRUCT(Tetrahedron); initialize_tetrahedron(new_tet0); initialize_tetrahedron(new_tet1); INSERT_BEFORE(new_tet0, &manifold->tet_list_end); INSERT_BEFORE(new_tet1, &manifold->tet_list_end); manifold->num_tetrahedra += 2; new_edge = NEW_STRUCT(EdgeClass); initialize_edge_class(new_edge); INSERT_BEFORE(new_edge, &manifold->edge_list_end); new_tet0->neighbor[0] = new_tet1; new_tet0->neighbor[1] = NULL; /* assigned below */ new_tet0->neighbor[2] = NULL; /* assigned below */ new_tet0->neighbor[3] = new_tet1; new_tet1->neighbor[0] = new_tet0; new_tet1->neighbor[1] = new_tet1; new_tet1->neighbor[2] = new_tet1; new_tet1->neighbor[3] = new_tet0; new_tet0->gluing[0] = CREATE_PERMUTATION(0, 0, 1, 2, 2, 1, 3, 3); new_tet0->gluing[1] = 0x00; /* assigned below */ new_tet0->gluing[2] = 0x00; /* assigned below */ new_tet0->gluing[3] = CREATE_PERMUTATION(0, 1, 1, 0, 2, 2, 3, 3); new_tet1->gluing[0] = CREATE_PERMUTATION(0, 0, 1, 2, 2, 1, 3, 3); new_tet1->gluing[1] = CREATE_PERMUTATION(0, 0, 1, 2, 2, 1, 3, 3); new_tet1->gluing[2] = CREATE_PERMUTATION(0, 0, 1, 2, 2, 1, 3, 3); new_tet1->gluing[3] = CREATE_PERMUTATION(0, 1, 1, 0, 2, 2, 3, 3); new_tet0->edge_class[0] = edge1; new_tet0->edge_class[1] = edge1; new_tet0->edge_class[2] = edge0; new_tet0->edge_class[3] = edge2; new_tet0->edge_class[4] = edge0; new_tet0->edge_class[5] = edge0; new_tet1->edge_class[0] = edge1; new_tet1->edge_class[1] = edge1; new_tet1->edge_class[2] = edge0; new_tet1->edge_class[3] = new_edge; new_tet1->edge_class[4] = edge0; new_tet1->edge_class[5] = edge0; edge0->order += 6; edge1->order += 4; edge2->order += 1; new_edge->order = 1; new_edge->incident_tet = new_tet1; new_edge->incident_edge_index = 3; edge_orientation0 = tet->edge_orientation[e]; edge_orientation1 = tet->edge_orientation[edge_between_vertices[v1][v2]]; edge_orientation2 = tet->edge_orientation[edge_between_vertices[v2][v0]]; new_tet0->edge_orientation[0] = edge_orientation1; new_tet0->edge_orientation[1] = edge_orientation1; new_tet0->edge_orientation[2] = edge_orientation0; new_tet0->edge_orientation[3] = edge_orientation2; new_tet0->edge_orientation[4] = edge_orientation0; new_tet0->edge_orientation[5] = edge_orientation0; new_tet1->edge_orientation[0] = edge_orientation1; new_tet1->edge_orientation[1] = edge_orientation1; new_tet1->edge_orientation[2] = edge_orientation0; new_tet1->edge_orientation[3] = right_handed; new_tet1->edge_orientation[4] = edge_orientation0; new_tet1->edge_orientation[5] = edge_orientation0; new_tet0->cusp[0] = tet->cusp[v0]; new_tet0->cusp[1] = tet->cusp[v0]; new_tet0->cusp[2] = tet->cusp[v0]; new_tet0->cusp[3] = tet->cusp[v2]; new_tet1->cusp[0] = tet->cusp[v0]; new_tet1->cusp[1] = tet->cusp[v0]; new_tet1->cusp[2] = tet->cusp[v0]; new_tet1->cusp[3] = tet->cusp[v2]; /* * Install the triangular-pillow-with-tunnel. */ tet->neighbor[f] = new_tet0; tet->gluing[f] = CREATE_PERMUTATION(f, 2, v0, 0, v1, 1, v2, 3); new_tet0->neighbor[2] = tet; new_tet0->gluing[2] = inverse_permutation[tet->gluing[f]]; nbr_tet->neighbor[ff] = new_tet0; nbr_tet->gluing[ff] = CREATE_PERMUTATION(ff, 1, vv0, 0, vv1, 2, vv2, 3); new_tet0->neighbor[1] = nbr_tet; new_tet0->gluing[1] = inverse_permutation[nbr_tet->gluing[ff]]; /* * Typically creating_new_cusp is FALSE, meaning that we are * connecting a spherical boundary component to a torus or * Klein bottle boundary component, and we simply extend the * existing peripheral curves across the new tetrahedra. * * In the exceptional case that creating_new_cusp is TRUE, * meaning that the manifold has no real cusps and we are * connecting the "special fake cusp" to itself, we must * install a meridian and longitude, and set up the Dehn filling. */ if (creating_new_cusp == FALSE) { /* * Extend the peripheral curves across the boundary of the * triangular-pillow-with-tunnel. * * Note: The orientations of new_tet0 and new_tet1 match that * of tet, so the right_handed and left_handed sheets match up * in the obvious way. */ for (c = 0; c < 2; c++) /* c = M, L */ for (h = 0; h < 2; h++) /* h = right_handed, left_handed */ { num_strands = tet->curve[c][h][v0][f]; new_tet0->curve[c][h][0][2] = -num_strands; new_tet0->curve[c][h][0][1] = +num_strands; num_strands = tet->curve[c][h][v1][f]; new_tet0->curve[c][h][1][2] = -num_strands; new_tet0->curve[c][h][1][0] = +num_strands; new_tet1->curve[c][h][2][0] = -num_strands; new_tet1->curve[c][h][2][1] = +num_strands; new_tet1->curve[c][h][1][2] = -num_strands; new_tet1->curve[c][h][1][0] = +num_strands; new_tet0->curve[c][h][2][0] = -num_strands; new_tet0->curve[c][h][2][1] = +num_strands; num_strands = tet->curve[c][h][v2][f]; new_tet0->curve[c][h][3][2] = -num_strands; new_tet0->curve[c][h][3][1] = +num_strands; } } else /* creating_new_cusp == TRUE */ { /* * We have just installed a tube connecting the (unique) * spherical "cusp" to itself, to convert it to a torus or * Klein bottle. */ unique_cusp = tet->cusp[v0]->matching_cusp; unique_cusp->is_complete = TRUE; /* to be filled below */ unique_cusp->index = 0; unique_cusp->is_finite = FALSE; manifold->num_cusps = 1; /* * Install an arbitrary meridian and longitude. */ peripheral_curves(manifold); count_cusps(manifold); /* * Two sides of the (truncated) vertex 0 of new_tet0 * (namely the sides incident to faces 1 and 2 of new_tet0) * define the Dehn filling curve by which we can recover * the closed manifold. Count how many times the newly * installed meridian and longitude cross this Dehn filling curve. * To avoid messy questions about which sheet of the cusp's * double cover we're on, use two (parallel) copies of the * Dehn filling curve, one on each sheet of the cover. * Ultimately we're looking for a linear combination of the * meridian and longitude whose intersection number with * the Dehn filling curve is zero, so it won't matter if * we're off by a factor of two. */ for (c = 0; c < 2; c++) /* c = M, L */ { intersection_number[c] = 0; for (h = 0; h < 2; h++) /* h = right_handed, left_handed */ { intersection_number[c] += new_tet0->curve[c][h][0][1]; intersection_number[c] += new_tet0->curve[c][h][0][2]; } } /* * Use the intersection numbers to deduce * the desired Dehn filling coefficients. */ the_gcd = gcd(intersection_number[M], intersection_number[L]); unique_cusp->is_complete = FALSE; unique_cusp->m = -intersection_number[L] / the_gcd; unique_cusp->l = +intersection_number[M] / the_gcd; /* * Switch to a basis in which the Dehn filling curve is a meridian. */ unique_cusp->cusp_shape[initial] = Zero; /* force current_curve_basis() to ignore the cusp shape */ current_curve_basis(manifold, unique_cusp->index, basis_change[0]); if (change_peripheral_curves(manifold, basis_change) != func_OK) uFatalError("drill_tube", "finite_vertices"); } }
static void kill_the_incident_generator( Triangulation *manifold, EdgeClass *edge) { PositionedTet ptet, ptet0; int dead_index; Tetrahedron *tet, *nbr_tet; Permutation gluing; FaceIndex face, nbr_face; /* * The EdgeClass edge is incident to a unique generator. * Find it. */ set_left_edge(edge, &ptet0); ptet = ptet0; while (TRUE) { /* * If we've found the active generator, * break out of the while loop. Otherwise . . . */ if (ptet.tet->generator_status[ptet.near_face] != not_a_generator) break; /* * . . . move on to the next Tetrahedron incident to the EdgeClass. */ veer_left(&ptet); /* * If we've come all the way around the EdgeClass without * finding a generator, something has gone terribly wrong. */ if (same_positioned_tet(&ptet, &ptet0)) uFatalError("kill_the_incident_generator", "choose_generators"); } /* * Note the index of the about to be killed generator . . . */ dead_index = ptet.tet->generator_index[ptet.near_face]; /* * . . . then kill it. */ nbr_tet = ptet.tet->neighbor[ptet.near_face]; gluing = ptet.tet->gluing[ptet.near_face]; nbr_face = EVALUATE(gluing, ptet.near_face); ptet.tet->generator_status[ptet.near_face] = not_a_generator; nbr_tet ->generator_status[nbr_face] = not_a_generator; ptet.tet->generator_index[ptet.near_face] = -1; /* garbage value */ nbr_tet ->generator_index[nbr_face] = -1; /* * The EdgeClass no longer represents an active relation. */ edge->active_relation = FALSE; /* * Decrement the num_incident_generators count at each of * the incident EdgeClasses. */ ptet.tet->edge_class[edge_between_faces[ptet.near_face][ptet.left_face] ]->num_incident_generators--; ptet.tet->edge_class[edge_between_faces[ptet.near_face][ptet.right_face] ]->num_incident_generators--; ptet.tet->edge_class[edge_between_faces[ptet.near_face][ptet.bottom_face]]->num_incident_generators--; /* * Decrement *number_of_generators. */ manifold->num_generators--; /* * If dead_index was not the highest numbered generator, then removing * it will have left a gap in the numbering scheme. Renumber the highest * numbered generator to keep the numbering contiguous. */ if (dead_index != manifold->num_generators) { for (tet = manifold->tet_list_begin.next; tet != &manifold->tet_list_end; tet = tet->next) for (face = 0; face < 4; face++) if (tet->generator_index[face] == manifold->num_generators) { if (tet->generator_status[face] == not_a_generator) uFatalError("kill_the_incident_generator", "choose_generators"); nbr_tet = tet->neighbor[face]; gluing = tet->gluing[face]; nbr_face = EVALUATE(gluing, face); tet ->generator_index[face] = dead_index; nbr_tet->generator_index[nbr_face] = dead_index; /* * Rather than worrying about breaking out of a * double loop, let's just return from here. */ return; } /* * The program should return from within the above double loop. */ uFatalError("kill_the_incident_generator", "choose_generators"); } else /* dead_index == manifold->num_generators, so nothing else to do */ return; }
static void compute_cusp_map( Triangulation *manifold0, Triangulation *manifold1, Isometry *isometry) { Tetrahedron *tet; VertexIndex v; int i; /* * Copy the manifold1's peripheral curves into * scratch_curves[0], and copy the images of manifold0's * peripheral curves into scratch_curves[1]. * * When the manifold is orientable and the Isometry is * orientation-reversing, and sometimes when the manifold * is nonorientable, the images of the peripheral curves * of a torus will lie on the "wrong" sheet of the Cusp's * orientation double cover. (See peripheral_curves.c for * background material.) Therefore we copy the images of * the peripheral curves of torus cusps to both sheets of * the orientation double cover, to guarantee that the * intersection numbers come out right. */ copy_curves_to_scratch(manifold1, 0, FALSE); copy_images_to_scratch(manifold0, 1, TRUE); /* * Compute the intersection numbers of the images of manifold0's * peripheral curves with manifold1's peripheral curves.. */ compute_intersection_numbers(manifold1); /* * Now extract the cusp_maps from the linking numbers. * * There's a lot of redundancy in this loop, but a trivial * computation so the redundancy hardly matters. * * Ignore negatively indexed Cusps -- they're finite vertices. */ for (tet = manifold0->tet_list_begin.next; tet != &manifold0->tet_list_end; tet = tet->next) for (v = 0; v < 4; v++) if (tet->cusp[v]->index >= 0) for (i = 0; i < 2; i++) /* i = M, L */ { isometry->cusp_map[tet->cusp[v]->index][M][i] = + tet->image->cusp[EVALUATE(tet->map, v)]->intersection_number[L][i]; isometry->cusp_map[tet->cusp[v]->index][L][i] = - tet->image->cusp[EVALUATE(tet->map, v)]->intersection_number[M][i]; } }
/* DJH */ void my_drill_tube( Triangulation *manifold, int singular_index ) { /* * Insert a triangular-pillow-with-tunnel (as described at the top * of this file) so as to connect the boundary component at one * end of the given edge to the boundary component at the other end. * The orientation on the triangular pillow will match the * orientation on tet, so that the orientation on the manifold * (if there is one) will be preserved. Edge orientations are also * respected. */ EdgeIndex e; VertexIndex v0, v1, v2, vv0, vv1, vv2; FaceIndex f, ff; Tetrahedron *nbr_tet, *tet, *tet0, *new_tet0, *new_tet1; Permutation gluing; EdgeClass *edge0, *edge1, *edge2, *edge, *new_edge, *edge3; Orientation edge_orientation0, edge_orientation1, edge_orientation2; PeripheralCurve c; Orientation h; int num_strands, i, intersection_number[2], the_gcd; Cusp *unique_cusp, *merged_cusp, *dead_cusp, *cusp; MatrixInt22 *basis_change = NULL; Boolean creating_new_cusp, same_cusp; int *cone_points, num_cone_points, dead_index; for( edge = manifold->edge_list_begin.next; edge!=&manifold->edge_list_end; edge = edge->next ) if (edge->is_singular) if (edge->singular_index == singular_index) break; if (edge == &manifold->edge_list_end) uFatalError("my_drill_tube", "finite_vertices"); tet = edge->incident_tet; e = edge->incident_edge_index; /* * Relative to the orientation of tet, the vertices v0, v1 and v2 * are arranged in counterclockwise order around the face f. */ v0 = one_vertex_at_edge[e]; v1 = other_vertex_at_edge[e]; if ( tet->cusp[v0] == tet->cusp[v1] && tet->cusp[v1]->num_cone_points ==2 /* if it's a $\S^2(n,n) orbifold then we are creating a torus cusp */ && tet->cusp[v1]->euler_characteristic==2) creating_new_cusp = TRUE; else creating_new_cusp = FALSE; v2 = remaining_face[v1][v0]; f = remaining_face[v0][v1]; /* * Note the matching face and its vertices. */ nbr_tet = tet->neighbor[f]; gluing = tet->gluing[f]; ff = EVALUATE(gluing, f); vv0 = EVALUATE(gluing, v0); vv1 = EVALUATE(gluing, v1); vv2 = EVALUATE(gluing, v2); /* * Note the incident EdgeClasses (which may or may not be distinct). */ edge0 = tet->edge_class[e]; edge1 = tet->edge_class[edge_between_vertices[v1][v2]]; edge2 = tet->edge_class[edge_between_vertices[v2][v0]]; /* * Construct the triangular-pillow-with-tunnel, as described * at the top of this file. */ new_tet0 = NEW_STRUCT(Tetrahedron); new_tet1 = NEW_STRUCT(Tetrahedron); initialize_tetrahedron(new_tet0); initialize_tetrahedron(new_tet1); INSERT_BEFORE(new_tet0, &manifold->tet_list_end); INSERT_BEFORE(new_tet1, &manifold->tet_list_end); manifold->num_tetrahedra += 2; new_edge = NEW_STRUCT(EdgeClass); initialize_edge_class(new_edge); INSERT_BEFORE(new_edge, &manifold->edge_list_end); new_tet0->neighbor[0] = new_tet1; new_tet0->neighbor[1] = NULL; /* assigned below */ new_tet0->neighbor[2] = NULL; /* assigned below */ new_tet0->neighbor[3] = new_tet1; new_tet1->neighbor[0] = new_tet0; new_tet1->neighbor[1] = new_tet1; new_tet1->neighbor[2] = new_tet1; new_tet1->neighbor[3] = new_tet0; new_tet0->gluing[0] = CREATE_PERMUTATION(0, 0, 1, 2, 2, 1, 3, 3); new_tet0->gluing[1] = 0x00; /* assigned below */ new_tet0->gluing[2] = 0x00; /* assigned below */ new_tet0->gluing[3] = CREATE_PERMUTATION(0, 1, 1, 0, 2, 2, 3, 3); new_tet1->gluing[0] = CREATE_PERMUTATION(0, 0, 1, 2, 2, 1, 3, 3); new_tet1->gluing[1] = CREATE_PERMUTATION(0, 0, 1, 2, 2, 1, 3, 3); new_tet1->gluing[2] = CREATE_PERMUTATION(0, 0, 1, 2, 2, 1, 3, 3); new_tet1->gluing[3] = CREATE_PERMUTATION(0, 1, 1, 0, 2, 2, 3, 3); new_tet0->edge_class[0] = edge1; new_tet0->edge_class[1] = edge1; new_tet0->edge_class[2] = edge0; new_tet0->edge_class[3] = edge2; new_tet0->edge_class[4] = edge0; new_tet0->edge_class[5] = edge0; new_tet1->edge_class[0] = edge1; new_tet1->edge_class[1] = edge1; new_tet1->edge_class[2] = edge0; new_tet1->edge_class[3] = new_edge; new_tet1->edge_class[4] = edge0; new_tet1->edge_class[5] = edge0; edge0->order += 6; edge1->order += 4; edge2->order += 1; new_edge->order = 1; new_edge->incident_tet = new_tet1; new_edge->incident_edge_index = 3; edge_orientation0 = tet->edge_orientation[e]; edge_orientation1 = tet->edge_orientation[edge_between_vertices[v1][v2]]; edge_orientation2 = tet->edge_orientation[edge_between_vertices[v2][v0]]; new_tet0->edge_orientation[0] = edge_orientation1; new_tet0->edge_orientation[1] = edge_orientation1; new_tet0->edge_orientation[2] = edge_orientation0; new_tet0->edge_orientation[3] = edge_orientation2; new_tet0->edge_orientation[4] = edge_orientation0; new_tet0->edge_orientation[5] = edge_orientation0; new_tet1->edge_orientation[0] = edge_orientation1; new_tet1->edge_orientation[1] = edge_orientation1; new_tet1->edge_orientation[2] = edge_orientation0; new_tet1->edge_orientation[3] = right_handed; new_tet1->edge_orientation[4] = edge_orientation0; new_tet1->edge_orientation[5] = edge_orientation0; new_tet0->cusp[0] = tet->cusp[v0]; new_tet0->cusp[1] = tet->cusp[v0]; new_tet0->cusp[2] = tet->cusp[v0]; new_tet0->cusp[3] = tet->cusp[v2]; new_tet1->cusp[0] = tet->cusp[v0]; new_tet1->cusp[1] = tet->cusp[v0]; new_tet1->cusp[2] = tet->cusp[v0]; new_tet1->cusp[3] = tet->cusp[v2]; /* * Install the triangular-pillow-with-tunnel. */ tet->neighbor[f] = new_tet0; tet->gluing[f] = CREATE_PERMUTATION(f, 2, v0, 0, v1, 1, v2, 3); new_tet0->neighbor[2] = tet; new_tet0->gluing[2] = inverse_permutation[tet->gluing[f]]; nbr_tet->neighbor[ff] = new_tet0; nbr_tet->gluing[ff] = CREATE_PERMUTATION(ff, 1, vv0, 0, vv1, 2, vv2, 3); new_tet0->neighbor[1] = nbr_tet; new_tet0->gluing[1] = inverse_permutation[nbr_tet->gluing[ff]]; for(c=0;c<2;c++) for(h=0;h<2;h++) { new_tet0->curve[c][h][3][2] = -nbr_tet->curve[c][h][v2][f]; new_tet0->curve[c][h][3][1] = -nbr_tet->curve[c][h][vv2][ff]; } /* * Typically creating_new_cusp is FALSE, meaning that we are * connecting a spherical boundary component to a torus or * Klein bottle boundary component, and we simply extend the * existing peripheral curves across the new tetrahedra. * * In the exceptional case that creating_new_cusp is TRUE, * meaning that the manifold has no real cusps and we are * connecting the "special fake cusp" to itself, we must * install a meridian and longitude, and set up the Dehn filling. */ if (creating_new_cusp == FALSE) { if (tet->cusp[v0]->index<tet->cusp[v1]->index) { merged_cusp = tet->cusp[v0]; dead_cusp = tet->cusp[v1]; } else { merged_cusp = tet->cusp[v1]; dead_cusp = tet->cusp[v0]; } if (merged_cusp==dead_cusp) same_cusp = TRUE; else same_cusp = FALSE; if (same_cusp) merged_cusp->euler_characteristic = merged_cusp->euler_characteristic - 2; else if (merged_cusp->euler_characteristic==2 || dead_cusp->euler_characteristic==2) merged_cusp->euler_characteristic = merged_cusp->euler_characteristic +dead_cusp->euler_characteristic - 2; else merged_cusp->euler_characteristic = merged_cusp->euler_characteristic +dead_cusp->euler_characteristic; merged_cusp->topology = unknown_topology; if (same_cusp) num_cone_points = merged_cusp->num_cone_points - 2; else num_cone_points = merged_cusp->num_cone_points + dead_cusp->num_cone_points -2; cone_points = NEW_ARRAY( num_cone_points, int ); num_cone_points = 0; for(i=0;i<merged_cusp->num_cone_points;i++) if (merged_cusp->cone_points[i]!=edge->singular_index) cone_points[num_cone_points++] = merged_cusp->cone_points[i]; my_free(merged_cusp->cone_points); if (!same_cusp) { dead_index = dead_cusp->index; /* fix cusp fields */ for( tet0 = manifold->tet_list_begin.next; tet0!=&manifold->tet_list_end; tet0 = tet0->next ) for( i = 0; i < 4; i++ ) if (tet0->cusp[i] == dead_cusp) tet0->cusp[i] = merged_cusp; for(i=0;i<dead_cusp->num_cone_points;i++) if (dead_cusp->cone_points[i]!=edge->singular_index) cone_points[num_cone_points++] = dead_cusp->cone_points[i]; my_free(dead_cusp->cone_points); REMOVE_NODE(dead_cusp); my_free(dead_cusp); } /* install new cone points */ merged_cusp->cone_points = cone_points; merged_cusp->num_cone_points = num_cone_points; for( cusp = manifold->cusp_list_begin.next; cusp!=&manifold->cusp_list_end; cusp = cusp->next ) { for (i=0;i < cusp->num_cone_points;i++) if (cusp->cone_points[i] > edge->singular_index) cusp->cone_points[i] = cusp->cone_points[i] - 1; if (!same_cusp && cusp->index > dead_index) cusp->index--; } for( edge3 = manifold->edge_list_begin.next; edge3!=&manifold->edge_list_end; edge3 = edge3->next ) if (edge3->is_singular && edge3->singular_index > edge->singular_index) edge3->singular_index--; edge->singular_index = -1; edge->is_singular = FALSE; edge->singular_order = 1; manifold->num_singular_arcs--; if (!same_cusp) { manifold->num_cusps--; manifold->num_or_cusps--; } } else /* creating_new_cusp == TRUE */ {
static void copy_images_to_scratch( Triangulation *manifold0, int which_set, Boolean double_copy_on_tori) { Tetrahedron *tet; int i, j, jj, k, kk, l, ll; /* * This function is modelled on copy_curves_to_scratch() * in intersection_numbers.c. */ /* * Note that even though we are passed manifold0 as an * explicit function parameter, we are ultimately writing * the image curves in manifold1. */ for (tet = manifold0->tet_list_begin.next; tet != &manifold0->tet_list_end; tet = tet->next) for (i = 0; i < 2; i++) for (k = 0; k < 4; k++) { kk = EVALUATE(tet->map, k); for (l = 0; l < 4; l++) { ll = EVALUATE(tet->map, l); if (tet->cusp[k]->topology == torus_cusp && double_copy_on_tori == TRUE) tet->image->scratch_curve[which_set][i][right_handed][kk][ll] = tet->image->scratch_curve[which_set][i][ left_handed][kk][ll] = tet->curve[i][right_handed][k][l] + tet->curve[i][ left_handed][k][l]; else /* * tet->cusp[k]->topology == Klein_cusp * || double_copy_on_tori == FALSE */ for (j = 0; j < 2; j++) { /* * parities can be tricky. * * When discussing gluings from a face of one Tetrahedron * to a face of another, an even parity corresponds to an * orientation-reversing gluing. * * When discussing a map from one Tetrahedron onto * another, an even parity is an orientation-preserving * map. */ /* * If tet->map has even parity (i.e. if it's an * orientation-preserving map) it will send the * right-handed vertex cross section to a right- * handed image. * * If tet->map has odd parity (i.e. if it's an * orientation-reversing map) it will send the * right-handed vertex cross section to a left- * handed image. */ jj = (parity[tet->map] == 0) ? j : !j; tet->image->scratch_curve[which_set][i][jj][kk][ll] = tet->curve[i][j][k][l]; } } } }
void create_one_cusp( Triangulation *manifold, Tetrahedron *tet, Boolean is_finite, VertexIndex v, int cusp_index) { Cusp *cusp; IdealVertex *queue; int queue_first, queue_last; Tetrahedron *tet1, *nbr; VertexIndex v1, nbr_v; FaceIndex f; /* * Create the cusp, add it to the list, and set * the is_finite and index fields. */ cusp = NEW_STRUCT(Cusp); initialize_cusp(cusp); INSERT_BEFORE(cusp, &manifold->cusp_list_end); cusp->is_finite = is_finite; cusp->index = cusp_index; /* * We don't set the topology, is_complete, m, l, holonomy, * cusp_shape or shape_precision fields. * * For "real" cusps the calling routine may * * (1) call peripheral_curves() to set the cusp->topology, * * (2) keep the default values of cusp->is_complete, * cusp->m and cusp->l as set by initialize_cusp(), and * * (3) let the holonomy and cusp_shape be computed automatically * when hyperbolic structure is computed. * * Alternatively, the calling routine may set these fields in other * ways, as it sees fit. * * If we were called by create_fake_cusps(), then the above fields * are all irrelevant and ignored. */ /* * Set the tet->cusp field at all vertices incident to the new cusp. */ /* * Allocate space for a queue of pointers to the IdealVertices. * Each IdealVertex will appear on the queue at most once, so an * array of length 4 * manifold->num_tetrahedra will suffice. */ queue = NEW_ARRAY(4 * manifold->num_tetrahedra, IdealVertex); /* * Set the cusp of the given IdealVertex... */ tet->cusp[v] = cusp; /* * ...and put it on the queue. */ queue_first = 0; queue_last = 0; queue[0].tet = tet; queue[0].v = v; /* * Start processing the queue. */ do { /* * Pull an IdealVertex off the front of the queue. */ tet1 = queue[queue_first].tet; v1 = queue[queue_first].v; queue_first++; /* * Look at the three neighboring IdealVertices. */ for (f = 0; f < 4; f++) { if (f == v1) continue; nbr = tet1->neighbor[f]; nbr_v = EVALUATE(tet1->gluing[f], v1); /* * If the neighbor's cusp hasn't been set... */ if (nbr->cusp[nbr_v] == NULL) { /* * ...set it... */ nbr->cusp[nbr_v] = cusp; /* * ...and add it to the end of the queue. */ ++queue_last; queue[queue_last].tet = nbr; queue[queue_last].v = nbr_v; } } } while (queue_first <= queue_last); /* * Free the memory used for the queue. */ my_free(queue); }