// This calculates the relative angle between two sides
    private float CalculateRelativeAngle(Sidedef a, Sidedef b)
    {
        // Determine angles
        float ana = a.Line.Angle; if (a.Line.End == basevertex)
        {
            ana += Angle2D.PI;
        }
        float anb = b.Line.Angle; if (b.Line.End == basevertex)
        {
            anb += Angle2D.PI;
        }

        // Take the difference from angles
        float n = Angle2D.Difference(ana, anb);

        // Get line end vertices a and b that are not connected to basevertex
        Vector2D va = (a.Line.Start == basevertex ? a.Line.End.Position : a.Line.Start.Position);
        Vector2D vb = (b.Line.Start == basevertex ? b.Line.End.Position : b.Line.Start.Position);

        // Determine rotation direction
        bool dir = baseside.IsFront;

        if (baseside.Line.End == basevertex)
        {
            dir = !dir;
        }

        // Check to which side the angle goes and adjust angle as needed
        float s = Line2D.GetSideOfLine(va, vb, basevertex.Position);

        if ((s < 0) && dir)
        {
            n = Angle2D.PI2 - n;
        }
        if ((s > 0) && !dir)
        {
            n = Angle2D.PI2 - n;
        }

        // Return result
        return(n);
    }
Example #2
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> n2;

        EarClipVertex[] t;
        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
        LinkedListNode <EarClipVertex> 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
            EarClipVertex 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();
            EarClipVertex v1 = t[0];
            EarClipVertex v2 = t[2];

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

            // Test first neighbour
            EarClipVertex[] t1 = GetTriangle(v1);
            //bool t1a = true;	//TriangleHasArea(t1);
            if (/*t1a && */ 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
            EarClipVertex[] t2 = GetTriangle(v2);
            //bool t2a = true;	//TriangleHasArea(t2);
            if (/*t2a && */ 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 && (/*!t1a || */ CheckValidEar(t1, reflexes)))
            {
                v1.AddEarTip(eartips);
            }
            else
            {
                v1.RemoveEarTip();
            }
            if (!v2.IsReflex && (/*!t2a || */ 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);
    }