コード例 #1
0
        /// <summary>
        /// Given an edge AB, it searches for the triangle that has an edge with the same vertices in the same order.
        /// </summary>
        /// <remarks>
        /// Remember that the vertices of a triangle are sorted counter-clockwise.
        /// </remarks>
        /// <param name="edgeVertexA">The index of the first vertex of the edge.</param>
        /// <param name="edgeVertexB">The index of the second vertex of the edge.</param>
        /// <returns>The data of the triangle.</returns>
        public DelaunayTriangleEdge FindTriangleThatContainsEdge(int edgeVertexA, int edgeVertexB)
        {
            DelaunayTriangleEdge foundTriangle = new DelaunayTriangleEdge(NOT_FOUND, NOT_FOUND, edgeVertexA, edgeVertexB);

            for (int i = 0; i < TriangleCount; ++i)
            {
                for (int j = 0; j < 3; ++j)
                {
                    if (m_triangleVertices[i * 3 + j] == edgeVertexA && m_triangleVertices[i * 3 + (j + 1) % 3] == edgeVertexB)
                    {
                        foundTriangle.TriangleIndex = i;
                        foundTriangle.EdgeIndex     = j;
                        break;
                    }
                }
            }

            return(foundTriangle);
        }
コード例 #2
0
        /// <summary>
        /// Adds an edge to the triangulation in such a way that it keeps there even if it form triangles that do not fulfill the Delaunay constraint.
        /// If the edge already exists, nothing will be done.
        /// </summary>
        /// <remarks>
        /// The order in which the vertices of the edges are provided is important, as the edge may be part of a polygon whose vertices are sorted CCW.
        /// </remarks>
        /// <param name="endpointAIndex">The index of the first vertex of the edge, in the existing triangulation.</param>
        /// <param name="endpointBIndex">The index of the second vertex of the edge, in the existing triangulation.</param>
        private void AddConstrainedEdgeToTriangulation(int endpointAIndex, int endpointBIndex)
        {
            // Detects if the edge already exists
            if (m_triangleSet.FindTriangleThatContainsEdge(endpointAIndex, endpointBIndex).TriangleIndex != NOT_FOUND)
            {
                return;
            }

            Vector2 edgeEndpointA = m_triangleSet.GetPointByIndex(endpointAIndex);
            Vector2 edgeEndpointB = m_triangleSet.GetPointByIndex(endpointBIndex);

            // 5.3.1: Search for the triangle that contains the beginning of the new edge
            int triangleContainingA = m_triangleSet.FindTriangleThatContainsLineEndpoint(endpointAIndex, endpointBIndex);


            // 5.3.2: Get all the triangle edges intersected by the constrained edge
            List <DelaunayTriangleEdge> intersectedTriangleEdges = new List <DelaunayTriangleEdge>();

            m_triangleSet.GetIntersectingEdges(edgeEndpointA, edgeEndpointB, triangleContainingA, intersectedTriangleEdges);

            List <DelaunayTriangleEdge> newEdges = new List <DelaunayTriangleEdge>();

            while (intersectedTriangleEdges.Count > 0)
            {
                DelaunayTriangleEdge currentIntersectedTriangleEdge = intersectedTriangleEdges[intersectedTriangleEdges.Count - 1];
                intersectedTriangleEdges.RemoveAt(intersectedTriangleEdges.Count - 1);

                // 5.3.3: Form quadrilaterals and swap intersected edges
                // Deduces the data for both triangles
                currentIntersectedTriangleEdge = m_triangleSet.FindTriangleThatContainsEdge(currentIntersectedTriangleEdge.EdgeVertexA, currentIntersectedTriangleEdge.EdgeVertexB);
                DelaunayTriangle intersectedTriangle = m_triangleSet.GetTriangle(currentIntersectedTriangleEdge.TriangleIndex);
                DelaunayTriangle oppositeTriangle    = m_triangleSet.GetTriangle(intersectedTriangle.adjacent[currentIntersectedTriangleEdge.EdgeIndex]);
                Triangle2D       trianglePoints      = m_triangleSet.GetTrianglePoints(currentIntersectedTriangleEdge.TriangleIndex);

                // Gets the opposite vertex of adjacent triangle, knowing the fisrt vertex of the shared edge
                int oppositeVertex = NOT_FOUND;

                //List<int> debugP = intersectedTriangle.DebugP;
                //List<int> debugA = intersectedTriangle.DebugAdjacent;
                //List<int> debugP2 = oppositeTriangle.DebugP;
                //List<int> debugA2 = oppositeTriangle.DebugAdjacent;

                int oppositeSharedEdgeVertex = NOT_FOUND; // The first vertex in the shared edge of the opposite triangle

                for (int j = 0; j < 3; ++j)
                {
                    if (oppositeTriangle.p[j] == intersectedTriangle.p[(currentIntersectedTriangleEdge.EdgeIndex + 1) % 3]) // Comparing with the endpoint B of the edge, since the edge AB is BA in the adjacent triangle
                    {
                        oppositeVertex           = oppositeTriangle.p[(j + 2) % 3];
                        oppositeSharedEdgeVertex = j;
                        break;
                    }
                }

                Vector2 oppositePoint = m_triangleSet.GetPointByIndex(oppositeVertex);

                if (MathUtils.IsQuadrilateralConvex(trianglePoints.p0, trianglePoints.p1, trianglePoints.p2, oppositePoint))
                {
                    // Swap
                    int notInEdgeTriangleVertex = (currentIntersectedTriangleEdge.EdgeIndex + 2) % 3;
                    SwapEdges(currentIntersectedTriangleEdge.TriangleIndex, intersectedTriangle, notInEdgeTriangleVertex, oppositeTriangle, oppositeSharedEdgeVertex);

                    // Refreshes triangle data after swapping
                    intersectedTriangle = m_triangleSet.GetTriangle(currentIntersectedTriangleEdge.TriangleIndex);

                    //oppositeTriangle = m_triangles.GetTriangle(intersectedTriangle.adjacent[(currentIntersectedTriangleEdge.EdgeIndex + 2) % 3]);
                    //debugP = intersectedTriangle.DebugP;
                    //debugA = intersectedTriangle.DebugAdjacent;
                    //debugP2 = oppositeTriangle.DebugP;
                    //debugA2 = oppositeTriangle.DebugAdjacent;

                    // Check new diagonal against the intersecting edge
                    Vector2 intersectionPoint;
                    int     newTriangleSharedEdgeVertex = (currentIntersectedTriangleEdge.EdgeIndex + 2) % 3; // Read SwapEdges method to understand the +2
                    Vector2 newTriangleSharedEdgePointA = m_triangleSet.GetPointByIndex(intersectedTriangle.p[newTriangleSharedEdgeVertex]);
                    Vector2 newTriangleSharedEdgePointB = m_triangleSet.GetPointByIndex(intersectedTriangle.p[(newTriangleSharedEdgeVertex + 1) % 3]);

                    DelaunayTriangleEdge newEdge = new DelaunayTriangleEdge(NOT_FOUND, NOT_FOUND, intersectedTriangle.p[newTriangleSharedEdgeVertex], intersectedTriangle.p[(newTriangleSharedEdgeVertex + 1) % 3]);

                    if (newTriangleSharedEdgePointA != edgeEndpointB && newTriangleSharedEdgePointB != edgeEndpointB && // Watch out! It thinks the line intersects with the edge when an endpoint coincides with a triangle vertex, this problem is avoided thanks to this conditions
                        newTriangleSharedEdgePointA != edgeEndpointA && newTriangleSharedEdgePointB != edgeEndpointA &&
                        MathUtils.IntersectionBetweenLines(edgeEndpointA, edgeEndpointB, newTriangleSharedEdgePointA, newTriangleSharedEdgePointB, out intersectionPoint))
                    {
                        // New triangles edge still intersects with the constrained edge, so it is returned to the list
                        intersectedTriangleEdges.Insert(0, newEdge);
                    }
                    else
                    {
                        newEdges.Add(newEdge);
                    }
                }
                else
                {
                    // Back to the list
                    intersectedTriangleEdges.Insert(0, currentIntersectedTriangleEdge);
                }
            }

            // 5.3.4. Check Delaunay constraint and swap edges
            for (int i = 0; i < newEdges.Count; ++i)
            {
                // Checks if the constrained edge coincides with the new edge
                Vector2 triangleEdgePointA = m_triangleSet.GetPointByIndex(newEdges[i].EdgeVertexA);
                Vector2 triangleEdgePointB = m_triangleSet.GetPointByIndex(newEdges[i].EdgeVertexB);

                if ((triangleEdgePointA == edgeEndpointA && triangleEdgePointB == edgeEndpointB) ||
                    (triangleEdgePointB == edgeEndpointA && triangleEdgePointA == edgeEndpointB))
                {
                    continue;
                }

                // Deduces the data for both triangles
                DelaunayTriangleEdge currentEdge         = m_triangleSet.FindTriangleThatContainsEdge(newEdges[i].EdgeVertexA, newEdges[i].EdgeVertexB);
                DelaunayTriangle     currentEdgeTriangle = m_triangleSet.GetTriangle(currentEdge.TriangleIndex);
                int              triangleVertexNotShared = (currentEdge.EdgeIndex + 2) % 3;
                Vector2          trianglePointNotShared  = m_triangleSet.GetPointByIndex(currentEdgeTriangle.p[triangleVertexNotShared]);
                DelaunayTriangle oppositeTriangle        = m_triangleSet.GetTriangle(currentEdgeTriangle.adjacent[currentEdge.EdgeIndex]);
                Triangle2D       oppositeTrianglePoints  = m_triangleSet.GetTrianglePoints(currentEdgeTriangle.adjacent[currentEdge.EdgeIndex]);

                //List<int> debugP = currentEdgeTriangle.DebugP;
                //List<int> debugA = currentEdgeTriangle.DebugAdjacent;
                //List<int> debugP2 = oppositeTriangle.DebugP;
                //List<int> debugA2 = oppositeTriangle.DebugAdjacent;

                if (MathUtils.IsPointInsideCircumcircle(oppositeTrianglePoints.p0, oppositeTrianglePoints.p1, oppositeTrianglePoints.p2, trianglePointNotShared))
                {
                    // Finds the edge of the opposite triangle that is shared with the other triangle, this edge will be swapped
                    int sharedEdgeVertexLocalIndex = 0;

                    for (; sharedEdgeVertexLocalIndex < 3; ++sharedEdgeVertexLocalIndex)
                    {
                        if (oppositeTriangle.adjacent[sharedEdgeVertexLocalIndex] == currentEdge.TriangleIndex)
                        {
                            break;
                        }
                    }

                    // Swap
                    SwapEdges(currentEdge.TriangleIndex, currentEdgeTriangle, triangleVertexNotShared, oppositeTriangle, sharedEdgeVertexLocalIndex);
                }
            }

            //Debug.DrawLine(edgeEndpointA, edgeEndpointB, Color.magenta, 10.0f);
        }
