Пример #1
0
        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);
        }
Пример #2
0
        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;
        }