Esempio n. 1
0
face_t new_tetrahedron()

{
edge_t edges[3];
vertex_t tv0, tv1, tv2, tv3;
vertex_t verts[4];
 face_t tf012, tf132, tf023, tf031;
 face_t tetrahedron;

/* note tv0 = new_vert(0, 0, 0, "v0"); won't work -- ints! yikes */


/* The nice thing about string names is you can represent the topology (like
   name an e01 if it goes from v. 0 to v. 1 and e20 if it goes from 2 to 0.) hmmm */


tv0 = new_vert(0.0, 0.0, 0.0,0);
verts[0] = tv0;
tv1 = new_vert(2.0, 2.0, 0.0,1);
verts[1] = tv1;
tv2 = new_vert(2.0, 0.0, 2.0,2);
verts[2] = tv2;
tv3 = new_vert(0.0, 2.0, 2.0,3);
verts[3] = tv3;

edges[0] = new_edge(tv0, tv1,0);
edges[1] = new_edge(tv1, tv2, 1);
edges[2] = new_edge(tv2, tv0, 2);

tf012 = new_face(edges, 3, 0);

edges[0] = new_edge(tv1, tv3, 3);
edges[1] = new_edge(tv3, tv2, 4);
edges[2] = new_edge(tv2, tv1,5);


tf132 = new_face(edges, 3, 1);


edges[0] = new_edge(tv0, tv2,6);
edges[1] = new_edge(tv2, tv3, 7);
edges[2] = new_edge(tv3, tv0, 8);

tf023 = new_face(edges, 3, 2);

edges[0] = new_edge(tv0, tv3,9);
edges[1] = new_edge(tv3, tv1, 10);
edges[2] = new_edge(tv1, tv0, 11);


 tetrahedron = tf012;
 tf012->next_face = tf132;
 tf132->next_face = tf023;
 tf023->next_face = tf031;
 tf031->next_face = tf012;

return(tetrahedron);

}
Esempio n. 2
0
void
Surface_mesh::
split(Face f, Vertex v)
{
    /*
     Split an arbitrary face into triangles by connecting each vertex of fh to vh.
     - fh will remain valid (it will become one of the triangles)
     - the halfedge handles of the new triangles will point to the old halfeges
     */

    Halfedge hend = halfedge(f);
    Halfedge h    = next_halfedge(hend);

    Halfedge hold = new_edge(to_vertex(hend), v);

    set_next_halfedge(hend, hold);
    set_face(hold, f);

    hold = opposite_halfedge(hold);

    while (h != hend)
    {
        Halfedge hnext = next_halfedge(h);

        Face fnew = new_face();
        set_halfedge(fnew, h);

        Halfedge hnew = new_edge(to_vertex(h), v);

        set_next_halfedge(hnew, hold);
        set_next_halfedge(hold, h);
        set_next_halfedge(h,    hnew);

        set_face(hnew, fnew);
        set_face(hold, fnew);
        set_face(h,    fnew);

        hold = opposite_halfedge(hnew);

        h = hnext;
    }

    set_next_halfedge(hold, hend);
    set_next_halfedge(next_halfedge(hend), hold);

    set_face(hold, f);

    set_halfedge(v, hold);
}
Esempio n. 3
0
void quake3_bsp_map::add_mesh_surface(const quake3_face& f) {
    shared_ptr<map_face> new_face(new basic_face());
    new_face->clear();

    //Get the triangles that make up this face
    for (int i = 0; i < f.totalMeshVertices; i += 3) {
        int idx1 = f.startVertexIndex + m_raw_face_index_data[f.meshVertexIndex + i];
        int idx2 = f.startVertexIndex + m_raw_face_index_data[f.meshVertexIndex + i + 2];
        int idx3 = f.startVertexIndex + m_raw_face_index_data[f.meshVertexIndex + i + 1];

        //Add the triangle to the new face
        new_face->add_triangle(m_vertices[idx1], m_vertices[idx2], m_vertices[idx3]);
    }

    new_face->set_texture_index(f.texID); //Set the index to the texture array
    m_faces.push_back(new_face);
}
Esempio n. 4
0
void
Surface_mesh::
triangulate(Face f)
{
    /*
     Split an arbitrary face into triangles by connecting
     each vertex of fh after its second to vh.

     - fh will remain valid (it will become one of the
     triangles)
     - the halfedge handles of the new triangles will
     point to the old halfedges
     */

    Halfedge base_h  = halfedge(f);
    Vertex   start_v = from_vertex(base_h);
    Halfedge next_h  = next_halfedge(base_h);

    while (to_vertex(next_halfedge(next_h)) != start_v)
    {
        Halfedge next_next_h(next_halfedge(next_h));

        Face new_f = new_face();
        set_halfedge(new_f, base_h);

        Halfedge new_h = new_edge(to_vertex(next_h), start_v);

        set_next_halfedge(base_h, next_h);
        set_next_halfedge(next_h, new_h);
        set_next_halfedge(new_h,  base_h);

        set_face(base_h, new_f);
        set_face(next_h, new_f);
        set_face(new_h,  new_f);

        base_h = opposite_halfedge(new_h);
        next_h = next_next_h;
    }
    set_halfedge(f, base_h);  //the last face takes the handle _fh

    set_next_halfedge(base_h, next_h);
    set_next_halfedge(next_halfedge(next_h), base_h);

    set_face(base_h, f);
}
Esempio n. 5
0
void quake3_bsp_map::add_curved_surface(const quake3_face& f) {
    int width = f.size[0], height = f.size[1]; //FIXME: get width and height

    int num_patches_wide = (width - 1) >> 1;
    int num_patches_high = (height - 1) >> 1;
    int total_patches = num_patches_high * num_patches_wide;

    vector<quake3_subpatch> sub_patches(total_patches);

    for (int y = 0; y < num_patches_high; ++y) {
        for (int x = 0; x < num_patches_wide; ++x) {
            int current_patch = y * num_patches_wide + x;

            for (int row = 0; row < 3; ++row) {
                for (int point = 0; point < 3; ++point) {
                    //Set the vertex for each point
                    int control_point_index = row * 3 + point;

                    int vertex_index = (y * 2 * width + x * 2) + row * width + point;

                    map_vertex* control_points = sub_patches[current_patch].get_control_points();


                    control_points[control_point_index] = m_vertices[f.startVertexIndex + vertex_index];
                    //m_SubPatches[currentPatch].m_ControlPoints[row * 3 + point].m_Normal.Normalize();
                }
            }

            //tesselate the subpatch
            sub_patches[current_patch].tesselate_vertices();
        }
    }

    shared_ptr<map_face> new_face(new basic_face());

    for (vector<quake3_subpatch>::iterator patch = sub_patches.begin();
            patch != sub_patches.end(); ++patch) {

        (*patch).calculate_indices();
        (*patch).append_triangles_to_array(new_face->get_vertices());
    }

    new_face->set_texture_index(f.texID); //Set the index to the texture array
    m_faces.push_back(new_face);
}
Esempio n. 6
0
/* one new saddle face with 4 edges */
void newsad (struct surface *this_srf, struct arc *arc1, struct arc *arc2, struct circle *circle1, struct circle *circle2, struct torus *torus_ptr, double wrap_angle)
{
	struct vertex *vertex1, *vertex2, *vertex3, *vertex4;
	struct arc *arc3, *arc4;
	struct face *saddle_fac;
	struct sphere *atom1, *atom2;

	atom1 = circle1 -> atm;
	atom2 = circle2 -> atm;

	/* gather vertices */
	vertex1 = arc1 -> vtx[0];
	vertex2 = arc1 -> vtx[1];
	vertex3 = arc2 -> vtx[0];
	vertex4 = arc2 -> vtx[1];

	/* set up arcs */
	arc3 = new_arc (circle2, vertex2, vertex3, CONVEX, 0, (double) 0.0, 0L, 0L, 0L);
	if (error()) return;
	this_srf -> n_arc++;
	arc4 = new_arc (circle1, vertex4, vertex1, CONVEX, 0, (double) 0.0, 0L, 0L, 0L);
	if (error()) return;
	this_srf -> n_arc++;
	arc3 -> phi = wrap_angle;
	arc4 -> phi = wrap_angle;

	/* add convex arcs to atom list */
	arc3 -> next = atom2 -> first_arc;
	atom2 -> first_arc = arc3;
	arc4 -> next = atom1 -> first_arc;
	atom1 -> first_arc = arc4;

	/* set up saddle face */
	saddle_fac = new_face (NULL, SADDLE); if (error()) return;
	saddle_fac -> ptr.tor = torus_ptr;
	link_face (this_srf, saddle_fac); if (error()) return;
	add2face (saddle_fac, arc1, arc3, arc2, arc4); if (error()) return;
}
Esempio n. 7
0
/* free (no collision) torus saddle surface */
void free_saddle (struct surface *this_srf, struct torus *torus_ptr)
{
	struct face *saddle_fac;
	struct circle *circle1, *circle2;
	struct arc *arc1, *arc2;
	struct sphere *atom1, *atom2;

	atom1 = (torus_ptr -> atm[0]);
	atom2 = (torus_ptr -> atm[1]);

	/* set up circles */

	circle1 = new_contact_circle (this_srf, torus_ptr, 0); if (error()) return;
	circle2 = new_contact_circle (this_srf, torus_ptr, 1); if (error()) return;

	/* set up arcs */
	arc1 = new_arc (circle2, NULL, NULL, CONVEX, 0, (double) 0.0, 0L, 0L, 0L);
	if (error()) return;
	this_srf -> n_arc++;
	arc2 = new_arc (circle1, NULL, NULL, CONVEX, 0, (double) 0.0, 0L, 0L, 0L);
	if (error()) return;
	this_srf -> n_arc++;
	arc1 -> phi = 2 * PI;
	arc2 -> phi = 2 * PI;

	/* add convex arcs to atom list */
	arc1 -> next = atom2 -> first_arc;
	atom2 -> first_arc = arc1;
	arc2 -> next = atom1 -> first_arc;
	atom1 -> first_arc = arc2;

	/* allocate saddle face */
	saddle_fac = new_face (NULL, SADDLE); if (error()) return;
	saddle_fac -> ptr.tor = torus_ptr;
	link_face (this_srf, saddle_fac); if (error()) return;
	add2face (saddle_fac, arc1, arc2, NULL, NULL); if (error()) return;
}
Esempio n. 8
0
/* new concave face */
void new_concave_face (struct surface *this_srf, struct probe *prb)
{
    int k;
    double probe_center[3];
	double vertex1_coor[3], vertex2_coor[3], vertex3_coor[3], vertex4_coor[3];
	double circle1_axis[3], circle2_axis[3], circle3_axis[3], circle4_axis[3];
	struct circle *circle1, *circle2, *circle3, *circle4;
	struct vertex *vertex1, *vertex2, *vertex3, *vertex4;
	struct arc *arc1, *arc2, *arc3, *arc4;
    struct sphere *atom1, *atom2, *atom3, *atom4;
	struct face *concave_fac;
    struct pair *torus1, *torus2, *torus3, *torus4;
	double dot1, dot2, dot3, dot4;
	char message[MAX_STRING];
    struct cept *ex;

	if (prb -> natom > 3) {
		sprintf (message, "%8ld probe square concave face", prb -> number);
		informd (message);
	}
	else {
		sprintf (message, "%8ld probe triangular concave face", prb -> number);
		informd2 (message);
	}
    atom1 = prb -> atm[0];
    atom2 = prb -> atm[1];
    atom3 = prb -> atm[2];
    atom4 = prb -> atm[3];
    torus1 = prb -> pairs[0];
    torus2 = prb -> pairs[1];
    torus3 = prb -> pairs[2];
    torus4 = prb -> pairs[3];
    for (k = 0; k < 3; k++)
		probe_center[k] = prb -> center[k];

	/* compute vertex coordinates */
	for (k = 0; k < 3; k++) {
		vertex1_coor[k] = (atom1 -> radius * probe_center[k] +
			this_srf -> probe_radius * atom1 -> center[k]) /
			(atom1 -> radius + this_srf -> probe_radius);
		vertex2_coor[k] = (atom2 -> radius * probe_center[k] +
			this_srf -> probe_radius * atom2 -> center[k]) /
			(atom2 -> radius + this_srf -> probe_radius);
		vertex3_coor[k] = (atom3 -> radius * probe_center[k] +
			this_srf -> probe_radius * atom3 -> center[k]) /
				(atom3 -> radius + this_srf -> probe_radius);
		if (atom4 != NULL) {
			vertex4_coor[k] = (atom4 -> radius * probe_center[k] +
				this_srf -> probe_radius * atom4 -> center[k]) /
					(atom4 -> radius + this_srf -> probe_radius);
		}
	}

	/* set up vertices */
	vertex1 = new_vertex (vertex1_coor, (struct sphere *) atom1, prb, NULL, NULL);
	if (vertex1 == NULL) return;
	link_vertex (this_srf, vertex1);
	vertex2 = new_vertex (vertex2_coor, (struct sphere *) atom2, prb, NULL, NULL);
	if (vertex2 == NULL) return;
	link_vertex (this_srf, vertex2);
	vertex3 = new_vertex (vertex3_coor, (struct sphere *) atom3, prb, NULL, NULL);
	if (vertex3 == NULL) return;
	link_vertex (this_srf, vertex3);
	if (atom4 != NULL) {
		vertex4 = new_vertex (vertex4_coor, (struct sphere *) atom4, prb, NULL, NULL);
		if (vertex4 == NULL) return;
		link_vertex (this_srf, vertex4);
	}
	else vertex4 = NULL;

	/* calculate axes and set up circles */
	setup_axis (probe_center, prb -> atm[0] -> center,
		prb -> atm[1] -> center, circle1_axis);
	setup_axis (probe_center, prb -> atm[1] -> center,
		prb -> atm[2] -> center, circle2_axis);
	if (atom4 == NULL) {
		setup_axis (probe_center, prb -> atm[2] -> center,
			prb -> atm[0] -> center, circle3_axis);
	}
	else if (atom4 != NULL) {
		setup_axis (probe_center, prb -> atm[2] -> center,
			prb -> atm[3] -> center, circle3_axis);
		setup_axis (probe_center, prb -> atm[3] -> center,
			prb -> atm[0] -> center, circle4_axis);
	}

	circle1 = new_circle (probe_center, this_srf -> probe_radius, circle1_axis);
	if (circle1 == NULL) return;
	link_circle (this_srf, circle1);
	circle1 -> theta = 0.0;
	circle1 -> subtype = GREAT_SUBTYPE;
	circle2 = new_circle (probe_center, this_srf -> probe_radius, circle2_axis);
	if (circle2 == NULL) return;
	link_circle (this_srf, circle2);
	circle2 -> theta = 0.0;
	circle2 -> subtype = GREAT_SUBTYPE;
	circle3 = new_circle (probe_center, this_srf -> probe_radius, circle3_axis);
	if (circle3 == NULL) return;
	link_circle (this_srf, circle3);
	circle3 -> theta = 0.0;
	circle3 -> subtype = GREAT_SUBTYPE;
	if (atom4 != NULL) {
		circle4 = new_circle (probe_center, this_srf -> probe_radius, circle4_axis);
		if (circle4 == NULL) return;
		link_circle (this_srf, circle4);
		circle4 -> theta = 0.0;
		circle4 -> subtype = GREAT_SUBTYPE;
	}
	else circle4 = NULL;

	/* set up arcs */
	arc1 = new_arc (circle1, vertex1, vertex2, CONCAVE, 0, (double) 0.0, 0L, 0L, 0L);
	if (arc1 == NULL) return;
	this_srf -> n_arc++;
	arc2 = new_arc (circle2, vertex2, vertex3, CONCAVE, 0, (double) 0.0, 0L, 0L, 0L);
	if (arc2 == NULL) return;
	this_srf -> n_arc++;
	if (circle4 == NULL) {
		arc3 = new_arc (circle3, vertex3, vertex1, CONCAVE, 0, (double) 0.0, 0L, 0L, 0L);
		if (arc3 == NULL) return;
		this_srf -> n_arc++;
		arc4 = NULL;
	}
	else if (circle4 != NULL) {
		arc3 = new_arc (circle3, vertex3, vertex4, CONCAVE, 0, (double) 0.0, 0L, 0L, 0L);
		if (arc3 == NULL) return;
		this_srf -> n_arc++;
		arc4 = new_arc (circle4, vertex4, vertex1, CONCAVE, 0, (double) 0.0, 0L, 0L, 0L);
		if (arc4 == NULL) return;
		this_srf -> n_arc++;
	}

	/* add arcs to tori */
	arc1 -> next = torus1 -> first_arc;
	torus1 -> first_arc = arc1;
	sprintf (message, "%8ld %8ld torus: add arc", 
		torus1 -> sph[0] -> number, torus1 -> sph[1] -> number);
	informd2(message);
	arc2 -> next = torus2 -> first_arc;
	torus2 -> first_arc = arc2;
	sprintf (message, "%8ld %8ld torus: add arc", 
		torus2 -> sph[0] -> number, torus2 -> sph[1] -> number);
	informd2(message);
	arc3 -> next = torus3 -> first_arc;
	torus3 -> first_arc = arc3;
	sprintf (message, "%8ld %8ld torus: add arc", 
		torus3 -> sph[0] -> number, torus3 -> sph[1] -> number);
	informd2(message);
	if (torus4 != NULL) {
		arc4 -> next = torus4 -> first_arc;
		torus4 -> first_arc = arc4;
		sprintf (message, "%8ld %8ld torus: add arc", 
			torus4 -> sph[0] -> number, torus4 -> sph[1] -> number);
		informd(message);
	}

	/* new concave face */
	concave_fac = new_face (NULL, CONCAVE);
	if (concave_fac == NULL) return;
	concave_fac -> ptr.prb = prb;
	concave_fac -> chi = 1;
	link_face (this_srf, concave_fac);
	add2face (concave_fac, arc1, arc2, arc3, arc4);

	/* back pointer for cusp corrections */
	prb -> fac = concave_fac;
	arc1 -> fac = concave_fac;
	arc2 -> fac = concave_fac;
	arc3 -> fac = concave_fac;
	if (arc4 != NULL) {
		arc4 -> fac = concave_fac;
	}
}
Esempio n. 9
0
void
Surface_mesh::
split(Edge e, Vertex v)
{
    Halfedge h0 = halfedge(e, 0);
    Halfedge o0 = halfedge(e, 1);

    Vertex   v2 = to_vertex(o0);

    Halfedge e1 = new_edge(v, v2);
    Halfedge t1 = opposite_halfedge(e1);

    Face     f0 = face(h0);
    Face     f3 = face(o0);

    set_halfedge(v, h0);
    set_vertex(o0, v);

    if (!is_boundary(h0))
    {
        Halfedge h1 = next_halfedge(h0);
        Halfedge h2 = next_halfedge(h1);

        Vertex   v1 = to_vertex(h1);

        Halfedge e0 = new_edge(v, v1);
        Halfedge t0 = opposite_halfedge(e0);

        Face f1 = new_face();
        set_halfedge(f0, h0);
        set_halfedge(f1, h2);

        set_face(h1, f0);
        set_face(t0, f0);
        set_face(h0, f0);

        set_face(h2, f1);
        set_face(t1, f1);
        set_face(e0, f1);

        set_next_halfedge(h0, h1);
        set_next_halfedge(h1, t0);
        set_next_halfedge(t0, h0);

        set_next_halfedge(e0, h2);
        set_next_halfedge(h2, t1);
        set_next_halfedge(t1, e0);
    }
    else
    {
        set_next_halfedge(prev_halfedge(h0), t1);
        set_next_halfedge(t1, h0);
        // halfedge handle of _vh already is h0
    }


    if (!is_boundary(o0))
    {
        Halfedge o1 = next_halfedge(o0);
        Halfedge o2 = next_halfedge(o1);

        Vertex v3 = to_vertex(o1);

        Halfedge e2 = new_edge(v, v3);
        Halfedge t2 = opposite_halfedge(e2);

        Face f2 = new_face();
        set_halfedge(f2, o1);
        set_halfedge(f3, o0);

        set_face(o1, f2);
        set_face(t2, f2);
        set_face(e1, f2);

        set_face(o2, f3);
        set_face(o0, f3);
        set_face(e2, f3);

        set_next_halfedge(e1, o1);
        set_next_halfedge(o1, t2);
        set_next_halfedge(t2, e1);

        set_next_halfedge(o0, e2);
        set_next_halfedge(e2, o2);
        set_next_halfedge(o2, o0);
    }
    else
    {
        set_next_halfedge(e1, next_halfedge(o0));
        set_next_halfedge(o0, e1);
        set_halfedge(v, e1);
    }

    if (halfedge(v2) == h0)
        set_halfedge(v2, t1);
}
Esempio n. 10
0
Surface_mesh::Face
Surface_mesh::
add_face(const std::vector<Vertex>& vertices)
{
    Vertex                   v;
    unsigned int             i, ii, n((int)vertices.size()), id;
    std::vector<Halfedge>    halfedges(n);
    std::vector<bool>        is_new(n), needs_adjust(n, false);
    Halfedge                 inner_next, inner_prev,
    outer_next, outer_prev,
    boundary_next, boundary_prev,
    patch_start, patch_end;

    // cache for set_next_halfedge and vertex' set_halfedge
    typedef std::pair<Halfedge, Halfedge>  NextCacheEntry;
    typedef std::vector<NextCacheEntry>    NextCache;

    NextCache    next_cache;
    next_cache.reserve(3*n);


    // don't allow degenerated faces
    assert (n > 2);


    // test for topological errors
    for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
    {
        if ( !is_boundary(vertices[i]) )
        {
            std::cerr << "Surface_meshT::add_face: complex vertex\n";
            return Face();
        }

        halfedges[i] = find_halfedge(vertices[i], vertices[ii]);
        is_new[i]    = !halfedges[i].is_valid();

        if (!is_new[i] && !is_boundary(halfedges[i]))
        {
            std::cerr << "Surface_meshT::add_face: complex edge\n";
            return Face();
        }
    }


    // re-link patches if necessary
    for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
    {
        if (!is_new[i] && !is_new[ii])
        {
            inner_prev = halfedges[i];
            inner_next = halfedges[ii];

            if (next_halfedge(inner_prev) != inner_next)
            {
                // here comes the ugly part... we have to relink a whole patch

                // search a free gap
                // free gap will be between boundary_prev and boundary_next
                outer_prev = opposite_halfedge(inner_next);
                outer_next = opposite_halfedge(inner_prev);
                boundary_prev = outer_prev;
                do
                    boundary_prev = opposite_halfedge(next_halfedge(boundary_prev));
                while (!is_boundary(boundary_prev) || boundary_prev==inner_prev);
                boundary_next = next_halfedge(boundary_prev);
                assert(is_boundary(boundary_prev));
                assert(is_boundary(boundary_next));


                // ok ?
                if (boundary_next == inner_next)
                {
                    std::cerr << "Surface_meshT::add_face: patch re-linking failed\n";
                    return Face();
                }

                // other halfedges' handles
                patch_start = next_halfedge(inner_prev);
                patch_end   = prev_halfedge(inner_next);

                // relink
                next_cache.push_back(NextCacheEntry(boundary_prev, patch_start));
                next_cache.push_back(NextCacheEntry(patch_end, boundary_next));
                next_cache.push_back(NextCacheEntry(inner_prev, inner_next));
            }
        }
    }



    // create missing edges
    for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
        if (is_new[i])
            halfedges[i] = new_edge(vertices[i], vertices[ii]);



    // create the face
    Face f(new_face());
    set_halfedge(f, halfedges[n-1]);



    // setup halfedges
    for (i=0, ii=1; i<n; ++i, ++ii, ii%=n)
    {
        v          = vertices[ii];
        inner_prev = halfedges[i];
        inner_next = halfedges[ii];

        id = 0;
        if (is_new[i])  id |= 1;
        if (is_new[ii]) id |= 2;

        if (id)
        {
            outer_prev = opposite_halfedge(inner_next);
            outer_next = opposite_halfedge(inner_prev);

            // set outer links
            switch (id)
            {
                case 1: // prev is new, next is old
                    boundary_prev = prev_halfedge(inner_next);
                    next_cache.push_back(NextCacheEntry(boundary_prev, outer_next));
                    set_halfedge(v, outer_next);
                    break;

                case 2: // next is new, prev is old
                    boundary_next = next_halfedge(inner_prev);
                    next_cache.push_back(NextCacheEntry(outer_prev, boundary_next));
                    set_halfedge(v, boundary_next);
                    break;

                case 3: // both are new
                    if (!halfedge(v).is_valid())
                    {
                        set_halfedge(v, outer_next);
                        next_cache.push_back(NextCacheEntry(outer_prev, outer_next));
                    }
                    else
                    {
                        boundary_next = halfedge(v);
                        boundary_prev = prev_halfedge(boundary_next);
                        next_cache.push_back(NextCacheEntry(boundary_prev, outer_next));
                        next_cache.push_back(NextCacheEntry(outer_prev, boundary_next));
                    }
                    break;
            }

            // set inner link
            next_cache.push_back(NextCacheEntry(inner_prev, inner_next));
        }
        else needs_adjust[ii] = (halfedge(v) == inner_next);


        // set face handle
        set_face(halfedges[i], f);
    }



    // process next halfedge cache
    NextCache::const_iterator ncIt(next_cache.begin()), ncEnd(next_cache.end());
    for (; ncIt != ncEnd; ++ncIt)
        set_next_halfedge(ncIt->first, ncIt->second);



    // adjust vertices' halfedge handle
    for (i=0; i<n; ++i)
        if (needs_adjust[i])
            adjust_outgoing_halfedge(vertices[i]);


    return f;
}