private void OnMesh(Mesh mesh)
 {
     //Log.Debug("  mesh!");
 }
예제 #2
0
        static bool RemoveDegenerateFaces(Mesh mesh)
        /*
         * 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.
         */
        {
            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;
        }
예제 #3
0
        void EmptyCache()
        {
            VertexAndIndex[] v = this.simpleVertexCache;

            this.mesh = new Mesh();

            for (int i = 0; i < this.cacheCount; i++)
            {
                this.AddVertex(v[i].x, v[i].y, v[i].vertexIndex);
            }
            this.cacheCount = 0;
            this.emptyCache = false;
        }
예제 #4
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;
		}
예제 #5
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)
         {
             this.CallBegin(Tesselator.TriangleListType.LineLoop);
             HalfEdge curHalfEdge = curFace.halfEdgeThisIsLeftFaceOf;
             do
             {
                 this.CallVertex(curHalfEdge.originVertex.clientIndex);
                 curHalfEdge = curHalfEdge.nextEdgeCCWAroundLeftFace;
             } while (curHalfEdge != curFace.halfEdgeThisIsLeftFaceOf);
             this.CallEnd();
         }
     }
 }
예제 #6
0
        /************************ Strips and Fans decomposition ******************/
        /* __gl_renderMesh( tess, mesh ) takes a mesh and breaks it into triangle
        * fans, strips, and separate triangles.  A substantial effort is made
        * to use as few rendering primitives as possible (ie. to make the fans
        * and strips as large as possible).
        *
        * The rendering output is provided as callbacks (see the api).
        */
        public void RenderMesh(Mesh mesh)
        {
            Face f;

            /* Make a list of separate triangles so we can render them all at once */
            this.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 System.Exception();
                    }
                }
            }
            if (this.lonelyTriList != null)
            {
                RenderLonelyTriangles(this.lonelyTriList);
                this.lonelyTriList = null;
            }
        }
