Exemplo n.º 1
0
            public WeilerAtherton(Polygon2D a_subject, Polygon2D a_clip)
            {
                // initialize variables
                Subject            = a_subject;
                Clip               = a_clip;
                SubjectList        = new LinkedList <WAPoint>();
                ClipList           = new LinkedList <WAPoint>();
                SubjectNode        = new Dictionary <WAPoint, LinkedListNode <WAPoint> >();
                ClipNode           = new Dictionary <WAPoint, LinkedListNode <WAPoint> >();
                EntryIntersections = new HashSet <WAPoint>();

                // store intersections for clipping line segment
                // saves recomputation of intersections and entry-exit categorization
                var intersectSegmentsClip = new Dictionary <LineSegment, List <WAPoint> >();

                foreach (var seg in a_clip.Segments)
                {
                    intersectSegmentsClip.Add(seg, new List <WAPoint>());
                }

                // find all intersections and create subject list
                foreach (var seg1 in a_subject.Segments)
                {
                    // retrieve intersection list
                    var vertices = new List <WAPoint>();

                    var point = new WAPoint(seg1.Point1, WAList.Vertex);
                    var node  = SubjectList.AddLast(point);
                    SubjectNode.Add(point, node);

                    foreach (var seg2 in a_clip.Segments)
                    {
                        var intersect = seg1.Intersect(seg2);
                        if (intersect.HasValue)
                        {
                            // store intersection point
                            point = new WAPoint(intersect.Value, WAList.Ignore);
                            vertices.Add(point);
                            intersectSegmentsClip[seg2].Add(point);
                        }
                    }

                    // sort intersections on distance to start vertex
                    vertices.Sort(new ClosestToPointComparer(seg1.Point1));

                    foreach (var vertex in vertices)
                    {
                        node = SubjectList.AddLast(vertex);
                        SubjectNode.Add(vertex, node);
                    }
                }


                // remove duplicates
                for (var node = SubjectList.First; node != null; node = node.Next)
                {
                    var next = node.Next ?? SubjectList.First;
                    while (node != next && MathUtil.EqualsEps(node.Value.Pos, next.Value.Pos))
                    {
                        if (node.Value.Type == WAList.Vertex)
                        {
                            node.Value.Type = WAList.Ignore;
                            SubjectList.Remove(node);
                            EntryIntersections.Remove(node.Value);
                            node = next;
                        }
                        else
                        {
                            next.Value.Type = WAList.Ignore;
                            SubjectList.Remove(next);
                            EntryIntersections.Remove(next.Value);
                        }
                        next = node.Next ?? SubjectList.First;
                    }
                }

                // set entry/exit types correctly
                for (var node = SubjectList.First; node != null; node = node.Next)
                {
                    var prev   = node.Previous ?? SubjectList.Last;
                    var vertex = node.Value;

                    var inside1 = Clip.ContainsInside(prev.Value.Pos);
                    var inside2 = Clip.ContainsInside(vertex.Pos);

                    if (!inside1 && inside2)
                    {
                        vertex.Type = WAList.Entry;
                    }
                    else if (inside1 && !inside2)
                    {
                        prev.Value.Type = WAList.Exit;
                        EntryIntersections.Remove(vertex);
                    }

                    if (vertex.Type == WAList.Entry)
                    {
                        EntryIntersections.Add(vertex);
                    }
                }

                // create clip list and intersections
                foreach (var seg in a_clip.Segments)
                {
                    var vertices = intersectSegmentsClip[seg];

                    // sort intersections on distance to start vertex
                    intersectSegmentsClip[seg].Sort(new ClosestToPointComparer(seg.Point1));

                    vertices.Insert(0, new WAPoint(seg.Point1, WAList.Vertex));

                    // loop over intersections
                    foreach (var vertex in vertices)
                    {
                        if (vertex.Type == WAList.Ignore)
                        {
                            continue;
                        }

                        // add intersection to clipping list
                        var node = ClipList.AddLast(vertex);
                        ClipNode.Add(vertex, node);
                    }
                }
            }
