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);
        }
Beispiel #2
0
        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);
        }
Beispiel #13
0
            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);
            }
Beispiel #14
0
            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);
            }
Beispiel #15
0
            /// <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);
            }
Beispiel #16
0
            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);
        }
Beispiel #18
0
        public static Mesh <BisectorVertex, EdgeBase, FaceBase> CreateFromPolygon(IEnumerable <Point2D> points)
        {
            AngularBisectorNetwork abn = new AngularBisectorNetwork(points, true);

            return(abn.skeleton);
        }
Beispiel #19
0
 public abstract bool CreateArcs(AngularBisectorNetwork network);
Beispiel #20
0
 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);
        }