static bool LocalConstraints(Segment segment, List <Segment> segments, Quadtree quadtree, DebugData debugData) { int priority = 0; Func <bool> action = null; float t0 = -1; var matches = quadtree.Retrieve(segment); for (int i = 0, j = 0, k = matches.Count - 1; j <= k; i = j += 1) { Segment other = (Segment)matches[i].reference; if (segment == other) { continue; } // intersection check if (priority <= 4) { Vector2 intersection; float t1; if (segment.Intersect(other, out intersection, out t1)) { if (t0 == -1 || t1 < t0) { t0 = t1; priority = 4; action = () => { float dirDiff = Mathf.Abs(other.Direction - segment.Direction) % 180.0f; float minDirectionDiff = Mathf.Min(dirDiff, Mathf.Abs(dirDiff - 180.0f)); if (minDirectionDiff < Config.minIntersectionDeviation) { return(false); } IntersectSegments(intersection, other, segment, segments, quadtree); if (debugData != null) { debugData.intersections.Add(intersection); } return(true); }; } } } // snap to crossing within radius check if (priority <= 3) { if ((segment.End - other.End).magnitude <= Config.snapDistance) { priority = 3; action = () => { List <Segment> links; segment.End = other.End; segment.Severed = true; foreach (var destination in segment.Destinations) { int index = destination.Sources.IndexOf(other); if (index != -1) { continue; } destination.Sources.Add(other); } links = other.StartIsBackwards() ? other.Forwards : other.Branches; if (links.Any((Segment link) => { return(((link.Start == segment.End) && (link.End == segment.Start)) || ((link.Start == segment.Start) && (link.End == segment.End))); })) { return(false); } links.ForEach((Segment link) => { link.LinksForEndContaining(other).Add(segment); segment.Forwards.Add(link); }); links.Add(segment); segment.Forwards.Add(other); if (debugData != null) { debugData.snaps.Add(other.End); } return(true); }; } } // intersection within radius check if (priority <= 2) { var e0 = (segment.End - other.Start); var e1 = (other.End - other.Start); Vector2 proj = Vector3.Project(e0, e1); Vector2 pointOnLine = (other.Start + proj); float distance2 = Vector2.SqrMagnitude(segment.End - pointOnLine); float lineProj2 = Mathf.Sign(Vector3.Dot(e0, e1)) * Vector2.SqrMagnitude(proj); float length2 = Vector2.SqrMagnitude(e1); if (distance2 < Config.snapDistance * Config.snapDistance && lineProj2 >= 0 && lineProj2 <= length2) { Vector2 point; point = pointOnLine; priority = 2; action = () => { float dirDiff = Math.Abs(other.Direction - segment.Direction) % 180.0f; float minDirDiff = Math.Min(dirDiff, Math.Abs(dirDiff - 180.0f)); if (minDirDiff < Config.minIntersectionDeviation) { return(false); } IntersectSegments(point, other, segment, segments, quadtree); if (debugData != null) { debugData.intersectionsRadius.Add(point); } return(true); }; } } } if (action != null) { return(action()); } return(true); }
static void IntersectSegments(Vector2 intersection, Segment segment0, Segment segment1, List <Segment> segments, Quadtree quadtree) { bool startIsBackwards = segment0.StartIsBackwards(); Segment splitPart = new Segment(segment0); splitPart.Destinations.Add(segment0); AddSegment(splitPart, segments, quadtree); splitPart.End = intersection; segment0.Start = intersection; foreach (var source0 in segment0.Sources) { int index = source0.Destinations.IndexOf(segment0); if (index == -1) { continue; } source0.Destinations[index] = splitPart; } splitPart.Sources = new List <Segment>(segment0.Sources); segment0.Sources.Clear(); segment0.Sources.Add(splitPart); segment0.Sources.Add(segment1); splitPart.Branches = new List <Segment>(segment0.Branches); splitPart.Forwards = new List <Segment>(segment0.Forwards); Segment firstSplit, secondSplit; List <Segment> linksToFix; if (startIsBackwards) { firstSplit = splitPart; secondSplit = segment0; linksToFix = splitPart.Branches; } else { firstSplit = segment0; secondSplit = splitPart; linksToFix = splitPart.Forwards; } foreach (var link in linksToFix) { int index = link.Branches.IndexOf(segment0); if (index != -1) { link.Branches[index] = splitPart; } else { index = link.Forwards.IndexOf(segment0); link.Forwards[index] = splitPart; } } firstSplit.Forwards = new List <Segment>(); firstSplit.Forwards.Add(segment1); firstSplit.Forwards.Add(secondSplit); secondSplit.Branches = new List <Segment>(); secondSplit.Branches.Add(segment1); secondSplit.Branches.Add(firstSplit); segment1.Forwards.Add(firstSplit); segment1.Forwards.Add(secondSplit); segment1.End = intersection; segment1.Destinations.Clear(); segment1.Severed = true; }