Exemplo n.º 2
0
        /// <summary>
        /// Creates a cutout given the relevant weiler atherton object containing subject and clipping lists
        /// Can result in multiple polygons.
        /// Assumes the cutting polygon is not entirely inside subject polygon!
        /// </summary>
        /// <param name="WA"></param>
        /// <returns></returns>
        private static MultiPolygon2D WeilerAthertonCutOut(WeilerAtherton WA)
        {
            var multiPoly = new MultiPolygon2D();

            // check if polygons have intersections
            if (WA.EntryIntersections.Count == 0)
            {
                if (!WA.Subject.Vertices.ToList().Exists(p => WA.Clip.ContainsInside(p)))
                {
                    multiPoly.AddPolygon(new Polygon2D(WA.Subject.Vertices));
                }
            }

            while (WA.EntryIntersections.Count > 0)
            {
                var vertices = new List <Vector2>();
                var visited  = new HashSet <LinkedListNode <WAPoint> >();

                // remove an entry intersection point
                var startPoint = WA.EntryIntersections.LastOrDefault();
                WA.EntryIntersections.Remove(startPoint);

                LinkedListNode <WAPoint> node;
                try
                {
                    node = WA.ClipNode[startPoint];
                }
                catch (KeyNotFoundException e)
                {
                    Debug.Log("entry point not found: " + e);
                    continue;
                }

                WAPoint last = null;

                while (!visited.Contains(node))
                {
                    // remove entry intersection from starting list
                    WA.EntryIntersections.Remove(node.Value);

                    // traverse clip polygon in counter-clockwise order until exit vertex found
                    while (node.Value.Type != WAList.Exit && !visited.Contains(node))
                    {
                        // check for duplicates
                        if (last == null || !MathUtil.EqualsEps(node.Value.Pos, last.Pos))
                        {
                            vertices.Add(node.Value.Pos);
                            visited.Add(node);
                        }
                        last = node.Value;
                        node = node.Previous ?? WA.ClipList.Last;
                    }

                    // might contains entry but no exit vertex
                    // should not occur, return no polygon
                    if (visited.Contains(node))
                    {
                        vertices.Clear(); break;
                    }

                    try
                    {
                        node = WA.SubjectNode[node.Value];
                    }
                    catch (KeyNotFoundException e)
                    {
                        Debug.Log("exit point not found: " + e.StackTrace);
                        break;
                    }

                    // traverse subject polygon in clockwise order until new entr vertex found
                    while (node.Value.Type != WAList.Entry && !visited.Contains(node))
                    {
                        if (last == null || !MathUtil.EqualsEps(node.Value.Pos, last.Pos))
                        {
                            vertices.Add(node.Value.Pos);
                            visited.Add(node);
                        }
                        last = node.Value;
                        node = node.Next ?? WA.SubjectList.First;
                    }

                    if (visited.Contains(node))
                    {
                        break;
                    }

                    try
                    {
                        node = WA.ClipNode[node.Value];
                    }
                    catch (KeyNotFoundException e)
                    {
                        Debug.Log("entry point not found: " + e);
                        break;
                    }
                }

                // add new polygon from the vertices
                if (vertices.Count > 2)
                {
                    multiPoly.AddPolygon(new Polygon2D(vertices));
                }
            }

            return(multiPoly);
        }
