예제 #1
0
        private void MergeIslands()
        {
            List <CDIslandLink> newLinks      = new List <CDIslandLink>();
            List <CDIslandLink> obsoleteLinks = (EnableMultithreading) ? new List <CDIslandLink>() : null;

            while (_links.Count > 0 && !_cancel)
            {
                lock (_syncRoot)
                {
                    // Find link with lowest decimation cost.
                    CDIslandLink bestLink      = _links[0];
                    int          bestLinkIndex = 0;
                    for (int i = 0; i < _links.Count; i++)
                    {
                        var link = _links[i];
                        if (link.DecimationCost < bestLink.DecimationCost)
                        {
                            bestLink      = link;
                            bestLinkIndex = i;
                        }
                    }

                    // Remove the found link.
                    _links.RemoveAt(bestLinkIndex);

                    // Ignore links that have exceeded the concavity limit.
                    if (bestLink.Concavity > AllowedConcavity)
                    {
                        continue;
                    }

                    // The created composite shape is now invalid again.
                    _decomposition = null;

                    // Remove island B
                    _islands.Remove(bestLink.IslandB);

                    // Merge the islands of the best link into island A.
                    foreach (var triangle in bestLink.IslandB.Triangles)
                    {
                        triangle.Island = bestLink.IslandA;
                    }
                    bestLink.IslandA.Triangles         = bestLink.IslandA.Triangles.Union(bestLink.IslandB.Triangles).ToArray();
                    bestLink.IslandA.Aabb              = bestLink.Aabb;
                    bestLink.IslandA.Vertices          = bestLink.Vertices;
                    bestLink.IslandA.ConvexHullBuilder = bestLink.ConvexHullBuilder;

                    // Remove old links where A and B are involved and add new
                    // links with A.
                    if (!EnableMultithreading)
                    {
                        for (int i = _links.Count - 1; i >= 0; i--)
                        {
                            var      link        = _links[i];
                            CDIsland otherIsland = null;
                            if (link.IslandA == bestLink.IslandA || link.IslandA == bestLink.IslandB)
                            {
                                otherIsland = link.IslandB;
                            }
                            else if (link.IslandB == bestLink.IslandA || link.IslandB == bestLink.IslandB)
                            {
                                otherIsland = link.IslandA;
                            }

                            // This link does not link to the merged islands.
                            if (otherIsland == null)
                            {
                                continue;
                            }

                            // Remove link.
                            _links.RemoveAt(i);

                            // If _newLinks already contains a link with otherIsland we are done.
                            bool linkExists = false;
                            foreach (var newLink in newLinks)
                            {
                                if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland)
                                {
                                    linkExists = true;
                                    break;
                                }
                            }

                            if (linkExists)
                            {
                                continue;
                            }

                            // Create link between otherIsland and bestLink.IslandA.
                            link = new CDIslandLink(otherIsland, bestLink.IslandA, AllowedConcavity, SmallIslandBoost,
                                                    IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters);
                            newLinks.Add(link);
                        }
                    }
                    else
                    {
                        // Experimental multithreading hack.
                        // Note: When multithreading is enabled the result is non-deterministic
                        // because the order of the links in the _links list change...
                        Parallel.ForEach(_links, link =>
                        {
                            CDIsland otherIsland = null;
                            if (link.IslandA == bestLink.IslandA || link.IslandA == bestLink.IslandB)
                            {
                                otherIsland = link.IslandB;
                            }
                            else if (link.IslandB == bestLink.IslandA || link.IslandB == bestLink.IslandB)
                            {
                                otherIsland = link.IslandA;
                            }

                            // This link does not link to the merged islands.
                            if (otherIsland == null)
                            {
                                return;
                            }

                            // Remove link.
                            lock (obsoleteLinks)
                                obsoleteLinks.Add(link);

                            // If _newLinks already contains a link with otherIsland we are done.
                            lock (newLinks)
                            {
                                foreach (var newLink in newLinks)
                                {
                                    if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland)
                                    {
                                        return;
                                    }
                                }
                            }

                            // Create link between otherIsland and bestLink.IslandA.
                            link = new CDIslandLink(otherIsland, bestLink.IslandA, AllowedConcavity, SmallIslandBoost,
                                                    IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters);

                            // Add link but only if another thread did not add a similar link.
                            // TODO: Can this happen or can we remove this check.
                            lock (newLinks)
                            {
                                foreach (var newLink in newLinks)
                                {
                                    if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland)
                                    {
                                        return;
                                    }
                                }

                                newLinks.Add(link);
                            }
                        });

                        foreach (var link in obsoleteLinks)
                        {
                            _links.Remove(link);
                        }

                        obsoleteLinks.Clear();
                    }

                    // Add new links.
                    _links.AddRange(newLinks);
                    newLinks.Clear();

                    OnProgressChanged((_mesh.NumberOfTriangles - _islands.Count) * 100 / _mesh.NumberOfTriangles);
                }
            }
        }
