Ejemplo n.º 1
0
        // This clips a polygon and returns the triangles
        // The polygon may not have any holes or islands
        // See: http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf
        private int DoEarClip(EarClipPolygon poly, List <Vector2D> verticeslist, List <Sidedef> sidedefslist)
        {
            LinkedList <EarClipVertex>     verts = new LinkedList <EarClipVertex>();
            List <EarClipVertex>           convexes = new List <EarClipVertex>(poly.Count);
            LinkedList <EarClipVertex>     reflexes = new LinkedList <EarClipVertex>();
            LinkedList <EarClipVertex>     eartips = new LinkedList <EarClipVertex>();
            LinkedListNode <EarClipVertex> n1, n2;
            EarClipVertex v, v1, v2;

            EarClipVertex[] t, t1, t2;
            int             countvertices = 0;

            // Go for all vertices to fill list
            foreach (EarClipVertex vec in poly)
            {
                vec.SetVertsLink(verts.AddLast(vec));
            }

            // Remove any zero-length lines, these will give problems
            n1 = verts.First;
            do
            {
                // Continue until adjacent zero-length lines are removed
                n2 = n1.Next ?? verts.First;
                Vector2D d = n1.Value.Position - n2.Value.Position;
                while ((Math.Abs(d.x) < 0.00001f) && (Math.Abs(d.y) < 0.00001f))
                {
                    n2.Value.Remove();
                    n2 = n1.Next ?? verts.First;
                    if (n2 != null)
                    {
                        d = n1.Value.Position - n2.Value.Position;
                    }
                    else
                    {
                        break;
                    }
                }

                // Next!
                n1 = n2;
            }while(n1 != verts.First);

            // Optimization: Vertices which have lines with the
            // same angle are useless. Remove them!
            n1 = verts.First;
            while (n1 != null)
            {
                // Get the next vertex
                n2 = n1.Next;

                // Get triangle for v
                t = GetTriangle(n1.Value);

                // Check if both lines have the same angle
                Line2D a = new Line2D(t[0].Position, t[1].Position);
                Line2D b = new Line2D(t[1].Position, t[2].Position);
                if (Math.Abs(Angle2D.Difference(a.GetAngle(), b.GetAngle())) < 0.00001f)
                {
                    // Same angles, remove vertex
                    n1.Value.Remove();
                }

                // Next!
                n1 = n2;
            }

            // Go for all vertices to determine reflex or convex
            foreach (EarClipVertex vv in verts)
            {
                // Add to reflex or convex list
                if (IsReflex(GetTriangle(vv)))
                {
                    vv.AddReflex(reflexes);
                }
                else
                {
                    convexes.Add(vv);
                }
            }

            // Go for all convex vertices to see if they are ear tips
            foreach (EarClipVertex cv in convexes)
            {
                // Add when this is a valid ear
                t = GetTriangle(cv);
                if (CheckValidEar(t, reflexes))
                {
                    cv.AddEarTip(eartips);
                }
            }

                        #if DEBUG
            if (OnShowPolygon != null)
            {
                OnShowPolygon(verts);
            }
                        #endif

            // Process ears until done
            while ((eartips.Count > 0) && (verts.Count > 2))
            {
                // Get next ear
                v = eartips.First.Value;
                t = GetTriangle(v);

                // Only save this triangle when it has an area
                if (TriangleHasArea(t))
                {
                    // Add ear as triangle
                    AddTriangleToList(t, verticeslist, sidedefslist, (verts.Count == 3));
                    countvertices += 3;
                }

                // Remove this ear from all lists
                v.Remove();
                v1 = t[0];
                v2 = t[2];

                                #if DEBUG
                if (TriangleHasArea(t))
                {
                    if (OnShowEarClip != null)
                    {
                        OnShowEarClip(t, verts);
                    }
                }
                                #endif

                // Test first neighbour
                t1 = GetTriangle(v1);
                if (IsReflex(t1))
                {
                    // List as reflex if not listed yet
                    if (!v1.IsReflex)
                    {
                        v1.AddReflex(reflexes);
                    }
                    v1.RemoveEarTip();
                }
                else
                {
                    // Remove from reflexes
                    v1.RemoveReflex();
                }

                // Test second neighbour
                t2 = GetTriangle(v2);
                if (IsReflex(t2))
                {
                    // List as reflex if not listed yet
                    if (!v2.IsReflex)
                    {
                        v2.AddReflex(reflexes);
                    }
                    v2.RemoveEarTip();
                }
                else
                {
                    // Remove from reflexes
                    v2.RemoveReflex();
                }

                // Check if any neightbour have become a valid or invalid ear
                if (!v1.IsReflex && (CheckValidEar(t1, reflexes)))
                {
                    v1.AddEarTip(eartips);
                }
                else
                {
                    v1.RemoveEarTip();
                }
                if (!v2.IsReflex && (CheckValidEar(t2, reflexes)))
                {
                    v2.AddEarTip(eartips);
                }
                else
                {
                    v2.RemoveEarTip();
                }
            }

                        #if DEBUG
            if (OnShowRemaining != null)
            {
                OnShowRemaining(verts);
            }
                        #endif

            // Dispose remaining vertices
            foreach (EarClipVertex ecv in verts)
            {
                ecv.Dispose();
            }

            // Return the number of vertices in the result
            return(countvertices);
        }