Ejemplo n.º 1
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");
	}
}
Ejemplo n.º 2
0
static void merge_incident_generators(
	Triangulation	*manifold,
	EdgeClass		*edge)
{
	PositionedTet	ptet,
					ptet0;
	Tetrahedron		*tetA,
					*tetB,
					*tet;
	FaceIndex		faceA,
					faceB,
					face;
	int				indexA,
					indexB;
	Boolean			generator_A_has_been_found,
					directions_agree;

	/*
	 *	Find the two incident generators by letting ptet
	 *	rotate around the EdgeClass.  The first time we
	 *	encounter a nontrivial generator, call it
	 *	faceA of tetA;  the second time, faceB of tetB.
	 */

	set_left_edge(edge, &ptet0);

	ptet = ptet0;

	generator_A_has_been_found = FALSE;

	while (TRUE)
	{
		/*
		 *	If we've found an active generator, record it.
		 *	If this is the second one we've found, break out of the loop.
		 */

		if (ptet.tet->generator_status[ptet.near_face] != not_a_generator)
		{
			if (generator_A_has_been_found == FALSE)
			{
				tetA = ptet.tet;
				faceA = ptet.near_face;
				generator_A_has_been_found = TRUE;
			}
			else
			{
				tetB = ptet.tet;
				faceB = ptet.near_face;
				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 both generators, something has gone terribly wrong.
		 */

		if (same_positioned_tet(&ptet, &ptet0))
			uFatalError("kill_the_incident_generator", "choose_generators");
	}


	/*
	 *	If the two generators are the same, then either their product is
	 *	aA (in which case there is no further work to be done) or aa (in
	 *	which case they cannot be merged).  Either way, we simply return.
	 *	[JRW 95/1/19.  Actually, I don't think the first case (aA) is
	 *	likely to occur.  The n-gons which are subdivided into triangles
	 *	have no interior vertices, so under normal circumstances the
	 *	generators we're merging should be distinct.  If they're not,
	 *	it means we have a "face" which is topologically a cylinder,
	 *	or something weird like that.  At any rate, we should return
	 *	without taking any action.]  
	 */

	indexA = tetA->generator_index[faceA];
	indexB = tetB->generator_index[faceB];
	if (indexA == indexB)
		return;

	/*
	 *	Do the directions of the generators agree or disagree?
	 *	Note that the generator will point in the same direction
	 *	relative to the boundary of the fundamental domain iff
	 *	one is an outbound_generator and the other is an inbound_generator
	 *	relative to the preceding cyclic traversal around the EdgeClass.
	 */ 

	directions_agree = (tetA->generator_status[faceA] != tetB->generator_status[faceB]);


	/*
	 *	If directions_agree is FALSE, reverse the direction of generator A.
	 *	Then let generator A inherit the index of generator B.
	 *
	 *	Let the highest numbered generator inherit the former index
	 *	of generator A, and decrement the number_of_generators count.
	 *
	 *	Even in the special cases where indexA or indexB is the highest
	 *	index, generators A and B get merged, and the previously highest
	 *	index will no longer occur.  This keeps the indices contiguous.
	 */

	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] == indexA)
			{
				if (directions_agree == FALSE)
				{
					if (tet->generator_status[face] == outbound_generator)
						tet->generator_status[face] = inbound_generator;
					else if (tet->generator_status[face] == inbound_generator)
						tet->generator_status[face] = outbound_generator;
					else
						uFatalError("merge_incident_generators", "choose_generators");
				}
				tet->generator_index[face] = indexB;
			}

			if (tet->generator_index[face] == manifold->num_generators)
				tet->generator_index[face] = indexA;
		}

	/*
	 *	The EdgeClass no longer represents an active relation.
	 */

	edge->active_relation = FALSE;
}
Ejemplo n.º 3
0
static void compute_translation(
    PositionedTet   *initial_ptet,
    PeripheralCurve which_curve,
    TraceDirection  which_direction,
    Complex         translation[2], /* returns translations based on ultimate   */
                                    /* and penultimate shapes                   */
    FillingStatus   which_structure)
{
    PositionedTet   ptet;
    int             i,
                    initial_strand,
                    strand,
                    *this_vertex,
                    near_strands,
                    left_strands;
    Complex         left_endpoint[2],   /*  left_endpoint[ultimate/penultimate]     */
                    right_endpoint[2],  /*  right_endpoint[ultimate/penultimate]    */
                    old_diff,
                    new_diff,
                    rotation;

    /*
     *  Place the near edge of the top vertex of the initial_ptet in the
     *  complex plane with its left endpoint at zero and its right endpoint at one.
     *  Trace the curve which_curve in the direction which_direction, using the
     *  shapes of the ideal tetrahedra to compute the position of endpoints of
     *  each edge we cross.  When we return to our starting point in the manifold,
     *  the position of the left endpoint (or the position of the right endpoint
     *  minus one) will tell us the translation.
     *
     *  Note that we are working in the orientation double cover of the cusp.
     *
     *  Here's how we keep track of where we are.  At each step, we are always
     *  at the near edge of the top vertex (i.e. the truncated vertex opposite
     *  the bottom face) of the PositionedTet ptet.  The curve (i.e. the
     *  meridian or longitude) may cross that edge several times.  The variable
     *  "strand" keeps track of which intersection we are at;  0 means we're at
     *  the strand on the far left, 1 means we're at the next strand, etc.
     */

    ptet            = *initial_ptet;
    initial_strand  = 0;
    strand          = initial_strand;
    for (i = 0; i < 2; i++)     /* i = ultimate, penultimate */
    {
        left_endpoint[i]    = Zero;
        right_endpoint[i]   = One;
    }

    do
    {
        /*
         *  Note the curve's intersection numbers with the near side and left side.
         */
        this_vertex =   ptet.tet->curve[which_curve][ptet.orientation][ptet.bottom_face];
        near_strands = this_vertex[ptet.near_face];
        left_strands = this_vertex[ptet.left_face];

        /*
         *  If we are tracing the curve backwards, negate the intersection numbers
         *  so the rest of compute_translation() can enjoy the illusion that we
         *  are tracing the curve forwards.
         */
        if (which_direction == trace_backwards)
        {
            near_strands = - near_strands;
            left_strands = - left_strands;
        }

        /*
         *  Does the current strand bend to the left or to the right?
         */

        if (strand < FLOW(near_strands, left_strands))
        {
            /*
             *  The current strand bends to the left.
             */

            /*
             *  The left_endpoint remains fixed.
             *  Update the right_endpoint.
             *
             *  The plan is to compute the vector old_diff which runs
             *  from left_endpoint to right_endpoint, multiply it by the
             *  complex edge parameter to get the vector new_diff which
             *  runs from left_endpoint to the new value of right_endpoint,
             *  and then add new_diff to left_endpoint to get the new
             *  value of right_endpoint itself.
             *
             *  Note that the complex edge parameters are always expressed
             *  relative to the right_handed Orientation, so if we are
             *  viewing this Tetrahedron relative to the left_handed
             *  Orientation, we must take the conjugate-inverse of the
             *  edge parameter.
             */
            for (i = 0; i < 2; i++)     /* i = ultimate, penultimate */
            {
                old_diff = complex_minus(right_endpoint[i], left_endpoint[i]);
                rotation = ptet.tet->shape[which_structure]->cwl[i][edge3_between_faces[ptet.near_face][ptet.left_face]].rect;
                if (ptet.orientation == left_handed)
                {
                    rotation        = complex_div(One, rotation);   /* invert . . .         */
                    rotation.imag   = - rotation.imag;              /* . . . and conjugate  */
                }
                new_diff = complex_mult(old_diff, rotation);
                right_endpoint[i] = complex_plus(left_endpoint[i], new_diff);
            }

            /*
             *  strand remains unchanged.
             */

            /*
             *  Move the PositionedTet onward, following the curve.
             */
            veer_left(&ptet);

        }
        else
        {
            /*
             *  The current strand bends to the right.
             *
             *  Proceed as above, but note that
             *
             *  (1) We now divide by the complex edge parameter
             *      instead of multiplying by it.
             *
             *  (2) We must adjust the variable "strand".  Some of the strands
             *      from the near edge may be peeling off to the left (in which
             *      case left_strands is negative), or some strands from the left
             *      edge may be joining those from the near edge in passing to
             *      the right edge (in which case left_strands is positive).
             *      Either way, the code "strand += left_strands" is correct.
             */

            for (i = 0; i < 2; i++)     /* i = ultimate, penultimate */
            {
                old_diff = complex_minus(left_endpoint[i], right_endpoint[i]);
                rotation = ptet.tet->shape[which_structure]->cwl[i][edge3_between_faces[ptet.near_face][ptet.right_face]].rect;
                if (ptet.orientation == left_handed)
                {
                    rotation        = complex_div(One, rotation);
                    rotation.imag   = - rotation.imag;
                }
                new_diff = complex_div(old_diff, rotation);
                left_endpoint[i] = complex_plus(right_endpoint[i], new_diff);
            }

            strand += left_strands;

            veer_right(&ptet);

        }
    }
    while ( ! same_positioned_tet(&ptet, initial_ptet) || strand != initial_strand);

    /*
     *  Write the computed translations, and return.
     */

    for (i = 0; i < 2; i++)     /* i = ultimate, penultimate */
        translation[i] = left_endpoint[i];
}
Ejemplo n.º 4
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;
}