예제 #1
0
 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;
 }
예제 #2
0
    public bool CheckIntersection(BeachLineEdge otherEdge, out Vector2 intersection)
    {
        intersection = Geometry.Intersection2D(mStart, mDirection, otherEdge.mStart, otherEdge.mDirection);

        // Check if intersection is in right direction
        if (intersection.x >= mStart.x && mDirection.x >= 0 || intersection.x < mStart.x && mDirection.x < 0)
        {
            // first edge intersection is valid
            if (intersection.x >= otherEdge.Start.x && otherEdge.Direction.x >= 0 || intersection.x < otherEdge.Start.x && otherEdge.Direction.x < 0)
            {
                // second edge intersection is valid
                return(true);
            }
        }
        return(false);
    }
예제 #3
0
    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);
    }
예제 #4
0
    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);
    }
예제 #5
0
    public void Draw(Color color)
    {
        float   step_size = 0.1f;
        Vector3 offset    = Vector3.zero;

        if (Directrix == Focus.y)
        {
            // Vertical
            Debug.DrawRay(Focus, Vector3.down * 20, color);
        }
        else
        {
            //BeachLineArc highArc = mLeftArc;
            //BeachLineArc lowArc = mRightArc;

            //if(highArc == null && lowArc != null)
            //{
            //    return;
            //}

            BeachLineEdge prevEdge = (BeachLineEdge)Prev;
            BeachLineEdge nextEdge = (BeachLineEdge)Next;
            float         startX   = prevEdge != null ? (prevEdge.Start + prevEdge.Direction).x : -10;
            float         endX     = nextEdge != null ? (nextEdge.Start + nextEdge.Direction).x : 10;

            //float startX = -10;
            //if (lowArc != null)
            //{
            //    //Vector2 i1, i2;
            //    //int res = Geometry.Intersection2D(out i1, out i2, mFocus, sweepLine, lowArc.Focus, sweepLine);
            //    //if (res == 2)
            //    //{
            //    //    //mStartX = Mathf.Max(i1.x, i2.x);
            //    //    // Find result between these arcs
            //    //    if (lowArc.Focus.x < i1.x && i1.x < Focus.x)
            //    //    {
            //    //        startX = i1.x;
            //    //    }
            //    //    else if (lowArc.Focus.x < i2.x && i2.x < Focus.x)
            //    //    {
            //    //        startX = i2.x;
            //    //    }
            //    //}
            //    startX = mStartX;
            //}

            //float endX = 10;
            //if (highArc != null)
            //{
            //    //Vector2 i1, i2;
            //    //int res = Geometry.Intersection2D(out i1, out i2, mFocus, sweepLine, highArc.Focus, sweepLine);
            //    //if (res == 2)
            //    //{
            //    //    //mEndX = Mathf.Min(i1.x, i2.x);
            //    //    // Find result between these arcs
            //    //    if (Focus.x < i1.x && i1.x < highArc.Focus.x)
            //    //    {
            //    //        endX = i1.x;
            //    //    }
            //    //    else if (Focus.x < i2.x && i2.x < highArc.Focus.x)
            //    //    {
            //    //        endX = i2.x;
            //    //    }
            //    //}
            //    endX = mEndX;
            //}


            int lines = Mathf.RoundToInt((endX - startX) / step_size);

            float t0 = 0f;
            float x0 = Mathf.Lerp(startX, endX, t0);
            float y0 = y(x0);
            for (int i = 0; i < lines; i++)
            {
                float t1 = (float)(i + 1) / lines;
                float x1 = Mathf.Lerp(startX, endX, t1);
                float y1 = y(x1);
                if (y1 == float.PositiveInfinity)
                {
                    y1 = float.MaxValue;
                }
                if (y1 == float.NegativeInfinity)
                {
                    y1 = float.MinValue;
                }

                Vector3 start = offset + new Vector3(x0, y0, 0);
                Vector3 end   = offset + new Vector3(x1, y1, 0);

                Debug.DrawLine(start, end, color);

                t0 = t1;
                x0 = x1;
                y0 = y1;
            }
        }
    }
예제 #6
0
    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);
    }
예제 #7
0
    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);
    }
예제 #8
0
    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));
    }
예제 #9
0
    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);
    }
예제 #10
0
    // 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);
        //    }
        //}
    }