示例#1
0
        /// <summary>
        /// Build a full topology data structure from the minimal data described by a face neighbor indexer.
        /// </summary>
        /// <param name="indexer">A minimal description of the faces and their neighbors constituting a topology.</param>
        /// <returns>A fully constructed topology matching the description of the provided face neighbor indexer.</returns>
        /// <remarks>
        /// <para>For the edge wrap data returned by the face neighbor indexer, only the vertex-to-edge, edge-to-vertex,
        /// and face-to-edge data needs to be supplied.  If there are no external faces, then the edge-to-vertex data is
        /// also unnecessary.</para>
        /// </remarks>
        public static Topology BuildTopology(IFaceNeighborIndexer indexer)
        {
            var vertexNeighborCounts   = new ushort[indexer.vertexCount];
            var vertexFirstEdgeIndices = new int[indexer.vertexCount];
            var edgeData             = new Topology.EdgeData[indexer.edgeCount];
            var faceNeighborCounts   = new ushort[indexer.faceCount];
            var faceFirstEdgeIndices = new int[indexer.faceCount];

            // Initialize the face roots and neighbor counts, and the next vertex, fNext, vNext, and wrap
            // fields of the internal edges.  The vNext fields will result in linked lists that contain the
            // correct members (aside from external edges), but in an unspecified order.
            int edgeIndex = 0;

            for (int faceIndex = 0; faceIndex < indexer.internalFaceCount; ++faceIndex)
            {
                var neighborCount = indexer.GetNeighborCount(faceIndex);
                faceNeighborCounts[faceIndex]   = neighborCount;
                faceFirstEdgeIndices[faceIndex] = edgeIndex;

                var priorVertexIndex = indexer.GetNeighborVertexIndex(faceIndex, neighborCount - 1);
                for (int neighborIndex = 0; neighborIndex < neighborCount; ++neighborIndex)
                {
                    var vertexIndex = indexer.GetNeighborVertexIndex(faceIndex, neighborIndex);
                    edgeData[edgeIndex].vertex = vertexIndex;
                    edgeData[edgeIndex].fNext  = edgeIndex + 1;
                    edgeData[edgeIndex].face   = -1;
                    edgeData[edgeIndex].twin   = -1;
                    edgeData[edgeIndex].wrap   = indexer.GetEdgeWrap(faceIndex, neighborIndex);

                    AddEdgeToVertexUnordered(edgeIndex, priorVertexIndex, vertexNeighborCounts, vertexFirstEdgeIndices, edgeData);
                    priorVertexIndex = vertexIndex;
                    ++edgeIndex;
                }

                // Correct the face's last edge to refer back to the face's first edge.
                edgeData[edgeIndex - 1].fNext = edgeIndex - neighborCount;
            }

            var internalEdgeCount = edgeIndex;

            // Use the partial information constructed in the prior loop to determine edge twins, and set
            // the vertex, fNext, vNext, and wrap fields for external edges too.
            edgeIndex = 0;
            var externalEdgeIndex = internalEdgeCount;

            for (int faceIndex = 0; faceIndex < indexer.internalFaceCount; ++faceIndex)
            {
                var neighborCount    = indexer.GetNeighborCount(faceIndex);
                var priorVertexIndex = indexer.GetNeighborVertexIndex(faceIndex, neighborCount - 1);
                for (int neighborIndex = 0; neighborIndex < neighborCount; ++neighborIndex)
                {
                    var vertexIndex = indexer.GetNeighborVertexIndex(faceIndex, neighborIndex);

                    if (edgeData[edgeIndex].twin == -1)
                    {
                        // The current edge is pointing at the current vertex index.  Its twin will be one
                        // of the edges pointing out from the current vertex, and will be pointing at the
                        // prior vertex.  Search for this edge.
                        var vertexFirstEdgeIndex = vertexFirstEdgeIndices[vertexIndex];
                        var vertexEdgeIndex      = vertexFirstEdgeIndex;
                        while (edgeData[vertexEdgeIndex].vertex != priorVertexIndex)
                        {
                            vertexEdgeIndex = edgeData[vertexEdgeIndex].vNext;
                            if (vertexEdgeIndex == vertexFirstEdgeIndex)
                            {
                                // This edge's twin is an external edge which needs to be initialized.
                                edgeData[externalEdgeIndex].vertex = priorVertexIndex;
                                edgeData[externalEdgeIndex].fNext  = -1;                                // Cannot be determined until the vNext linked lists are in the correct order.
                                edgeData[externalEdgeIndex].face   = -1;
                                edgeData[externalEdgeIndex].wrap   = EdgeWrapUtility.Invert(edgeData[edgeIndex].wrap);

                                AddEdgeToVertexUnordered(externalEdgeIndex, vertexIndex, vertexNeighborCounts, vertexFirstEdgeIndices, edgeData);

                                vertexEdgeIndex = externalEdgeIndex;
                                ++externalEdgeIndex;
                                break;
                            }
                        }
                        edgeData[vertexEdgeIndex].twin = edgeIndex;
                        edgeData[edgeIndex].twin       = vertexEdgeIndex;
                    }

                    ++edgeIndex;
                    priorVertexIndex = vertexIndex;
                }
            }

            // Correct the order of the vNext linked lists, and set the face indices of the twins of all internal edges.
            edgeIndex = 0;
            for (int faceIndex = 0; faceIndex < indexer.internalFaceCount; ++faceIndex)
            {
                var neighborCount  = indexer.GetNeighborCount(faceIndex);
                var priorEdgeIndex = edgeIndex + neighborCount - 1;
                for (int neighborIndex = 0; neighborIndex < neighborCount; ++neighborIndex)
                {
                    var twinEdgeIndex = edgeData[priorEdgeIndex].twin;
                    PutEdgesInSequence(edgeIndex, twinEdgeIndex, edgeData);

                    edgeData[twinEdgeIndex].face = faceIndex;

                    priorEdgeIndex = edgeIndex;
                    ++edgeIndex;
                }
            }

            if (indexer.externalFaceCount > 0)
            {
                // Now that all vertex and edge relationships are established, locate all edges that don't have a
                // face relationship specified (those which are pointing out toward external faces) and spin around
                // each face to establish those edge -> face relationships and count external face neighbors.
                var faceIndex = indexer.internalFaceCount;
                for (edgeIndex = 0; edgeIndex < indexer.edgeCount; ++edgeIndex)
                {
                    if (edgeData[edgeIndex].face == -1)
                    {
                        // Starting with the current edge, follow the edge links appropriately to wind around the
                        // implicit face counter-clockwise and link the edges to the face.
                        var neighborCount      = 0;
                        var twinEdgeIndex      = edgeIndex;
                        var faceEdgeIndex      = edgeData[edgeIndex].twin;
                        var faceFirstEdgeIndex = faceEdgeIndex;
                        do
                        {
                            edgeData[twinEdgeIndex].face = faceIndex;
                            twinEdgeIndex = edgeData[faceEdgeIndex].vNext;
                            var nextFaceEdgeIndex = edgeData[twinEdgeIndex].twin;
                            edgeData[nextFaceEdgeIndex].fNext = faceEdgeIndex;
                            faceEdgeIndex = nextFaceEdgeIndex;
                            ++neighborCount;
                            if (neighborCount > vertexFirstEdgeIndices.Length)
                            {
                                throw new InvalidOperationException("Face neighbors were specified such that an external face was misconfigured.");
                            }
                        } while (twinEdgeIndex != edgeIndex);

                        faceNeighborCounts[faceIndex]   = (ushort)neighborCount;
                        faceFirstEdgeIndices[faceIndex] = faceFirstEdgeIndex;
                        ++faceIndex;
                    }
                }
            }

            // Fill out the remainder of the edge wrap data, based on the possibly limited info supplied.
            for (edgeIndex = 0; edgeIndex < indexer.edgeCount; ++edgeIndex)
            {
                var twinIndex = edgeData[edgeIndex].twin;
                if (edgeIndex < twinIndex)
                {
                    EdgeWrapUtility.CrossMergeTwins(ref edgeData[edgeIndex].wrap, ref edgeData[twinIndex].wrap);
                }
            }

            return(Topology.Create(vertexNeighborCounts, vertexFirstEdgeIndices, edgeData, faceNeighborCounts, faceFirstEdgeIndices, indexer.internalFaceCount));
        }