예제 #7
0
        public void EndPolygon()
        {
            RequireState(ProcessingState.InPolygon);
            processingState = ProcessingState.Dormant;

            if (this.mesh == null)
            {
                if (!this.EdgeCallBackSet && this.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 (this.boundaryOnly)
            {
                rc = this.mesh.SetWindingNumber(1, true);
            }
            else
            {
                rc = this.mesh.TessellateInterior();
            }

            this.mesh.CheckMesh();

            if (this.callBegin != null || this.callEnd != null
                || this.callVertex != null || this.callEdgeFlag != null)
            {
                if (this.boundaryOnly)
                {
                    RenderBoundary(mesh);  /* output boundary contours */
                }
                else
                {
                    RenderMesh(mesh);	   /* output strips and fans */
                }
            }
            if (this.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 */
                this.mesh = null;
                return;
            }
            this.mesh = null;
        }
예제 #8
0
        public virtual void BeginPolygon()
        {
            RequireState(ProcessingState.Dormant);

            processingState = ProcessingState.InPolygon;
            cacheCount = 0;
            emptyCache = false;
            mesh = null;
        }
예제 #9
0
        /*
         * 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.
         */
        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;
        }
예제 #10
0
 void EmptyCache()
 {
     Vertex[] vCaches = this.simpleVertexCache;
     int[] index_caches = this.indexCached;
     this.mesh = new Mesh();
     int count = this.cacheCount;
     for (int i = 0; i < count; i++)
     {
         Vertex v = vCaches[i];
         this.AddVertex(v.x, v.y, index_caches[i]);
     }
     this.cacheCount = 0;
     this.emptyCache = false;
 }
예제 #11
0
        /* face.TessellateMonoRegion() tessellates a monotone region
         * (what else would it do??)  The region must consist of a single
         * loop of half-edges (see mesh.h) oriented CCW.  "Monotone" in this
         * case means that any vertical line intersects the interior of the
         * region in a single interval.
         *
         * Tessellation consists of adding interior edges (actually pairs of
         * half-edges), to split the region into non-overlapping triangles.
         *
         * The basic idea is explained in Preparata and Shamos (which I don''t
         * have handy right now), although their implementation is more
         * complicated than this one.  The are two edge chains, an upper chain
         * and a lower chain.  We process all vertices from both chains in order,
         * from right to left.
         *
         * The algorithm ensures that the following invariant holds after each
         * vertex is processed: the untessellated region consists of two
         * chains, where one chain (say the upper) is a single edge, and
         * the other chain is concave.  The left vertex of the single edge
         * is always to the left of all vertices in the concave chain.
         *
         * Each step consists of adding the rightmost unprocessed vertex to one
         * of the two chains, and forming a fan of triangles from the rightmost
         * of two chain endpoints.  Determining whether we can add each triangle
         * to the fan is a simple orientation test.  By making the fan as large
         * as possible, we restore the invariant (check it yourself).
         */

        internal bool TessellateMonoRegion()
        {
            /* All edges are oriented CCW around the boundary of the region.
             * First, find the half-edge whose origin vertex is rightmost.
             * Since the sweep goes from left to right, face.anEdge should
             * be close to the edge we want.
             */
            HalfEdge up = this.halfEdgeThisIsLeftFaceOf;

            if (up.nextEdgeCCWAroundLeftFace == up || up.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundLeftFace == up)
            {
                throw new Exception();
            }

            for (; up.directionVertex.VertLeq(up.originVertex); up = up.Lprev)
            {
                ;
            }
            for (; up.originVertex.VertLeq(up.directionVertex); up = up.nextEdgeCCWAroundLeftFace)
            {
                ;
            }

            HalfEdge lo = up.Lprev;

            while (up.nextEdgeCCWAroundLeftFace != lo)
            {
                if (up.directionVertex.VertLeq(lo.originVertex))
                {
                    /* up.Dst is on the left.  It is safe to form triangles from lo.Org.
                     * The EdgeGoesLeft test guarantees progress even when some triangles
                     * are CW, given that the upper and lower chains are truly monotone.
                     */
                    while (lo.nextEdgeCCWAroundLeftFace != up && (lo.nextEdgeCCWAroundLeftFace.EdgeGoesLeft() ||
                                                                  ContourVertex.EdgeSign(lo.originVertex, lo.directionVertex, lo.nextEdgeCCWAroundLeftFace.directionVertex) <= 0))
                    {
                        HalfEdge tempHalfEdge = Mesh.meshConnect(lo.nextEdgeCCWAroundLeftFace, lo);
                        lo = tempHalfEdge.otherHalfOfThisEdge;
                    }
                    lo = lo.Lprev;
                }
                else
                {
                    /* lo.Org is on the left.  We can make CCW triangles from up.Dst. */
                    while (lo.nextEdgeCCWAroundLeftFace != up && (up.Lprev.EdgeGoesRight() ||
                                                                  ContourVertex.EdgeSign(up.directionVertex, up.originVertex, up.Lprev.originVertex) >= 0))
                    {
                        HalfEdge tempHalfEdge = Mesh.meshConnect(up, up.Lprev);
                        up = tempHalfEdge.otherHalfOfThisEdge;
                    }
                    up = up.nextEdgeCCWAroundLeftFace;
                }
            }

            // Now lo.Org == up.Dst == the leftmost vertex.  The remaining region
            // can be tessellated in a fan from this leftmost vertex.
            if (lo.nextEdgeCCWAroundLeftFace == up)
            {
                throw new Exception();
            }
            while (lo.nextEdgeCCWAroundLeftFace.nextEdgeCCWAroundLeftFace != up)
            {
                HalfEdge tempHalfEdge = Mesh.meshConnect(lo.nextEdgeCCWAroundLeftFace, lo);
                lo = tempHalfEdge.otherHalfOfThisEdge;
            }

            return(true);
        }