예제 #2
0
        private void MergeIslands()
        {
            List<CDIslandLink> newLinks = new List<CDIslandLink>();
              List<CDIslandLink> obsoleteLinks = (EnableMultithreading) ? new List<CDIslandLink>() : null;

              while (_links.Count > 0 && !_cancel)
              {
            lock (_syncRoot)
            {
              // Find link with lowest decimation cost.
              CDIslandLink bestLink = _links[0];
              int bestLinkIndex = 0;
              for (int i = 0; i < _links.Count; i++)
              {
            var link = _links[i];
            if (link.DecimationCost < bestLink.DecimationCost)
            {
              bestLink = link;
              bestLinkIndex = i;
            }
              }

              // Remove the found link.
              _links.RemoveAt(bestLinkIndex);

              // Ignore links that have exceeded the concavity limit.
              if (bestLink.Concavity > AllowedConcavity)
            continue;

              // The created composite shape is now invalid again.
              _decomposition = null;

              // Remove island B
              _islands.Remove(bestLink.IslandB);

              // Merge the islands of the best link into island A.
              foreach (var triangle in bestLink.IslandB.Triangles)
            triangle.Island = bestLink.IslandA;
              bestLink.IslandA.Triangles = bestLink.IslandA.Triangles.Union(bestLink.IslandB.Triangles).ToArray();
              bestLink.IslandA.Aabb = bestLink.Aabb;
              bestLink.IslandA.Vertices = bestLink.Vertices;
              bestLink.IslandA.ConvexHullBuilder = bestLink.ConvexHullBuilder;

              // Remove old links where A and B are involved and add new
              // links with A.
              if (!EnableMultithreading)
              {
            for (int i = _links.Count - 1; i >= 0; i--)
            {
              var link = _links[i];
              CDIsland otherIsland = null;
              if (link.IslandA == bestLink.IslandA || link.IslandA == bestLink.IslandB)
                otherIsland = link.IslandB;
              else if (link.IslandB == bestLink.IslandA || link.IslandB == bestLink.IslandB)
                otherIsland = link.IslandA;

              // This link does not link to the merged islands.
              if (otherIsland == null)
                continue;

              // Remove link.
              _links.RemoveAt(i);

              // If _newLinks already contains a link with otherIsland we are done.
              bool linkExists = false;
              foreach (var newLink in newLinks)
              {
                if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland)
                {
                  linkExists = true;
                  break;
                }
              }

              if (linkExists)
                continue;

              // Create link between otherIsland and bestLink.IslandA.
              link = new CDIslandLink(otherIsland, bestLink.IslandA, AllowedConcavity, SmallIslandBoost,
                                      IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters);
              newLinks.Add(link);
            }
              }
              else
              {
            // Experimental multithreading hack.
            // Note: When multithreading is enabled the result is non-deterministic
            // because the order of the links in the _links list change...
            Parallel.ForEach(_links, link =>
            {
              CDIsland otherIsland = null;
              if (link.IslandA == bestLink.IslandA || link.IslandA == bestLink.IslandB)
                otherIsland = link.IslandB;
              else if (link.IslandB == bestLink.IslandA || link.IslandB == bestLink.IslandB)
                otherIsland = link.IslandA;

              // This link does not link to the merged islands.
              if (otherIsland == null)
                return;

              // Remove link.
              lock (obsoleteLinks)
                obsoleteLinks.Add(link);

              // If _newLinks already contains a link with otherIsland we are done.
              lock (newLinks)
              {
                foreach (var newLink in newLinks)
                  if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland)
                    return;
              }

              // Create link between otherIsland and bestLink.IslandA.
              link = new CDIslandLink(otherIsland, bestLink.IslandA, AllowedConcavity, SmallIslandBoost,
                                      IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters);

              // Add link but only if another thread did not add a similar link.
              // TODO: Can this happen or can we remove this check.
              lock (newLinks)
              {
                foreach (var newLink in newLinks)
                  if (newLink.IslandA == otherIsland || newLink.IslandB == otherIsland)
                    return;

                newLinks.Add(link);
              }
            });

            foreach (var link in obsoleteLinks)
              _links.Remove(link);

            obsoleteLinks.Clear();
              }

              // Add new links.
              _links.AddRange(newLinks);
              newLinks.Clear();

              OnProgressChanged((_mesh.NumberOfTriangles - _islands.Count) * 100 / _mesh.NumberOfTriangles);
            }
              }
        }
