Esempio n. 1
0
        private static int GetBestCutPlane(List <Plane> planes, DcelMesh mesh)
        {
            // The plane cost is inspired by Stan Melax's convex hull implementation.
            // It can be found in John Ratcliff's Convex Decomposition library.
            float bestPlaneCost = 0;
            int   bestPlane     = -1;

            for (int i = 0; i < planes.Count; i++)
            {
                var plane = planes[i];

                // Get min and max distance.
                float minDistance = 0;
                float maxDistance = 0;
                foreach (var v in mesh.Vertices)
                {
                    float distance = Vector3.Dot(v.Position, plane.Normal) - plane.DistanceFromOrigin;
                    minDistance = Math.Min(distance, minDistance);
                    maxDistance = Math.Max(distance, maxDistance);
                }

                float diff = maxDistance - minDistance;

                // The plane cost is the normalized maxDistance.
                float planeCost = maxDistance / diff;
                if (planeCost > bestPlaneCost)
                {
                    bestPlaneCost = planeCost;
                    bestPlane     = i;
                }
            }

            return(bestPlane);
        }
Esempio n. 2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="VertexAdjacency"/> class.
        /// </summary>
        /// <param name="mesh">The mesh for which the adjacency information is built.</param>
        /// <exception cref="NotSupportedException">
        /// Too many vertices in convex hull. Max. 65534 vertices in convex hull are supported.
        /// </exception>
        public VertexAdjacency(DcelMesh mesh)
        {
            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }

            int numberOfVertices = mesh.Vertices.Count;

            if (numberOfVertices >= ushort.MaxValue)
            {
                throw new NotSupportedException("Too many vertices in convex hull. Max. 65534 vertices in convex hull are supported.");
            }

            Debug.Assert(mesh.Vertices.All(v => v.Tag == 0), "Tags of DcelMesh should be cleared.");

            // Store the index of each vertex in its tag for fast lookup.
            for (int i = 0; i < numberOfVertices; i++)
            {
                mesh.Vertices[i].Tag = i;
            }

            ListIndices = new ushort[numberOfVertices + 1];
            List <ushort> adjacencyLists = new List <ushort>(numberOfVertices * 4);

            for (int i = 0; i < numberOfVertices; i++)
            {
                DcelVertex vertex = mesh.Vertices[i];
                ListIndices[i] = (ushort)adjacencyLists.Count;

                // Gather all adjacent vertices.
                DcelEdge startEdge = vertex.Edge;
                DcelEdge edge      = startEdge;
                do
                {
                    DcelVertex adjacentVertex = edge.Next.Origin;
                    int        adjacentIndex  = adjacentVertex.Tag;
                    Debug.Assert(mesh.Vertices[adjacentIndex] == adjacentVertex, "Indices stored in DcelVertex.Tag are invalid.");
                    adjacencyLists.Add((ushort)adjacentIndex);
                    edge = edge.Twin.Next;
                } while (edge != startEdge);
            }

            // Add one additional entry which determines the end of the last adjacency list.
            ListIndices[numberOfVertices] = (ushort)adjacencyLists.Count;

            // Copy adjacency lists into static array.
            Lists = adjacencyLists.ToArray();
        }
        public static DcelMesh FromTriangleMesh(TriangleMesh mesh)
        {
            // TODO: To optimize, check tricks of TriangleMeshShape.ComputeNeighbors.

            if (mesh == null)
            {
                throw new ArgumentNullException("mesh");
            }
            if (mesh.Vertices == null || mesh.Indices == null)
            {
                throw new ArgumentException("Input mesh has no vertices or vertex indices.");
            }

            // Create vertices.
            int numberOfVertices = mesh.Vertices.Count;
            var vertices         = new List <DcelVertex>(numberOfVertices);

            foreach (var position in mesh.Vertices)
            {
                vertices.Add(new DcelVertex(position, null));
            }

            // Weld similar vertices.
            for (int i = 0; i < numberOfVertices; i++)
            {
                for (int j = i + 1; j < numberOfVertices; j++)
                {
                    if (Vector3.AreNumericallyEqual(vertices[i].Position, vertices[j].Position))
                    {
                        vertices[i] = vertices[j];
                    }
                }
            }

            // Create edges and faces for each triangle.
            // We need at least 3 edges for each triangle. We might need more edges if we have to
            // connect unconnected islands of triangles.
            var edges = new List <DcelEdge>(mesh.NumberOfTriangles * 3 * 2);
            var faces = new List <DcelFace>(mesh.NumberOfTriangles);

            for (int i = 0; i < mesh.NumberOfTriangles; i++)
            {
                // Get triangle indices.
                var index0 = mesh.Indices[i * 3 + 0];
                var index1 = mesh.Indices[i * 3 + 1];
                var index2 = mesh.Indices[i * 3 + 2];

                // Get DCEL vertices.
                var vertex0 = vertices[index0];
                var vertex1 = vertices[index1];
                var vertex2 = vertices[index2];

                // Create 3 edges.
                var edge0 = new DcelEdge();
                var edge1 = new DcelEdge();
                var edge2 = new DcelEdge();

                // Create 1 face.
                var face = new DcelFace();

                // Fill out face info.
                face.Boundary = edge0;

                // Fill out vertex info.
                vertex0.Edge = edge0;
                vertex1.Edge = edge1;
                vertex2.Edge = edge2;

                // Fill out edge info.
                // Twin links are created later.
                edge0.Face     = face;
                edge0.Origin   = vertex0;
                edge0.Next     = edge1;
                edge0.Previous = edge2;

                edge1.Face     = face;
                edge1.Origin   = vertex1;
                edge1.Next     = edge2;
                edge1.Previous = edge0;

                edge2.Face     = face;
                edge2.Origin   = vertex2;
                edge2.Next     = edge0;
                edge2.Previous = edge1;

                // Add to lists.
                edges.Add(edge0);
                edges.Add(edge1);
                edges.Add(edge2);
                faces.Add(face);
            }

            // Connect triangles that share an edge.
            for (int i = 0; i < faces.Count; i++)
            {
                // Get face and its 3 edges.
                var faceI  = faces[i];
                var edgeI0 = faceI.Boundary;
                var edgeI1 = edgeI0.Next;
                var edgeI2 = edgeI1.Next;
                Debug.Assert(edgeI2.Next == edgeI0);

                for (int j = i + 1; j < faces.Count; j++)
                {
                    // Get face and its 3 edges.
                    var faceJ  = faces[j];
                    var edgeJ0 = faceJ.Boundary;
                    var edgeJ1 = edgeJ0.Next;
                    var edgeJ2 = edgeJ1.Next;
                    Debug.Assert(edgeJ2.Next == edgeJ0);

                    TryLink(edgeI0, edgeJ0);
                    TryLink(edgeI0, edgeJ1);
                    TryLink(edgeI0, edgeJ2);

                    TryLink(edgeI1, edgeJ0);
                    TryLink(edgeI1, edgeJ1);
                    TryLink(edgeI1, edgeJ2);

                    TryLink(edgeI2, edgeJ0);
                    TryLink(edgeI2, edgeJ1);
                    TryLink(edgeI2, edgeJ2);
                }
            }

            // If the mesh is not closed, we have to add twin edges at the boundaries
            foreach (var edge in edges.ToArray())
            {
                if (edge.Twin == null)
                {
                    var twin = new DcelEdge();
                    twin.Origin = edge.Next.Origin;
                    twin.Twin   = edge;
                    edge.Twin   = twin;
                    edges.Add(twin);
                }
            }

            // Yet, twin.Next/Previous were not set.
            foreach (var edge in edges)
            {
                if (edge.Previous == null)
                {
                    // The previous edge has not been set.
                    // Search the edges around the origin until we find the previous unconnected edge.
                    var origin     = edge.Origin;
                    var originEdge = edge.Twin.Next; // Another edge with the same origin.
                    while (originEdge.Twin.Next != null)
                    {
                        Debug.Assert(originEdge.Origin == origin);
                        originEdge = originEdge.Twin.Next;
                    }

                    var previous = originEdge.Twin;
                    previous.Next = edge;
                    edge.Previous = previous;
                }
            }

            // Check if we have one connected mesh.
            if (vertices.Count > 0)
            {
                const int Tag = 1;
                TagLinkedComponents(vertices[0], Tag);

                // Check if all components were reached.
                if (vertices.Any(v => v.Tag != Tag) ||
                    edges.Any(e => e.Tag != Tag) ||
                    faces.Any(f => f.Tag != Tag))
                {
                    throw new NotSupportedException("The triangle mesh consists of several unconnected components or sub-meshes.");
                }
            }

            var dcelMesh = new DcelMesh {
                Vertex = vertices.FirstOrDefault()
            };

            dcelMesh.ResetTags();

            return(dcelMesh);
        }
