Exemplo n.º 1
0
    /*
     * Create a trapezoid represented by two linesegments above and below, and two points left and right
     */
    public Trapezoid(Vector2 l, Vector2 r, LineSegment t, LineSegment b)
    {
        top    = t;
        bottom = b;
        left   = l;
        right  = r;

        // cleanup eventually (or not, error messages are always useful)
        if (left.x > right.x)
        {
            Debug.LogError("Created trapezoid with wrong points\n" + this.show());
        }
        if (top.Above(bottom.point1) || top.Above(bottom.point2))
        {
            Debug.LogError("Created trapezoid with bottom segment point above the top segment\n" + this.show());
        }
    }
Exemplo n.º 2
0
    /*
     * Split all trapezoids that are being intersected by a segment 'seg'
     *  Replace top and bottom segments with the given segment
     *  Add new trapezoids at the start and end points (if those endpoints are not yet in the VD)
     *  Ensure all neighbors are correctly assigned
     *
     *  Merge trapezoids where the vertical line has disappeard because of the segment
     */
    private List <Trapezoid> CreateTrapezoids(List <Trapezoid> toSplit, LineSegment seg)
    {
        List <Trapezoid> newTrapezoids   = new List <Trapezoid>();
        List <Trapezoid> finalTrapezoids = new List <Trapezoid>();
        Trapezoid        newUpper;
        Trapezoid        newLower;
        Trapezoid        oldUpper        = null;
        Trapezoid        oldLower        = null;
        Trapezoid        begin           = null; // Used for a degenerate start
        bool             StartDegenerate = false;
        bool             EndDegenerate   = false;

        /*
         * Simple case where the inserted segment is fully contained in one trapezoid
         *
         * If the endpoints of the inserted segment touch another segment, use the regular case to avoid infinitesmall trapezoids
         */
        if (toSplit.Count == 1 && (toSplit[0].left != seg.point1 && toSplit[0].right != seg.point2))
        {
            Trapezoid start = new Trapezoid(toSplit[0].left, seg.point1, toSplit[0].top, toSplit[0].bottom);
            Trapezoid end   = new Trapezoid(seg.point2, toSplit[0].right, toSplit[0].top, toSplit[0].bottom);
            foreach (Trapezoid neighbor in toSplit[0].Neighbors)
            {
                neighbor.DeleteNeighbor(toSplit[0]);
                // All left neighbors are neighbors of start, all right neighbors are neighbors of end
                if (neighbor.right.x > toSplit[0].left.x)
                {
                    neighbor.AddNeighbor(end);
                    end.AddNeighbor(neighbor);
                }
                else
                {
                    neighbor.AddNeighbor(start);
                    start.AddNeighbor(neighbor);
                }
            }
            Trapezoid above = new Trapezoid(seg.point1, seg.point2, toSplit[0].top, seg);
            Trapezoid below = new Trapezoid(seg.point1, seg.point2, seg, toSplit[0].bottom);
            above.AddNeighbor(start);
            above.AddNeighbor(end);
            below.AddNeighbor(start);
            below.AddNeighbor(end);
            start.AddNeighbor(above);
            start.AddNeighbor(below);
            end.AddNeighbor(above);
            end.AddNeighbor(below);
            // Add all trapezoids to output
            finalTrapezoids.Add(start);
            finalTrapezoids.Add(end);
            finalTrapezoids.Add(above);
            finalTrapezoids.Add(below);
            Debug.Log("Simple case, created trapezoids:\n" + start.show() + "\n" + end.show() + "\n" + above.show() + "\n" + below.show());
            return(finalTrapezoids);
        }

        /*
         * Complex case where the inserted segment intersects multiple trapezoids
         */
        // If the left endpoint of the segment does not yet exist, create a trapezoid between that point and the left point of the first old trapezoid
        if (seg.point1.x != toSplit[0].left.x)
        {
            // This trapezoid will neighbor both next upper and lower neighbors
            begin = new Trapezoid(toSplit[0].left, seg.point1, toSplit[0].top, toSplit[0].bottom);
            foreach (Trapezoid neighbor in toSplit[0].Neighbors)
            {
                // Take the neighbors of the old trapezoid and add them to new trapezoid, except if the neighbor has been intersected by the segment
                neighbor.DeleteNeighbor(toSplit[0]);
                if (neighbor.left.x > begin.left.x)
                {
                    continue;
                }
                neighbor.AddNeighbor(begin);
                begin.AddNeighbor(neighbor);
            }
            newTrapezoids.Add(begin);
            StartDegenerate = true;
        }
        // Split each intersected trapezoid in two, one trapezoid above the segment and one below (merging of trapezoids happens later)
        for (int i = 0; i < toSplit.Count; i++)
        {
            newUpper = new Trapezoid(toSplit[i].left, toSplit[i].right, toSplit[i].top, seg);
            newLower = new Trapezoid(toSplit[i].left, toSplit[i].right, seg, toSplit[i].bottom);
            Debug.Log("Considering trapezoid " + i + ". The oldLower is " + ((oldLower == null) ? "null" : oldLower.show()));
            // If the first trapezoid is split in three, don't start the new trapezoids at the left point of trapezoid, but at segment
            if (StartDegenerate)
            {
                newUpper = new Trapezoid(seg.point1, toSplit[i].right, toSplit[i].top, seg);
                newLower = new Trapezoid(seg.point1, toSplit[i].right, seg, toSplit[i].bottom);
                begin.AddNeighbor(newUpper);
                begin.AddNeighbor(newLower);
                newUpper.AddNeighbor(begin);
                newLower.AddNeighbor(begin);
            }
            if (i == toSplit.Count - 1 && seg.point2.x != toSplit[toSplit.Count - 1].right.x)
            {
                // If the end is split in three, don't start new trapezoids at the right point, but at segment
                EndDegenerate = true;
                newUpper      = new Trapezoid(toSplit[i].left, seg.point2, toSplit[i].top, seg);
                newLower      = new Trapezoid(toSplit[i].left, seg.point2, seg, toSplit[i].bottom);
            }
            if (oldUpper != null)
            {
                newUpper.AddNeighbor(oldUpper);
                oldUpper.AddNeighbor(newUpper);
            }
            if (oldLower != null)
            {
                newLower.AddNeighbor(oldLower);
                oldLower.AddNeighbor(newLower);
            }
            // Every existing neighbor of the old trapezoid is either replaced (also intersected) or is a neighbor to the new top or lower
            foreach (Trapezoid neighbor in toSplit[i].Neighbors)
            {
                // Delete the trapezoid we are replacing from the neighbor list of all neighbors
                neighbor.DeleteNeighbor(toSplit[i]);
                // Don't add the neighbor if it has or will be replaced
                if (toSplit.Contains(neighbor))
                {
                    continue;
                }
                // Test if the neighbor belongs to upper or lower
                //  If the neighbor is left, its right point has to be above segment (to be upper neighbor)
                //  If the neighbor is right, its left point has to be above segment (to be upper neighbor)
                //      Neighbor is left if its right point is left of the right point of this trapezoid (neighboring trapezoids cannot have right points at same x)
                if (neighbor.right.x < toSplit[i].right.x)
                {
                    // Neighbor is left (Do not add any left neighbors on a degenerate start, as this is wrong)
                    if (StartDegenerate)
                    {
                        continue;
                    }
                    // If the right point is on the segment, then there is a non degenerate start, and the neighbor could be the upper neighbor
                    //  Check if it is upper neighbor by checking if the right point of the neighbors bottom line on the segment
                    //   or the existing segment that contains seg.point2 is the top or bottom of the inital trapezoid
                    //      This rule is determined by schrift case 2
                    //  If it is lower neighbor, then seg.Above is also false and neighbor will be asigned in the else-clause
                    if (neighbor.right == seg.point1 && (neighbor.bottom.point2 == seg.point1 || toSplit[i].bottom.point1 == seg.point1))
                    {
                        newUpper.AddNeighbor(neighbor);
                        neighbor.AddNeighbor(newUpper);
                    }
                    else if (seg.Above(neighbor.right))
                    {
                        // Neighbor is upper neighbor
                        newUpper.AddNeighbor(neighbor);
                        neighbor.AddNeighbor(newUpper);
                    }
                    else
                    {
                        // Neighbor is lower neighbor
                        newLower.AddNeighbor(neighbor);
                        neighbor.AddNeighbor(newLower);
                    }
                }
                else
                {
                    // Neighbor is right (Do not add any right neighbors on a degenerate end, as the degenerate trapezoid will still be placed)
                    if (EndDegenerate)
                    {
                        continue;
                    }
                    // If the left point is on the segment, then there is a non degenerate end, and the neighbor could be the upper neighbor
                    //  Check if it is upper neighbor by checking if the left point of the neighbors bottom line is on the segment
                    //   or the existing segment that contains seg.point2 is the top or bottom of the inital trapezoid
                    //      This rule is determined by schrift case 2
                    //  If it is lower neighbor, then seg.Above is also false and neighbor will be asigned in the else-clause
                    if (neighbor.left == seg.point2 && (neighbor.bottom.point1 == seg.point2 || toSplit[i].bottom.point2 == seg.point2))
                    {
                        newUpper.AddNeighbor(neighbor);
                        neighbor.AddNeighbor(newUpper);
                    }
                    else if (seg.Above(neighbor.left))
                    {
                        // Neighbor is upper neighbor
                        newUpper.AddNeighbor(neighbor);
                        neighbor.AddNeighbor(newUpper);
                    }
                    else
                    {
                        // Neighbor is lower neighbor
                        newLower.AddNeighbor(neighbor);
                        neighbor.AddNeighbor(newLower);
                    }
                }
            }
            Debug.Log("CreatingTraps:\n" + newUpper.show() + " AND\n" + newLower.show());
            newTrapezoids.Add(newUpper);
            newTrapezoids.Add(newLower);
            // Point the old trapezoid to the replacements
            toSplit[i].LowerReplacement = newLower;
            toSplit[i].UpperReplacement = newUpper;
            // Set new trapezoids to old for next iteration
            oldUpper = newUpper;
            oldLower = newLower;
            // After one iteration we have passed the start
            StartDegenerate = false;
        }
        // If the right endpoint of the segment does not yet exist, create a trapezoid between that point and the right point of the last old trapezoid
        if (seg.point2.x != toSplit[toSplit.Count - 1].right.x)
        {
            // This trapezoid will neigbor both previous lower and upper trapezoids (It's called newupper because that name is available now)
            newUpper = new Trapezoid(seg.point2, toSplit[toSplit.Count - 1].right, toSplit[toSplit.Count - 1].top, toSplit[toSplit.Count - 1].bottom);
            newUpper.AddNeighbor(oldUpper);
            oldUpper.AddNeighbor(newUpper);
            newUpper.AddNeighbor(oldLower);
            oldLower.AddNeighbor(newUpper);
            // This trapezoid will also neighbor all right neighbors of the old trapezoid
            foreach (Trapezoid neighbor in toSplit[toSplit.Count - 1].Neighbors)
            {
                // Take the neighbors of the old trapezoid and add them to new trapezoid, except if the neighbor has been intersected by the segment
                neighbor.DeleteNeighbor(toSplit[toSplit.Count - 1]);
                if (neighbor.right.x < newUpper.right.x)
                {
                    continue;
                }
                neighbor.AddNeighbor(newUpper);
                newUpper.AddNeighbor(neighbor);
            }
            newTrapezoids.Add(newUpper);
            Debug.Log("Created degenerate end trapezoid: " + newUpper.show());
        }

        /* Merge trapezoids
         * If the trapezoid has the segment as top, but the right point is above the segment, this trapezoid should be merged with its neighbor
         * If the trapezoid has the segment as bottom, but the right point is below the segment, this trapezoid should be merged with its neighbor
         *  Note, if the right point is on the segment, we have reached the end of the segment and nothing should be done
         */
        for (int i = 0; i < newTrapezoids.Count; i++)
        {
            if (newTrapezoids[i].top == seg)
            {
                // Trapezoid is lower trapezoid
                if (seg.Above(newTrapezoids[i].right)) // Will only be true if point is above segment
                {
                    // Find neighbor and merge
                    // Note that there can only be 1 neighbor to the right of this trapezoid
                    bool foundNeighbor = false;
                    foreach (Trapezoid t in newTrapezoids[i].Neighbors)
                    {
                        if (t.right.x >= newTrapezoids[i].right.x)
                        {
                            foundNeighbor = true;
                            // Merge the two trapezoids by modifying 't' and replacing all neighbors with 't'
                            //  Note: newTrapezoids[i].top = t.top = seg and newTrapezoids[i].bottom = t.bottom
                            //  Note: t.right should stay t.right, thus only t.left has to be updated
                            t.left = newTrapezoids[i].left;
                            // Add all neighbors of newTrapezoids[i] to t, also update the neighbors
                            foreach (Trapezoid neighbor in newTrapezoids[i].Neighbors)
                            {
                                neighbor.DeleteNeighbor(newTrapezoids[i]);
                                if (neighbor.Equals(t))
                                {
                                    continue;
                                }
                                neighbor.AddNeighbor(t);
                                t.AddNeighbor(neighbor);
                            }
                            // Change replacement pointer from newTrapezoid[i] to t
                            newTrapezoids[i].LowerReplacement = t;
                            // Note: t will be tested in a next iteration to see if it has to be merged again or if it can be reported
                        }
                    }
                    if (!foundNeighbor)
                    {
                        Debug.LogError("A lower trapezoid should be merged but no suitable neighbor can be found\n" + newTrapezoids[i].show());
                        string neighbors = "";
                        foreach (Trapezoid n in newTrapezoids[i].Neighbors)
                        {
                            neighbors = neighbors + "\n" + n.show();
                        }
                        Debug.LogError("Neighbors: " + neighbors);
                    }
                }
                else
                {
                    // There is no problem, just add the trapezoid to the output
                    finalTrapezoids.Add(newTrapezoids[i]);
                }
            }
            else if (newTrapezoids[i].bottom == seg)
            {
                // Trapezoid is upper trapezoid
                if (!seg.Above(newTrapezoids[i].right) && (seg.point2 != newTrapezoids[i].right)) // Wil also be true if point is on segment, test for that too
                {
                    // Find neighbor and merge
                    // Note that there can only be 1 neighbor to the right of this trapezoid
                    bool foundNeighbor = false;
                    foreach (Trapezoid t in newTrapezoids[i].Neighbors)
                    {
                        if (t.right.x >= newTrapezoids[i].right.x)
                        {
                            foundNeighbor = true;
                            // Merge the two trapezoids by modifying 't' and replacing all neighbors with 't'
                            //  Note: newTrapezoids[i].top = t.top and newTrapezoids[i].bottom = t.bottom = seg
                            //  Note: t.right should stay t.right, thus only t.left has to be updated
                            t.left = newTrapezoids[i].left;
                            // Add all neighbors of newTrapezoids[i] to t, also update the neighbors
                            foreach (Trapezoid neighbor in newTrapezoids[i].Neighbors)
                            {
                                neighbor.DeleteNeighbor(newTrapezoids[i]);
                                if (neighbor.Equals(t))
                                {
                                    continue;
                                }
                                neighbor.AddNeighbor(t);
                                t.AddNeighbor(neighbor);
                            }
                            // Change replacement pointer from newTrapezoid[i] to t
                            newTrapezoids[i].UpperReplacement = t;
                            // Note: t will be tested in a next iteration to see if it has to be merged again or if it can be reported
                        }
                    }
                    if (!foundNeighbor)
                    {
                        Debug.LogError("An upper trapezoid should be merged but no suitable neighbor can be found\n" + newTrapezoids[i].show());
                        string neighbors = "";
                        foreach (Trapezoid n in newTrapezoids[i].Neighbors)
                        {
                            neighbors = neighbors + "\n" + n.show();
                        }
                        Debug.LogError("Neighbors: " + neighbors);
                    }
                }
                else
                {
                    // No problem, add trapezoid to output
                    finalTrapezoids.Add(newTrapezoids[i]);
                }
            }
            else
            {
                // These are the outer trapezoids next to the segment, these will never have to be merged, so add them to the output
                finalTrapezoids.Add(newTrapezoids[i]);
            }
        }
        return(finalTrapezoids);
    }
