/// <summary> /// Performs algorithm and returns skeleton /// </summary> public List<Point2D> Skeleton() { List<Point2D> ret = new List<Point2D>(); int i = 0; while (Q.Count != 0) { Event currentEvent = Q.Dequeue(); CircularLinkedList<Vertex> currentLAV = SLAV[currentEvent.getLAVID()]; Console.WriteLine("------ Iteration " + i + " LAV ID " + currentEvent.getLAVID() + " ------"); if (currentLAV.Count > 0) { foreach (Vertex vertex in currentLAV) { if (vertex != null) { Console.WriteLine("Vertex with ID= " + vertex.getID() + (vertex.isActive() ? " is active " : " is not active")); } } Console.WriteLine("---------------------------------"); } i++; if (currentEvent.getType() == EventType.Edge) { Console.WriteLine("Edge event between " + currentEvent.getFirstPoint().getID() + " and " + currentEvent.getSecondPoint().getID()); Node<Vertex> prevNode = currentLAV.Find(currentEvent.getFirstPoint()); Node<Vertex> nextNode = currentLAV.Find(currentEvent.getSecondPoint()); //check if event is outdated if (prevNode == null || nextNode == null || (!prevNode.Value.isActive() && !nextNode.Value.isActive())) { Console.WriteLine("Skipped edge event"); continue; } Vertex prevV = prevNode.Value; Vertex nextV = nextNode.Value; //check if we remain to the last 3 points if (prevNode.PrevActive().PrevActive().Value.Equals(nextV)) { Point2D intersect = new Point2D(LineTools.LineIntersect(prevV.getPoint(), prevV.getRayStepPoint(), nextV.getPoint(), nextV.getRayStepPoint())); ret.Add(prevV.getPoint()); ret.Add(intersect); ret.Add(nextV.getPoint()); ret.Add(intersect); ret.Add(prevNode.PrevActive().Value.getPoint()); ret.Add(intersect); currentLAV.Find(prevV).Value.setActive(false); currentLAV.Find(nextV).Value.setActive(false); currentLAV.Find(prevV).PrevActive().Value.setActive(false); continue; } //output two arcs ret.Add(currentEvent.getFirstPoint().getPoint()); ret.Add(currentEvent.getIntersection()); ret.Add(currentEvent.getSecondPoint().getPoint()); ret.Add(currentEvent.getIntersection()); //modify list currentLAV.Find(currentEvent.getFirstPoint()).Value.setActive(false); currentLAV.Find(currentEvent.getSecondPoint()).Value.setActive(false); Point2D intersection = currentEvent.getIntersection(); if (!intersection.Equals(Point2D.Zero)) { Vertex newV = new Vertex(intersection, id++); newV.prevEdge = prevV.prevEdge; newV.nextEdge = nextV.nextEdge; newV.update(); Node<Vertex> newNode = new Node<Vertex>(newV); currentLAV.AddAfter(prevV, newV); //currentLAV.Remove(prevV); //currentLAV.Remove(nextV); findClosestIntersectionAndStore(currentLAV, currentLAV.Find(newV).PrevActive().Value, currentLAV.Find(newV).Value, currentLAV.Find(newV).NextActive().Value); } } else { Console.WriteLine("Split event " + currentEvent.getFirstPoint().getID()); Node<Vertex> prevNode = currentLAV.Find(currentEvent.getFirstPoint()); //check if event is outdated if (prevNode == null || !prevNode.Value.isActive()) { Console.WriteLine("Skipped split event"); continue; } Vertex prevV = prevNode.Value; prevV.setActive(false); //check if we remain to the last 3 points if (prevNode.PrevActive().PrevActive().Value.Equals(prevNode.NextActive().Value)) { Point2D intersect = new Point2D(LineTools.LineIntersect(prevV.getPoint(), prevV.getRayStepPoint(), prevNode.Next.Value.getPoint(), prevNode.Next.Value.getRayStepPoint())); ret.Add(prevNode.Value.getPoint()); ret.Add(intersect); ret.Add(prevNode.NextActive().Value.getPoint()); ret.Add(intersect); ret.Add(prevNode.PrevActive().Value.getPoint()); ret.Add(intersect); continue; } //output only VI ret.Add(prevV.getPoint()); ret.Add(currentEvent.getIntersection()); //split LAV reset que etc Vertex newNodeV1 = new Vertex(currentEvent.getIntersection(), id++); newNodeV1.prevEdge = currentEvent.getFirstPoint().prevEdge; newNodeV1.nextEdge = currentEvent.getFirstEdgePoint().nextEdge; newNodeV1.update(); Vertex newNodeV2 = new Vertex(currentEvent.getIntersection(), id++); newNodeV2.prevEdge = currentEvent.getFirstPoint().nextEdge; newNodeV2.nextEdge = currentEvent.getFirstEdgePoint().nextEdge; newNodeV2.update(); CircularLinkedList<Vertex> newLAV = new CircularLinkedList<Vertex>(); newLAV.AddFirst(newNodeV2); Node<Vertex> current = SLAV[currentEvent.getLAVID()].Find(currentEvent.getFirstPoint()); while(!current.Next.Value.Equals(currentEvent.getSecondEdgePoint())) { if (current.Next.Equals(current)) { break; } current = current.Next; newLAV.AddLast(current.Value); //current.Value.setActive(false); SLAV[currentEvent.getLAVID()].Remove(current.Value); } SLAV.Add(newLAV); SLAV[currentEvent.getLAVID()].AddAfter(currentEvent.getFirstPoint(),newNodeV1); //SLAV[currentEvent.getLAVID()].Find(currentEvent.getFirstPoint()).Value.setActive(false); //SLAV[currentEvent.getLAVID()].Remove(currentEvent.getFirstPoint()); //test for (int x = 0; x < newLAV.Count; x++) { Vertex prev = newLAV[x].PrevActive().Value; Vertex curr = newLAV[x].Value; Vertex next = newLAV[x].NextActive().Value; findClosestIntersectionAndStore(newLAV, prev, curr, next); } //findClosestIntersectionAndStore(newLAV, newLAV.Find(newNodeV2).PrevActive().Value, newLAV.Find(newNodeV2).Value, newLAV.Find(newNodeV2).NextActive().Value); findClosestIntersectionAndStore(SLAV[currentEvent.getLAVID()], SLAV[currentEvent.getLAVID()].Find(newNodeV1).PrevActive().Value, SLAV[currentEvent.getLAVID()].Find(newNodeV1).Value, SLAV[currentEvent.getLAVID()].Find(newNodeV1).NextActive().Value); } } return ret; }
private OwnVector2 findNearestOppositeEdge(CircularLinkedList<Vertex> LAV, Vertex current, out Vertex firstEdgePoint, out Vertex secondEdgePoint) { firstEdgePoint = null; secondEdgePoint = null; Node<Vertex> temp = LAV.Find(current).Next; Point2D intersectionPoint = new Point2D(0,0); Point2D currentClosest = new Point2D(0, 0); Vertices testPoly = new Vertices(); foreach(Vertex v in LAV) { testPoly.Add(v.getPoint()); } while (!temp.Next.Value.Equals(current)) { //check if the edge is not behind the vertex if(LineTools.LineIntersect( current.getRayStart(), new Point2D(current.getRayStart().X + (-current.getRayDirection().X * int.MaxValue), -current.getRayStart().Y + (-current.getRayDirection().Y * int.MaxValue)), temp.Value.getPoint(), temp.Next.Value.getPoint(), true,false, out intersectionPoint)) { //Calc Bi (intersection ray current + bisector of triangle) Point2D intersect1 = new Point2D(LineTools.LineIntersect( current.prevEdge.getFirstPoint(), current.prevEdge.getSecondPoint(), temp.Value.getPoint(), temp.Next.Value.getPoint())); Point2D intersect2 = new Point2D(LineTools.LineIntersect( current.nextEdge.getFirstPoint(), current.nextEdge.getSecondPoint(), temp.Value.getPoint(), temp.Next.Value.getPoint())); Vertices tempVer = new Vertices(); tempVer.Add(current.getPoint()); tempVer.Add(intersect1); tempVer.Add(intersect2); Vertex edgeBisector1 = new Vertex(intersect1, -1); edgeBisector1.prevEdge = new Edge(current.getPoint(), intersect1); edgeBisector1.nextEdge = new Edge(intersect1, intersect2); edgeBisector1.update(); Point2D Bi = new Point2D(LineTools.LineIntersect( current.getRayStart(), current.getRayStepPoint(), edgeBisector1.getRayStart(), edgeBisector1.getRayStepPoint())); if (tempVer.PointInPolygon(ref Bi) == -1) { edgeBisector1 = new Vertex(intersect2, -1); edgeBisector1.prevEdge = new Edge(current.getPoint(), intersect2); edgeBisector1.nextEdge = new Edge(intersect2, intersect1); edgeBisector1.update(); Bi = new Point2D(LineTools.LineIntersect( current.getRayStart(), current.getRayStepPoint(), edgeBisector1.getRayStart(), edgeBisector1.getRayStepPoint())); if (tempVer.PointInPolygon(ref Bi) == -1) { temp = temp.Next; continue; } } //check if Bi inside polygon to begin with if (testPoly.PointInPolygon(ref Bi) == -1) { temp = temp.Next; continue; } //check if Bi is in area defined by opposing edge and it's bisectors //first check if both bisectors of edge are convex so we can see if Bi is inside the defined triangle if(temp.Value.isConvex() && temp.Next.Value.isConvex()) { OwnVector2 trianglePoint = LineTools.LineIntersect( temp.Value.getRayStart(), temp.Value.getRayStepPoint(), temp.Next.Value.getRayStart(), temp.Next.Value.getRayStepPoint()); if (!MathHelper.PointInTriangle(trianglePoint, temp.Value.getPoint(), temp.Next.Value.getPoint(), Bi)) { temp = temp.Next; continue; } } else{ Vertices test = new Vertices(); int sign1 = temp.Value.isConvex() ? 1 : -1; int sign2 = temp.Next.Value.isConvex() ? 1 : -1; test.Add(temp.Value.getPoint()); test.Add(temp.Next.Value.getPoint()); test.Add(new Point2D( temp.Next.Value.getPoint().X + (sign2 * temp.Next.Value.getRayDirection().X * int.MaxValue), temp.Next.Value.getPoint().Y + (sign2 * temp.Next.Value.getRayDirection().Y * int.MaxValue))); test.Add(new Point2D( temp.Value.getPoint().X + (sign1 * temp.Value.getRayDirection().X * int.MaxValue), temp.Value.getPoint().Y + (sign1 * temp.Value.getRayDirection().Y * int.MaxValue))); if (test.PointInPolygon(ref Bi) == -1) { temp = temp.Next; continue; } } if (currentClosest.Equals(Point2D.Zero) || Point2D.Distance(current.getPoint(), currentClosest) > Point2D.Distance(current.getPoint(), Bi)) { currentClosest = Bi; firstEdgePoint = temp.Value; secondEdgePoint = temp.Next.Value; } } temp = temp.Next; } testDots.Add(currentClosest); return currentClosest; }
/// <summary> /// Setup all the necessary lists for the algorithm to work /// </summary> private void setup() { //initialize SLAV SLAV = new List<CircularLinkedList<Vertex>>(); //initialize priority queue Q Q = new HeapPriorityQueue<Event>(500); //initialize first LAV CircularLinkedList<Vertex> LAV = new CircularLinkedList<Vertex>(); for (int i = 0; i < polygon.ControlVertices.Count; i++) { //Create vertex for each controlpoint and store edges + calc bisector ray Vertex vertex = new Vertex(polygon.ControlVertices[i], id++); vertex.prevEdge = new Edge(polygon.ControlVertices.PreviousVertex(i), vertex.getPoint()); vertex.nextEdge = new Edge(vertex.getPoint(), polygon.ControlVertices.NextVertex(i)); vertex.update(); //Add them to initial LAV LAV.AddLast(vertex); } SLAV.Add(LAV); //initial event creation testDots = new List<OwnVector2>(); for(int i = 0; i < LAV.Count; i++) { Vertex prev = LAV[i].Previous.Value; Vertex current = LAV[i].Value; Vertex next = LAV[i].Next.Value; findClosestIntersectionAndStore(LAV, prev, current, next); } }
private void findClosestIntersectionAndStore(CircularLinkedList<Vertex> LAV, Vertex prev, Vertex current, Vertex next) { Vertices testPoly = new Vertices(); foreach (Vertex v in LAV) { testPoly.Add(v.getPoint()); } OwnVector2 prevIntersection = LineTools.LineIntersect( prev.getRayStart(), prev.getRayStepPoint(), current.getRayStart(), current.getRayStepPoint()); OwnVector2 nextIntersection = LineTools.LineIntersect( current.getRayStart(), current.getRayStepPoint(), next.getRayStart(), next.getRayStepPoint()); OwnVector2 nearestOppositeIntersection = OwnVector2.Zero; Point2D testPrev = new Point2D(prevIntersection); if (testPoly.PointInPolygon(ref testPrev) == -1) { prevIntersection = Point2D.Zero; } Point2D testNext = new Point2D(nextIntersection); if (testPoly.PointInPolygon(ref testNext) == -1) { nextIntersection = Point2D.Zero; } Vertex firstEdgePoint = null; Vertex secondEdgePoint = null; if(current.isConcave()) { nearestOppositeIntersection = findNearestOppositeEdge(LAV, current, out firstEdgePoint, out secondEdgePoint); } float distPrev = prevIntersection.Equals(Point2D.Zero) ? float.MaxValue : OwnVector2.Distance(current.getPoint(), prevIntersection); float distNext = nextIntersection.Equals(Point2D.Zero) ? float.MaxValue : OwnVector2.Distance(current.getPoint(), nextIntersection); float distOpposite = float.MaxValue; if (distPrev == 0) { prevIntersection = Point2D.Zero; } if (distNext == 0) { nextIntersection = Point2D.Zero; } if (current.isConcave()) { distOpposite = OwnVector2.Distance(current.getPoint(), nearestOppositeIntersection); } if (prevIntersection.Equals(OwnVector2.Zero) && nextIntersection.Equals(OwnVector2.Zero) && nearestOppositeIntersection.Equals(OwnVector2.Zero)) { return; } if ((nextIntersection.Equals(OwnVector2.Zero) && nearestOppositeIntersection.Equals(OwnVector2.Zero)) || distPrev < distNext && distPrev < distOpposite) { Event e = new Event(new Point2D(prevIntersection), SLAV.IndexOf(LAV), EventType.Edge); e.storeFirstPoint(prev); e.storeSecondPoint(current); Q.Enqueue(e, distPrev); } else if ((nearestOppositeIntersection.Equals(OwnVector2.Zero) && prevIntersection.Equals(OwnVector2.Zero)) || distNext <= distPrev && distNext <= distOpposite) { Event e = new Event(new Point2D(nextIntersection), SLAV.IndexOf(LAV), EventType.Edge); e.storeFirstPoint(current); e.storeSecondPoint(next); Q.Enqueue(e, distNext); } else { Event e = new Event(new Point2D(nearestOppositeIntersection), SLAV.IndexOf(LAV), EventType.Split); e.storeFirstPoint(current); e.storeFirstEdgePoint(firstEdgePoint); e.storeSecondEdgePoint(secondEdgePoint); Q.Enqueue(e, distOpposite); } }
public void storeSecondPoint(Vertex point) { this.VB = point; }
public void storeSecondEdgePoint(Vertex point) { this.EB = point; }
public void storeFirstPoint(Vertex point) { this.VA = point; }
public void storeFirstEdgePoint(Vertex point) { this.EA = point; }