private void AddRightEdges(ActiveRegion regUp, MeshUtils.Edge eFirst, MeshUtils.Edge eLast, MeshUtils.Edge eTopLeft, bool cleanUp) { bool flag = true; MeshUtils.Edge edge = eFirst; do { AddRegionBelow(regUp, edge._Sym); edge = edge._Onext; }while (edge != eLast); if (eTopLeft == null) { eTopLeft = RegionBelow(regUp)._eUp._Rprev; } ActiveRegion activeRegion = regUp; MeshUtils.Edge edge2 = eTopLeft; while (true) { ActiveRegion activeRegion2 = RegionBelow(activeRegion); edge = activeRegion2._eUp._Sym; if (edge._Org != edge2._Org) { break; } if (edge._Onext != edge2) { _mesh.Splice(edge._Oprev, edge); _mesh.Splice(edge2._Oprev, edge); } activeRegion2._windingNumber = activeRegion._windingNumber - edge._winding; activeRegion2._inside = Geom.IsWindingInside(_windingRule, activeRegion2._windingNumber); activeRegion._dirty = true; if (!flag && CheckForRightSplice(activeRegion)) { Geom.AddWinding(edge, edge2); DeleteRegion(activeRegion); _mesh.Delete(edge2); } flag = false; activeRegion = activeRegion2; edge2 = edge; } activeRegion._dirty = true; if (cleanUp) { WalkDirtyRegions(activeRegion); } }
public void MergeConvexFaces(int maxVertsPerFace) { for (var f = _fHead._next; f != _fHead; f = f._next) { // Skip faces which are outside the result if (!f._inside) { continue; } var eCur = f._anEdge; var vStart = eCur._Org; while (true) { var eNext = eCur._Lnext; var eSym = eCur._Sym; if (eSym != null && eSym._Lface != null && eSym._Lface._inside) { // Try to merge the neighbour faces if the resulting polygons // does not exceed maximum number of vertices. int curNv = f.VertsCount; int symNv = eSym._Lface.VertsCount; if ((curNv + symNv - 2) <= maxVertsPerFace) { // Merge if the resulting poly is convex. if (Geom.VertCCW(eCur._Lprev._Org, eCur._Org, eSym._Lnext._Lnext._Org) && Geom.VertCCW(eSym._Lprev._Org, eSym._Org, eCur._Lnext._Lnext._Org)) { eNext = eSym._Lnext; Delete(eSym); eCur = null; } } } if (eCur != null && eCur._Lnext._Org == vStart) { break; } // Continue to next edge. eCur = eNext; } } }
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 ConnectLeftDegenerate(ActiveRegion regUp, MeshUtils.Vertex vEvent) { MeshUtils.Edge eUp = regUp._eUp; if (Geom.VertEq(eUp._Org, vEvent)) { throw new InvalidOperationException("Vertices should have been merged before"); } if (!Geom.VertEq(eUp._Dst, vEvent)) { _mesh.SplitEdge(eUp._Sym); if (regUp._fixUpperEdge) { _mesh.Delete(eUp._Onext); regUp._fixUpperEdge = false; } _mesh.Splice(vEvent._anEdge, eUp); SweepEvent(vEvent); return; } throw new InvalidOperationException("Vertices should have been merged before"); }
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 void WalkDirtyRegions(ActiveRegion regUp) { ActiveRegion activeRegion = RegionBelow(regUp); while (true) { if (activeRegion._dirty) { regUp = activeRegion; activeRegion = RegionBelow(activeRegion); } else { if (!regUp._dirty) { activeRegion = regUp; regUp = RegionAbove(regUp); if (regUp == null || !regUp._dirty) { break; } } regUp._dirty = false; MeshUtils.Edge eUp = regUp._eUp; MeshUtils.Edge eUp2 = activeRegion._eUp; if (eUp._Dst != eUp2._Dst && CheckForLeftSplice(regUp)) { if (activeRegion._fixUpperEdge) { DeleteRegion(activeRegion); _mesh.Delete(eUp2); activeRegion = RegionBelow(regUp); eUp2 = activeRegion._eUp; } else if (regUp._fixUpperEdge) { DeleteRegion(regUp); _mesh.Delete(eUp); regUp = RegionAbove(activeRegion); eUp = regUp._eUp; } } if (eUp._Org != eUp2._Org) { if (eUp._Dst != eUp2._Dst && !regUp._fixUpperEdge && !activeRegion._fixUpperEdge && (eUp._Dst == _event || eUp2._Dst == _event)) { if (CheckForIntersect(regUp)) { break; } } else { CheckForRightSplice(regUp); } } if (eUp._Org == eUp2._Org && eUp._Dst == eUp2._Dst) { Geom.AddWinding(eUp2, eUp); DeleteRegion(regUp); _mesh.Delete(eUp); regUp = RegionAbove(activeRegion); } } } }
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 ComputeWinding(ActiveRegion reg) { reg._windingNumber = RegionAbove(reg)._windingNumber + reg._eUp._winding; reg._inside = Geom.IsWindingInside(_windingRule, reg._windingNumber); }
public void MergeConvexFaces(int maxVertsPerFace) { for (MeshUtils.Face next = _fHead._next; next != _fHead; next = next._next) { if (next._inside) { MeshUtils.Edge edge = next._anEdge; MeshUtils.Vertex org = edge._Org; while (true) { MeshUtils.Edge lnext = edge._Lnext; MeshUtils.Edge sym = edge._Sym; if (sym != null && sym._Lface != null && sym._Lface._inside) { int vertsCount = next.VertsCount; int vertsCount2 = sym._Lface.VertsCount; if (vertsCount + vertsCount2 - 2 <= maxVertsPerFace && Geom.VertCCW(edge._Lprev._Org, edge._Org, sym._Lnext._Lnext._Org) && Geom.VertCCW(sym._Lprev._Org, sym._Org, edge._Lnext._Lnext._Org)) { lnext = sym._Lnext; Delete(sym); edge = null; } } if (edge != null && edge._Lnext._Org == org) { break; } edge = lnext; } } } }