/*
         * Delete any degenerate faces with only two edges.  WalkDirtyRegions()
         * will catch almost all of these, but it won't catch degenerate faces
         * produced by splice operations on already-processed edges.
         * The two places this can happen are in FinishLeftRegions(), when
         * we splice in a "temporary" edge produced by ConnectRightVertex(),
         * and in CheckForLeftSplice(), where we splice already-processed
         * edges to ensure that our dictionary invariants are not violated
         * by numerical errors.
         *
         * In both these cases it is *very* dangerous to delete the offending
         * edge at the time, since one of the routines further up the stack
         * will sometimes be keeping a pointer to that edge.
         */
        private static bool RemoveDegenerateFaces(Mesh mesh)
        {
            Face f, fNext;
            HalfEdge e;

            for (f = mesh.faceHead.nextFace; f != mesh.faceHead; f = fNext)
            {
                fNext = f.nextFace;
                e = f.halfEdgeThisIsLeftFaceOf;
                if (e.nextEdgeCCWAroundLeftFace == e)
                {
                    throw new Exception();
                }

                if (e.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundLeftFace == e)
                {
                    /* A face with only two edges */
                    AddWinding(e.nextEdgeCCWAroundOrigin, e);
                    Mesh.DeleteHalfEdge(e);
                }
            }

            return true;
        }
Exemple #2
0
        /* __gl_meshUnion( mesh1, mesh2 ) forms the union of all structures in
        * both meshes, and returns the new mesh (the old meshes are destroyed).
        */
        private Mesh meshUnion(Mesh mesh1, Mesh mesh2)
        {
            Face f1 = mesh1.faceHead;
            ContourVertex v1 = mesh1.vertexHead;
            HalfEdge e1 = mesh1.halfEdgeHead;
            Face f2 = mesh2.faceHead;
            ContourVertex v2 = mesh2.vertexHead;
            HalfEdge e2 = mesh2.halfEdgeHead;

            /* Add the faces, vertices, and edges of mesh2 to those of mesh1 */
            if (f2.nextFace != f2)
            {
                f1.prevFace.nextFace = f2.nextFace;
                f2.nextFace.prevFace = f1.prevFace;
                f2.prevFace.nextFace = f1;
                f1.prevFace = f2.prevFace;
            }

            if (v2.nextVertex != v2)
            {
                v1.prevVertex.nextVertex = v2.nextVertex;
                v2.nextVertex.prevVertex = v1.prevVertex;
                v2.prevVertex.nextVertex = v1;
                v1.prevVertex = v2.prevVertex;
            }

            if (e2.nextHalfEdge != e2)
            {
                e1.otherHalfOfThisEdge.nextHalfEdge.otherHalfOfThisEdge.nextHalfEdge = e2.nextHalfEdge;
                e2.nextHalfEdge.otherHalfOfThisEdge.nextHalfEdge = e1.otherHalfOfThisEdge.nextHalfEdge;
                e2.otherHalfOfThisEdge.nextHalfEdge.otherHalfOfThisEdge.nextHalfEdge = e1;
                e1.otherHalfOfThisEdge.nextHalfEdge = e2.otherHalfOfThisEdge.nextHalfEdge;
            }

            mesh2 = null;
            return mesh1;
        }
Exemple #3
0
        public void RenderMesh(Mesh mesh)
        {
            Face f;

            /* Make a list of separate triangles so we can render them all at once */
            lonelyTriList = null;

            for (f = mesh.faceHead.nextFace; f != mesh.faceHead; f = f.nextFace)
            {
                f.marked = false;
            }
            for (f = mesh.faceHead.nextFace; f != mesh.faceHead; f = f.nextFace)
            {
                /* We examine all faces in an arbitrary order.  Whenever we find
                * an unprocessed face F, we output a group of faces including F
                * whose size is maximum.
                */
                if (f.isInterior && !f.marked)
                {
                    RenderMaximumFaceGroup(f);
                    if (!f.marked)
                    {
                        throw new Exception();
                    }
                }
            }
            if (lonelyTriList != null)
            {
                RenderLonelyTriangles(lonelyTriList);
                lonelyTriList = null;
            }
        }