예제 #3
0
        private void CreateDualGraph()
        {
            var triangles = new List <CDTriangle>();

            // Convert to TriangleMesh.
            var triangleMesh = _mesh as TriangleMesh;

            if (triangleMesh == null)
            {
                triangleMesh = new TriangleMesh();
                triangleMesh.Add(_mesh, false);
                triangleMesh.WeldVertices();
            }

            // Initialize vertex normals.
            var normals        = new Vector3F[triangleMesh.Vertices.Count]; // Vertex normals.
            var neighborCounts = new int[triangleMesh.Vertices.Count];      // Numbers of triangles that touch each vertex.

            for (int i = 0; i < triangleMesh.Vertices.Count; i++)
            {
                normals[i]        = Vector3F.Zero;
                neighborCounts[i] = 0;
            }

            // Go through all triangles. Add the normal to normals and increase the neighborCounts
            for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
            {
                Triangle triangle = triangleMesh.GetTriangle(i);
                var      normal   = triangle.Normal;

                for (int j = 0; j < 3; j++)
                {
                    var vertexIndex = triangleMesh.Indices[(i * 3) + j];
                    normals[vertexIndex]        = normals[vertexIndex] + normal;
                    neighborCounts[vertexIndex] = neighborCounts[vertexIndex] + 1;
                }
            }

            // Create triangles.
            for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
            {
                Triangle triangle   = triangleMesh.GetTriangle(i);
                var      cdTriangle = new CDTriangle
                {
                    Id       = i,
                    Vertices = new[] { triangle.Vertex0, triangle.Vertex1, triangle.Vertex2 },
                    Normal   = triangle.Normal, // TODO: Special care for degenerate triangles needed?
                };

                for (int j = 0; j < 3; j++)
                {
                    var vertexIndex   = triangleMesh.Indices[(i * 3) + j];
                    var normalSum     = normals[vertexIndex];
                    var neighborCount = neighborCounts[vertexIndex];
                    if (neighborCount > 0)
                    {
                        var normal = normalSum / neighborCount;
                        normal.TryNormalize();
                        cdTriangle.VertexNormals[j] = normal;
                    }
                }

                triangles.Add(cdTriangle);
            }

            // Create an island for each triangle.
            _islands = new List <CDIsland>(triangles.Count);
            for (int i = 0; i < triangles.Count; i++)
            {
                var triangle = triangles[i];

                var island = new CDIsland();
                island.Id        = i;
                island.Triangles = new[] { triangle };
                island.Vertices  = triangle.Vertices;

                island.Aabb = new Aabb(triangle.Vertices[0], triangle.Vertices[0]);
                island.Aabb.Grow(triangle.Vertices[1]);
                island.Aabb.Grow(triangle.Vertices[2]);

                triangle.Island = island;

                _islands.Add(island);
            }

            // Find connectivity (= add neighbor links).
            for (int i = 0; i < triangles.Count; i++)
            {
                var a = triangles[i];
                for (int j = i + 1; j < triangles.Count; j++)
                {
                    var b = triangles[j];
                    CDTriangle.FindNeighbors(a, b);
                }
            }

            // Create links.
            _links = new List <CDIslandLink>();
            for (int i = 0; i < _islands.Count; i++)
            {
                var island   = _islands[i];
                var triangle = island.Triangles[0];

                // Go through all neighbors.
                // If there is a neighbor, create a link.
                // To avoid two links per triangle, we create the link only if the id of this triangle
                // is less than the other island id.
                for (int j = 0; j < 3; j++)
                {
                    CDTriangle neighborTriangle = triangle.Neighbors[j];
                    if (neighborTriangle != null && neighborTriangle.Island.Id > i)
                    {
                        var link = new CDIslandLink(island, neighborTriangle.Island, AllowedConcavity, SmallIslandBoost, IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters);
                        _links.Add(link);
                    }
                }
            }

            // Now, we have a lot of islands with 1 triangle each.
        }
