//////////////////////////////////////////////////////////////////////////////////////////////////// /// <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); }