Exemple #4
0
 /************************ Boundary contour decomposition ******************/
 /* Takes a mesh, and outputs one
 * contour for each face marked "inside".  The rendering output is
 * provided as callbacks.
 */
 public void RenderBoundary(Mesh mesh)
 {
     for (Face curFace = mesh.faceHead.nextFace; curFace != mesh.faceHead; curFace = curFace.nextFace)
     {
         if (curFace.isInterior)
         {
             CallBegin(TriangleListType.LineLoop);
             HalfEdge curHalfEdge = curFace.halfEdgeThisIsLeftFaceOf;
             do
             {
                 CallVertex(curHalfEdge.originVertex.clientIndex);
                 curHalfEdge = curHalfEdge.nextEdgeCCWAroundLeftFace;
             } while (curHalfEdge != curFace.halfEdgeThisIsLeftFaceOf);
             CallEnd();
         }
     }
 }
Exemple #5
0
        public void EndPolygon()
        {
            RequireState(ProcessingState.InPolygon);
            processingState = ProcessingState.Dormant;

            if (mesh == null)
            {
                if (!EdgeCallBackSet && callMesh == null)
                {
                    /* Try some special code to make the easy cases go quickly
                    * (eg. convex polygons).  This code does NOT handle multiple contours,
                    * intersections, edge flags, and of course it does not generate
                    * an explicit mesh either.
                    */
                    if (RenderCache())
                    {
                        return;
                    }
                }

                EmptyCache(); /* could've used a label*/
            }

            /* Determine the polygon normal and project vertices onto the plane
            * of the polygon.
            */
            ProjectPolygon();

            /* __gl_computeInterior( this ) computes the planar arrangement specified
            * by the given contours, and further subdivides this arrangement
            * into regions.  Each region is marked "inside" if it belongs
            * to the polygon, according to the rule given by this.windingRule.
            * Each interior region is guaranteed to be monotone.
            */
            ActiveRegion.ComputeInterior(this);

            bool rc = true;

            /* If the user wants only the boundary contours, we throw away all edges
            * except those which separate the interior from the exterior.
            * Otherwise we tessellate all the regions marked "inside".
            */
            if (boundaryOnly)
            {
                rc = mesh.SetWindingNumber(1, true);
            }
            else
            {
                rc = mesh.TessellateInterior();
            }

            mesh.CheckMesh();

            if (callBegin != null || callEnd != null
                || callVertex != null || callEdgeFlag != null)
            {
                if (boundaryOnly)
                {
                    RenderBoundary(mesh); /* output boundary contours */
                }
                else
                {
                    RenderMesh(mesh); /* output strips and fans */
                }
            }
            if (callMesh != null)
            {
                /* Throw away the exterior faces, so that all faces are interior.
                * This way the user doesn't have to check the "inside" flag,
                * and we don't need to even reveal its existence.  It also leaves
                * the freedom for an implementation to not generate the exterior
                * faces in the first place.
                */
                mesh.DiscardExterior();
                callMesh(mesh); /* user wants the mesh itself */
                mesh = null;
                return;
            }
            mesh = null;
        }
Exemple #6
0
        public void EmptyCache()
        {
            VertexAndIndex[] v = simpleVertexCache;

            mesh = new Mesh();

            for (int i = 0; i < cacheCount; i++)
            {
                AddVertex(v[i].x, v[i].y, v[i].vertexIndex);
            }
            cacheCount = 0;
            emptyCache = false;
        }
Exemple #7
0
        public virtual void BeginPolygon()
        {
            RequireState(ProcessingState.Dormant);

            processingState = ProcessingState.InPolygon;
            cacheCount = 0;
            emptyCache = false;
            mesh = null;
        }