Esempio n. 1
0
 /// <summary>
 /// Adds a halfedge to the halfedge list.
 /// </summary>
 /// <param name="halfedge">The halfedge to add.</param>
 protected void AppendToHalfedgeList(DXHalfedge halfedge)
 {
     halfedge.Index = halfedges.Count;
     halfedges.Add(halfedge);
 }
Esempio n. 2
0
            /// <summary>
            /// Adds a face to the mesh with the specified face traits.
            /// </summary>
            /// <param name="faceTraits">The custom traits for the face to add to the mesh.</param>
            /// <param name="faceVertices">The vertices of the face in counterclockwise order.</param>
            /// <returns>The face created by this method.</returns>
            /// <exception cref="BadTopologyException">
            /// Thrown when fewer than three vertices are given or the vertices cannot form a valid face.
            /// </exception>
            /// <exception cref="ArgumentNullException">Thrown when a null vertex is given.</exception>
            private DXFace CreateFace(TFaceTraits faceTraits, params DXVertex[] faceVertices)
            {
                int n = faceVertices.Length;

                // Require at least 3 vertices
                if (n < 3)
                {
                    throw new DXBadTopologyException("Cannot create a polygon with fewer than three vertices.");
                }

                DXEdge e;
                DXFace f;

                DXHalfedge[] faceHalfedges = new DXHalfedge[n];
                bool[]       isNewEdge     = new bool[n], isUsedVertex = new bool[n];

                // Make sure input is (mostly) acceptable before making any changes to the mesh
                for (int i = 0; i < n; ++i)
                {
                    int j = (i + 1) % n;

                    if (faceVertices[i] == null)
                    {
                        throw new ArgumentNullException("Can't add a null vertex to a face.");
                    }
                    if (!faceVertices[i].OnBoundary)
                    {
                        throw new DXBadTopologyException("Can't add an edge to a vertex on the interior of a mesh.");
                    }

                    // Find existing halfedges for this face
                    faceHalfedges[i] = faceVertices[i].FindHalfedgeTo(faceVertices[j]);
                    isNewEdge[i]     = (faceHalfedges[i] == null);
                    isUsedVertex[i]  = (faceVertices[i].Halfedge != null);

                    if (!isNewEdge[i] && !faceHalfedges[i].OnBoundary)
                    {
                        throw new DXBadTopologyException("Can't add more than two faces to an edge.");
                    }
                }

                // Create face
                f = new DXFace(faceTraits);
                mesh.AppendToFaceList(f);

                // Create new edges
                for (int i = 0; i < n; ++i)
                {
                    int j = (i + 1) % n;

                    if (isNewEdge[i])
                    {
                        // Create new edge
                        e = new DXEdge();
                        mesh.AppendToEdgeList(e);

                        // Create new halfedges
                        faceHalfedges[i] = new DXHalfedge();
                        mesh.AppendToHalfedgeList(faceHalfedges[i]);

                        faceHalfedges[i].Opposite = new DXHalfedge();
                        mesh.AppendToHalfedgeList(faceHalfedges[i].Opposite);

                        // Connect opposite halfedge to inner halfedge
                        faceHalfedges[i].Opposite.Opposite = faceHalfedges[i];

                        // Connect edge to halfedges
                        e.Halfedge0 = faceHalfedges[i];

                        // Connect halfedges to edge
                        faceHalfedges[i].Edge          = e;
                        faceHalfedges[i].Opposite.Edge = e;

                        // Connect halfedges to vertices
                        faceHalfedges[i].ToVertex          = faceVertices[j];
                        faceHalfedges[i].Opposite.ToVertex = faceVertices[i];

                        // Connect vertex to outgoing halfedge if it doesn't have one yet
                        if (faceVertices[i].Halfedge == null)
                        {
                            faceVertices[i].Halfedge = faceHalfedges[i];
                        }
                    }

                    if (faceHalfedges[i].Face != null)
                    {
                        throw new DXBadTopologyException("An inner halfedge already has a face assigned to it.");
                    }

                    // Connect inner halfedge to face
                    faceHalfedges[i].Face = f;

                    //Debug.Assert(faceHalfedges[i].FromVertex == faceVertices[i] && faceHalfedges[i].ToVertex == faceVertices[j]);
                }

                // Connect next/previous halfedges
                for (int i = 0; i < n; ++i)
                {
                    int j = (i + 1) % n;

                    // Outer halfedges
                    if (isNewEdge[i] && isNewEdge[j] && isUsedVertex[j])  // Both edges are new and vertex has faces connected already
                    {
                        DXHalfedge closeHalfedge = null;

                        // Find the closing halfedge of the first available opening
                        foreach (DXHalfedge h in faceVertices[j].Halfedges)
                        {
                            if (h.Face == null)
                            {
                                closeHalfedge = h;
                                break;
                            }
                        }

                        //Debug.Assert(closeHalfedge != null);

                        DXHalfedge openHalfedge = closeHalfedge.Previous;

                        // Link new outer halfedges into this opening
                        faceHalfedges[i].Opposite.Previous = openHalfedge;
                        openHalfedge.Next = faceHalfedges[i].Opposite;
                        faceHalfedges[j].Opposite.Next = closeHalfedge;
                        closeHalfedge.Previous         = faceHalfedges[j].Opposite;
                    }
                    else if (isNewEdge[i] && isNewEdge[j])  // Both edges are new
                    {
                        faceHalfedges[i].Opposite.Previous = faceHalfedges[j].Opposite;
                        faceHalfedges[j].Opposite.Next     = faceHalfedges[i].Opposite;
                    }
                    else if (isNewEdge[i] && !isNewEdge[j])  // This is new, next is old
                    {
                        faceHalfedges[i].Opposite.Previous = faceHalfedges[j].Previous;
                        faceHalfedges[j].Previous.Next     = faceHalfedges[i].Opposite;
                    }
                    else if (!isNewEdge[i] && isNewEdge[j])  // This is old, next is new
                    {
                        faceHalfedges[i].Next.Previous = faceHalfedges[j].Opposite;
                        faceHalfedges[j].Opposite.Next = faceHalfedges[i].Next;
                    }
                    else if (!isNewEdge[i] && !isNewEdge[j] && faceHalfedges[i].Next != faceHalfedges[j])  // Relink faces before adding new edges if they are in the way of a new face
                    {
                        DXHalfedge closeHalfedge = faceHalfedges[i].Opposite;

                        // Find the closing halfedge of the opening opposite the opening halfedge i is on
                        do
                        {
                            closeHalfedge = closeHalfedge.Previous.Opposite;
                        } while (closeHalfedge.Face != null && closeHalfedge != faceHalfedges[j] && closeHalfedge != faceHalfedges[i].Opposite);

                        if (closeHalfedge == faceHalfedges[j] || closeHalfedge == faceHalfedges[i].Opposite)
                        {
                            throw new DXBadTopologyException("Unable to find an opening to relink an existing face.");
                        }

                        DXHalfedge openHalfedge = closeHalfedge.Previous;

                        // Remove group of faces between two openings, close up gap to form one opening
                        openHalfedge.Next = faceHalfedges[i].Next;
                        faceHalfedges[i].Next.Previous = openHalfedge;

                        // Insert group of faces into target opening
                        faceHalfedges[j].Previous.Next = closeHalfedge;
                        closeHalfedge.Previous         = faceHalfedges[j].Previous;
                    }

                    // Inner halfedges
                    faceHalfedges[i].Next     = faceHalfedges[j];
                    faceHalfedges[j].Previous = faceHalfedges[i];
                }

                // Connect face to an inner halfedge
                f.Halfedge = faceHalfedges[0];

                return(f);
            }