private void ProcessSiteEvent(FortunesAlgorithmState state, SiteEvent e) { var sweepY = e.Y; var newParabolaFocus = e.Point; if (state.Root == null) { state.Root = new Node(new ParabolaData(newParabolaFocus)); return; } var cutNode = state.Root.FindDeepestNodeAtX(newParabolaFocus.X, newParabolaFocus.Y); if (!cutNode.IsLeaf()) { throw new NotSupportedException("Cutting edge node not supported."); } var cutParabolaFocus = ((ParabolaData)cutNode.Data).Focus; Node leftParabola, centerParabola, rightParabola; Node newNode = BeachlineNodeOperations.ComputeThreeParabolasFromDifferentYParabolaNodeCut( cutParabolaFocus, newParabolaFocus, out leftParabola, out centerParabola, out rightParabola); NodeOperations.ReplaceNode(cutNode, newNode, ref state.Root); state.DelanayEdges.Add(new VoronoiEdge(newParabolaFocus, true, cutParabolaFocus, true)); Node leftLeftParabola; if (leftParabola.TryGetLeftLeaf(out leftLeftParabola)) { HandleAddCircleEvent(state, leftLeftParabola, leftParabola, centerParabola, sweepY); } Node rightRightParabola; if (rightParabola.TryGetRightLeaf(out rightRightParabola)) { HandleAddCircleEvent(state, centerParabola, rightParabola, rightRightParabola, sweepY); } }
void ProcessCircleEvent(FortunesAlgorithmState state, CircleEvent e) { var sweepY = e.Y; var swallowedParabolaNode = e.SwallowedParabolaNode; if (swallowedParabolaNode.Parent == null) { return; } Node leftAncestor, rightAncestor; swallowedParabolaNode.FindDirectionalAncestors(out leftAncestor, out rightAncestor); var leftAncestorEdgeRayData = (EdgeRayData)leftAncestor.Data; var rightAncestorEdgeRayData = (EdgeRayData)rightAncestor.Data; state.VoronoiEdges.Add(new VoronoiEdge( leftAncestorEdgeRayData.Origin, leftAncestorEdgeRayData.IsOriginBounded, e.Circumcenter, true)); state.VoronoiEdges.Add(new VoronoiEdge( rightAncestorEdgeRayData.Origin, leftAncestorEdgeRayData.IsOriginBounded, e.Circumcenter, true)); var leftParabolaNode = leftAncestor.Left.GetRightmost(); var leftParabolaFocus = ((ParabolaData)leftParabolaNode.Data).Focus; var rightParabolaNode = rightAncestor.Right.GetLeftmost(); var rightParabolaFocus = ((ParabolaData)rightParabolaNode.Data).Focus; state.DelanayEdges.Add(new VoronoiEdge(leftParabolaFocus, true, rightParabolaFocus, true)); // One ancestor will become the edge shared by the left/right parabolas, // the other will be deleted. It's guranteed our parent is one of these // ancestors and that the other ancestor is above it (that is, it has a // parent) so opt to delete our parent. var nodeParent = swallowedParabolaNode.Parent; var nodeSibling = nodeParent.Left == swallowedParabolaNode ? nodeParent.Right : nodeParent.Left; NodeOperations.ReplaceNode(nodeParent, nodeSibling, ref state.Root); nodeParent.Left = nodeParent.Right = null; var olderAncestor = nodeParent == leftAncestor ? rightAncestor : leftAncestor; var leftFocusRightFocus = rightParabolaFocus - leftParabolaFocus; // x is positive var edgeDirection = new TVector2(-leftFocusRightFocus.Y, leftFocusRightFocus.X); var leftRightFocusCenter = new TVector2( MathUtil.Average(leftParabolaFocus.X, rightParabolaFocus.X), MathUtil.Average(leftParabolaFocus.Y, rightParabolaFocus.Y)); var dy = sweepY - leftRightFocusCenter.Y; var edgeStart = e.Circumcenter; olderAncestor.Data = new EdgeRayData(true, edgeStart, edgeDirection); // add new potential circle events Node leftLeftLeaf; if (leftParabolaNode.TryGetLeftLeaf(out leftLeftLeaf)) { HandleAddCircleEvent(state, leftLeftLeaf, leftParabolaNode, rightParabolaNode, sweepY); } Node rightRightLeaf; if (rightParabolaNode.TryGetRightLeaf(out rightRightLeaf)) { HandleAddCircleEvent(state, leftParabolaNode, rightParabolaNode, rightRightLeaf, sweepY); } }