public void ConstructFromThreePointsStraight() { Point2D a = new Point2D(0.0, 0.0); Point2D b = new Point2D(1.0, 0.0); Point2D c = new Point2D(2.0, 0.0); var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { a, b, c }); Assert.AreEqual(3, mesh.VertexCount); Assert.AreEqual(0, mesh.EdgeCount); var aFirst = mesh.Find(new AngularBisectorNetwork.BisectorVertex(a)); Assert.AreEqual(a, aFirst.Position); Assert.AreEqual(new Direction2D(0.0, -1.0), aFirst.Direction); var bFirst = mesh.Find(new AngularBisectorNetwork.BisectorVertex(b)); Assert.AreEqual(b, bFirst.Position); Assert.AreEqual(new Direction2D(0.0, -1.0), bFirst.Direction); var cFirst = mesh.Find(new AngularBisectorNetwork.BisectorVertex(c)); Assert.AreEqual(c, cFirst.Position); Assert.AreEqual(new Direction2D(0.0, -1.0), cFirst.Direction); }
public static Mesh <BisectorVertex, EdgeBase, FaceBase> CreateFromPolylineDoubleSided(IEnumerable <Point2D> points) { // Avoids zero length edges at the ends of the polyline IEnumerable <Point2D> doubleSidedPolyline = points.Concat(points.Reverse().Skip(1).Take(points.Count() - 2)); AngularBisectorNetwork abn = new AngularBisectorNetwork(doubleSidedPolyline, true); return(abn.skeleton); }
public void ConstructFromThreePoints2() { Point2D a = new Point2D(200.0, 200.0); Point2D b = new Point2D(250.0, 160.0); Point2D c = new Point2D(300.0, 200.0); var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { a, b, c }); }
public void ConstructFromFourPoints3() { Point2D a = new Point2D(200.0, 200.0); Point2D b = new Point2D(348.0, 88.0); Point2D c = new Point2D(357.0, 277.0); Point2D d = new Point2D(477.0, 181.0); var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { a, b, c, d }); }
public void ConstructFromFourPoints5() { Point2D a = new Point2D(200.0, 100.0); Point2D b = new Point2D(100.0, 200.0); Point2D c = new Point2D(400.0, 200.0); Point2D d = new Point2D(300.0, 100.0); var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { a, b, c, d }); }
public void ConstructFromSevenPointsReflex1() { var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { new Point2D(2.0, 2.0), new Point2D(2.5, 1.6), new Point2D(3.0, 2.0), new Point2D(4.0, 2.0), new Point2D(3.0, 1.0), new Point2D(2.0, 1.0), new Point2D(1.0, 2.0), }); }
public void ConstructFromSevenPointsReflex3() { var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { new Point2D(100.0, 100.0), new Point2D(200.0, 200.0), new Point2D(200.0, 400.0), new Point2D(300.0, 500.0), new Point2D(400.0, 500.0), new Point2D(500.0, 300.0), new Point2D(550.0, 350.0) }); }
public void ConstructFromSevenPointsReflex2() { var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { new Point2D(200, 200), new Point2D(250, 160), new Point2D(300, 200), new Point2D(400, 200), new Point2D(300, 100), new Point2D(200, 100), new Point2D(100, 200), }); }
public void ConstructFromSevenPointsReflex5() { var mesh = AngularBisectorNetwork.CreateFromPolyline( new Point2D[] { new Point2D(200.0, 200.0), new Point2D(250.0, 160.0), new Point2D(300.0, 200.0), new Point2D(400.0, 200.0), new Point2D(300.0, 100.0), new Point2D(200.0, 100.0), new Point2D(100.0, 200.0) }); Assert.AreEqual(12, mesh.EdgeCount); }
public void ConstructFromSevenPointsReflex6() { var mesh = AngularBisectorNetwork.CreateFromPolyline( new Point2D[] { new Point2D(160.0, 335.0), new Point2D(213.0, 333.0), new Point2D(385.0, 426.0), new Point2D(488.0, 77.0), new Point2D(273.0, 69.0), new Point2D(263.0, 212.0), new Point2D(100.0, 200.0) }); Assert.AreEqual(12, mesh.EdgeCount); }
public void ConstructFromSevenPointsReflex7() { var mesh = AngularBisectorNetwork.CreateFromPolyline( new Point2D[] { new Point2D(79, 444), new Point2D(188, 434), new Point2D(418, 465), new Point2D(681, 541), new Point2D(880, 276), new Point2D(443, 151), new Point2D(76, 174) }); Assert.AreEqual(12, mesh.EdgeCount); }
public void ConstructFromSevenPoints() { var mesh = AngularBisectorNetwork.CreateFromPolyline( new Point2D[] { new Point2D(362, 113), new Point2D(204, 158), new Point2D(235, 256), new Point2D(275, 353), new Point2D(412, 355), new Point2D(459, 181), new Point2D(418, 184) }); Assert.AreEqual(12, mesh.EdgeCount); }
public override void ModifyLav(AngularBisectorNetwork network) { Debug.Assert(nodeA.List == nodeB.List); CircularLinkedList <Vertex> lav = nodeA.List; Vertex vA = nodeA.Value; Vertex vB = nodeB.Value; // * Create a new Vertex V with the coordinates of the intersection I Vertex v = new Vertex(this.Position); // * insert the new vertex into the LAV. That means connect it with the predecessor // of Va and the successor of Vb in the LAV CircularLinkedListNode <Vertex> nodeV = new CircularLinkedListNode <Vertex>(v); lav.AddAfter(nodeA, nodeV); lav.Remove(nodeA); lav.Remove(nodeB); // * link the new node V with the appropriate edges ea and eb (pointed to by vertices // Va and Vb // TODO: This needs some work for start and end nodes. What should happen? v.inEdge = vA.inEdge; v.outEdge = vB.outEdge; // f. for the new node V, created from I, compute: // * the new angle bisector b between the line segments ea and eb, and // TODO: This bisector sometimes needs to be revered! But under what circumstances? Direction2D bisector = AngularBisector(nodeV.Value.inEdge, nodeV.Value.outEdge); // Determine whether the triangle A B V has an acute or obtuse angle at V // this is used to determine the direction of the bisector Triangle2D triangle = new Triangle2D(vA.Position, vB.Position, v.Position); if (triangle.AngleC > (Math.PI / 2.0)) { bisector = -bisector; } nodeV.Value.Bisector = new Ray2D(nodeV.Value.Bisector.Source, bisector); // * the intersections of this bisector with the bisectors starting from the neighbour vertices in // the LAV in the same way as in the step 1c // * store the nearer intersection (if it exists) in the priority queue network.EnqueueNearestBisectorIntersection(lav, nodeV); }
public override bool CreateArcs(AngularBisectorNetwork network) { // 2c. do the same as in the convex case, only the meaning is a bit different, because // more local peaks of the roof exist. // c. if the predecessor of Va is equal to Vb (peak of the roof), then output three // straight skeleton arcs VaI, VbI and VcI where Vc is the predecessor of Va and // the successor of Vb in the LAV simultaneously, and continue on the step 2 // NOTE: Cannot occur without circular LAV (i.e. polygon) //if (nodeA.Previous == nodeB) //{ //Vertex vC = nodeV.Next.Value; //network.AddArc(vC, this); //network.AddArc(vB, this); //network.AddArc(vC, this); //return true; //} // 2d. Output one arc VI of the straight skeleton, where vertex/node V is the one pointed // to by the intersection point I. Intersections of the split event type point to one // vertex in LAV/SLAV. network.AddArc(V, this); return(false); }
/// <summary> /// /// </summary> /// <param name="network"></param> /// <returns>true if the skeleton output is the peak of the 'roof'</returns> public override bool CreateArcs(AngularBisectorNetwork network) { Vertex vA = nodeA.Value; Vertex vB = nodeB.Value; // c. if the predecessor of Va is equal to Vb (peak of the roof), then output three // straight skeleton arcs VaI, VbI and VcI where Vc is the predecessor of Va and // the successor of Vb in the LAV simultaneously, and continue on the step 2 // NOTE: Cannot occur without circular LAV (i.e. polygon) if (nodeA.Previous == nodeB) { Vertex vC = nodeA.Previous.Value; network.AddArc(vA, this); network.AddArc(vB, this); network.AddArc(vC, this); return(true); } // Convex: d. Output two skeleton arcs of the straight skeleton VaI and VbI network.AddArc(vA, this); network.AddArc(vB, this); return(false); }
public override void ModifyLav(AngularBisectorNetwork network) { Debug.Assert(nodeV.List != null); CircularLinkedList <Vertex> lav1 = nodeV.List; // * Create two new nodes V1 and V2 with the same co-ordinates as the intersection point I CircularLinkedListNode <Vertex> nodeV1 = new CircularLinkedListNode <Vertex>(new Vertex(this.Position)); CircularLinkedListNode <Vertex> nodeV2 = new CircularLinkedListNode <Vertex>(new Vertex(this.Position)); // * Search the opposite edge in SLAV sequentially CircularLinkedListNode <Vertex> oppositeNode = lav1.FindPair(delegate(Vertex va, Vertex vb) { // Ignore testing againt the in and out edges of V if (va == V || vb == V) { return(false); } // and the candiate "opposite" line Line2D oppositeLine = new Line2D(va.outEdge.source.Position, va.outEdge.target.Position); // TODO: Check which way round these lines are - so the the positive side defines our zone of interest Line2D oppositeBoundary1 = va.Bisector.SupportingLine.Opposite; Line2D oppositeBoundary2 = vb.Bisector.SupportingLine; OrientedSide sideA = oppositeBoundary1.Side(this.Position); OrientedSide sideB = oppositeLine.Side(this.Position); OrientedSide sideC = oppositeBoundary2.Side(this.Position); //return sideA == OrientedSide.Negative && sideB == OrientedSide.Negative && sideC == OrientedSide.Negative; return(sideA == OrientedSide.Negative && sideB == OrientedSide.Negative && sideC == OrientedSide.Negative); }); // TODO: Is this legitimate? if (oppositeNode == null) { Debug.Assert(false); return; } // oppositeNode is Y in the paper Debug.Assert(oppositeNode != null); // * insert both new nodes into the SLAV (break one LAV into two parts). Vertex V1 will be // interconnected between the predecessor of V and the vertex/node which is an end point of // the opposite line segment. V2 will be connected between the successor of V and the vertex/ // node which is a starting point of the opposite line segment. This step actually splits the // polygon shape into two parts. // Set up nodes according to the naming conventions in the Felkel et al paper. CircularLinkedListNode <Vertex> nodeY = oppositeNode; CircularLinkedListNode <Vertex> nodeX = oppositeNode.Next; CircularLinkedListNode <Vertex> nodeM = nodeV.Previous; CircularLinkedListNode <Vertex> nodeN = nodeV.Next; // The LinkedList is split into two parts. The first part remains in the original list, // the second part is placed into a new list. CircularLinkedList <Vertex> lav2 = network.CreateLav(); // We search the list for either M or Y, whichever comes first. This tells us which // algorithm to use to split the lav in two. CircularLinkedListNode <Vertex> found = lav1.FindNode(node => node == nodeM || node == nodeY); lav1.Remove(nodeV); // Splice nodes from lav1 into lav2 Debug.Assert(found != null); if (found == nodeY) { // Splice two sections of lav1 into lav2 with V1 and V2 // TODO: We have four nodes in a linked list defining two ranges First--->Y and N--->Last // These ranges may be non-overlapping, or may be overlapping in some way. e.g. Y may come after N. // 1) Find none overlapping range or ranges // 2) Copy the range(s) to lav2 // 3) Insert nodeV2 into the correct place in lav2 after Y // Another alternative 2 // 1. Is the break in the list between N and Y? bool continuousNY = null != lav1.FindNodeFrom(nodeN, node => node == nodeY); if (continuousNY) { lav2.AddLast(nodeV2); lav2.SpliceLast(nodeN, nodeY); lav2.IsCircular = true; } else // !continuousNY { lav2.SpliceLast(lav1.First, nodeY); lav2.AddLast(nodeV2); lav2.SpliceLast(nodeN, lav1.Last); lav2.IsCircular = lav1.IsCircular; } // Alternative approach //// 1. Remember whether lav1 is circular //bool lav1Circularity = lav1.IsCircular; //// 1a. Determine whether lav2 should be circular- by whether it is continuous between nodeN and nodeY //bool continuousNY = null != lav1.FindNodeFrom(nodeN, node => node == nodeY); //bool lav2Circularity = lav1Circularity || continuousNY; //// 2. Make lav1 circular, so we can safely iterate from N to Y irrespective of the location of the list head //lav1.IsCircular = true; //// 3. Add nodeV2 into lav2 //lav2.AddLast(nodeV2); //// 4. Splice from N to Y into Lav2 //lav2.SpliceLast(nodeN, nodeY); //// 5. Restore the circularity of lav1 and lav2 //lav1.IsCircular = lav1Circularity; //lav2.IsCircular = lav2Circularity; // X--->M->V1 if (lav1.Count > 0) // <--- Is this needed? { Debug.Assert(lav1.First == nodeX); Debug.Assert(lav1.Last == nodeM); lav1.AddLast(nodeV1); lav1.IsCircular = true; } } else { Debug.Assert(found == nodeM); // Splice one section of lav1 into lav2 // N--->Y->V2 lav2.SpliceFirst(nodeN, nodeY); lav2.AddLast(nodeV2); // First--->M->V2->X--->Last if (lav1.Count > 0) { Debug.Assert(nodeM.Next == nodeX); lav1.AddAfter(nodeM, nodeV1); } } // * link the new nodes V1 and V2 with the appropriate edges nodeV1.Value.inEdge = V.inEdge; nodeV1.Value.outEdge = nodeY.Value.outEdge; nodeV2.Value.inEdge = nodeY.Value.outEdge; nodeV2.Value.outEdge = V.outEdge; // f. for both nodes V1 and V2: // * compute the new angle bisectors betwenne the line segment linked to them is step 2e nodeV1.Value.Bisector = new Ray2D(nodeV1.Value.Bisector.Source, AngularBisector(nodeV1.Value.inEdge, nodeV1.Value.outEdge)); nodeV2.Value.Bisector = new Ray2D(nodeV2.Value.Bisector.Source, AngularBisector(nodeV2.Value.inEdge, nodeV2.Value.outEdge)); // * compute the intersections of these bisectors with the bisectors starting at their neighbour // vertices according to the LAVs (e.g. at points N and Y and M and X in fig 6a.), the same // way as in step 1c. New intersection points of both types may occur // * store the nearest intersection into the priority queue // TODO: [ Does this mean the nearest for V1 and the nearest for V2, or only the nearest of them both? ] network.EnqueueNearestBisectorIntersection(lav1, nodeV1); network.EnqueueNearestBisectorIntersection(lav2, nodeV2); }
public void ConstructFromThreePoints() { Point2D a = new Point2D(0.0, 0.0); Point2D b = new Point2D(1.0, 0.0); Point2D c = new Point2D(2.0, -1.0); var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { a, b, c }); Assert.AreEqual(5, mesh.VertexCount); Assert.AreEqual(4, mesh.EdgeCount); var aNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(a)); Assert.AreEqual(a, aNode.Position); var bNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(b)); Assert.AreEqual(b, bNode.Position); var cNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(c)); Assert.AreEqual(c, cNode.Position); Assert.AreEqual(1, aNode.Degree); Assert.AreEqual(1, bNode.Degree); Assert.AreEqual(1, cNode.Degree); var aEnumerator = aNode.Edges.GetEnumerator(); aEnumerator.MoveNext(); EdgeBase apEdge = aEnumerator.Current; var bEnumerator = bNode.Edges.GetEnumerator(); bEnumerator.MoveNext(); EdgeBase bpEdge = bEnumerator.Current; Assert.AreSame(apEdge.Target, bpEdge.Target); var pNode = apEdge.Target as AngularBisectorNetwork.BisectorVertex; Assert.AreEqual(3, pNode.Degree); Assert.AreEqual(0.0, pNode.Position.X, epsilon); Assert.AreEqual(-Math.Sqrt(2.0) - 1.0, pNode.Position.Y, epsilon); var cEnumerator = cNode.Edges.GetEnumerator(); cEnumerator.MoveNext(); EdgeBase cqEdge = cEnumerator.Current; var qNode = cqEdge.Target as AngularBisectorNetwork.BisectorVertex; Assert.IsNotNull(qNode); Assert.AreEqual(2, qNode.Degree); EdgeBase pqEdge = mesh.Find(pNode, qNode); Assert.IsNotNull(pqEdge); Assert.IsNotNull(qNode.Direction); Assert.AreEqual(-1.9634954084936209, qNode.Direction.Value.Bearing, epsilon); }
public static Mesh <BisectorVertex, EdgeBase, FaceBase> CreateFromPolygon(IEnumerable <Point2D> points) { AngularBisectorNetwork abn = new AngularBisectorNetwork(points, true); return(abn.skeleton); }
public abstract bool CreateArcs(AngularBisectorNetwork network);
public abstract void ModifyLav(AngularBisectorNetwork network);
public void ConstructFromFourPoints1() { Point2D a = new Point2D(0.0, 0.0); Point2D b = new Point2D(1.0, 1.0); Point2D c = new Point2D(3.0, 1.0); Point2D d = new Point2D(4.0, 0.0); var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { a, b, c, d }); Assert.AreEqual(6, mesh.VertexCount); Assert.AreEqual(5, mesh.EdgeCount); var aNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(a)); Assert.AreEqual(a, aNode.Position); Assert.IsNull(aNode.Direction); var bNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(b)); Assert.AreEqual(b, bNode.Position); Assert.IsNull(bNode.Direction); var cNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(c)); Assert.AreEqual(c, cNode.Position); Assert.IsNull(cNode.Direction); var dNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(d)); Assert.AreEqual(d, dNode.Position); Assert.IsNull(dNode.Direction); Assert.AreEqual(1, aNode.Degree); Assert.AreEqual(1, bNode.Degree); Assert.AreEqual(1, cNode.Degree); Assert.AreEqual(1, dNode.Degree); var bEnumerator = bNode.Edges.GetEnumerator(); bEnumerator.MoveNext(); EdgeBase bpEdge = bEnumerator.Current; var cEnumerator = cNode.Edges.GetEnumerator(); cEnumerator.MoveNext(); EdgeBase cpEdge = cEnumerator.Current; Assert.AreSame(bpEdge.Target, cpEdge.Target); var pNode = bpEdge.Target as AngularBisectorNetwork.BisectorVertex; Assert.AreEqual(2.0, pNode.Position.X); Assert.AreEqual(-Math.Sqrt(2.0), pNode.Position.Y, epsilon); Assert.IsNull(pNode.Direction); var aEnumerator = aNode.Edges.GetEnumerator(); aEnumerator.MoveNext(); EdgeBase aqEdge = aEnumerator.Current; var dEnumerator = dNode.Edges.GetEnumerator(); dEnumerator.MoveNext(); EdgeBase dqEdge = dEnumerator.Current; Assert.AreSame(aqEdge.Target, dqEdge.Target); var qNode = aqEdge.Target as AngularBisectorNetwork.BisectorVertex; Assert.AreEqual(2.0, qNode.Position.X); Assert.AreEqual(-2.0, qNode.Position.Y, epsilon); EdgeBase pqEdge = mesh.Find(pNode, qNode); Assert.IsNotNull(pqEdge); Assert.IsNotNull(qNode.Direction); Assert.AreEqual(new Direction2D(0.0, -1.0), qNode.Direction); }
public void ConstructFromFivePointsReflex() { Point2D a = new Point2D(0.0, 0.0); Point2D b = new Point2D(1.0, 0.0); Point2D c = new Point2D(2.0, -1.0); Point2D d = new Point2D(3.0, 0.0); Point2D e = new Point2D(4.0, 0.0); var mesh = AngularBisectorNetwork.CreateFromPolyline(new Point2D[] { a, b, c, d, e }); Assert.AreEqual(7, mesh.VertexCount); Assert.AreEqual(4, mesh.EdgeCount); var aNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(a)); Assert.AreEqual(a, aNode.Position); Assert.IsNull(aNode.Direction); var bNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(b)); Assert.AreEqual(b, bNode.Position); Assert.IsNull(bNode.Direction); var cNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(c)); Assert.AreEqual(c, cNode.Position); Assert.IsNotNull(cNode.Direction); Assert.AreEqual(new Direction2D(0.0, -1.0), cNode.Direction); var dNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(d)); Assert.AreEqual(d, dNode.Position); Assert.IsNull(dNode.Direction); var eNode = mesh.Find(new AngularBisectorNetwork.BisectorVertex(e)); Assert.AreEqual(e, eNode.Position); Assert.IsNull(eNode.Direction); Assert.AreEqual(1, aNode.Degree); Assert.AreEqual(1, bNode.Degree); Assert.AreEqual(0, cNode.Degree); Assert.AreEqual(1, dNode.Degree); Assert.AreEqual(1, eNode.Degree); var aEnumerator = aNode.Edges.GetEnumerator(); aEnumerator.MoveNext(); EdgeBase apEdge = aEnumerator.Current; var bEnumerator = bNode.Edges.GetEnumerator(); bEnumerator.MoveNext(); EdgeBase bpEdge = bEnumerator.Current; Assert.AreSame(apEdge.Target, bpEdge.Target); var pNode = apEdge.Target as AngularBisectorNetwork.BisectorVertex; Assert.AreEqual(0.0, pNode.Position.X); Assert.AreEqual(-1.0 - Math.Sqrt(2.0), pNode.Position.Y, epsilon); Assert.IsNotNull(pNode.Direction); Assert.AreEqual(2, pNode.Degree); Assert.AreEqual(-1.9634954084936209, pNode.Direction.Value.Bearing, epsilon); var dEnumerator = dNode.Edges.GetEnumerator(); dEnumerator.MoveNext(); EdgeBase dqEdge = dEnumerator.Current; var eEnumerator = eNode.Edges.GetEnumerator(); eEnumerator.MoveNext(); EdgeBase eqEdge = eEnumerator.Current; Assert.AreSame(dqEdge.Target, eqEdge.Target); var qNode = dqEdge.Target as AngularBisectorNetwork.BisectorVertex; Assert.AreEqual(4.0, qNode.Position.X); Assert.AreEqual(-1.0 - Math.Sqrt(2.0), qNode.Position.Y, epsilon); Assert.IsNotNull(qNode.Direction); Assert.AreEqual(2, qNode.Degree); Assert.AreEqual(-1.1780972450961724, qNode.Direction.Value.Bearing, epsilon); }