public static EdgeSign ( LibTessDotNet.MeshUtils.Vertex u, LibTessDotNet.MeshUtils.Vertex v, LibTessDotNet.MeshUtils.Vertex w ) : Real | ||
u | LibTessDotNet.MeshUtils.Vertex | |
v | LibTessDotNet.MeshUtils.Vertex | |
w | LibTessDotNet.MeshUtils.Vertex | |
Результат | Real |
private bool EdgeLeq(ActiveRegion reg1, ActiveRegion reg2) { MeshUtils.Edge eUp = reg1._eUp; MeshUtils.Edge eUp2 = reg2._eUp; if (eUp._Dst == _event) { if (eUp2._Dst == _event) { if (Geom.VertLeq(eUp._Org, eUp2._Org)) { return(Geom.EdgeSign(eUp2._Dst, eUp._Org, eUp2._Org) <= 0f); } return(Geom.EdgeSign(eUp._Dst, eUp2._Org, eUp._Org) >= 0f); } return(Geom.EdgeSign(eUp2._Dst, _event, eUp2._Org) <= 0f); } if (eUp2._Dst == _event) { return(Geom.EdgeSign(eUp._Dst, _event, eUp._Org) >= 0f); } float num = Geom.EdgeEval(eUp._Dst, _event, eUp._Org); float num2 = Geom.EdgeEval(eUp2._Dst, _event, eUp2._Org); return(num >= num2); }
private bool CheckForLeftSplice(ActiveRegion regUp) { ActiveRegion activeRegion = RegionBelow(regUp); MeshUtils.Edge eUp = regUp._eUp; MeshUtils.Edge eUp2 = activeRegion._eUp; if (Geom.VertLeq(eUp._Dst, eUp2._Dst)) { if (Geom.EdgeSign(eUp._Dst, eUp2._Dst, eUp._Org) < 0f) { return(false); } RegionAbove(regUp)._dirty = (regUp._dirty = true); MeshUtils.Edge edge = _mesh.SplitEdge(eUp); _mesh.Splice(eUp2._Sym, edge); edge._Lface._inside = regUp._inside; } else { if (Geom.EdgeSign(eUp2._Dst, eUp._Dst, eUp2._Org) > 0f) { return(false); } regUp._dirty = (activeRegion._dirty = true); MeshUtils.Edge edge2 = _mesh.SplitEdge(eUp2); _mesh.Splice(eUp._Lnext, eUp2._Sym); edge2._Rface._inside = regUp._inside; } return(true); }
/// <summary> /// TessellateMonoRegion( 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). /// </summary> private void TessellateMonoRegion(MeshUtils.Face face) { // 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. var up = face._anEdge; Debug.Assert(up._Lnext != up && up._Lnext._Lnext != up); int dummy = 0; for (; Geom.VertLeq(up._Dst, up._Org); up = up._Lprev) { dummy += 1; } for (; Geom.VertLeq(up._Org, up._Dst); up = up._Lnext) { dummy += 1; } var lo = up._Lprev; while (up._Lnext != lo) { if (Geom.VertLeq(up._Dst, lo._Org)) { // 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._Lnext != up && (Geom.EdgeGoesLeft(lo._Lnext) || Geom.EdgeSign(lo._Org, lo._Dst, lo._Lnext._Dst) <= 0.0f)) { lo = _mesh.Connect(lo._Lnext, lo)._Sym; } lo = lo._Lprev; } else { // lo.Org is on the left. We can make CCW triangles from up.Dst. while (lo._Lnext != up && (Geom.EdgeGoesRight(up._Lprev) || Geom.EdgeSign(up._Dst, up._Org, up._Lprev._Org) >= 0.0f)) { up = _mesh.Connect(up, up._Lprev)._Sym; } up = up._Lnext; } } // Now lo.Org == up.Dst == the leftmost vertex. The remaining region // can be tessellated in a fan from this leftmost vertex. Debug.Assert(lo._Lnext != up); while (lo._Lnext._Lnext != up) { lo = _mesh.Connect(lo._Lnext, lo)._Sym; } }
private void ConnectLeftVertex(MeshUtils.Vertex vEvent) { ActiveRegion activeRegion = new ActiveRegion(); activeRegion._eUp = vEvent._anEdge._Sym; ActiveRegion key = _dict.Find(activeRegion).Key; ActiveRegion activeRegion2 = RegionBelow(key); if (activeRegion2 != null) { MeshUtils.Edge eUp = key._eUp; MeshUtils.Edge eUp2 = activeRegion2._eUp; if (Geom.EdgeSign(eUp._Dst, vEvent, eUp._Org) == 0f) { ConnectLeftDegenerate(key, vEvent); } else { ActiveRegion activeRegion3 = Geom.VertLeq(eUp2._Dst, eUp._Dst) ? key : activeRegion2; if (key._inside || activeRegion3._fixUpperEdge) { MeshUtils.Edge edge = (activeRegion3 != key) ? _mesh.Connect(eUp2._Dnext, vEvent._anEdge)._Sym : _mesh.Connect(vEvent._anEdge._Sym, eUp._Lnext); if (activeRegion3._fixUpperEdge) { FixUpperEdge(activeRegion3, edge); } else { ComputeWinding(AddRegionBelow(key, edge)); } SweepEvent(vEvent); } else { AddRightEdges(key, vEvent._anEdge, vEvent._anEdge, null, true); } } } }
private bool CheckForRightSplice(ActiveRegion regUp) { ActiveRegion activeRegion = RegionBelow(regUp); MeshUtils.Edge eUp = regUp._eUp; MeshUtils.Edge eUp2 = activeRegion._eUp; if (Geom.VertLeq(eUp._Org, eUp2._Org)) { if (Geom.EdgeSign(eUp2._Dst, eUp._Org, eUp2._Org) > 0f) { return(false); } if (!Geom.VertEq(eUp._Org, eUp2._Org)) { _mesh.SplitEdge(eUp2._Sym); _mesh.Splice(eUp, eUp2._Oprev); regUp._dirty = (activeRegion._dirty = true); } else if (eUp._Org != eUp2._Org) { _pq.Remove(eUp._Org._pqHandle); SpliceMergeVertices(eUp2._Oprev, eUp); } } else { if (Geom.EdgeSign(eUp._Dst, eUp2._Org, eUp._Org) < 0f) { return(false); } RegionAbove(regUp)._dirty = (regUp._dirty = true); _mesh.SplitEdge(eUp._Sym); _mesh.Splice(eUp2._Oprev, eUp); } return(true); }
private bool CheckForIntersect(ActiveRegion regUp) { ActiveRegion activeRegion = RegionBelow(regUp); MeshUtils.Edge eUp = regUp._eUp; MeshUtils.Edge eUp2 = activeRegion._eUp; MeshUtils.Vertex org = eUp._Org; MeshUtils.Vertex org2 = eUp2._Org; MeshUtils.Vertex dst = eUp._Dst; MeshUtils.Vertex dst2 = eUp2._Dst; if (org == org2) { return(false); } float num = Math.Min(org._t, dst._t); float num2 = Math.Max(org2._t, dst2._t); if (num > num2) { return(false); } if (Geom.VertLeq(org, org2)) { if (Geom.EdgeSign(dst2, org, org2) > 0f) { return(false); } } else if (Geom.EdgeSign(dst, org2, org) < 0f) { return(false); } MeshUtils.Vertex vertex = MeshUtils.Pooled <MeshUtils.Vertex> .Create(); Geom.EdgeIntersect(dst, org, dst2, org2, vertex); if (Geom.VertLeq(vertex, _event)) { vertex._s = _event._s; vertex._t = _event._t; } MeshUtils.Vertex vertex2 = Geom.VertLeq(org, org2) ? org : org2; if (Geom.VertLeq(vertex2, vertex)) { vertex._s = vertex2._s; vertex._t = vertex2._t; } if (Geom.VertEq(vertex, org) || Geom.VertEq(vertex, org2)) { CheckForRightSplice(regUp); return(false); } if ((!Geom.VertEq(dst, _event) && Geom.EdgeSign(dst, _event, vertex) >= 0f) || (!Geom.VertEq(dst2, _event) && Geom.EdgeSign(dst2, _event, vertex) <= 0f)) { if (dst2 == _event) { _mesh.SplitEdge(eUp._Sym); _mesh.Splice(eUp2._Sym, eUp); regUp = TopLeftRegion(regUp); eUp = RegionBelow(regUp)._eUp; FinishLeftRegions(RegionBelow(regUp), activeRegion); ActiveRegion regUp2 = regUp; MeshUtils.Edge oprev = eUp._Oprev; MeshUtils.Edge edge = eUp; AddRightEdges(regUp2, oprev, edge, edge, true); return(true); } if (dst == _event) { _mesh.SplitEdge(eUp2._Sym); _mesh.Splice(eUp._Lnext, eUp2._Oprev); activeRegion = regUp; regUp = TopRightRegion(regUp); MeshUtils.Edge rprev = RegionBelow(regUp)._eUp._Rprev; activeRegion._eUp = eUp2._Oprev; eUp2 = FinishLeftRegions(activeRegion, null); AddRightEdges(regUp, eUp2._Onext, eUp._Rprev, rprev, true); return(true); } if (Geom.EdgeSign(dst, _event, vertex) >= 0f) { RegionAbove(regUp)._dirty = (regUp._dirty = true); _mesh.SplitEdge(eUp._Sym); eUp._Org._s = _event._s; eUp._Org._t = _event._t; } if (Geom.EdgeSign(dst2, _event, vertex) <= 0f) { regUp._dirty = (activeRegion._dirty = true); _mesh.SplitEdge(eUp2._Sym); eUp2._Org._s = _event._s; eUp2._Org._t = _event._t; } return(false); } _mesh.SplitEdge(eUp._Sym); _mesh.SplitEdge(eUp2._Sym); _mesh.Splice(eUp2._Oprev, eUp); eUp._Org._s = vertex._s; eUp._Org._t = vertex._t; eUp._Org._pqHandle = _pq.Insert(eUp._Org); if (eUp._Org._pqHandle._handle == PQHandle.Invalid) { throw new InvalidOperationException("PQHandle should not be invalid"); } GetIntersectData(eUp._Org, org, dst, org2, dst2); RegionAbove(regUp)._dirty = (regUp._dirty = (activeRegion._dirty = true)); return(false); }
private void TessellateMonoRegion(MeshUtils.Face face) { MeshUtils.Edge edge = face._anEdge; while (Geom.VertLeq(edge._Dst, edge._Org)) { edge = edge._Lprev; } while (Geom.VertLeq(edge._Org, edge._Dst)) { edge = edge._Lnext; } MeshUtils.Edge edge2 = edge._Lprev; while (edge._Lnext != edge2) { if (Geom.VertLeq(edge._Dst, edge2._Org)) { while (edge2._Lnext != edge && (Geom.EdgeGoesLeft(edge2._Lnext) || Geom.EdgeSign(edge2._Org, edge2._Dst, edge2._Lnext._Dst) <= 0f)) { edge2 = _mesh.Connect(edge2._Lnext, edge2)._Sym; } edge2 = edge2._Lprev; } else { while (edge2._Lnext != edge && (Geom.EdgeGoesRight(edge._Lprev) || Geom.EdgeSign(edge._Dst, edge._Org, edge._Lprev._Org) >= 0f)) { Mesh mesh = _mesh; MeshUtils.Edge edge3 = edge; edge = mesh.Connect(edge3, edge3._Lprev)._Sym; } edge = edge._Lnext; } } while (edge2._Lnext._Lnext != edge) { edge2 = _mesh.Connect(edge2._Lnext, edge2)._Sym; } }