public void TestFindCircleEventAbove() { var beachLine = new BeachLine(0); var site1 = new Point { X = 130, Y = 160 }; var site2 = new Point { X = 110, Y = 150 }; var site3 = new Point { X = 170, Y = 140 }; var site4 = new Point { X = 140, Y = 120 }; beachLine.InsertSite(site1); //beachLine.GenerateCircleEvent(site1); beachLine.InsertSite(site2); //beachLine.GenerateCircleEvent(site2); var insert = beachLine.InsertSite(site3); var circleEvents = beachLine.GenerateCircleEvent(insert.Leaves, site3.Y); var result = beachLine.FindCircleEventAbove(site4); Assert.IsNotNull(result); Assert.AreEqual(circleEvents.Single().Point, result.Point); }
public void TestRemoveLeaf() { var beachLine = new BeachLine(0); var site1 = new Point { X = 40, Y = 60 }; var site2 = new Point { X = 20, Y = 40 }; var site3 = new Point { X = 60, Y = 40 }; beachLine.InsertSite(site1); beachLine.InsertSite(site2); var insert = beachLine.InsertSite(site3); var circleEvents = beachLine.GenerateCircleEvent(insert.Leaves, site3.Y); var circleEvent = circleEvents.Single(); beachLine.RemoveLeaf(circleEvent.Arc); var rightSubtree = ((Node)beachLine.Root).Right as Node; var leafLeft = rightSubtree.Left as Leaf; var leafRight = rightSubtree.Right as Leaf; Assert.IsNotNull(leafLeft); Assert.IsNotNull(leafRight); Assert.AreEqual(rightSubtree.Breakpoint.Left, site3); Assert.AreEqual(rightSubtree.Breakpoint.Right, site1); Assert.AreEqual(leafLeft.Site, site3); Assert.AreEqual(leafRight.Site, site1); }
public void TestGenerateCircleEvent() { var beachLine = new BeachLine(0); var site1 = new Point { X = 130, Y = 160 }; var site2 = new Point { X = 110, Y = 150 }; var site3 = new Point { X = 170, Y = 140 }; beachLine.InsertSite(site1); beachLine.InsertSite(site2); var insert = beachLine.InsertSite(site3); var expectedCricleEvent = new Point { X = 136, Y = 84 }; var result = beachLine.GenerateCircleEvent(insert.Leaves, site3.Y); Assert.IsNotNull(result); Assert.AreEqual(1, result.Count); Assert.AreEqual(expectedCricleEvent.XInt, result.Single().Point.XInt); Assert.AreEqual(expectedCricleEvent.YInt, result.Single().Point.YInt); //Assert.AreEqual(site2, result.Single().LeftArc.Site); Assert.AreEqual(site1, result.Single().Arc.Site); //Assert.AreEqual(site3, result.Single().RightArc.Site); }
public void TestGenerateCircleEventZeroLengthArc() { var beachLine = new BeachLine(2000); var site1 = new Point { X = 40, Y = 60 }; var site2 = new Point { X = 20, Y = 40 }; var site3 = new Point { X = 60, Y = 40 }; beachLine.InsertSite(site1); beachLine.InsertSite(site2); var insert = beachLine.InsertSite(site3); var expectedCricleEvent = new Point { X = 40, Y = 20 }; var result = beachLine.GenerateCircleEvent(insert.Leaves, site3.Y); Assert.IsNotNull(result); Assert.AreEqual(1, result.Count); Assert.AreEqual(expectedCricleEvent, result.Single().Point); //Assert.AreEqual(site2, result.Single().LeftArc.Site); Assert.AreEqual(site1, result.Single().Arc.Site); //Assert.AreEqual(site3, result.Single().RightArc.Site); }
public Vector2[][] GenerateVoronoi(Vector2[] points, Vector2 center) { eq.ClearAll(); Cell[] allCells; float boundaryLow = -1; float boundaryHigh = 1; float boundaryLeft = -1; float boundaryRight = 1; // Read input points. allCells = new Cell[points.Length]; for (int i = 0; i < points.Length; i++) { float x = points[i].x; float y = points[i].y; allCells[i] = new Cell(0, i, x, y); eq.Enqueue(allCells[i]); } Vector2 centerV2 = new Vector2(center.x, center.y); BeachLine BL = new BeachLine(allCells, centerV2); float lastY = float.MaxValue; while (!eq.IsEmpty()) { Site eventP = eq.Dequeue(); if (eventP.type == 0) { BL.Insert(eventP); } else if (eventP.type == 1) { BL.HandleVVEvent((VoronoiVertexPoint)eventP); } BL.Print(); } Vector2[][] OutputPoints = new Vector2[points.Length][]; for (uint i = 0; i < points.Length; ++i) { Cell cell = allCells[i]; cell.HandleEdges(boundaryHigh, boundaryLow, boundaryLeft, boundaryRight); cell.Sort(); OutputPoints[i] = new Vector2[cell.relatedVoronoiVertex.Count]; for (int j = 0; j < cell.relatedVoronoiVertex.Count; ++j) { OutputPoints[i][j] = new Vector2(cell.relatedVoronoiVertex[j].x, cell.relatedVoronoiVertex[j].y + cell.relatedVoronoiVertex[j].radius); } } return(OutputPoints); }
// Use this for initialization void Start() { //points = new List<Vector2>(); point_objects = new List <Transform>(); line_objects = new List <Transform>(); events = new List <VoronoiEvent>(); beachLine = new BeachLine(); }
public static LinkedList <VEdge> Run(List <FortuneSite> sites, double minX, double minY, double maxX, double maxY) { var eventQueue = new MinHeap <FortuneEvent>(5 * sites.Count); foreach (var s in sites) { eventQueue.Insert(new FortuneSiteEvent(s)); } //init tree var beachLine = new BeachLine(); var edges = new LinkedList <VEdge>(); var deleted = new HashSet <FortuneCircleEvent>(); //init edge list while (eventQueue.Count != 0) { var fEvent = eventQueue.Pop(); if (fEvent is FortuneSiteEvent) { beachLine.AddBeachSection((FortuneSiteEvent)fEvent, eventQueue, deleted, edges); } else { if (deleted.Contains((FortuneCircleEvent)fEvent)) { deleted.Remove((FortuneCircleEvent)fEvent); } else { beachLine.RemoveBeachSection((FortuneCircleEvent)fEvent, eventQueue, deleted, edges); } } } //clip edges var edgeNode = edges.First; while (edgeNode != null) { var edge = edgeNode.Value; var next = edgeNode.Next; var valid = ClipEdge(edge, minX, minY, maxX, maxY); if (!valid) { edges.Remove(edgeNode); } //advance edgeNode = next; } return(edges); }
public LinkedList <Edge> GenerateVoronoi(List <FortuneSite> sites, double minX, double minY, double maxX, double maxY) { MinHeap <FortuneEvent> eventQueue = new MinHeap <FortuneEvent>(5 * sites.Count); foreach (FortuneSite site in sites) { eventQueue.Insert(new FortuneSiteEvent(site)); } BeachLine beachLine = new BeachLine(); LinkedList <Edge> edges = new LinkedList <Edge>(); HashSet <FortuneCircleEvent> deleted = new HashSet <FortuneCircleEvent>(); while (eventQueue.count != 0) { FortuneEvent fortuneEvent = eventQueue.Pop(); if (fortuneEvent is FortuneSiteEvent) { beachLine.AddSection((FortuneSiteEvent)fortuneEvent, eventQueue, deleted, edges); } else { if (deleted.Contains((FortuneCircleEvent)fortuneEvent)) { deleted.Remove((FortuneCircleEvent)fortuneEvent); } else { beachLine.RemoveBeachSection((FortuneCircleEvent)fortuneEvent, eventQueue, deleted, edges); } } } LinkedListNode <Edge> edgeNode = edges.First; while (edgeNode != null) { Edge edge = edgeNode.Value; LinkedListNode <Edge> nextNode = edgeNode.Next; if (!ClipEdge(edge, minX, minY, maxX, maxY)) { edges.Remove(edgeNode); } edgeNode = nextNode; } return(edges); }
public void TestAddSingleLeaf() { var beachLine = new BeachLine(2000); var site = new Point { X = 464, Y = 500 }; beachLine.InsertSite(site); var leaf = beachLine.Root as Leaf; Assert.IsNotNull(leaf); Assert.AreEqual(site, leaf.Site); }
public void DetachBeachSection(TreeNode beachSectionNode) { //this.detachCircleEvent(beachsection); // detach potentially attached circle event //this.beachline.rbRemoveNode(beachsection); // remove from RB-tree //this.beachsectionJunkyard.push(beachsection); // mark for reuse DetachCircleEvent(beachSectionNode); BeachLine.RemoveNode(beachSectionNode); //BeachLine.Dump("BeachLine removing node", beachLineCounter++); BeachLine.Dump("detachBeachSection, remove", beachLineCounter++); //dumpTree(this.beachline, "detachBeachSection, remove", beachLineCounter); beachLineCounter++; }
public void TestAddThreeLeaves() { var beachLine = new BeachLine(2000); var site1 = new Point { X = 20, Y = 1000 }; var site2 = new Point { X = 4000, Y = 500 }; var site3 = new Point { X = 464, Y = 64 }; beachLine.InsertSite(site1); beachLine.InsertSite(site2); beachLine.InsertSite(site3); var root = beachLine.Root as Node; Assert.IsNotNull(root); var nodeLeft = root.Left as Node; var nodeLeftLeft = nodeLeft.Left as Node; var nodeLeftLeftLeft = nodeLeftLeft.Left as Node; Assert.IsNotNull(nodeLeft); Assert.IsNotNull(nodeLeftLeft); Assert.IsNotNull(nodeLeftLeftLeft); var leafRight = root.Right as Leaf; var leafLeftRight = nodeLeft.Right as Leaf; var leafLeftLeftRight = nodeLeftLeft.Right as Leaf; var leafLeftLeftLeftLeft = nodeLeftLeftLeft.Left as Leaf; var leafLeftLeftLeftRight = nodeLeftLeftLeft.Right as Leaf; Assert.IsNotNull(leafRight); Assert.IsNotNull(leafLeftRight); Assert.IsNotNull(leafLeftLeftRight); Assert.IsNotNull(leafLeftLeftLeftLeft); Assert.IsNotNull(leafLeftLeftLeftRight); Assert.AreEqual(site1, leafRight.Site); Assert.AreEqual(site2, leafLeftRight.Site); Assert.AreEqual(site1, leafLeftLeftRight.Site); Assert.AreEqual(site1, leafLeftLeftLeftLeft.Site); Assert.AreEqual(site3, leafLeftLeftLeftRight.Site); }
public void TestAddTwoLeaves() { var beachLine = new BeachLine(2000); var site1 = new Point { X = 20, Y = 1000 }; var site2 = new Point { X = 464, Y = 500 }; beachLine.InsertSite(site1); beachLine.InsertSite(site2); var root = beachLine.Root as Node; Assert.IsNotNull(root); Assert.IsNotNull(root.HalfEdge); Assert.AreEqual(site1, root.HalfEdge.Right); Assert.AreEqual(site2, root.HalfEdge.Left); var nodeLeft = root.Left as Node; Assert.IsNotNull(nodeLeft); Assert.IsNotNull(nodeLeft.HalfEdge); Assert.AreEqual(site1, nodeLeft.HalfEdge.Left); Assert.AreEqual(site2, nodeLeft.HalfEdge.Right); var leafRight = root.Right as Leaf; var leafLeftLeft = nodeLeft.Left as Leaf; var leafLeftRight = nodeLeft.Right as Leaf; Assert.IsNotNull(leafRight); Assert.IsNotNull(leafLeftLeft); Assert.IsNotNull(leafLeftRight); Assert.AreEqual(site2, leafLeftRight.Site); Assert.AreEqual(site1, leafLeftLeft.Site); Assert.AreEqual(site1, leafRight.Site); Assert.AreEqual(root.Breakpoint.Left, site2); Assert.AreEqual(root.Breakpoint.Right, site1); Assert.AreEqual(nodeLeft.Breakpoint.Left, site1); Assert.AreEqual(nodeLeft.Breakpoint.Right, site2); }
public VoronoiMap CreateVoronoiMap(int height, int width, int pointQuantity) { _eventQueue = new EventQueue(); _beachLine = new BeachLine(height); try { var sites = _siteGenerator.GenerateSites(width, height, pointQuantity); return(CreateVoronoiMap(height, width, sites)); } catch (Exception e) { _logger.Log(e.Message); _logger.Log(e.StackTrace); _logger.ToFile(); return(null); } }
public void TestHandleEvent() { var beachLine = new BeachLine(10); var center = beachLine.InsertSite(new Point(4, 6)); var right = beachLine.InsertSite(new Point(6, 4)); var left = beachLine.InsertSite(new Point(2, 3)); //var centerLeaf = ((Node)((Node)((Node)beachLine.Root).Left).Left).Right; //var sweepEvent = new CircleEvent //{ // LeftArc = new Leaf(new Point(2, 3)), // CenterArc = left.Leaves[0], // RightArc = new Leaf(new Point(6, 4)), // Edges = new List<HalfEdge> { // halfEdgesLeft[1], // halfEdgesRight[1] // }, // Point = new Point(4, 2), // Vertex = new Point(4, 4) //}; //var eventQueue = new EventQueue(); //var strategy = new CircleEventHandlerStrategy(); //var result = strategy.HandleEvent(sweepEvent, eventQueue, beachLine).ToList(); //Assert.IsNotNull(result); //var vertex = ((Vertex)result.Single(g => g is Vertex)); //Assert.AreEqual(sweepEvent.Vertex, vertex.Point); //Assert.AreEqual(3, vertex.HalfEdges.Count); //var start = vertex.HalfEdges.Single(h => h.Start != null); //Assert.IsNull(start.End); //Assert.AreEqual(new Point(2, 3), start.Left); //Assert.AreEqual(new Point(6, 4), start.Right); //var ends = vertex.HalfEdges.Where(h => h.End != null); //Assert.AreEqual(2, ends.Count()); //Assert.IsTrue(!ends.Contains(start)); //Assert.IsTrue(ends.All(h => h.Start == null)); }
// Update is called once per frame void Update() { // Destroy existing gameobjects foreach (Transform t in point_objects) { Destroy(t.gameObject); } point_objects.Clear(); foreach (Transform t in line_objects) { Destroy(t.gameObject); } line_objects.Clear(); if (randomize) { UnityEngine.Random.InitState(seed); points.Clear(); // Generate points for (int i = 0; i < num_points; i++) { Vector2 point = new Vector2( UnityEngine.Random.Range( (-x_range / 2) - edge_size, (x_range / 2) + edge_size ), UnityEngine.Random.Range( (-y_range / 2) - edge_size, (y_range / 2) + edge_size )); points.Add(point); } } // Add points to event list foreach (Vector2 point in points) { events.Add(new VoronoiEvent(point)); } // Sort events by y_value events.Sort(); bool complete_early = false; int iterations = 0; beachLine = new BeachLine(); while (!(events.Count == 0) && !complete_early) { VoronoiEvent e = events[0]; // Get first event // Update directrix for beach line beachLine.SetDirectrix(e.y_value); if (beachLine.root == null) { // This is the first event beachLine.Add(new BeachLineArc(new Arc(e.site, e.y_value))); } // If site event else if (e.IsSiteEvent()) { // Create new arc //Arc newArc = new Arc(e.site, e.y_value); Vector2 intersection = Vector2.zero; Vector2 direction = Vector2.zero; BeachLineArc arcToSplit = beachLine.GetArcAtX(e.site.x, out intersection, out direction); if (arcToSplit != null) { Arc newLeftArc = new Arc(arcToSplit.arc.focus, arcToSplit.arc.directrix); newLeftArc.start_x = arcToSplit.arc.start_x; newLeftArc.end_x = e.site.x; BeachLineArc newLeftBLArc = new BeachLineArc(newLeftArc); Arc newRightArc = new Arc(arcToSplit.arc.focus, arcToSplit.arc.directrix); newRightArc.start_x = e.site.x; newRightArc.end_x = arcToSplit.arc.end_x; BeachLineArc newRightBLArc = new BeachLineArc(newRightArc); Edge newLeftEdge = new Edge(intersection, direction, 0); Edge newRightEdge = new Edge(intersection, -direction, 0); BeachLineEdge newLeftBLEdge = new BeachLineEdge(newLeftEdge); BeachLineEdge newRightBLEdge = new BeachLineEdge(newRightEdge); BeachLineElement parentElement = arcToSplit.parent; bool isLeft = false; if (parentElement != null) { if (parentElement.leftChild == arcToSplit) { isLeft = true; } } arcToSplit.parent = newRightBLEdge; newRightBLEdge.leftChild = arcToSplit; newRightBLArc.parent = newRightBLEdge; newRightBLEdge.rightChild = newRightBLArc; newRightBLEdge.parent = newLeftBLEdge; newLeftBLEdge.rightChild = newRightBLEdge; newLeftBLArc.parent = newLeftBLEdge; newLeftBLEdge.leftChild = newLeftBLArc; if (parentElement == null) { beachLine.root = newLeftBLEdge; newLeftBLEdge.parent = null; } else { newLeftBLEdge.parent = parentElement; if (isLeft) { parentElement.leftChild = newLeftBLEdge; } else { parentElement.rightChild = newLeftBLEdge; } } } //Arc leftArc = arcToSplit.SplitLeft(e.site.x); //Arc rightArc = arcToSplit.SplitRight(e.site.x); //// Direction should always point left //BeachLineEdge leftEdge = new BeachLineEdge(new Edge(intersection, direction, 0)); //BeachLineEdge rightEdge = new BeachLineEdge(new Edge(intersection, -direction, 0)); ////beachLine.Add(new BeachLineArc(newArc)); //arcToSplit.ReplaceWith(leftEdge); //leftEdge.SetLeftChild(new BeachLineArc(leftArc)); //leftEdge.SetRightChild(rightEdge); //rightEdge.SetLeftChild(new BeachLineArc(rightArc)); // This arc is going to split existing arc // We will end of with a left/right arc, plus a left right edge } // Event handled. Remove event from list. events.RemoveAt(0); iterations++; if (iterations == max_iterations) { complete_early = true; } } beachLine.Draw(transform.position); foreach (Vector2 point in points) { Transform point_object = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform; point_object.parent = transform; point_object.localScale = new Vector3(point_size, point_size, point_size); point_object.localPosition = new Vector3(point.x, point.y, 0f); point_objects.Add(point_object); } // TEST Transform newLine = CreateLine(points[0], points[1]); line_objects.Add(newLine); //foreach(Vector2 point in points) //{ // if(point != points[0]) // { // Transform newLine = CreateLine(point, points[0]); // line_objects.Add(newLine); // } //} }
public ICollection <IGeometry> HandleEvent(CircleEvent sweepEvent, EventQueue eventQueue, BeachLine beachLine) { if (sweepEvent.Arc.Parent == null) { throw new InvalidOperationException($"CircleEvent: Arc {sweepEvent.Arc.Site}: Parent of node {0} is null"); } var leftParent = sweepEvent.Arc.GetParent(TraverseDirection.CounterClockwise); var rightParent = sweepEvent.Arc.GetParent(TraverseDirection.Clockwise); var left = leftParent?.GetLeaf(TraverseDirection.CounterClockwise); var right = rightParent?.GetLeaf(TraverseDirection.Clockwise); if (left == null || right == null) { throw new InvalidOperationException($"Neighbor of node {sweepEvent.Arc.Site} is null."); } if (left.CircleEvent != null) { eventQueue.Remove(left.CircleEvent); left.CircleEvent = null; } if (right.CircleEvent != null) { eventQueue.Remove(right.CircleEvent); right.CircleEvent = null; } var p = new Point(sweepEvent.Point.X, _calculationService.GetY(sweepEvent.Arc.Site, sweepEvent.Point)); leftParent.HalfEdge.EndPoint = p; rightParent.HalfEdge.EndPoint = p; var vertex = new Vertex { Point = p }; ConnectHalfEdgeWithVertex(leftParent.HalfEdge, vertex, (e, v) => e.End = v); ConnectHalfEdgeWithVertex(rightParent.HalfEdge, vertex, (e, v) => e.End = v); // Add third half edge var halfEdge = new HalfEdge(p, left.Site, right.Site); ConnectHalfEdgeWithVertex(halfEdge, vertex, (e, v) => e.Start = v); Logger.Instance.Log($"Left parent: {leftParent.HalfEdge}"); Logger.Instance.Log($"Right parent: {rightParent.HalfEdge}"); var higher = sweepEvent.Arc.GetFirstParent(leftParent, rightParent); Logger.Instance.Log($"Higher node: {higher}"); Logger.Instance.Log($"Higher edge old: {higher.HalfEdge}"); higher.HalfEdge = halfEdge; if (vertex.HalfEdges.Count != 3) { var message = $"Halfedge {halfEdge} is already connected to Vertex {vertex}"; Logger.Instance.Log(message); Logger.Instance.ToFile(); throw new InvalidOperationException(message); } Logger.Instance.Log($"CircleEvent: Remove Arc {sweepEvent.Arc.Site}"); beachLine.RemoveLeaf(sweepEvent.Arc); var circleEvents = beachLine.GenerateCircleEvent(new[] { left, right }, sweepEvent.Point.Y); eventQueue.Insert(circleEvents); return(new List <IGeometry> { vertex, halfEdge }); }
public VoronoiMap CreateVoronoiMap(int height, int width, IEnumerable <Site> sites) { if (sites == null) { throw new ArgumentNullException("sites"); } if (sites.GroupBy(s => s.Point).Count() != sites.Count()) { throw new ArgumentException("Multiple sites with the same coordinates passed!"); } var siteList = string.Join(", ", sites.Select(s => s.Point.ToString()).ToArray()); _logger.Log($"Create Voronoi map with sites: {siteList}"); _eventQueue = new EventQueue(); _beachLine = new BeachLine(height); var map = new VoronoiMap(); _eventQueue.Initialize(sites.Select(s => s.Point)); map.AddRange(sites.Cast <IGeometry>()); while (_eventQueue.HasEvents) { var sweepEvent = _eventQueue.GetNextEvent(); var siteEvent = sweepEvent as SiteEvent; if (siteEvent != null) { _logger.Log($"Sweepline SiteEvent: {siteEvent.Point}"); var halfEdges = _siteEventHandler.HandleEvent(siteEvent, _eventQueue, _beachLine); map.AddRange(halfEdges); foreach (var geo in halfEdges) { _logger.Log($"Add {geo}"); } continue; } var circleEvent = sweepEvent as CircleEvent; if (circleEvent == null) { throw new InvalidOperationException("SweepEvent is neither SiteEvent nor CircleEvent"); } //_logger.Log($"Sweepline CircleEvent: {circleEvent.Point} for arc {circleEvent.Arc.Site}"); var circleEventResult = _circleEventHandler.HandleEvent(circleEvent, _eventQueue, _beachLine); foreach (var geo in circleEventResult) { _logger.Log($"Add {geo}"); } // Add vertex and new half edge map.AddRange(circleEventResult); } _beachLine.FinishEdge(_beachLine.Root, width); //map.FinishEdges(width); map.ConnectEdges(); _logger.Log("Finished Voronoi map creation"); foreach (var edge in map.Where(g => g is HalfEdge).Cast <HalfEdge>()) { _logger.Log(edge.ToString()); } return(map); }
public List <BeachLineEdge> DoVoronoi(List <VoronoiSite> siteList) { List <BeachLineEdge> outEdges = new List <BeachLineEdge>(); beachLine = new BeachLine(); events = new List <VoronoiEvent>(); // Add site list to event list. foreach (VoronoiSite site in siteList) { events.Add(new SiteEvent(site)); } // Sort site list. events.Sort(); // Test for first two events being very close in y if (events.Count >= 2) { if (events[0].y - events[1].y < 0.01f) { // Add another site events far above them to prevent this from happening events.Insert(0, new SiteEvent(new VoronoiSite(new Vector2(0, -10)))); } } // Start processing events int iterations = 0; while (events.Count != 0) { if (use_max_iterations && iterations == max_iterations) { break; } else { iterations++; } // Pop event off front of list VoronoiEvent thisEvent = events[0]; // Set sweepline sweepLine = thisEvent.y; if (sweepLine >= target_sweepline) { sweepLine = target_sweepline; beachLine.Update(sweepLine); break; } beachLine.Update(sweepLine); if (thisEvent.IsValid()) { // Check event type if (thisEvent is SiteEvent) { SiteEvent siteEvent = (SiteEvent)thisEvent; // Create a new arc for this event. BeachLineArc newArc = new BeachLineArc(siteEvent.Site.Point, sweepLine); // Find arc at this site BeachLineArc arcToSplit = beachLine.SearchX(siteEvent.x); if (arcToSplit == null) { // We could not find an arc, meaning this is the first one. // Lets just add it to the beachline as root. beachLine.SetRoot(newArc); } else { // Split the arc arcToSplit.Split(newArc); // The split will have added newArc to the tree and also created two new edges. // We need to check those for intersections. List <BeachLineArc> arcsToSqueeze = new List <BeachLineArc> { newArc.LeftArc, newArc.RightArc }; foreach (BeachLineArc arc in arcsToSqueeze) { CheckForNewEdgeEvents(arc); } } } else if (thisEvent is EdgeEvent) { EdgeEvent edgeEvent = (EdgeEvent)thisEvent; if (edgeEvent.SqueezedArc != null) { if (edgeEvent.SqueezedArc.LeftEdge != null && edgeEvent.SqueezedArc.RightEdge != null) { BeachLineEdge newEdge; List <BeachLineEdge> outputEdges = edgeEvent.SqueezedArc.Squeeze(out newEdge); // Add edges to output foreach (BeachLineEdge edge in outputEdges) { outEdges.Add(edge); } // Squeeze function will have removed arc and edges from tree and created a new edge. // We need to check that edge for any new intersections. CheckForNewEdgeEvents(newEdge.LeftArc); CheckForNewEdgeEvents(newEdge.RightArc); } } // Otherwise, this must have been pre-empted but not invalidated for some reason } else { Debug.LogError("Wrong event type! Should not happen!"); } } events.RemoveAt(0); } if (iterations != max_iterations) { sweepLine = target_sweepline; beachLine.Update(sweepLine); } if (events.Count == 0) { // We completed the events list. // Add the remaining edges to the output. BeachLineElement node = beachLine.GetRoot(); if (node != null) { // Mode node to start while (node.Prev != null) { node = node.Prev; } // Add all remaining edges while (node.Next != null) { if (node is BeachLineEdge) { outEdges.Add(node as BeachLineEdge); } node = node.Next; } } } return(outEdges); }
public void SetBeachLine(BeachLine beachLine) { mBeachLine = beachLine; }
public void AddBeachSection(Site site) { //var x = site.x, // directrix = site.y; var x = site.X; var dir = site.Y; //var lArc, rArc, // dxl, dxr, // node = this.beachline.root; TreeNode lArc = null, rArc = null; double dxl, dxr; TreeNode node = BeachLine.root; while (node != null) { // dxl = this.leftBreakPoint(node, directrix) - x; dxl = GetLeftBreakPoint(node.BeachSection, node, dir) - x; // // x lessThanWithEpsilon xl => falls somewhere before the left edge of the beachsection // if (dxl > 1e-9) // { // node = node.rbLeft; // } // else // { if (dxl > epsilon) { node = node.Left; } else { // dxr = x - this.rightBreakPoint(node, directrix); dxr = x - GetRightBreakPoint(node.BeachSection, node, dir); // // x greaterThanWithEpsilon xr => falls somewhere after the right edge of the beachsection // if (dxr > 1e-9) // { // if (!node.rbRight) // { // lArc = node; // break; // } // node = node.rbRight; // } if (dxr > epsilon) { if (node.Right == null) { lArc = node; break; } node = node.Right; } else { if (dxl > -epsilon) { lArc = node.Previous; rArc = node; } else if (dxr > -epsilon) { lArc = node; rArc = node.Next; } else { lArc = node; rArc = node; } break; } // else // { // // x equalWithEpsilon xl => falls exactly on the left edge of the beachsection // if (dxl > -1e-9) // { // lArc = node.rbPrevious; // rArc = node; // } // // x equalWithEpsilon xr => falls exactly on the right edge of the beachsection // else if (dxr > -1e-9) // { // lArc = node; // rArc = node.rbNext; // } // // falls exactly somewhere in the middle of the beachsection // else // { // lArc = rArc = node; // } // break; // } // } } } //var newArc = this.createBeachsection(site); //this.beachline.rbInsertSuccessor(lArc, newArc); var newArc = CreateBeachSection(site); var newArcNode = new TreeNode { BeachSection = newArc, X = site.X, Y = site.Y, Site = site }; BeachLine.InsertSuccessor(lArc, newArcNode); //dumpTree(this.beachline, "BeachLine, addBeachSection first insert", beachLineCounter); BeachLine.Dump("BeachLine, addBeachSection first insert", beachLineCounter++); //if (!lArc && !rArc) //{ // return; //} if (lArc == null && rArc == null) { return; } //if (lArc === rArc) //{ // this.detachCircleEvent(lArc); // rArc = this.createBeachsection(lArc.site); // this.beachline.rbInsertSuccessor(newArc, rArc); // newArc.edge = rArc.edge = this.createEdge(lArc.site, newArc.site); // this.a--ttachCircleEvent(lArc); // this.a--ttachCircleEvent(rArc); // return; //} if (lArc == rArc) { DetachCircleEvent(lArc); var s = lArc.BeachSection.Site; rArc = new TreeNode { BeachSection = CreateBeachSection(s), X = s.X, Y = s.Y, Site = s }; BeachLine.InsertSuccessor(newArcNode, rArc); BeachLine.Dump("BeachLine, addBeachSection second insert", beachLineCounter++); newArc.Edge = CreateEdge(lArc.BeachSection.Site, newArc.Site, null, null); rArc.BeachSection.Edge = newArc.Edge; AttachCircleEvent(lArc); AttachCircleEvent(rArc); return; } //if (lArc && !rArc) //{ // newArc.edge = this.createEdge(lArc.site, newArc.site); // return; //} if (lArc != null && rArc == null) { newArc.Edge = CreateEdge(lArc.BeachSection.Site, newArc.Site, null, null); return; } ////if (!lArc && rArc) { //// throw "Voronoi.addBeachsection(): What is this I don't even"; //// } /// if (lArc == null && rArc != null) { Console.WriteLine("SHOULD NOT HAPPEN"); } //if (lArc !== rArc) //{ // this.detachCircleEvent(lArc); // this.detachCircleEvent(rArc); // var lSite = lArc.site, // ax = lSite.x, // ay = lSite.y, // bx = site.x - ax, // by = site.y - ay, // rSite = rArc.site, // cx = rSite.x - ax, // cy = rSite.y - ay, // d = 2 * (bx * cy - by * cx), // hb = bx * bx + by * by, // hc = cx * cx + cy * cy, // vertex = this.createVertex((cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay); // this.setEdgeStartpoint(rArc.edge, lSite, rSite, vertex); // newArc.edge = this.createEdge(lSite, site, undefined, vertex); // rArc.edge = this.createEdge(site, rSite, undefined, vertex); // this.a--ttachCircleEvent(lArc); // this.a--ttachCircleEvent(rArc); // return; //} if (lArc != rArc) { DetachCircleEvent(lArc); DetachCircleEvent(rArc); var lSite = lArc.BeachSection.Site; var ax = lSite.X; var ay = lSite.Y; var bx = site.X - ax; var by = site.Y - ay; var rSite = rArc.BeachSection.Site; var cx = rSite.X - ax; var cy = rSite.Y - ay; var d = 2 * (bx * cy - by * cx); var hb = bx * bx + by * by; var hc = cx * cx + cy * cy; var vertex = CreateVertex((cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay); rArc.BeachSection.Edge = CreateEdge(lSite, site, null, vertex); newArc.Edge = CreateEdge(lSite, site, null, vertex); rArc.BeachSection.Edge = CreateEdge(site, rSite, null, vertex); AttachCircleEvent(lArc); AttachCircleEvent(rArc); return; } }
public void Setup() { _eventQueue = new EventQueue(); _beachLine = new BeachLine(10); _strategy = new SiteEventHandlerStrategy(); }
public ICollection <IGeometry> HandleEvent(SiteEvent sweepEvent, EventQueue eventQueue, BeachLine beachLine) { var circleEvent = beachLine.FindCircleEventAbove(sweepEvent.Point); if (circleEvent != null) { Logger.Instance.Log($"SiteEvent: {sweepEvent.Point.ToString()}: Remove CircleEvent {circleEvent.Point} from queue."); eventQueue.Remove(circleEvent); } Logger.Instance.Log($"SiteEvent: {sweepEvent.Point.ToString()}: Insert site into beach line"); var result = beachLine.InsertSite(sweepEvent.Point); var circleEvents = beachLine.GenerateCircleEvent(result?.Leaves, sweepEvent.Point.Y); eventQueue.Insert(circleEvents); if (result != null) { return new List <IGeometry> { result.HalfEdge } } ; return(new List <IGeometry>()); } }