public virtual void gluTessVertex(double[] coords, int coords_offset, System.Object vertexData) { int i; bool tooLarge = false; double x; double[] clamped = new double[3]; requireState(TessState.T_IN_CONTOUR); if (flushCacheOnNextVertex) { if (!flushCache()) { callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY); return; } lastEdge = null; } for (i = 0; i < 3; ++i) { x = coords[i + coords_offset]; if (x < -GLU.GLU_TESS_MAX_COORD) { x = -GLU.GLU_TESS_MAX_COORD; tooLarge = true; } if (x > GLU.GLU_TESS_MAX_COORD) { x = GLU.GLU_TESS_MAX_COORD; tooLarge = true; } clamped[i] = x; } if (tooLarge) { callErrorOrErrorData(GLU.GLU_TESS_COORD_TOO_LARGE); } if (mesh == null) { if (cacheCount < TESS_MAX_CACHE) { cacheVertex(clamped, vertexData); return; } if (!flushCache()) { callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY); return; } } if (!addVertex(clamped, vertexData)) { callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY); } }
private void makeDormant() { /* Return the tessellator to its original dormant state. */ if (mesh != null) { Mesh.__gl_meshDeleteMesh(mesh); } state = TessState.T_DORMANT; lastEdge = null; mesh = null; }
private bool addVertex(double[] coords, System.Object vertexData) { GLUhalfEdge e; e = lastEdge; if (e == null) { /* Make a self-loop (one vertex, one edge). */ e = Mesh.__gl_meshMakeEdge(mesh); if (e == null) { return(false); } if (!Mesh.__gl_meshSplice(e, e.Sym)) { return(false); } } else { /* Create a new vertex and edge which immediately follow e * in the ordering around the left face. */ if (Mesh.__gl_meshSplitEdge(e) == null) { return(false); } e = e.Lnext; } /* The new vertex is now e.Org. */ e.Org.data = vertexData; e.Org.coords[0] = coords[0]; e.Org.coords[1] = coords[1]; e.Org.coords[2] = coords[2]; /* The winding of an edge says how the winding number changes as we * cross from the edge''s right face to its left face. We add the * vertices in such an order that a CCW contour will add +1 to * the winding number of the region inside the contour. */ e.winding = 1; e.Sym.winding = -1; lastEdge = e; return(true); }
public virtual void gluTessBeginContour() { requireState(TessState.T_IN_POLYGON); state = TessState.T_IN_CONTOUR; lastEdge = null; if (cacheCount > 0) { /* Just set a flag so we don't get confused by empty contours * -- these can be generated accidentally with the obsolete * NextContour() interface. */ flushCacheOnNextVertex = true; } }
/* __gl_meshTessellateMonoRegion( face ) 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 static bool __gl_meshTessellateMonoRegion(GLUface face) { GLUhalfEdge up, lo; /* 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. */ up = face.anEdge; //assert(up.Lnext != up && up.Lnext.Lnext != up); for (; Geom.VertLeq(up.Sym.Org, up.Org); up = up.Onext.Sym) { ; } for (; Geom.VertLeq(up.Org, up.Sym.Org); up = up.Lnext) { ; } lo = up.Onext.Sym; while (up.Lnext != lo) { if (Geom.VertLeq(up.Sym.Org, lo.Org)) { /* up.Sym.Org 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.Lnext != up && (Geom.EdgeGoesLeft(lo.Lnext) || Geom.EdgeSign(lo.Org, lo.Sym.Org, lo.Lnext.Sym.Org) <= 0)) { GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(lo.Lnext, lo); if (tempHalfEdge == null) { return(false); } lo = tempHalfEdge.Sym; } lo = lo.Onext.Sym; } else { /* lo.Org is on the left. We can make CCW triangles from up.Sym.Org. */ while (lo.Lnext != up && (Geom.EdgeGoesRight(up.Onext.Sym) || Geom.EdgeSign(up.Sym.Org, up.Org, up.Onext.Sym.Org) >= 0)) { GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(up, up.Onext.Sym); if (tempHalfEdge == null) { return(false); } up = tempHalfEdge.Sym; } up = up.Lnext; } } /* Now lo.Org == up.Sym.Org == the leftmost vertex. The remaining region * can be tessellated in a fan from this leftmost vertex. */ //assert(lo.Lnext != up); while (lo.Lnext.Lnext != up) { GLUhalfEdge tempHalfEdge = Mesh.__gl_meshConnect(lo.Lnext, lo); if (tempHalfEdge == null) { return(false); } lo = tempHalfEdge.Sym; } return(true); }
private bool addVertex(double[] coords, System.Object vertexData) { GLUhalfEdge e; e = lastEdge; if (e == null) { /* Make a self-loop (one vertex, one edge). */ e = Mesh.__gl_meshMakeEdge(mesh); if (e == null) return false; if (!Mesh.__gl_meshSplice(e, e.Sym)) return false; } else { /* Create a new vertex and edge which immediately follow e * in the ordering around the left face. */ if (Mesh.__gl_meshSplitEdge(e) == null) return false; e = e.Lnext; } /* The new vertex is now e.Org. */ e.Org.data = vertexData; e.Org.coords[0] = coords[0]; e.Org.coords[1] = coords[1]; e.Org.coords[2] = coords[2]; /* The winding of an edge says how the winding number changes as we * cross from the edge''s right face to its left face. We add the * vertices in such an order that a CCW contour will add +1 to * the winding number of the region inside the contour. */ e.winding = 1; e.Sym.winding = - 1; lastEdge = e; return true; }
public virtual void gluTessVertex(double[] coords, int coords_offset, System.Object vertexData) { int i; bool tooLarge = false; double x; double[] clamped = new double[3]; requireState(TessState.T_IN_CONTOUR); if (flushCacheOnNextVertex) { if (!flushCache()) { callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY); return ; } lastEdge = null; } for (i = 0; i < 3; ++i) { x = coords[i + coords_offset]; if (x < - GLU.GLU_TESS_MAX_COORD) { x = - GLU.GLU_TESS_MAX_COORD; tooLarge = true; } if (x > GLU.GLU_TESS_MAX_COORD) { x = GLU.GLU_TESS_MAX_COORD; tooLarge = true; } clamped[i] = x; } if (tooLarge) { callErrorOrErrorData(GLU.GLU_TESS_COORD_TOO_LARGE); } if (mesh == null) { if (cacheCount < TESS_MAX_CACHE) { cacheVertex(clamped, vertexData); return ; } if (!flushCache()) { callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY); return ; } } if (!addVertex(clamped, vertexData)) { callErrorOrErrorData(GLU.GLU_OUT_OF_MEMORY); } }
internal static bool EdgeGoesRight(GLUhalfEdge e) { return VertLeq(e.Org, e.Sym.Org); }
internal static bool EdgeGoesRight(GLUhalfEdge e) { return(VertLeq(e.Org, e.Sym.Org)); }