Exemple #1
0
/* 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;
}
Exemple #2
0
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);
}
Exemple #4
0
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] );
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
Exemple #7
0
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;
}
Exemple #8
0
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;
}
Exemple #10
0
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;
}
Exemple #11
0
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;
}
Exemple #12
0
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;
}
Exemple #13
0
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];
			}

		}
	}
}
Exemple #14
0
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");
}
Exemple #15
0
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++;

            }
        }
}
Exemple #17
0
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");
	}
}
Exemple #18
0
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;
}
Exemple #19
0
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];
				}
}
Exemple #20
0
/* 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 */
	{
Exemple #21
0
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];
						}
				}
			}
}
Exemple #22
0
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);
}