/* * 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()); } }
/* * 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); }
/* * 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); }