//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Insert a new parabola into the beachline when the beachline spans the X axis. </summary> /// <remarks> /// This is the normal case. We insert our new parabola and split the parabola above our site in /// two. This means one new leaf node is created for leftmost of the two nodes in the split (the /// old lfn is recycled to become the right node of the split). Also a new internal node to /// parent all this. /// </remarks> /// <param name="lfnOld"> Parabola above the new site. </param> /// <param name="lfnNewParabola"> parabola for the new site. </param> /// <param name="innSubRoot"> /// Parent node of both lfnOld and lfnNewParabola represneting /// the breakpoint between them. /// </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private static void InsertAtDifferentY(LeafNode lfnOld, LeafNode lfnNewParabola, InternalNode innSubRoot) { // The old lfn will become the new right half of the split but we need a new leaf node // for the left half of the split... var lfnLeftHalf = new LeafNode(lfnOld.Poly); var innSubRootLeftChild = new InternalNode(lfnOld.Poly, lfnNewParabola.Poly); var edge = new FortuneEdge(); // This is all fairly straightforward (albeit dense) insertion of a node into a binary tree. innSubRoot.RightChild = lfnOld; innSubRoot.LeftChild = innSubRootLeftChild; innSubRoot.SetEdge(edge); innSubRoot.AddEdgeToPolygons(edge); innSubRootLeftChild.LeftChild = lfnLeftHalf; innSubRootLeftChild.RightChild = lfnNewParabola; innSubRootLeftChild.SetEdge(edge); lfnNewParabola.LeftAdjacentLeaf = lfnLeftHalf; lfnNewParabola.RightAdjacentLeaf = lfnOld; lfnLeftHalf.LeftAdjacentLeaf = lfnOld.LeftAdjacentLeaf; lfnLeftHalf.RightAdjacentLeaf = lfnNewParabola; if (lfnOld.LeftAdjacentLeaf != null) { lfnOld.LeftAdjacentLeaf.RightAdjacentLeaf = lfnLeftHalf; } lfnOld.LeftAdjacentLeaf = lfnNewParabola; edge.SetPolys(innSubRoot.PolyRight, innSubRoot.PolyLeft); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Handle the top N nodes located on a single horizontal line. </summary> /// <remarks> /// This only handles the corner case where the top N nodes are on the same horizontal /// line. In that case the parabolas from previous points are vertically straight up and only /// project to a single point on the x axis so that the beachline is a series of points rather /// than a series of parabolas. When that is the case we can't "intersect" new points with /// parabolas that span the x axis. After the scanline passes that initial set of topmost points, /// there will always be a parabola which projects to the entire x axis so no need for this /// special handling. Normally, we produce two new parabolas at a site event like this - the new /// parabola for the site itself and the new parabola produced when we split the parabola above /// us. In this case there is no parabola above us so we only produce one new parabola - the one /// inserted by the site. /// </remarks> /// <param name="lfn"> LeafNode of the (degenerate) parabola nearest us. </param> /// <param name="lfnNewParabola"> LeafNode we're inserting. </param> /// <param name="innParent"> Parent of lfnOld. </param> /// <param name="innSubRoot"> Root of the tree. </param> /// <param name="fLeftChild"> Left child of innParent. </param> //////////////////////////////////////////////////////////////////////////////////////////////////// private static void NdInsertAtSameY( LeafNode lfn, LeafNode lfnNewParabola, InternalNode innParent, InternalNode innSubRoot, bool fLeftChild) { // Locals LeafNode lfnLeft, lfnRight; var lfnAdjacentParabolaLeft = lfn.LeftAdjacentLeaf; var lfnAdjacentParabolaRight = lfn.RightAdjacentLeaf; if (lfnNewParabola.Poly.VoronoiPoint.X < lfn.Poly.VoronoiPoint.X) { lfnLeft = lfnNewParabola; lfnRight = lfn; } else { //! Note: I don't think this case ever occurs in practice since we pull events off with higher //! x coordinates before events with lower x coordinates lfnLeft = lfn; lfnRight = lfnNewParabola; } innSubRoot.PolyLeft = lfnLeft.Poly; innSubRoot.PolyRight = lfnRight.Poly; innSubRoot.LeftChild = lfnLeft; innSubRoot.RightChild = lfnRight; var edge = new FortuneEdge(); innSubRoot.SetEdge(edge); innSubRoot.AddEdgeToPolygons(edge); lfnLeft.LeftAdjacentLeaf = lfnAdjacentParabolaLeft; lfnLeft.RightAdjacentLeaf = lfnRight; lfnRight.LeftAdjacentLeaf = lfnLeft; lfnRight.RightAdjacentLeaf = lfnAdjacentParabolaRight; if (innParent != null) { if (fLeftChild) { innParent.PolyLeft = lfnRight.Poly; } else { innParent.PolyRight = lfnLeft.Poly; } } edge.SetPolys(innSubRoot.PolyRight, innSubRoot.PolyLeft); }
//////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> Insert a new LeafNode into the tree. </summary> /// <remarks> Darrellp, 2/19/2011. </remarks> /// <param name="lfn"> Place to put the new leaf node. </param> /// <param name="evt"> The event to insert. </param> /// <returns> . </returns> //////////////////////////////////////////////////////////////////////////////////////////////////// private static InternalNode NdCreateInsertionSubtree(LeafNode lfn, SiteEvent evt) { // Initialize locals var innParent = lfn.NdParent; var lfnNewParabola = new LeafNode(evt.Poly); var innSubRoot = new InternalNode(evt.Poly, lfn.Poly); var fLeftChild = true; // If this isn't on the root node, shuffle things around a bit if (innParent != null) { fLeftChild = lfn.IsLeftChild; lfn.SnipFromParent(); if (fLeftChild) { innParent.LeftChild = innSubRoot; } else { innParent.RightChild = innSubRoot; } } // Watch for the odd corner case of the top n generators having the same y coordinate. See comments // on NdInsertAtSameY(). if (Geometry2D.FCloseEnough(evt.Pt.Y, lfn.Poly.VoronoiPoint.Y)) { NdInsertAtSameY(lfn, lfnNewParabola, innParent, innSubRoot, fLeftChild); } else { InsertAtDifferentY(lfn, lfnNewParabola, innSubRoot); } return(innSubRoot); }