Example #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 = Vector3F.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);
        }
Example #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();
        }
Example #3
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();
    }
Example #4
0
        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 (Vector3F.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;
        }
Example #5
0
        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 (Vector3F.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);
        }
Example #6
0
 private void BuildVertexAdjacencyLists(DcelMesh convexHull)
 {
   _vertexAdjacency = new VertexAdjacency(convexHull);
 }
Example #7
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 = Vector3F.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;
        }
Example #8
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.");
        }
Example #9
0
 public void Reset()
 {
     // Reset fields.
       _faces = new List<DcelFace>();
       _taggedEdges = new List<DcelEdge>();
       _isPlanar = false;
       _type = ConvexHullType.Empty;
       _mesh = new DcelMesh();
 }