Ejemplo n.º 1
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);
            }
Ejemplo n.º 2
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);
            }