Exemplo n.º 3
0
            public WeilerAtherton(Polygon2D a_subject, Polygon2D a_clip)
            {
                // initialize variables
                Subject     = a_subject;
                Clip        = a_clip;
                SubjectList = new LinkedList <WAPoint>(Subject.Vertices.Select(v => new WAPoint(v, WAList.Vertex)));
                ClipList    = new LinkedList <WAPoint>(Clip.Vertices.Select(v => new WAPoint(v, WAList.Vertex)));
                SubjectNode = new Dictionary <WAPoint, LinkedListNode <WAPoint> >();
                ClipNode    = new Dictionary <WAPoint, LinkedListNode <WAPoint> >();
                Entry       = new HashSet <WAPoint>();
                Exit        = new HashSet <WAPoint>();

                // find all intersections and create subject and clip list
                for (var node1 = SubjectList.First; node1 != null; node1 = node1.Next)
                {
                    // calculate subject segment
                    var next1 = node1.Next ?? SubjectList.First;
                    var seg1  = new LineSegment(node1.Value.Pos, next1.Value.Pos);

                    // obtain intersection lists
                    var intersections  = new List <Vector2>();
                    var intersectNodes = new Dictionary <Vector2, LinkedListNode <WAPoint> >();
                    for (var node2 = ClipList.Last; node2 != null; node2 = node2.Previous)
                    {
                        var prev2 = node2.Previous ?? ClipList.Last;
                        var seg2  = new LineSegment(node2.Value.Pos, prev2.Value.Pos);

                        var intersect = seg1.Intersect(seg2);
                        if (intersect.HasValue && !intersectNodes.ContainsKey(intersect.Value))
                        {
                            // store intersection point
                            intersectNodes.Add(intersect.Value, node2);
                            intersections.Add(intersect.Value);
                        }
                    }

                    // sort intersections on distance to start vertex
                    intersections.Sort(new ClosestToPointComparer(seg1.Point1));

                    // insert intersections into subject/clip lists
                    foreach (var vertex in intersections)
                    {
                        var point = new WAPoint(vertex, WAList.Ignore);

                        var newNode1 = SubjectList.AddAfter(node1, point);
                        SubjectNode.Add(point, newNode1);

                        var newNode2 = ClipList.AddBefore(intersectNodes[vertex], point);
                        ClipNode.Add(point, newNode2);

                        // increment node1 since we added a vertex
                        node1 = newNode1;
                    }
                }

                // remove duplicates of subject
                for (var node = SubjectList.First; node != null;)
                {
                    var next = node.Next ?? SubjectList.First;
                    while (MathUtil.EqualsEps(node.Value.Pos, next.Value.Pos, MathUtil.EPS * 10))
                    {
                        if (next.Value.Type != WAList.Vertex)
                        {
                            if (ClipNode.ContainsKey(node.Value))
                            {
                                ClipList.Remove(ClipNode[node.Value]);
                            }
                            SubjectList.Remove(node);
                            node = next;
                        }
                        else
                        {
                            SubjectList.Remove(next);
                        }
                        if (node == null)
                        {
                            break;
                        }
                        next = node.Next ?? SubjectList.First;
                    }
                    if (node != null)
                    {
                        node = node.Next;
                    }
                }

                // remove duplicates of clip
                for (var node = ClipList.Last; node != null;)
                {
                    var prev = node.Previous ?? ClipList.Last;
                    while (MathUtil.EqualsEps(node.Value.Pos, prev.Value.Pos, MathUtil.EPS * 10))
                    {
                        if (prev.Value.Type != WAList.Vertex)
                        {
                            if (SubjectNode.ContainsKey(node.Value))
                            {
                                SubjectList.Remove(SubjectNode[node.Value]);
                            }
                            ClipList.Remove(node);
                            node = prev;
                        }
                        else
                        {
                            ClipList.Remove(prev);
                        }
                        if (node == null)
                        {
                            break;
                        }
                        prev = node.Previous ?? ClipList.Last;
                    }
                    if (node != null)
                    {
                        node = node.Previous;
                    }
                }

                // set entry/exit types correctly
                for (var node = SubjectList.First; node != null; node = node.Next)
                {
                    if (node.Value.Type == WAList.Vertex)
                    {
                        continue;
                    }

                    var prev = node.Previous ?? SubjectList.Last;
                    var next = node.Next ?? SubjectList.First;

                    var inside1 = Clip.ContainsInside(prev.Value.Pos) || Clip.OnBoundary(prev.Value.Pos);
                    var inside2 = Clip.ContainsInside(next.Value.Pos) || Clip.OnBoundary(next.Value.Pos);

                    if (!inside1 && inside2)
                    {
                        node.Value.Type = WAList.Entry;
                        Entry.Add(node.Value);
                    }
                    else if (inside1 && !inside2)
                    {
                        node.Value.Type = WAList.Exit;
                        Exit.Add(node.Value);
                    }
                }
            }