Esempio n. 4
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DcelMesh" /> class that is a copy of the given
        /// mesh.
        /// </summary>
        /// <param name="mesh">
        /// The source mesh to copy. Can be <see langword="null"/> to create an empty
        /// <see cref="DcelMesh"/>.
        /// </param>
        /// <remarks>
        /// This constructor creates a new <see cref="DcelMesh"/> which is a copy of the given
        /// <paramref name="mesh"/>.
        /// </remarks>
        public DcelMesh(DcelMesh mesh)
        {
            if (mesh == null)
            {
                return;
            }

            var originalVertices = mesh.Vertices;
            var originalEdges    = mesh.Edges;
            var originalFaces    = mesh.Faces;

            // 3 empty lists.
            _vertices = new List <DcelVertex>(originalVertices.Count);
            _edges    = new List <DcelEdge>(originalEdges.Count);
            _faces    = new List <DcelFace>(originalFaces.Count);

            // Use the internal tags to store list indices.
            for (int i = 0; i < originalVertices.Count; i++)
            {
                originalVertices[i].InternalTag = i;
            }

            for (int i = 0; i < originalEdges.Count; i++)
            {
                originalEdges[i].InternalTag = i;
            }

            for (int i = 0; i < originalFaces.Count; i++)
            {
                originalFaces[i].InternalTag = i;
            }

            // Add empty instances to the new lists.
            for (int i = 0; i < originalVertices.Count; i++)
            {
                _vertices.Add(new DcelVertex());
            }

            for (int i = 0; i < originalEdges.Count; i++)
            {
                _edges.Add(new DcelEdge());
            }

            for (int i = 0; i < originalFaces.Count; i++)
            {
                _faces.Add(new DcelFace());
            }

            // Clone the DCEL parts.
            for (int i = 0; i < originalVertices.Count; i++)
            {
                var s = originalVertices[i]; // source
                var t = _vertices[i];        // target

                t.Position = s.Position;

                if (s.Edge != null)
                {
                    t.Edge = _edges[s.Edge.InternalTag];
                }

                t.Tag      = s.Tag;
                t.UserData = s.UserData;
            }

            for (int i = 0; i < originalEdges.Count; i++)
            {
                var s = originalEdges[i];
                var t = _edges[i];

                if (s.Origin != null)
                {
                    t.Origin = _vertices[s.Origin.InternalTag];
                }

                if (s.Twin != null)
                {
                    t.Twin = _edges[s.Twin.InternalTag];
                }

                if (s.Face != null)
                {
                    t.Face = _faces[s.Face.InternalTag];
                }

                if (s.Next != null)
                {
                    t.Next = _edges[s.Next.InternalTag];
                }

                if (s.Previous != null)
                {
                    t.Previous = _edges[s.Previous.InternalTag];
                }

                t.Tag      = s.Tag;
                t.UserData = s.UserData;
            }

            for (int i = 0; i < originalFaces.Count; i++)
            {
                var s = originalFaces[i];
                var t = _faces[i];
                if (s.Boundary != null)
                {
                    t.Boundary = _edges[s.Boundary.InternalTag];
                }

                if (s.Holes != null)
                {
                    t.Holes = new List <DcelEdge>(s.Holes.Count);
                    for (int j = 0; j < s.Holes.Count; j++)
                    {
                        if (s.Holes[j] != null)
                        {
                            t.Holes.Add(_edges[s.Holes[j].InternalTag]);
                        }
                    }
                }

                t.Tag      = s.Tag;
                t.UserData = s.UserData;
            }

            Dirty = false;

            if (mesh.Vertex != null)
            {
                Vertex = _vertices[mesh.Vertex.InternalTag];
            }

            mesh.ResetInternalTags();

            Debug.Assert(_vertices.Count == mesh._vertices.Count, "Cloning of DcelMesh failed. Clone has different number of vertices.");
            Debug.Assert(_edges.Count == mesh._edges.Count, "Cloning of DcelMesh failed. Clone has different number of edges.");
            Debug.Assert(_faces.Count == mesh._faces.Count, "Cloning of DcelMesh failed. Clone has different number of faces.");
        }