Exemplo n.º 3
0
    /*
     * Return all trapezoids that are intersecting a given segment
     *  Assumes that the segment does not cross any segments (VD assumption)
     */
    private List <Trapezoid> FindIntersecting(LineSegment seg)
    {
        // Find all trapezoids intersecting the segment
        List <Trapezoid> Intersecting     = new List <Trapezoid>();
        Trapezoid        CurrentTrapezoid = this.Search(seg.point1, seg);

        Intersecting.Add(CurrentTrapezoid);
        while (seg.point2.x > CurrentTrapezoid.right.x && CurrentTrapezoid.Neighbors.Count > 0)
        {
            // Check neighbors to find if there are one or two neighbors, will return a list with one or two entries
            List <Trapezoid> RightNeighbors = CurrentTrapezoid.Neighbors.FindAll(
                delegate(Trapezoid trap)
            {
                return(trap.left.x >= CurrentTrapezoid.right.x);
            });
            // If there is only one neighbor, it is the new trapezoid, else check which one is
            if (RightNeighbors.Count == 0)
            {
                Debug.LogWarning("Detected trapezoid that is not the right most trapezoid, but has no right neighbors:\n" + CurrentTrapezoid.show() + "\nWith segment: " + seg.show());
                string neighbors = "";
                foreach (Trapezoid n in CurrentTrapezoid.Neighbors)
                {
                    neighbors = neighbors + "\n" + n.show();
                }
                Debug.LogWarning(neighbors);
                break;
            }
            else if (RightNeighbors.Count == 1)
            {
                CurrentTrapezoid = RightNeighbors[0];
            }
            else if (RightNeighbors.Count > 1)
            {
                if (RightNeighbors.Count != 2)
                {
                    string neighbors = "";
                    foreach (Trapezoid n in CurrentTrapezoid.Neighbors)
                    {
                        neighbors = neighbors + "\n" + n.show();
                    }
                    Debug.LogError("A trapezoid cannot have more than 2 right neighbors, says it has: " + RightNeighbors.Count + "\n" + CurrentTrapezoid.show() + "\nAll Neighbors:" + neighbors);
                }
                // Report upper or lower, and find which one it is
                // If the right point of the current trapezoid is above the segment, then the next trapezoid is the lower neighbor, else the above neighbor
                if (seg.Above(CurrentTrapezoid.right))
                {
                    // If the left point of the bottom segment is equal to the right point of current, then it is upper neighbor. Except if there is only one neighbor
                    if (RightNeighbors[0].bottom.point1 == CurrentTrapezoid.right)
                    {
                        // Point is above the segment and second neighbor is lower neighbor
                        CurrentTrapezoid = RightNeighbors[1];
                    }
                    else
                    {
                        // Point is above segment and first neighbor is lower neighbor
                        CurrentTrapezoid = RightNeighbors[0];
                    }
                }
                else
                {
                    // If the left point of top segment is equal to the right point of current, then it is lower neighbor. Except if there is only one neighbor
                    if (RightNeighbors[0].top.point1 == CurrentTrapezoid.right)
                    {
                        // Point is below segment and second neighbor is upper neighbor
                        CurrentTrapezoid = RightNeighbors[1];
                    }
                    else
                    {
                        // Point is below segment and first neighbor is upper neighbor
                        CurrentTrapezoid = RightNeighbors[0];
                    }
                }
            }
            Intersecting.Add(CurrentTrapezoid);
            if (Intersecting.Count > 100)
            {
                Debug.LogError("Breaking out of suspected infinite loop at findIntersecting");
                break;
            }
        }
        string ts = "";

        foreach (Trapezoid t in Intersecting)
        {
            ts = ts + "\n" + t.show();
        }
        Debug.Log("Amount of found intersecting trapezoids: " + Intersecting.Count + ts);
        return(Intersecting);
    }