public static VertLeq ( LibTessDotNet.MeshUtils.Vertex lhs, LibTessDotNet.MeshUtils.Vertex rhs ) : bool | ||
lhs | LibTessDotNet.MeshUtils.Vertex | |
rhs | LibTessDotNet.MeshUtils.Vertex | |
리턴 | bool |
private void FloatDown(int curr) { int child; int hCurr, hChild; hCurr = _nodes[curr]; while (true) { child = curr << 1; if (child < _size && Geom.VertLeq(_handles[_nodes[child + 1]]._key, _handles[_nodes[child]]._key)) { ++child; } Debug.Assert(child <= _max); hChild = _nodes[child]; if (child > _size || Geom.VertLeq(_handles[hCurr]._key, _handles[hChild]._key)) { _nodes[curr] = hCurr; _handles[hCurr]._node = curr; break; } _nodes[curr] = hChild; _handles[hChild]._node = curr; curr = child; } }
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); }
public void Remove(int handle) { Debug.Assert(_initialized); int hCurr = handle; Debug.Assert(hCurr >= 1 && hCurr <= _max && _handles[hCurr]._key != null); int curr = _handles[hCurr]._node; _nodes[curr] = _nodes[_size]; _handles[_nodes[curr]]._node = curr; if (curr <= --_size) { if (curr <= 1 || Geom.VertLeq(_handles[_nodes[curr >> 1]]._key, _handles[_nodes[curr]]._key)) { FloatDown(curr); } else { FloatUp(curr); } } _handles[hCurr]._key = null; _handles[hCurr]._node = _freeList; _freeList = hCurr; }
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); }
/// <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 ConnectRightVertex(ActiveRegion regUp, MeshUtils.Edge eBottomLeft) { MeshUtils.Edge edge = eBottomLeft._Onext; ActiveRegion activeRegion = RegionBelow(regUp); MeshUtils.Edge eUp = regUp._eUp; MeshUtils.Edge eUp2 = activeRegion._eUp; bool flag = false; if (eUp._Dst != eUp2._Dst) { CheckForIntersect(regUp); } if (Geom.VertEq(eUp._Org, _event)) { _mesh.Splice(edge._Oprev, eUp); regUp = TopLeftRegion(regUp); edge = RegionBelow(regUp)._eUp; FinishLeftRegions(RegionBelow(regUp), activeRegion); flag = true; } if (Geom.VertEq(eUp2._Org, _event)) { _mesh.Splice(eBottomLeft, eUp2._Oprev); eBottomLeft = FinishLeftRegions(activeRegion, null); flag = true; } if (flag) { ActiveRegion regUp2 = regUp; MeshUtils.Edge onext = eBottomLeft._Onext; MeshUtils.Edge edge2 = edge; AddRightEdges(regUp2, onext, edge2, edge2, true); } else { MeshUtils.Edge eDst = (!Geom.VertLeq(eUp2._Org, eUp._Org)) ? eUp : eUp2._Oprev; eDst = _mesh.Connect(eBottomLeft._Lprev, eDst); ActiveRegion regUp3 = regUp; MeshUtils.Edge edge3 = eDst; AddRightEdges(regUp3, edge3, edge3._Onext, eDst._Onext, false); eDst._Sym._activeRegion._fixUpperEdge = true; WalkDirtyRegions(regUp); } }
internal MeshUtils.Vertex Minimum() { Debug.Assert(_initialized); if (_size == 0) { return(_heap.Minimum()); } MeshUtils.Vertex sortMin = _keys[_order[_size - 1]]; if (!_heap.Empty) { MeshUtils.Vertex heapMin = _heap.Minimum(); if (Geom.VertLeq(heapMin, sortMin)) { return(heapMin); } } return(sortMin); }
private void FloatUp(int curr) { int parent; int hCurr, hParent; hCurr = _nodes[curr]; while (true) { parent = curr >> 1; hParent = _nodes[parent]; if (parent == 0 || Geom.VertLeq(_handles[hParent]._key, _handles[hCurr]._key)) { _nodes[curr] = hCurr; _handles[hCurr]._node = curr; break; } _nodes[curr] = hParent; _handles[hParent]._node = curr; curr = parent; } }
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 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; } }
internal MeshUtils.Vertex ExtractMin() { Debug.Assert(_initialized); if (_size == 0) { return(_heap.ExtractMin()); } MeshUtils.Vertex sortMin = _keys[_order[_size - 1]]; if (!_heap.Empty) { MeshUtils.Vertex heapMin = _heap.Minimum(); if (Geom.VertLeq(heapMin, sortMin)) { return(_heap.ExtractMin()); } } do { --_size; } while (_size > 0 && _keys[_order[_size - 1]] == null); return(sortMin); }
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); }
public void Init() { var stack = ArrayPool <StackItem> .Create(_size + 1, true); int stackPos = -1; int p, r, i, j, piv; uint seed = 2016473283; p = 0; r = _size - 1; _order = ArrayPool <int> .Create(_size + 1, true); for (piv = 0, i = p; i <= r; ++piv, ++i) { _order[i] = piv; } stack[++stackPos] = new StackItem { p = p, r = r }; while (stackPos >= 0) { var top = stack[stackPos--]; p = top.p; r = top.r; while (r > p + 10) { seed = seed * 1539415821 + 1; i = p + (int)(seed % (r - p + 1)); piv = _order[i]; _order[i] = _order[p]; _order[p] = piv; i = p - 1; j = r + 1; do { do { ++i; } while (!Geom.VertLeq(_keys[_order[i]], _keys[piv])); do { --j; } while (!Geom.VertLeq(_keys[piv], _keys[_order[j]])); Swap(ref _order[i], ref _order[j]); } while (i < j); Swap(ref _order[i], ref _order[j]); if (i - p < r - j) { stack[++stackPos] = new StackItem { p = j + 1, r = r }; r = i - 1; } else { stack[++stackPos] = new StackItem { p = p, r = i - 1 }; p = j + 1; } } for (i = p + 1; i <= r; ++i) { piv = _order[i]; for (j = i; j > p && !Geom.VertLeq(_keys[piv], _keys[_order[j - 1]]); --j) { _order[j] = _order[j - 1]; } _order[j] = piv; } } #if DEBUG p = 0; r = _size - 1; for (i = p; i < r; ++i) { Debug.Assert(Geom.VertLeq(_keys[_order[i + 1]], _keys[_order[i]]), "Wrong sort"); } #endif ArrayPool <StackItem> .Free(stack); _max = _size; _initialized = true; _heap.Init(); }
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); }