private TestCase SetupTripleArcTestCase(BreakpointNode leftBP, BreakpointNode rightBP, ArcNode leftArc, ArcNode middleArc, ArcNode rightArc, ArcNode expectedResult, Vector newSitePos) { leftArc.Parent = leftBP; middleArc.Parent = rightBP; rightArc.Parent = rightBP; leftBP.LeftChild = leftArc; leftBP.RightChild = rightBP; rightBP.Parent = leftBP; rightBP.LeftChild = middleArc; rightBP.RightChild = rightArc; return new TestCase { RootNode = leftBP, ExpectedResult = expectedResult, NewSitePosition = newSitePos }; }
public void FindsCorrectArcNode() { // First object is root node, second object is expected result arc node. var tests = new List<TestCase>(); // A single arc. { var singleArc = new ArcNode(new Site(new Vector(0, 1))); tests.Add(new TestCase { RootNode = singleArc, ExpectedResult = singleArc, NewSitePosition = new Vector(0, 0) }); } // Simple tree with three arcs. { /* var leftArc = new ArcNode(new Site(new Vector(0, 10))); var middleArc = new ArcNode(new Site(new Vector(5, 2))); var rightArc = new ArcNode(leftArc.DefiningSite); var leftBP = new BreakpointNode(leftArc.DefiningSite, middleArc.DefiningSite, null, true); var rightBP = new BreakpointNode(leftArc.DefiningSite, middleArc.DefiningSite, null, false); tests.Add(SetupTripleArcTestCase( leftBP, rightBP, leftArc, middleArc, rightArc, leftArc, new Vector(-5, 0))); tests.Add(SetupTripleArcTestCase( leftBP, rightBP, leftArc, middleArc, rightArc, middleArc, new Vector(5, 0))); tests.Add(SetupTripleArcTestCase( leftBP, rightBP, leftArc, middleArc, rightArc, rightArc, new Vector(500, 0))); */ } // Three arc tree with sites vertically aligned. { // Breakpoints are at +- 7.01... var leftArc = new ArcNode(new Site(new Vector(0, 10))); var middleArc = new ArcNode(new Site(new Vector(0, 5))); var rightArc = new ArcNode(leftArc.DefiningSite); var leftBP = new BreakpointNode(leftArc.DefiningSite, middleArc.DefiningSite, null, true); var rightBP = new BreakpointNode(leftArc.DefiningSite, middleArc.DefiningSite, null, false); tests.Add(SetupTripleArcTestCase( leftBP, rightBP, leftArc, middleArc, rightArc, leftArc, new Vector(-250, 0))); tests.Add(SetupTripleArcTestCase( leftBP, rightBP, leftArc, middleArc, rightArc, middleArc, new Vector(-1, 0))); tests.Add(SetupTripleArcTestCase( leftBP, rightBP, leftArc, middleArc, rightArc, middleArc, new Vector(0, 0))); tests.Add(SetupTripleArcTestCase( leftBP, rightBP, leftArc, middleArc, rightArc, middleArc, new Vector(1, 0))); tests.Add(SetupTripleArcTestCase( leftBP, rightBP, leftArc, middleArc, rightArc, rightArc, new Vector(250, 0))); } foreach (var test in tests) Assert.That(Helpers.FindArcSplitByNewSite(test.NewSitePosition, test.RootNode), Is.EqualTo(test.ExpectedResult)); }
private void HandleSiteEvent(SiteEvent ev, State state) { // If the beach line data structure is empty, initialize // it with the arc created by the new site into it and return. if (state.BeachLine == null) { state.BeachLine = new ArcNode(ev.Site); return; } // Find the arc split by the new site. var splitArcNode = Helpers.FindArcSplitByNewSite(ev.Site.Position, state.BeachLine); // If the arc being split has a circle event, it is a false alarm, // so delete it from the event queue. if (splitArcNode.DisappearanceEvent != null) state.EventQueue.Remove(splitArcNode.DisappearanceEvent.Index); // The following pieces of the final Voronoi diagram are created // during a site event: // - The Face defined by the new site. // - Both HalfEdges of the edge that will be traced out by the // two new breakpoints. var newFace = new Face {UserData = ev.Site.UserData}; var halfEdgeFacingOldSite = new HalfEdge(); var halfEdgeFacingNewSite = new HalfEdge(); state.Faces.Add(ev.Site, newFace); state.HalfEdges.Add(halfEdgeFacingOldSite); state.HalfEdges.Add(halfEdgeFacingNewSite); // Link all the diagram pieces together that can be linked at this time. halfEdgeFacingOldSite.Interior = state.Faces[splitArcNode.DefiningSite]; halfEdgeFacingNewSite.Interior = newFace; halfEdgeFacingOldSite.Twin = halfEdgeFacingNewSite; halfEdgeFacingNewSite.Twin = halfEdgeFacingOldSite; // During a site event, an existing arc is split into two // new arcs with an additional arc in the middle. We reflect // this change in beach line status tree data structure by // replacing the split arc node with a new subtree with five // nodes total: two for the two new breakpoints, and three // for the three new arcs on the beach line. var leftBP = new BreakpointNode(ev.Site, splitArcNode.DefiningSite, halfEdgeFacingOldSite, true); var rightBP = new BreakpointNode(ev.Site, splitArcNode.DefiningSite, halfEdgeFacingNewSite, false); var leftArc = new ArcNode(splitArcNode.DefiningSite); var middleArc = new ArcNode(ev.Site); var rightArc = new ArcNode(splitArcNode.DefiningSite); // Set up new subtree. leftBP.LeftChild = leftArc; leftBP.RightChild = rightBP; rightBP.LeftChild = middleArc; rightBP.RightChild = rightArc; rightBP.Parent = leftBP; leftArc.Parent = leftBP; middleArc.Parent = rightBP; rightArc.Parent = rightBP; // Graft new subtree into existing beach line status tree data structure. // First check for the special case where the split arc node was the // root element of the tree (aka the only element). if (splitArcNode.Parent == null) { if (state.BeachLine != splitArcNode) throw new SanityCheckFailedException( "The splitArcNode's parent was null, but it was not the root of the beach line status tree data structure."); state.BeachLine = leftBP; } // Otherwise, graft into existing tree. Here is where // we would perform rebalancing operations on the tree. else { if (splitArcNode.Parent.LeftChild == splitArcNode) { splitArcNode.Parent.LeftChild = leftBP; leftBP.Parent = splitArcNode.Parent; } else { splitArcNode.Parent.RightChild = leftBP; leftBP.Parent = splitArcNode.Parent; } } }