예제 #4
0
        private void CreateDualGraph()
        {
            var triangles = new List<CDTriangle>();

              // Convert to TriangleMesh.
              var triangleMesh = _mesh as TriangleMesh;
              if (triangleMesh == null)
              {
            triangleMesh = new TriangleMesh();
            triangleMesh.Add(_mesh, false);
            triangleMesh.WeldVertices();
              }

              // Initialize vertex normals.
              var normals = new Vector3F[triangleMesh.Vertices.Count];    // Vertex normals.
              var neighborCounts = new int[triangleMesh.Vertices.Count];  // Numbers of triangles that touch each vertex.
              for (int i = 0; i < triangleMesh.Vertices.Count; i++)
              {
            normals[i] = Vector3F.Zero;
            neighborCounts[i] = 0;
              }

              // Go through all triangles. Add the normal to normals and increase the neighborCounts
              for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
              {
            Triangle triangle = triangleMesh.GetTriangle(i);
            var normal = triangle.Normal;

            for (int j = 0; j < 3; j++)
            {
              var vertexIndex = triangleMesh.Indices[(i * 3) + j];
              normals[vertexIndex] = normals[vertexIndex] + normal;
              neighborCounts[vertexIndex] = neighborCounts[vertexIndex] + 1;
            }
              }

              // Create triangles.
              for (int i = 0; i < triangleMesh.NumberOfTriangles; i++)
              {
            Triangle triangle = triangleMesh.GetTriangle(i);
            var cdTriangle = new CDTriangle
            {
              Id = i,
              Vertices = new[] { triangle.Vertex0, triangle.Vertex1, triangle.Vertex2 },
              Normal = triangle.Normal,   // TODO: Special care for degenerate triangles needed?
            };

            for (int j = 0; j < 3; j++)
            {
              var vertexIndex = triangleMesh.Indices[(i * 3) + j];
              var normalSum = normals[vertexIndex];
              var neighborCount = neighborCounts[vertexIndex];
              if (neighborCount > 0)
              {
            var normal = normalSum / neighborCount;
            normal.TryNormalize();
            cdTriangle.VertexNormals[j] = normal;
              }
            }

            triangles.Add(cdTriangle);
              }

              // Create an island for each triangle.
              _islands = new List<CDIsland>(triangles.Count);
              for (int i = 0; i < triangles.Count; i++)
              {
            var triangle = triangles[i];

            var island = new CDIsland();
            island.Id = i;
            island.Triangles = new[] { triangle };
            island.Vertices = triangle.Vertices;

            island.Aabb = new Aabb(triangle.Vertices[0], triangle.Vertices[0]);
            island.Aabb.Grow(triangle.Vertices[1]);
            island.Aabb.Grow(triangle.Vertices[2]);

            triangle.Island = island;

            _islands.Add(island);
              }

              // Find connectivity (= add neighbor links).
              for (int i = 0; i < triangles.Count; i++)
              {
            var a = triangles[i];
            for (int j = i + 1; j < triangles.Count; j++)
            {
              var b = triangles[j];
              CDTriangle.FindNeighbors(a, b);
            }
              }

              // Create links.
              _links = new List<CDIslandLink>();
              for (int i = 0; i < _islands.Count; i++)
              {
            var island = _islands[i];
            var triangle = island.Triangles[0];

            // Go through all neighbors.
            // If there is a neighbor, create a link.
            // To avoid two links per triangle, we create the link only if the id of this triangle
            // is less than the other island id.
            for (int j = 0; j < 3; j++)
            {
              CDTriangle neighborTriangle = triangle.Neighbors[j];
              if (neighborTriangle != null && neighborTriangle.Island.Id > i)
              {
            var link = new CDIslandLink(island, neighborTriangle.Island, AllowedConcavity, SmallIslandBoost, IntermediateVertexLimit, SampleTriangleVertices, SampleTriangleCenters);
            _links.Add(link);
              }
            }
              }

              // Now, we have a lot of islands with 1 triangle each.
        }