コード例 #3
0
        /// <summary>
        /// Given the outline of a closed polygon, expressed as a list of vertices, it finds all the triangles that lay inside of the figure.
        /// </summary>
        /// <param name="polygonOutline">The outline, a list of vertex indices sorted counter-clockwise.</param>
        /// <param name="outputTrianglesInPolygon">The list where the triangles found inside the polygon will be added. No elements are removed from this list.</param>
        public void GetTrianglesInPolygon(List <int> polygonOutline, List <int> outputTrianglesInPolygon)
        {
            // This method assumes that the edges of the triangles to find were created using the same vertex order
            // It also assumes all triangles are inside a supertriangle, so no adjacent triangles are -1

            Stack <int> adjacentTriangles = new Stack <int>();

            // First it gets all the triangles of the outline
            for (int i = 0; i < polygonOutline.Count; ++i)
            {
                // For every edge, it gets the inner triangle that contains such edge
                DelaunayTriangleEdge triangleEdge = FindTriangleThatContainsEdge(polygonOutline[i], polygonOutline[(i + 1) % polygonOutline.Count]);

                // A triangle may form a corner, with 2 consecutive outline edges. This avoids adding it twice
                if (outputTrianglesInPolygon.Count > 0 &&
                    (outputTrianglesInPolygon[outputTrianglesInPolygon.Count - 1] == triangleEdge.TriangleIndex || // Is the last added triangle the same as current?
                     outputTrianglesInPolygon[0] == triangleEdge.TriangleIndex))                                   // Is the first added triangle the same as the current, which is the last to be added (closes the polygon)?
                {
                    continue;
                }

                outputTrianglesInPolygon.Add(triangleEdge.TriangleIndex);

                int previousOutlineEdgeVertexA = polygonOutline[(i + polygonOutline.Count - 1) % polygonOutline.Count];
                int previousOutlineEdgeVertexB = polygonOutline[i];
                int nextOutlineEdgeVertexA     = polygonOutline[(i + 1) % polygonOutline.Count];
                int nextOutlineEdgeVertexB     = polygonOutline[(i + 2) % polygonOutline.Count];

                for (int j = 1; j < 3; ++j) // For the 2 adjacent triangles of the other 2 edges
                {
                    int  adjacentTriangle            = m_adjacentTriangles[triangleEdge.TriangleIndex * 3 + (triangleEdge.EdgeIndex + j) % 3];
                    bool isAdjacentTriangleInOutline = false;

                    // Compares the contiguous edges of the outline, to the right and to the left of the current one, flipped and not flipped, with the adjacent triangle's edges
                    for (int k = 0; k < 3; ++k)
                    {
                        int currentTriangleEdgeVertexA = m_triangleVertices[adjacentTriangle * 3 + k];
                        int currentTriangleEdgeVertexB = m_triangleVertices[adjacentTriangle * 3 + (k + 1) % 3];

                        if ((currentTriangleEdgeVertexA == previousOutlineEdgeVertexA && currentTriangleEdgeVertexB == previousOutlineEdgeVertexB) ||
                            (currentTriangleEdgeVertexA == previousOutlineEdgeVertexB && currentTriangleEdgeVertexB == previousOutlineEdgeVertexA) ||
                            (currentTriangleEdgeVertexA == nextOutlineEdgeVertexA && currentTriangleEdgeVertexB == nextOutlineEdgeVertexB) ||
                            (currentTriangleEdgeVertexA == nextOutlineEdgeVertexB && currentTriangleEdgeVertexB == nextOutlineEdgeVertexA))
                        {
                            isAdjacentTriangleInOutline = true;
                        }
                    }

                    if (!isAdjacentTriangleInOutline && !outputTrianglesInPolygon.Contains(adjacentTriangle))
                    {
                        adjacentTriangles.Push(adjacentTriangle);
                    }
                }
            }

            // Then it propagates by adjacency, stopping when an adjacent triangle has already been included in the list
            // Since all the outline triangles have been added previously, it will not propagate outside of the polygon
            while (adjacentTriangles.Count > 0)
            {
                int currentTriangle = adjacentTriangles.Pop();

                // The triangle may have been added already in a previous iteration
                if (outputTrianglesInPolygon.Contains(currentTriangle))
                {
                    continue;
                }

                for (int i = 0; i < 3; ++i)
                {
                    int adjacentTriangle = m_adjacentTriangles[currentTriangle * 3 + i];

                    if (adjacentTriangle != NO_ADJACENT_TRIANGLE && !outputTrianglesInPolygon.Contains(adjacentTriangle))
                    {
                        adjacentTriangles.Push(adjacentTriangle);
                    }
                }

                outputTrianglesInPolygon.Add(currentTriangle);
            }
        }