void HeapInsert(SweepEvent[] heap, int heapsize, SweepEvent newevent) { double eventx, eventy; int eventnum; int parent; bool notdone; eventx = newevent.xkey; eventy = newevent.ykey; eventnum = heapsize; notdone = eventnum > 0; while (notdone) { parent = (eventnum - 1) >> 1; if ((heap[parent].ykey < eventy) || ((heap[parent].ykey == eventy) && (heap[parent].xkey <= eventx))) { notdone = false; } else { heap[eventnum] = heap[parent]; heap[eventnum].heapposition = eventnum; eventnum = parent; notdone = eventnum > 0; } } heap[eventnum] = newevent; newevent.heapposition = eventnum; }
void Heapify(SweepEvent[] heap, int heapsize, int eventnum) { SweepEvent thisevent; double eventx, eventy; int leftchild, rightchild; int smallest; bool notdone; thisevent = heap[eventnum]; eventx = thisevent.xkey; eventy = thisevent.ykey; leftchild = 2 * eventnum + 1; notdone = leftchild < heapsize; while (notdone) { if ((heap[leftchild].ykey < eventy) || ((heap[leftchild].ykey == eventy) && (heap[leftchild].xkey < eventx))) { smallest = leftchild; } else { smallest = eventnum; } rightchild = leftchild + 1; if (rightchild < heapsize) { if ((heap[rightchild].ykey < heap[smallest].ykey) || ((heap[rightchild].ykey == heap[smallest].ykey) && (heap[rightchild].xkey < heap[smallest].xkey))) { smallest = rightchild; } } if (smallest == eventnum) { notdone = false; } else { heap[eventnum] = heap[smallest]; heap[eventnum].heapposition = eventnum; heap[smallest] = thisevent; thisevent.heapposition = smallest; eventnum = smallest; leftchild = 2 * eventnum + 1; notdone = leftchild < heapsize; } } }
// Правильнее было назвать GetList() internal void ForEach(List <SweepEvent> list, Visit visit, SweepEvent lo = null, SweepEvent hi = null) { if (this.root == null) { return; } int arguments_length = 3; if (hi == null) { arguments_length--; } if (lo == null) { arguments_length--; } if (visit == null) { return; } switch (arguments_length) { case 1: doVisitFull(list, visit, this.root); break; case 2: doVisitHalf(lo, this.compare, list, visit, this.root); break; case 3: if (this.compare(lo, hi) >= 0) { return; } doVisit(lo, hi, this.compare, list, visit, this.root); break; } }
//Insert a new item into the tree internal RedBlackTree insert(SweepEvent key, SweepEvent value) { Comporator cmp = this.compare; //Find point to insert new node at RBNode n1 = this.root; List <RBNode> n_stack = new List <RBNode>(); List <int?> d_stack = new List <int?>(); while (n1 != null) { int?d = cmp(key, n1.key); n_stack.Add(n1); d_stack.Add(d); if (d <= 0) { n1 = n1.left; } else { n1 = n1.right; } } //Rebuild path to leaf node n_stack.Add(new RBNode(RBTreeNodeColor.RED, key, value, null, null, 1)); for (int i = n_stack.Count - 2; i > -1; i--) { RBNode n_i = n_stack[i]; if (d_stack[i] <= 0) { n_stack[i] = new RBNode(n_i.color, n_i.key, n_i.value, n_stack[i + 1], n_i.right, n_i.count + 1); } else { n_stack[i] = new RBNode(n_i.color, n_i.key, n_i.value, n_i.left, n_stack[i + 1], n_i.count + 1); } } //Rebalance tree using rotations for (int i = n_stack.Count - 1; i > 1; i--) { RBNode p = n_stack[i - 1]; RBNode n = n_stack[i]; if (p.color == RBTreeNodeColor.BLACK || n.color == RBTreeNodeColor.BLACK) { break; } RBNode pp = n_stack[i - 2]; if (pp.left == p) { if (p.left == n) { RBNode y = pp.right; if (y != null && y.color == RBTreeNodeColor.RED) { p.color = RBTreeNodeColor.BLACK; pp.right = y.repaint(RBTreeNodeColor.BLACK); pp.color = RBTreeNodeColor.RED; i--; } else { pp.color = RBTreeNodeColor.RED; pp.left = p.right; p.color = RBTreeNodeColor.BLACK; p.right = pp; n_stack[i - 2] = p; n_stack[i - 1] = n; pp.recount(); p.recount(); if (i >= 3) { RBNode ppp = n_stack[i - 3]; if (ppp.left == pp) { ppp.left = p; } else { ppp.right = p; } } break; } } else { RBNode y = pp.right; if (y != null && y.color == RBTreeNodeColor.RED) { p.color = RBTreeNodeColor.BLACK; pp.right = y.repaint(RBTreeNodeColor.BLACK); pp.color = RBTreeNodeColor.RED; i--; } else { p.right = n.left; pp.color = RBTreeNodeColor.RED; pp.left = n.right; n.color = RBTreeNodeColor.BLACK; n.left = p; n.right = pp; n_stack[i - 2] = n; n_stack[i - 1] = p; pp.recount(); p.recount(); n.recount(); if (i >= 3) { RBNode ppp = n_stack[i - 3]; if (ppp.left == pp) { ppp.left = n; } else { ppp.right = n; } } break; } } } else { if (p.right == n) { RBNode y = pp.left; if (y != null && y.color == RBTreeNodeColor.RED) { p.color = RBTreeNodeColor.BLACK; pp.left = y.repaint(RBTreeNodeColor.BLACK); pp.color = RBTreeNodeColor.RED; i--; } else { pp.color = RBTreeNodeColor.RED; pp.right = p.left; p.color = RBTreeNodeColor.BLACK; p.left = pp; n_stack[i - 2] = p; n_stack[i - 1] = n; pp.recount(); p.recount(); if (i >= 3) { RBNode ppp = n_stack[i - 3]; if (ppp.right == pp) { ppp.right = p; } else { ppp.left = p; } } break; } } else { RBNode y = pp.left; if (y != null && y.color == RBTreeNodeColor.RED) { p.color = RBTreeNodeColor.BLACK; pp.left = y.repaint(RBTreeNodeColor.BLACK); pp.color = RBTreeNodeColor.RED; i--; } else { p.left = n.right; pp.color = RBTreeNodeColor.RED; pp.right = n.left; n.color = RBTreeNodeColor.BLACK; n.right = p; n.left = pp; n_stack[i - 2] = n; n_stack[i - 1] = p; pp.recount(); p.recount(); n.recount(); if (i >= 3) { RBNode ppp = n_stack[i - 3]; if (ppp.right == pp) { ppp.right = n; } else { ppp.left = n; } } break; } } } } //Return new tree n_stack[0].color = RBTreeNodeColor.BLACK; return(new RedBlackTree(cmp, n_stack[0])); }
internal static int possibleIntersection(SweepEvent se1, SweepEvent se2, TinyQueue queue) { // that disallows self-intersecting polygons, // did cost us half a day, so I'll leave it // out of respect // if (se1.isSubject === se2.isSubject) return; var inter = SegmentIntersection(se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point); var nintersections = inter != null ? inter.Length : 0; if (nintersections == 0) { return(0); // no intersection } // the line segments intersect at an endpoint of both line segments if ((nintersections == 1) && (equals(se1.point, se2.point) || equals(se1.otherEvent.point, se2.otherEvent.point))) { return(0); } if (nintersections == 2 && se1.isSubject == se2.isSubject) { // if(se1.contourId === se2.contourId){ // console.warn('Edges of the same polygon overlap', // se1.point, se1.otherEvent.point, se2.point, se2.otherEvent.point); // } //throw new Error('Edges of the same polygon overlap'); return(0); } // The line segments associated to se1 and se2 intersect if (nintersections == 1) { // if the intersection point is not an endpoint of se1 if (!equals(se1.point, inter[0]) && !equals(se1.otherEvent.point, inter[0])) { divideSegment(se1, inter[0], queue); } // if the intersection point is not an endpoint of se2 if (!equals(se2.point, inter[0]) && !equals(se2.otherEvent.point, inter[0])) { divideSegment(se2, inter[0], queue); } return(1); } // The line segments associated to se1 and se2 overlap var events = new List <SweepEvent>(); var leftCoincide = false; var rightCoincide = false; if (equals(se1.point, se2.point)) { leftCoincide = true; // linked } else if (compareEvents(se1, se2) == 1) { events.Add(se2); events.Add(se1); } else { events.Add(se1); events.Add(se2); } if (equals(se1.otherEvent.point, se2.otherEvent.point)) { rightCoincide = true; } else if (compareEvents(se1.otherEvent, se2.otherEvent) == 1) { events.Add(se2.otherEvent); events.Add(se1.otherEvent); } else { events.Add(se1.otherEvent); events.Add(se2.otherEvent); } if ((leftCoincide && rightCoincide) || leftCoincide) // both line segments are equal or share the left endpoint { se1.type = EdgeType.NON_CONTRIBUTING; se2.type = (se1.inOut == se2.inOut) ? EdgeType.SAME_TRANSITION : EdgeType.DIFFERENT_TRANSITION; if (leftCoincide && !rightCoincide) { // honestly no idea, but changing events selection from [2, 1] to [0, 1] fixes the overlapping self-intersecting polygons issue divideSegment(events[1].otherEvent, events[0].point, queue); } return(2); } if (rightCoincide) // the line segments share the right endpoint { divideSegment(events[0], events[1].point, queue); return(3); } if (events[0] != events[3].otherEvent) // no line segment includes totally the other one { divideSegment(events[0], events[1].point, queue); divideSegment(events[1], events[2].point, queue); return(3); } // one line segment includes the other one divideSegment(events[0], events[1].point, queue); divideSegment(events[3].otherEvent, events[2].point, queue); return(3); }
void Check4DeadEvent(ref Otri checktri, SweepEvent[] eventheap, ref int heapsize) { SweepEvent deadevent; SweepEventVertex eventvertex; int eventnum = -1; eventvertex = checktri.Org() as SweepEventVertex; if (eventvertex != null) { deadevent = eventvertex.evt; eventnum = deadevent.heapposition; HeapDelete(eventheap, heapsize, eventnum); heapsize--; checktri.SetOrg(null); } }
void CreateHeap(out SweepEvent[] eventheap) { Vertex thisvertex; int maxevents; int i; SweepEvent evt; maxevents = (3 * mesh.invertices) / 2; eventheap = new SweepEvent[maxevents]; i = 0; foreach (var v in mesh.vertices.Values) { thisvertex = v; evt = new SweepEvent(); evt.vertexEvent = thisvertex; evt.xkey = thisvertex.x; evt.ykey = thisvertex.y; HeapInsert(eventheap, i++, evt); } }
public Polygon Compute(OperationType ot) { connector.OnAddEdgeEvent += OnAddEdge; if (subject == null) { return(clipper); } else if (clipper == null) { return(subject); } Polygon result = new Polygon(); futureSweepLineEvents.Clear(); // Test 1 for trivial result case if (subject.GetNumPaths() * clipper.GetNumPaths() == 0) { // At least one of the polygons is empty if (ot == OperationType.DIFFERENCE) { result = subject; } if (ot == OperationType.UNION) { result = (subject.GetNumPaths() == 0) ? clipper : subject; } return(result); } // Test 2 for trivial result case bbSubject = subject.GetBoundingBox(); bbClipper = clipper.GetBoundingBox(); if (bbSubject.min.x > bbClipper.max.x || bbSubject.min.y > bbClipper.max.y || bbClipper.min.x > bbSubject.max.x || bbClipper.min.y > bbSubject.max.y) { // the bounding boxes do not overlap if (ot == OperationType.DIFFERENCE) { result = subject; } if (ot == OperationType.UNION) { result = subject; for (int i = 0; i < clipper.GetNumPaths(); ++i) { result.Add(clipper.GetPath(i)); } } return(result); } // Insert all the endpoints associated to the line segments into the event queue for (int currentPath = 0; currentPath < subject.GetNumPaths(); ++currentPath) { for (int currentEdge = 0; currentEdge < subject.GetPath(currentPath).GetNumPoints(); ++currentEdge) { ProcessEdge(subject.GetPath(currentPath).GetEdge(currentEdge), Operand.SUBJECT); } } for (int currentPath = 0; currentPath < clipper.GetNumPaths(); ++currentPath) { for (int currentEdge = 0; currentEdge < clipper.GetPath(currentPath).GetNumPoints(); ++currentEdge) { ProcessEdge(clipper.GetPath(currentPath).GetEdge(currentEdge), Operand.CLIPPER); } } minMaxX = Mathf.Min(bbSubject.max.x, bbClipper.max.x); while (!futureSweepLineEvents.IsEmpty()) { SweepEvent currentEvent = futureSweepLineEvents.ExtractFirst(); currentEvent.Number = ++seCounter; if (AlreadyFinished(ref result, ot, currentEvent)) { return(result); } if (currentEvent.Left) { HandleLeftEvent(currentEvent); } else { HandleRightEvent(ot, currentEvent); } } return(connector.CreatePolygon()); }
public Mesh Triangulate(List <Vertex> points) { mesh = TrianglePool.AllocMesh(); mesh.TransferNodes(points); // Nonexistent x value used as a flag to mark circle events in sweepline // Delaunay algorithm. xminextreme = 10 * mesh.bounds.Left - 9 * mesh.bounds.Right; SweepEvent[] eventheap; SweepEvent nextevent; SweepEvent newevent; SplayNode splayroot; Otri bottommost = default(Otri); Otri searchtri = default(Otri); Otri fliptri; Otri lefttri = default(Otri); Otri righttri = default(Otri); Otri farlefttri = default(Otri); Otri farrighttri = default(Otri); Otri inserttri = default(Otri); Vertex firstvertex, secondvertex; Vertex nextvertex, lastvertex; Vertex connectvertex; Vertex leftvertex, midvertex, rightvertex; double lefttest, righttest; int heapsize; bool check4events, farrightflag = false; splaynodes = new List <SplayNode>(); splayroot = null; CreateHeap(out eventheap); //, out events, out freeevents); heapsize = mesh.invertices; mesh.MakeTriangle(ref lefttri); mesh.MakeTriangle(ref righttri); lefttri.Bond(ref righttri); lefttri.Lnext(); righttri.Lprev(); lefttri.Bond(ref righttri); lefttri.Lnext(); righttri.Lprev(); lefttri.Bond(ref righttri); firstvertex = eventheap[0].vertexEvent; HeapDelete(eventheap, heapsize, 0); heapsize--; do { if (heapsize == 0) { throw new Exception("Input vertices are all identical."); } secondvertex = eventheap[0].vertexEvent; HeapDelete(eventheap, heapsize, 0); heapsize--; if ((firstvertex.X == secondvertex.X) && (firstvertex.Y == secondvertex.Y)) { secondvertex.type = VertexType.UndeadVertex; mesh.undeads++; } } while ((firstvertex.X == secondvertex.X) && (firstvertex.Y == secondvertex.Y)); lefttri.SetOrg(firstvertex); lefttri.SetDest(secondvertex); righttri.SetOrg(secondvertex); righttri.SetDest(firstvertex); lefttri.Lprev(ref bottommost); lastvertex = secondvertex; while (heapsize > 0) { nextevent = eventheap[0]; HeapDelete(eventheap, heapsize, 0); heapsize--; check4events = true; if (nextevent.xkey < mesh.bounds.Left) { fliptri = nextevent.otriEvent; fliptri.Oprev(ref farlefttri); Check4DeadEvent(ref farlefttri, eventheap, ref heapsize); fliptri.Onext(ref farrighttri); Check4DeadEvent(ref farrighttri, eventheap, ref heapsize); if (farlefttri.Equal(bottommost)) { fliptri.Lprev(ref bottommost); } mesh.Flip(ref fliptri); fliptri.SetApex(null); fliptri.Lprev(ref lefttri); fliptri.Lnext(ref righttri); lefttri.Sym(ref farlefttri); if (randomnation(SAMPLERATE) == 0) { fliptri.Sym(); leftvertex = fliptri.Dest(); midvertex = fliptri.Apex(); rightvertex = fliptri.Org(); splayroot = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey); } } else { nextvertex = nextevent.vertexEvent; if ((nextvertex.X == lastvertex.X) && (nextvertex.Y == lastvertex.Y)) { nextvertex.type = VertexType.UndeadVertex; mesh.undeads++; check4events = false; } else { lastvertex = nextvertex; splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag); //bottommost.Copy(ref searchtri); //farrightflag = false; //while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex)) //{ // searchtri.OnextSelf(); // farrightflag = searchtri.Equal(bottommost); //} Check4DeadEvent(ref searchtri, eventheap, ref heapsize); searchtri.Copy(ref farrighttri); searchtri.Sym(ref farlefttri); mesh.MakeTriangle(ref lefttri); mesh.MakeTriangle(ref righttri); connectvertex = farrighttri.Dest(); lefttri.SetOrg(connectvertex); lefttri.SetDest(nextvertex); righttri.SetOrg(nextvertex); righttri.SetDest(connectvertex); lefttri.Bond(ref righttri); lefttri.Lnext(); righttri.Lprev(); lefttri.Bond(ref righttri); lefttri.Lnext(); righttri.Lprev(); lefttri.Bond(ref farlefttri); righttri.Bond(ref farrighttri); if (!farrightflag && farrighttri.Equal(bottommost)) { lefttri.Copy(ref bottommost); } if (randomnation(SAMPLERATE) == 0) { splayroot = SplayInsert(splayroot, lefttri, nextvertex); } else if (randomnation(SAMPLERATE) == 0) { righttri.Lnext(ref inserttri); splayroot = SplayInsert(splayroot, inserttri, nextvertex); } } } if (check4events) { leftvertex = farlefttri.Apex(); midvertex = lefttri.Dest(); rightvertex = lefttri.Apex(); lefttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex); if (lefttest > 0.0) { newevent = new SweepEvent(); newevent.xkey = xminextreme; newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, lefttest); newevent.otriEvent = lefttri; HeapInsert(eventheap, heapsize, newevent); heapsize++; lefttri.SetOrg(new SweepEventVertex(newevent)); } leftvertex = righttri.Apex(); midvertex = righttri.Org(); rightvertex = farrighttri.Apex(); righttest = RobustPredicates.CounterClockwise(leftvertex, midvertex, rightvertex); if (righttest > 0.0) { newevent = new SweepEvent(); newevent.xkey = xminextreme; newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, righttest); newevent.otriEvent = farrighttri; HeapInsert(eventheap, heapsize, newevent); heapsize++; farrighttri.SetOrg(new SweepEventVertex(newevent)); } } } splaynodes.Clear(); bottommost.Lprev(); mesh.hullsize = RemoveGhosts(ref bottommost); return(mesh); }
// Return value is whether or not we added a new segment. bool AddSegment(Point start, Point end, Obstacle eventObstacle , BasicObstacleSide lowNborSide, BasicObstacleSide highNborSide , SweepEvent action, double weight) { DevTraceInfoVgGen(1, "Adding Segment [{0} -> {1} {2}] weight {3}", start, end, weight); DevTraceInfoVgGen(2, " side {0}", lowNborSide); DevTraceInfoVgGen(2, " -> side {0}", highNborSide); if (PointComparer.Equal(start, end)) { return(false); } // See if the new segment subsumes or can be subsumed by the last one. gbcList may be null. PointAndCrossingsList gbcList = CurrentGroupBoundaryCrossingMap.GetOrderedListBetween(start, end); bool extendStart, extendEnd; bool wasSubsumed = ScanSegment.Subsume(ref hintScanSegment, start, end, weight, gbcList, ScanDirection , ParallelScanSegments, out extendStart, out extendEnd); if (!wasSubsumed) { Debug.Assert((weight != ScanSegment.ReflectionWeight) || (ParallelScanSegments.Find(start, end) == null), "Reflection segments already in the ScanSegmentTree should should have been detected before calling AddSegment"); hintScanSegment = ParallelScanSegments.InsertUnique(new ScanSegment(start, end, weight, gbcList)).Item; } else if (weight == ScanSegment.ReflectionWeight) { // Do not continue this; it is probably a situation where a side is at a tiny angle from the axis, // resulting in an initial reflection segment that is parallel and very close to the extreme-vertex-derived // segment, so as the staircase progresses they eventually converge due to floating-point rounding. // See RectilinearFilesTest.ReflectionStaircasesConverge. return(false); } // Do reflections only if the new segment is not overlapped. if (ScanSegment.OverlappedWeight != weight) { // If these fire, it's probably an indication that isOverlapped is not correctly set // and one of the neighbors is an OverlapSide from CreateScanSegments. Debug.Assert(lowNborSide is HighObstacleSide, "lowNbor is not HighObstacleSide"); Debug.Assert(highNborSide is LowObstacleSide, "highNbor is not LowObstacleSide"); // If we are closing the obstacle then the initial Obstacles of the reflections (the ones it // will bounce between) are the opposite neighbors. Otherwise, the OpenVertexEvent obstacle // is the ReflectionEvent initial obstacle. if (action is CloseVertexEvent) { // If both neighbor sides reflect upward, they can't intersect, so we don't need // to store a lookahead site (if neither reflect upward, StoreLookaheadSite no-ops). if (!SideReflectsUpward(lowNborSide) || !SideReflectsUpward(highNborSide)) { // Try to store both; only one will "take" (for the upward-reflecting side). // The initial Obstacle is the opposite neighbor. if (extendStart) { this.StoreLookaheadSite(highNborSide.Obstacle, lowNborSide, start, wantExtreme: false); } if (extendEnd) { this.StoreLookaheadSite(lowNborSide.Obstacle, highNborSide, end, wantExtreme: false); } } } else { if (extendStart) { StoreLookaheadSite(eventObstacle, LowNeighborSides.GroupSideInterveningBeforeLowNeighbor, lowNborSide, start); } if (extendEnd) { StoreLookaheadSite(eventObstacle, HighNeighborSides.GroupSideInterveningBeforeHighNeighbor, highNborSide, end); } } } DevTraceInfoVgGen(2, "HintScanSegment {0}{1}", hintScanSegment, wasSubsumed ? " (subsumed)" : ""); DevTrace_DumpScanSegmentsDuringAdd(3); return(true); }
public bool BelongsToSamePolygonAs(SweepEvent o) { return(o.owningPolygon == this.owningPolygon); }
public bool IsCollinearTo(SweepEvent se) { return(Orientation(Point, Other.Point, se.Point) == 0 && Orientation(Point, Other.Point, se.Other.Point) == 0); }
public void ComputeHoles() { exteriors.Clear(); if (GetNumPaths() < 2) { if (GetNumPaths() == 1 && GetPath(0).IsClockwise()) { GetPath(0).ToggleDirection(); exteriors.Add(0); } return; } List <SweepEvent> events = CreateHoleEvents(); AVLTree <SweepEvent> sweepLineEvents = new AVLTree <SweepEvent>(new EdgeComparer()); List <bool> processed = new List <bool>(Enumerable.Repeat(false, GetNumPaths())); List <int> holeOf = new List <int>(Enumerable.Repeat(-1, GetNumPaths())); int numProcessedEvents = 0; for (int i = 0; i < events.Count && numProcessedEvents < GetNumPaths(); ++i) { SweepEvent currentEvent = events[i]; if (currentEvent.Left) { currentEvent.positionInS = sweepLineEvents.Insert(currentEvent); if (!processed[currentEvent.OwningPolygon]) { processed[currentEvent.OwningPolygon] = true; ++numProcessedEvents; AVLNode <SweepEvent> prevNode = currentEvent.positionInS.GetPredecessor(); if (prevNode == null) { GetPath(currentEvent.OwningPolygon).SetCounterClockwise(); exteriors.Add(currentEvent.OwningPolygon); } else { SweepEvent prev = prevNode.Value; if (!prev.InOut) { holeOf[currentEvent.OwningPolygon] = prev.OwningPolygon; GetPath(currentEvent.OwningPolygon).SetHole(true); GetPath(prev.OwningPolygon).AddHole(currentEvent.OwningPolygon); if (GetPath(prev.OwningPolygon).IsCounterClockwise()) { GetPath(currentEvent.OwningPolygon).SetClockwise(); } else { GetPath(currentEvent.OwningPolygon).SetCounterClockwise(); exteriors.Add(currentEvent.OwningPolygon); } } else if (holeOf[prev.OwningPolygon] != -1) { holeOf[currentEvent.OwningPolygon] = holeOf[prev.OwningPolygon]; GetPath(currentEvent.OwningPolygon).SetHole(true); GetPath(holeOf[currentEvent.OwningPolygon]).AddHole(currentEvent.OwningPolygon); if (GetPath(holeOf[currentEvent.OwningPolygon]).IsCounterClockwise()) { GetPath(currentEvent.OwningPolygon).SetClockwise(); } else { GetPath(currentEvent.OwningPolygon).SetCounterClockwise(); exteriors.Add(currentEvent.OwningPolygon); } } else { GetPath(currentEvent.OwningPolygon).SetCounterClockwise(); exteriors.Add(currentEvent.OwningPolygon); } } } } else // remove the edge from the sweep line status { // sweepLineEvents.Delete(currentEvent.Other.positionInS); sweepLineEvents.Remove(currentEvent.Other); } } }
///* eslint-disable no-unused-vars, no-debugger, no-undef */ //function iteratorEquals(it1, it2) { // return it1._cursor === it2._cursor; //} //function _renderSweepLine(sweepLine, pos, _event) //{ //var map = window.map; //if (!map) return; //if (window.sws) window.sws.forEach(function (p) { //map.removeLayer(p); //}); //window.sws = []; //sweepLine.forEach(function (e) { //var poly = L.polyline([ // e.point.slice().reverse(), // e.otherEvent.point.slice().reverse() //], {color: 'green'}).addTo(map); //window.sws.push(poly); //}); //if (window.vt) map.removeLayer(window.vt); //var v = pos.slice(); //var b = map.getBounds(); //window.vt = L.polyline([ //[b.getNorth(), v[0]], //[b.getSouth(), v[0]] //], {color: 'green', weight: 1}).addTo(map); //if (window.ps) map.removeLayer(window.ps); //window.ps = L.polyline([ //_event.point.slice().reverse(), //_event.otherEvent.point.slice().reverse() //], {color: 'black', weight: 9, opacity: 0.4}).addTo(map); //debugger; //} ///* eslint-enable no-unused-vars, no-debugger, no-undef */ internal static List <SweepEvent> subdivideSegments(TinyQueue eventQueue, Point[][][] subject, Point[][][] clipping, double[] sbbox, double[] cbbox, Operation operation) { RedBlackTree sweepLine = new RedBlackTree(_comp_Segm); List <SweepEvent> sortedEvents = new List <SweepEvent>(); double rightbound = Math.Min(sbbox[2], cbbox[2]); RedBlackTreeIterator prev, next; SweepEvent prevEvent, prevprevEvent; while (eventQueue.length > 0) { SweepEvent _event = eventQueue.pop(); sortedEvents.Add(_event); // optimization by bboxes for intersection and difference goes here - коммент оригинала if ((operation == Operation.INTERSECTION && _event.point.X > rightbound) || (operation == Operation.DIFFERENCE && _event.point.X > sbbox[2])) { break; } if (_event.left) { sweepLine = sweepLine.insert(_event, _event); //_renderSweepLine(sweepLine, _event.point, _event); - коммент оригинала next = sweepLine.find(_event); prev = sweepLine.find(_event); _event.iterator = sweepLine.find(_event); if (!prev.node.Equals(sweepLine.begin.node)) // ??? (prev.node !== sweepLine.begin) { prev.prev(); } else { prev = sweepLine.begin; prev.prev(); prev.next(); } next.next(); //--- prevEvent = (prev.key || null), prevprevEvent; prevEvent = (SweepEvent)Convert.ChangeType(prev.key, typeof(SweepEvent)); computeFields(_event, prevEvent, operation); if (next.node != null) { if (possibleIntersection(_event, (SweepEvent)Convert.ChangeType(next.key, typeof(SweepEvent)), eventQueue) == 2) { computeFields(_event, prevEvent, operation); computeFields(_event, (SweepEvent)Convert.ChangeType(next.key, typeof(SweepEvent)), operation); } } if (prev.node != null) { if (possibleIntersection((SweepEvent)Convert.ChangeType(prev.key, typeof(SweepEvent)), _event, eventQueue) == 2) { RedBlackTreeIterator prevprev = sweepLine.find((SweepEvent)Convert.ChangeType(prev.key, typeof(SweepEvent))); if (!prevprev.node.Equals(sweepLine.begin.node)) //prevprev.node != sweepLine.begin { prevprev.prev(); } else { prevprev = sweepLine.find((SweepEvent)Convert.ChangeType(sweepLine.end.key, typeof(SweepEvent))); prevprev.next(); } prevprevEvent = (SweepEvent)Convert.ChangeType(prevprev.key, typeof(SweepEvent)); computeFields(prevEvent, prevprevEvent, operation); computeFields(_event, prevEvent, operation); } } } else { _event = _event.otherEvent; next = sweepLine.find(_event); prev = sweepLine.find(_event); // _renderSweepLine(sweepLine, _event.otherEvent.point, _event); - коммент оригинала if (!(prev != null && next != null)) { continue; } if (!prev.node.Equals(sweepLine.begin.node)) // prev.node != sweepLine.begin { prev.prev(); } else { prev = sweepLine.begin; prev.prev(); prev.next(); } next.next(); sweepLine = sweepLine.remove(_event); // _renderSweepLine(sweepLine, _event.otherEvent.point, _event); - коммент оригинала if (next.node != null && prev.node != null) { if (prev.node.value != null && next.node.value != null) //-- if (typeof prev.node.value != 'undefined' && typeof next.node.value != 'undefined') { possibleIntersection((SweepEvent)Convert.ChangeType(prev.key, typeof(SweepEvent)), (SweepEvent)Convert.ChangeType(next.key, typeof(SweepEvent)), eventQueue); } } } } return(sortedEvents); }
public int Triangulate(Mesh mesh) { this.mesh = mesh; // Nonexistent x value used as a flag to mark circle events in sweepline // Delaunay algorithm. xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax; SweepEvent[] eventheap; SweepEvent nextevent; SweepEvent newevent; SplayNode splayroot; Otri bottommost = default(Otri); Otri searchtri = default(Otri); Otri fliptri; Otri lefttri = default(Otri); Otri righttri = default(Otri); Otri farlefttri = default(Otri); Otri farrighttri = default(Otri); Otri inserttri = default(Otri); Vertex firstvertex, secondvertex; Vertex nextvertex, lastvertex; Vertex connectvertex; Vertex leftvertex, midvertex, rightvertex; float lefttest, righttest; int heapsize; bool check4events, farrightflag = false; splaynodes = new List <SplayNode>(); splayroot = null; CreateHeap(out eventheap);//, out events, out freeevents); heapsize = mesh.invertices; mesh.MakeTriangle(ref lefttri); mesh.MakeTriangle(ref righttri); lefttri.Bond(ref righttri); lefttri.LnextSelf(); righttri.LprevSelf(); lefttri.Bond(ref righttri); lefttri.LnextSelf(); righttri.LprevSelf(); lefttri.Bond(ref righttri); firstvertex = eventheap[0].vertexEvent; HeapDelete(eventheap, heapsize, 0); heapsize--; do { if (heapsize == 0) { SimpleLog.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()"); throw new Exception("Input vertices are all identical."); } secondvertex = eventheap[0].vertexEvent; HeapDelete(eventheap, heapsize, 0); heapsize--; if ((firstvertex.x == secondvertex.x) && (firstvertex.y == secondvertex.y)) { if (Behavior.Verbose) { SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().1"); } secondvertex.type = VertexType.UndeadVertex; mesh.undeads++; } } while ((firstvertex.x == secondvertex.x) && (firstvertex.y == secondvertex.y)); lefttri.SetOrg(firstvertex); lefttri.SetDest(secondvertex); righttri.SetOrg(secondvertex); righttri.SetDest(firstvertex); lefttri.Lprev(ref bottommost); lastvertex = secondvertex; while (heapsize > 0) { nextevent = eventheap[0]; HeapDelete(eventheap, heapsize, 0); heapsize--; check4events = true; if (nextevent.xkey < mesh.bounds.Xmin) { fliptri = nextevent.otriEvent; fliptri.Oprev(ref farlefttri); Check4DeadEvent(ref farlefttri, eventheap, ref heapsize); fliptri.Onext(ref farrighttri); Check4DeadEvent(ref farrighttri, eventheap, ref heapsize); if (farlefttri.Equal(bottommost)) { fliptri.Lprev(ref bottommost); } mesh.Flip(ref fliptri); fliptri.SetApex(null); fliptri.Lprev(ref lefttri); fliptri.Lnext(ref righttri); lefttri.Sym(ref farlefttri); if (randomnation(SAMPLERATE) == 0) { fliptri.SymSelf(); leftvertex = fliptri.Dest(); midvertex = fliptri.Apex(); rightvertex = fliptri.Org(); splayroot = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey); } } else { nextvertex = nextevent.vertexEvent; if ((nextvertex.x == lastvertex.x) && (nextvertex.y == lastvertex.y)) { if (Behavior.Verbose) { SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().2"); } nextvertex.type = VertexType.UndeadVertex; mesh.undeads++; check4events = false; } else { lastvertex = nextvertex; splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag); // bottommost.Copy(ref searchtri); farrightflag = false; while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex)) { searchtri.OnextSelf(); farrightflag = searchtri.Equal(bottommost); } Check4DeadEvent(ref searchtri, eventheap, ref heapsize); searchtri.Copy(ref farrighttri); searchtri.Sym(ref farlefttri); mesh.MakeTriangle(ref lefttri); mesh.MakeTriangle(ref righttri); connectvertex = farrighttri.Dest(); lefttri.SetOrg(connectvertex); lefttri.SetDest(nextvertex); righttri.SetOrg(nextvertex); righttri.SetDest(connectvertex); lefttri.Bond(ref righttri); lefttri.LnextSelf(); righttri.LprevSelf(); lefttri.Bond(ref righttri); lefttri.LnextSelf(); righttri.LprevSelf(); lefttri.Bond(ref farlefttri); righttri.Bond(ref farrighttri); if (!farrightflag && farrighttri.Equal(bottommost)) { lefttri.Copy(ref bottommost); } if (randomnation(SAMPLERATE) == 0) { splayroot = SplayInsert(splayroot, lefttri, nextvertex); } else if (randomnation(SAMPLERATE) == 0) { righttri.Lnext(ref inserttri); splayroot = SplayInsert(splayroot, inserttri, nextvertex); } } } if (check4events) { leftvertex = farlefttri.Apex(); midvertex = lefttri.Dest(); rightvertex = lefttri.Apex(); lefttest = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex); if (lefttest > 0.0) { newevent = new SweepEvent(); newevent.xkey = xminextreme; newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, lefttest); newevent.otriEvent = lefttri; HeapInsert(eventheap, heapsize, newevent); heapsize++; lefttri.SetOrg(new SweepEventVertex(newevent)); } leftvertex = righttri.Apex(); midvertex = righttri.Org(); rightvertex = farrighttri.Apex(); righttest = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex); if (righttest > 0.0) { newevent = new SweepEvent(); newevent.xkey = xminextreme; newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, righttest); newevent.otriEvent = farrighttri; HeapInsert(eventheap, heapsize, newevent); heapsize++; farrighttri.SetOrg(new SweepEventVertex(newevent)); } } } splaynodes.Clear(); bottommost.LprevSelf(); return(RemoveGhosts(ref bottommost)); }
public SweepEventVertex(SweepEvent e) { evt = e; }
private void HandleEvent(IBST <SweepEvent> events, IBST <StatusItem> status, SweepEvent ev) { ResultEvents.Add(ev); // Optimization 2 if ((Operation == OperationType.Intersection && ev.Point.x > RightBound) || (Operation == OperationType.Difference && ev.Point.x > SubjectBoundingBox.xMax)) { // We need to connect edges now, so just clear all events. This will result in us immediately // going to ConnectEdges() since there are no more events to handle. InitializeEvents(new List <SweepEvent>()); return; } if (ev.IsStart) // The line segment must be inserted into status { ev.StatusItem = new StatusItem(ev); if (!status.Insert(ev.StatusItem)) { throw new ArgumentException("Failed to insert into state"); } StatusItem prev; var prevFound = status.FindNextSmallest(ev.StatusItem, out prev); ComputeFields(ev, prev, prevFound); StatusItem next; if (status.FindNextBiggest(ev.StatusItem, out next)) { // Process a possible intersection between "ev" and its next neighbor in status if (PossibleIntersection(ev, next.SweepEvent, events) == 2) { ComputeFields(ev, prev, prevFound); ComputeFields(next.SweepEvent, ev.StatusItem, true); } } // Process a possible intersection between "ev" and its previous neighbor in status if (prevFound) { if (PossibleIntersection(prev.SweepEvent, ev, events) == 2) { StatusItem prevprev; var prevprevFound = status.FindNextSmallest(prev, out prevprev); ComputeFields(prev.SweepEvent, prevprev, prevprevFound); ComputeFields(ev, prev, prevFound); } } } else { // The line segment must be removed from status ev = ev.OtherEvent; // We work with the left event StatusItem prev, next; var prevFound = status.FindNextSmallest(ev.StatusItem, out prev); var nextFound = status.FindNextBiggest(ev.StatusItem, out next); // Delete line segment associated to "ev" from status and check for intersection between the neighbors of "ev" in status status.Delete(ev.StatusItem); if (nextFound && prevFound) { PossibleIntersection(prev.SweepEvent, next.SweepEvent, events); } } }
void HeapDelete(SweepEvent[] heap, int heapsize, int eventnum) { SweepEvent moveevent; double eventx, eventy; int parent; bool notdone; moveevent = heap[heapsize - 1]; if (eventnum > 0) { eventx = moveevent.xkey; eventy = moveevent.ykey; do { parent = (eventnum - 1) >> 1; if ((heap[parent].ykey < eventy) || ((heap[parent].ykey == eventy) && (heap[parent].xkey <= eventx))) { notdone = false; } else { heap[eventnum] = heap[parent]; heap[eventnum].heapposition = eventnum; eventnum = parent; notdone = eventnum > 0; } } while (notdone); } heap[eventnum] = moveevent; moveevent.heapposition = eventnum; Heapify(heap, heapsize - 1, eventnum); }
private int PossibleIntersection(SweepEvent ev1, SweepEvent ev2, IBST <SweepEvent> events) { Vector2D intersectionPoint; var nIntersections = FindIntersections(ev1.Point, ev1.OtherEvent.Point, ev2.Point, ev2.OtherEvent.Point, out intersectionPoint); if (nIntersections == 0) { return(0); // no intersection } // If the intersection is between two endpoints if (nIntersections == 1 && (ev1.Point.Equals(ev2.Point) || ev1.OtherEvent.Point.Equals(ev2.OtherEvent.Point))) { return(0); // the line segments intersect at an endpoint of both line segments } if (nIntersections == 2 && ev1.PolygonType == ev2.PolygonType) { // The line segments overlap, but they belong to the same polygon throw new ArgumentException(string.Format("Sorry, edges of the same polygon overlap ({0} and {1})", ev1, ev2)); } // The line segments associated to ev1 and ev2 intersect if (nIntersections == 1) { if (!ev1.Point.Equals(intersectionPoint) && !ev1.OtherEvent.Point.Equals(intersectionPoint) ) // If the intersection point is not an endpoint of ev1.Segment { DivideSegment(ev1, intersectionPoint, events); } if (!ev2.Point.Equals(intersectionPoint) && !ev2.OtherEvent.Point.Equals(intersectionPoint) ) // If the intersection point is not an endpoint of ev2.Segment { DivideSegment(ev2, intersectionPoint, events); } return(1); } // The line segments associated to ev1 and ev2 overlap var sortedEvents = new List <SweepEvent>(); var leftEqual = false; var rightEqual = false; if (ev1.Point.Equals(ev2.Point)) { leftEqual = true; } else if (SweepEvent.CompareTo(ev1, ev2) == 1) { sortedEvents.Add(ev2); sortedEvents.Add(ev1); } else { sortedEvents.Add(ev1); sortedEvents.Add(ev2); } if (ev1.OtherEvent.Point.Equals(ev2.OtherEvent.Point)) { rightEqual = true; } else if (SweepEvent.CompareTo(ev1.OtherEvent, ev2.OtherEvent) == 1) { sortedEvents.Add(ev2.OtherEvent); sortedEvents.Add(ev1.OtherEvent); } else { sortedEvents.Add(ev1.OtherEvent); sortedEvents.Add(ev2.OtherEvent); } if (leftEqual) { // Both line segments are equal or share the left endpoint ev2.EdgeType = EdgeType.NonContributing; ev1.EdgeType = (ev2.InOut == ev1.InOut) ? EdgeType.SameTransition : EdgeType.DifferentTransition; if (!rightEqual) { DivideSegment(sortedEvents[1].OtherEvent, sortedEvents[0].Point, events); } return(2); } if (rightEqual) { // The line segments share the right endpoint DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); return(3); } if (sortedEvents[0] != sortedEvents[3].OtherEvent) { // No line segment includes totally the other one DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); DivideSegment(sortedEvents[1], sortedEvents[2].Point, events); return(3); } // One line segment includes the other one DivideSegment(sortedEvents[0], sortedEvents[1].Point, events); DivideSegment(sortedEvents[3].OtherEvent, sortedEvents[2].Point, events); return(3); }
private ContourPolygon ConnectEdges() { var result = new ContourPolygon(); var resultEvents = ResultEvents .Where(it => (it.IsStart && it.InResult) || (!it.IsStart && it.OtherEvent.InResult)).ToList(); // Due to overlapping edges the resultEvents list can be not wholly sorted var sorted = false; while (!sorted) { sorted = true; for (int i = 0; i < resultEvents.Count; i++) { if (i + 1 < resultEvents.Count && SweepEvent.CompareTo(resultEvents[i], resultEvents[i + 1]) == 1) { var tmp = resultEvents[i]; resultEvents[i] = resultEvents[i + 1]; resultEvents[i + 1] = tmp; sorted = false; } } } // We cannot do a foreach because we need to set PositionInResult for (int i = 0; i < resultEvents.Count; i++) { var resultEvent = resultEvents[i]; resultEvent.PositionInResult = i; } foreach (var resultEvent in resultEvents) { if (!resultEvent.IsStart) { var tmp = resultEvent.PositionInResult; resultEvent.PositionInResult = resultEvent.OtherEvent.PositionInResult; resultEvent.OtherEvent.PositionInResult = tmp; } } var processed = new BitArray(resultEvents.Count); var depth = new List <int>(); var holeOf = new List <int>(); for (int i = 0; i < resultEvents.Count; i++) { if (processed[i]) { continue; } var contour = new Contour(); result.Add(contour); var contourId = result.NumberOfContours - 1; depth.Add(0); holeOf.Add(-1); if (resultEvents[i].PreviousInResult != null) { var lowerContourId = resultEvents[i].PreviousInResult.ContourId; if (!resultEvents[i].PreviousInResult.ResultInOut) { result[lowerContourId].AddHole(contourId); holeOf[contourId] = lowerContourId; depth[contourId] = depth[lowerContourId] + 1; contour.External = false; } else if (!result[lowerContourId].External) { result[holeOf[lowerContourId]].AddHole(contourId); holeOf[contourId] = holeOf[lowerContourId]; depth[contourId] = depth[lowerContourId]; contour.External = false; } } var pos = i; var initial = resultEvents[i].Point; contour.AddVertex(initial); while (pos >= i) { processed[pos] = true; if (resultEvents[pos].IsStart) { resultEvents[pos].ResultInOut = false; resultEvents[pos].ContourId = contourId; } else { resultEvents[pos].OtherEvent.ResultInOut = true; resultEvents[pos].OtherEvent.ContourId = contourId; } pos = resultEvents[pos].PositionInResult; processed[pos] = true; contour.AddVertex(resultEvents[pos].Point); pos = NextPos(pos, resultEvents, processed, i); } pos = pos == -1 ? i : pos; processed[pos] = processed[resultEvents[pos].PositionInResult] = true; resultEvents[pos].OtherEvent.ResultInOut = true; resultEvents[pos].OtherEvent.ContourId = contourId; if ((depth[contourId] & 1) != 0) { contour.ChangeOrientation(); } } return(result); }
public bool Equals(SweepEvent other) { throw new NotImplementedException(); }
public int Triangulate(Mesh mesh) { this.mesh = mesh; // Nonexistent x value used as a flag to mark circle events in sweepline // Delaunay algorithm. xminextreme = 10 * mesh.bounds.Xmin - 9 * mesh.bounds.Xmax; SweepEvent[] eventheap; SweepEvent nextevent; SweepEvent newevent; SplayNode splayroot; Otri bottommost = default(Otri); Otri searchtri = default(Otri); Otri fliptri; Otri lefttri = default(Otri); Otri righttri = default(Otri); Otri farlefttri = default(Otri); Otri farrighttri = default(Otri); Otri inserttri = default(Otri); Vertex firstvertex, secondvertex; Vertex nextvertex, lastvertex; Vertex connectvertex; Vertex leftvertex, midvertex, rightvertex; double lefttest, righttest; int heapsize; bool check4events, farrightflag = false; splaynodes = new List<SplayNode>(); splayroot = null; CreateHeap(out eventheap);//, out events, out freeevents); heapsize = mesh.invertices; mesh.MakeTriangle(ref lefttri); mesh.MakeTriangle(ref righttri); lefttri.Bond(ref righttri); lefttri.LnextSelf(); righttri.LprevSelf(); lefttri.Bond(ref righttri); lefttri.LnextSelf(); righttri.LprevSelf(); lefttri.Bond(ref righttri); firstvertex = eventheap[0].vertexEvent; HeapDelete(eventheap, heapsize, 0); heapsize--; do { if (heapsize == 0) { SimpleLog.Instance.Error("Input vertices are all identical.", "SweepLine.SweepLineDelaunay()"); throw new Exception("Input vertices are all identical."); } secondvertex = eventheap[0].vertexEvent; HeapDelete(eventheap, heapsize, 0); heapsize--; if ((firstvertex.x == secondvertex.x) && (firstvertex.y == secondvertex.y)) { if (Behavior.Verbose) { SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().1"); } secondvertex.type = VertexType.UndeadVertex; mesh.undeads++; } } while ((firstvertex.x == secondvertex.x) && (firstvertex.y == secondvertex.y)); lefttri.SetOrg(firstvertex); lefttri.SetDest(secondvertex); righttri.SetOrg(secondvertex); righttri.SetDest(firstvertex); lefttri.Lprev(ref bottommost); lastvertex = secondvertex; while (heapsize > 0) { nextevent = eventheap[0]; HeapDelete(eventheap, heapsize, 0); heapsize--; check4events = true; if (nextevent.xkey < mesh.bounds.Xmin) { fliptri = nextevent.otriEvent; fliptri.Oprev(ref farlefttri); Check4DeadEvent(ref farlefttri, eventheap, ref heapsize); fliptri.Onext(ref farrighttri); Check4DeadEvent(ref farrighttri, eventheap, ref heapsize); if (farlefttri.Equal(bottommost)) { fliptri.Lprev(ref bottommost); } mesh.Flip(ref fliptri); fliptri.SetApex(null); fliptri.Lprev(ref lefttri); fliptri.Lnext(ref righttri); lefttri.Sym(ref farlefttri); if (randomnation(SAMPLERATE) == 0) { fliptri.SymSelf(); leftvertex = fliptri.Dest(); midvertex = fliptri.Apex(); rightvertex = fliptri.Org(); splayroot = CircleTopInsert(splayroot, lefttri, leftvertex, midvertex, rightvertex, nextevent.ykey); } } else { nextvertex = nextevent.vertexEvent; if ((nextvertex.x == lastvertex.x) && (nextvertex.y == lastvertex.y)) { if (Behavior.Verbose) { SimpleLog.Instance.Warning("A duplicate vertex appeared and was ignored.", "SweepLine.SweepLineDelaunay().2"); } nextvertex.type = VertexType.UndeadVertex; mesh.undeads++; check4events = false; } else { lastvertex = nextvertex; splayroot = FrontLocate(splayroot, bottommost, nextvertex, ref searchtri, ref farrightflag); // bottommost.Copy(ref searchtri); farrightflag = false; while (!farrightflag && RightOfHyperbola(ref searchtri, nextvertex)) { searchtri.OnextSelf(); farrightflag = searchtri.Equal(bottommost); } Check4DeadEvent(ref searchtri, eventheap, ref heapsize); searchtri.Copy(ref farrighttri); searchtri.Sym(ref farlefttri); mesh.MakeTriangle(ref lefttri); mesh.MakeTriangle(ref righttri); connectvertex = farrighttri.Dest(); lefttri.SetOrg(connectvertex); lefttri.SetDest(nextvertex); righttri.SetOrg(nextvertex); righttri.SetDest(connectvertex); lefttri.Bond(ref righttri); lefttri.LnextSelf(); righttri.LprevSelf(); lefttri.Bond(ref righttri); lefttri.LnextSelf(); righttri.LprevSelf(); lefttri.Bond(ref farlefttri); righttri.Bond(ref farrighttri); if (!farrightflag && farrighttri.Equal(bottommost)) { lefttri.Copy(ref bottommost); } if (randomnation(SAMPLERATE) == 0) { splayroot = SplayInsert(splayroot, lefttri, nextvertex); } else if (randomnation(SAMPLERATE) == 0) { righttri.Lnext(ref inserttri); splayroot = SplayInsert(splayroot, inserttri, nextvertex); } } } if (check4events) { leftvertex = farlefttri.Apex(); midvertex = lefttri.Dest(); rightvertex = lefttri.Apex(); lefttest = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex); if (lefttest > 0.0) { newevent = new SweepEvent(); newevent.xkey = xminextreme; newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, lefttest); newevent.otriEvent = lefttri; HeapInsert(eventheap, heapsize, newevent); heapsize++; lefttri.SetOrg(new SweepEventVertex(newevent)); } leftvertex = righttri.Apex(); midvertex = righttri.Org(); rightvertex = farrighttri.Apex(); righttest = Primitives.CounterClockwise(leftvertex, midvertex, rightvertex); if (righttest > 0.0) { newevent = new SweepEvent(); newevent.xkey = xminextreme; newevent.ykey = CircleTop(leftvertex, midvertex, rightvertex, righttest); newevent.otriEvent = farrighttri; HeapInsert(eventheap, heapsize, newevent); heapsize++; farrighttri.SetOrg(new SweepEventVertex(newevent)); } } } splaynodes.Clear(); bottommost.LprevSelf(); return RemoveGhosts(ref bottommost); }
internal StatusItem(SweepEvent sweepEvent) { SweepEvent = sweepEvent; }
//public int defaultCompare(SweepEvent a, SweepEvent b) //{ // return a < b ? -1 : a > b ? 1 : 0; //} internal void push(SweepEvent item) { this.data.Add(item); this.length++; this._up(this.length - 1); }