public EdgeEvent(Vector2 intersection, BeachLineArc squeezedArc, BeachLineEdge leftEdge, BeachLineEdge rightEdge) : base(new VoronoiSite(intersection.x, intersection.y + (intersection - squeezedArc.Focus).magnitude)) { mSqueezedArc = squeezedArc; mLeftEdge = leftEdge; mRightEdge = rightEdge; mIntersection = intersection; }
public override BeachLineArc GetArcAtX(float x, out Vector2 intersection, out Vector2 direction) { // This is not an arc. We just need to check child nodes BeachLineArc foundArc = leftChild.GetArcAtX(x, out intersection, out direction); if (foundArc != null) { // We found are arc. We are done and can return. return(foundArc); } // Try right child return(rightChild.GetArcAtX(x, out intersection, out direction)); }
public static bool GetValidIntersection(out Vector2 intersection, BeachLineArc arc, BeachLineEdge edge) { Vector2 i1, i2; int interX = Geometry.Intersection(out i1, out i2, arc, edge); intersection = i1; bool intersectionValid = false; if (interX != 0) { if (interX == 1) { intersection = i1; if (Vector2.Dot(edge.Direction, i1 - edge.Start) > 0) { intersectionValid = true; } } else { bool i1_valid = false; bool i2_valid = false; if (Vector2.Dot(edge.Direction, i1 - edge.Start) > 0) { i1_valid = true; intersection = i1; } if (Vector2.Dot(edge.Direction, i2 - edge.Start) > 0) { i2_valid = true; intersection = i2; } if (i1_valid && i2_valid) { // Use closest intersection = Vector2.Distance(i1, edge.Start) < Vector2.Distance(i2, edge.Start) ? i1 : i2; } intersectionValid = i1_valid || i2_valid; } if (intersectionValid) { return(true); } } return(false); }
bool CheckForNewEdgeEvents(BeachLineArc arc) { if (arc != null) { // Check left and right edge of this arc for intersections. BeachLineEdge leftEdge = arc.LeftEdge; BeachLineEdge rightEdge = arc.RightEdge; if (leftEdge != null && rightEdge != null) { // Check for edge intersection Vector2 intersection; if (leftEdge.CheckIntersection(rightEdge, out intersection)) { // These edges intersect. We need to add a new edge event. // This event may invalidate a previous one. Search for an existing event for this arc. foreach (VoronoiEvent e in events) { if (e is EdgeEvent) { EdgeEvent edgeEvent = e as EdgeEvent; if (edgeEvent.LeftEdge == leftEdge && edgeEvent.RightEdge == rightEdge) { e.Invalidate(); } } } events.Add(new EdgeEvent(intersection, arc, leftEdge, rightEdge)); events.Sort(); return(true); } } } return(false); }
public void Split(BeachLineArc newArc) { float splitX = newArc.Focus.x; float sweepLine = newArc.Focus.y; BeachLineArc newLeftArc = new BeachLineArc(this); BeachLineArc newRightArc = new BeachLineArc(this); Vector2 splitPoint = new Vector2(splitX, y(splitX)); Vector2 edgeDirection = Tangent(splitX); // Make edgeDirection always point in the positive x direction edgeDirection = edgeDirection.x < 0 ? -edgeDirection : edgeDirection; BeachLineEdge newLeftEdge = new BeachLineEdge(splitPoint, -edgeDirection); BeachLineEdge newRightEdge = new BeachLineEdge(splitPoint, edgeDirection); newLeftEdge.SetLeftChild(newLeftArc); newLeftEdge.SetRightChild(newRightEdge); newLeftEdge.SetParent(Parent); newRightEdge.SetLeftChild(newArc); newRightEdge.SetRightChild(newRightArc); newRightEdge.SetParent(newLeftEdge); newLeftArc.SetParent(newLeftEdge); newRightArc.SetParent(newRightEdge); newArc.SetParent(newRightEdge); // Change next and prev links BeachLineEdge prevEdge = (BeachLineEdge)Prev; BeachLineEdge nextEdge = (BeachLineEdge)Next; LinkRemove(); if (prevEdge != null) { prevEdge.LinkInsertAfter(newLeftArc); } else { // newLeftArc is going to be the new start of the list if (nextEdge != null) { newLeftArc.SetNext(nextEdge); nextEdge.SetPrev(newLeftArc); } } newLeftArc.LinkInsertAfter(newLeftEdge) .LinkInsertAfter(newArc) .LinkInsertAfter(newRightEdge) .LinkInsertAfter(newRightArc); //if (nextEdge != null) //{ // newRightArc.SetNext(nextEdge); // nextEdge.SetPrev(newRightArc); //} BeachLineElement parent = Parent; if (parent == null) { // This is root. Replace this with left edge. BeachLineRoot.SetRoot(newLeftEdge); } else { // Set parent to point to new construct if (parent.LeftChild == this) { parent.SetLeftChild(newLeftEdge); } else if (parent.RightChild == this) { parent.SetRightChild(newLeftEdge); } else { Debug.LogError("Error in Split - couldn't find child in parent."); } } // We can now remove this node //SetLeftArc(null); //SetRightArc(null); //SetLeftEdge(null); //SetRightEdge(null); SetLeftChild(null); SetRightChild(null); SetParent(null); }
public BeachLineArc(BeachLineArc arc) { mFocus = arc.Focus; mDirectrix = arc.mDirectrix; }
public List <BeachLineEdge> Squeeze(out BeachLineEdge newEdge) { // These are the output edges BeachLineEdge leftEdge = (BeachLineEdge)Prev; BeachLineEdge rightEdge = (BeachLineEdge)Next; BeachLineArc leftArc = (BeachLineArc)leftEdge.Prev; BeachLineArc rightArc = (BeachLineArc)rightEdge.Next; // Create new edge // To create it, we need the intersection point of the two output edges plus the // focuses of the two arcs. Vector2 intersection; leftEdge.CheckIntersection(rightEdge, out intersection); Vector2 focus1 = leftArc.Focus; Vector2 focus2 = rightArc.Focus; Vector2 perpendicular = focus2 - focus1; Vector2 newEdgeDirection = new Vector2(perpendicular.y, -perpendicular.x); if (Vector2.Dot(leftEdge.Direction.normalized + rightEdge.Direction.normalized, -newEdgeDirection) > 0) //if (newEdgeDirection.y < 0) { newEdgeDirection = -newEdgeDirection; } newEdge = new BeachLineEdge(intersection, newEdgeDirection.normalized); BeachLineEdge edgeToReplace = leftEdge == Parent ? rightEdge : leftEdge; //newEdge.SetLeftArc(LeftArc); //newEdge.SetRightArc(RightArc); // Replace other edge with new edge edgeToReplace.ReplaceWithSingleNode(newEdge); // Replace parent with sibling BeachLineElement sibling = Sibling; sibling.SetParent(null); bool iAmLeftChild = this == Parent.LeftChild; if (iAmLeftChild) { Parent.SetRightChild(null); } else { Parent.SetLeftChild(null); } BeachLineElement parentsParent = Parent.Parent; bool parentIsLeftChild = Parent == parentsParent.LeftChild; if (parentIsLeftChild) { parentsParent.SetLeftChild(sibling); } else { parentsParent.SetRightChild(sibling); } sibling.SetParent(parentsParent); //Parent.ReplaceWith(Sibling); //Parent.SetLeftChild(null); //Parent.SetRightChild(null); // Set next/prev for altered nodes leftArc.SetNext(newEdge); newEdge.SetPrev(leftArc); newEdge.SetNext(rightArc); rightArc.SetPrev(newEdge); // Remove this node from tree SetParent(null); SetLeftChild(null); SetRightChild(null); SetNext(null); SetPrev(null); leftEdge.SetParent(null); leftEdge.SetLeftChild(null); leftEdge.SetRightChild(null); leftEdge.SetNext(null); leftEdge.SetPrev(null); rightEdge.SetParent(null); rightEdge.SetLeftChild(null); rightEdge.SetRightChild(null); rightEdge.SetNext(null); rightEdge.SetPrev(null); leftEdge.SetEndpoint(intersection); rightEdge.SetEndpoint(intersection); List <BeachLineEdge> outputList = new List <BeachLineEdge> { leftEdge, rightEdge }; return(outputList); }
public bool GetValidIntersection(out Vector2 intersection, BeachLineArc arc, BeachLineEdge edge) { //Vector3 arcCoeff = Geometry.QuadraticFocusDirectrixToABCCoefficents(arc.Focus, arc.Directrix); //// Coefficients = [x^2, x, y] // y = ax^2 + bx + c // => ax^2 + bx - y = c // // dx + ey = f // Input matrix / output vector // | a b -1 | c | // | 0 d e | f | // Get line equation in homogeneous coordinates //Vector3 line = Vector3.Cross(new Vector3(edge.Start.x, edge.Start.y, 1), new Vector3(edge.End.x, edge.End.y, 1)); //const int dimension = 3; //double[,] inputMatrix = new double[,] { // { arcCoeff.x, arcCoeff.y, -1 }, // { 0, line.x, line.y } }; //double[] outputVector = new double[] { arcCoeff.z, line.z }; //SystemOfLinearEquations.SolveUsingLU(inputMatrix, outputVector, dimension); Vector2 i1, i2; int interX = Geometry.Intersection(out i1, out i2, arc, edge); intersection = i1; bool intersectionValid = false; if (interX != 0) { if (interX == 1) { intersection = i1; if (Vector2.Dot(edge.Direction, i1 - edge.Start) > 0) { intersectionValid = true; } } else { bool i1_valid = false; bool i2_valid = false; if (Vector2.Dot(edge.Direction, i1 - edge.Start) > 0) { i1_valid = true; intersection = i1; } if (Vector2.Dot(edge.Direction, i2 - edge.Start) > 0) { i2_valid = true; intersection = i2; } if (i1_valid && i2_valid) { // Use closest intersection = Vector2.Distance(i1, edge.Start) < Vector2.Distance(i2, edge.Start) ? i1 : i2; } intersectionValid = i1_valid || i2_valid; DrawCross(i1, 0.1f, Color.blue); DrawCross(i2, 0.1f, Color.magenta); } if (intersectionValid) { DrawCross(intersection, 0.2f, Color.white); return(true); } } return(false); }
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 static int Intersection(out Vector2 intersection1, out Vector2 intersection2, BeachLineArc arc, BeachLineEdge edge) { if (edge.Direction.x == 0) { // If vertical, just return quadratic at x intersection1 = new Vector2(edge.Start.x, arc.y(edge.Start.x)); intersection2 = intersection1; return(1); } Vector3 quadraticAbc = QuadraticFocusDirectrixToABCCoefficents(arc.Focus, arc.Directrix); Vector2 rayAb = RayToABCoefficients(edge.Start, edge.Direction); return(Intersection2D(out intersection1, out intersection2, quadraticAbc.x, quadraticAbc.y, quadraticAbc.z, 0, rayAb.x, rayAb.y)); }
// 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); // } //} }