Beispiel #1
0
        public void Infinite()
        {
            GlobalSettings.ValidationLevel = 0xff;

            var partition = new AabbTree <int>
            {
                EnableSelfOverlaps = true,
                GetAabbForItem     = GetAabbForItem
            };

            partition.Add(1);
            partition.Add(0);
            partition.Add(2);
            partition.Add(3);

            Assert.AreEqual(new Aabb(new Vector3F(float.NegativeInfinity), new Vector3F(float.PositiveInfinity)), partition.Aabb);

            var overlaps = partition.GetOverlaps().ToArray();

            Assert.AreEqual(4, overlaps.Length);
            Assert.IsTrue(overlaps.Contains(new Pair <int>(0, 1)));
            Assert.IsTrue(overlaps.Contains(new Pair <int>(0, 2)));
            Assert.IsTrue(overlaps.Contains(new Pair <int>(0, 3)));
            Assert.IsTrue(overlaps.Contains(new Pair <int>(1, 2)));
        }
Beispiel #2
0
        public void NaNWithValidation()
        {
            GlobalSettings.ValidationLevel = 0xff;

            var partition = new AabbTree <int>();

            partition.EnableSelfOverlaps = true;
            partition.GetAabbForItem     = GetAabbForItem;

            partition.Add(1);
            partition.Add(4);
            partition.Add(2);
            partition.Add(3);

            // Full rebuild.
            Assert.Throws <GeometryException>(() => partition.Update(true));

            partition = new AabbTree <int>();
            partition.EnableSelfOverlaps = true;
            partition.GetAabbForItem     = GetAabbForItem;

            partition.Add(1);
            partition.Add(2);
            partition.Add(3);
            partition.Update(true);
            partition.Add(4);

            // Partial rebuild.
            Assert.Throws <GeometryException>(() => partition.Update(false));
        }
    protected override AabbTree<T> Read(ContentReader input, AabbTree<T> existingInstance)
    {
      if (existingInstance == null)
        existingInstance = new AabbTree<T>();
      else
        existingInstance.Clear();

      existingInstance.EnableSelfOverlaps = input.ReadBoolean();
      existingInstance.BottomUpBuildThreshold = input.ReadInt32();
      input.ReadSharedResource<IPairFilter<T>>(filter => existingInstance.Filter = filter);
      return existingInstance;
    }
Beispiel #4
0
        public void NaN()
        {
            GlobalSettings.ValidationLevel = 0x00;

            var partition = new AabbTree <int>
            {
                EnableSelfOverlaps = true,
                GetAabbForItem     = GetAabbForItem
            };

            partition.Add(1);
            partition.Add(4);
            partition.Add(2);
            partition.Add(3);

            // Aabb builder throws exception.
            Assert.Throws <GeometryException>(() => partition.Update(false));
        }
Beispiel #5
0
        public void NaN()
        {
            GlobalSettings.ValidationLevel = 0x00;

              var partition = new AabbTree<int>
              {
            EnableSelfOverlaps = true,
            GetAabbForItem = GetAabbForItem
              };

              partition.Add(1);
              partition.Add(4);
              partition.Add(2);
              partition.Add(3);

              // Aabb builder throws exception.
              Assert.Throws<GeometryException>(() => partition.Update(false));
        }
Beispiel #6
0
        public void Clone()
        {
            AabbTree<int> partition = new AabbTree<int>();
              partition.GetAabbForItem = i => new Aabb();
              partition.EnableSelfOverlaps = true;
              partition.Filter = new DelegatePairFilter<int>(pair => true);
              partition.Add(0);
              partition.Add(1);
              partition.Add(2);
              partition.Add(3);

              var clone = partition.Clone();
              Assert.NotNull(clone);
              Assert.AreNotSame(clone, partition);
              Assert.AreEqual(clone.EnableSelfOverlaps, partition.EnableSelfOverlaps);
              Assert.AreEqual(clone.Filter, partition.Filter);
              Assert.AreEqual(0, clone.Count);

              clone.Add(0);
              Assert.AreEqual(4, partition.Count);
              Assert.AreEqual(1, clone.Count);
        }
Beispiel #7
0
        public void Clone()
        {
            AabbTree <int> partition = new AabbTree <int>();

            partition.GetAabbForItem     = i => new Aabb();
            partition.EnableSelfOverlaps = true;
            partition.Filter             = new DelegatePairFilter <int>(pair => true);
            partition.Add(0);
            partition.Add(1);
            partition.Add(2);
            partition.Add(3);

            var clone = partition.Clone();

            Assert.NotNull(clone);
            Assert.AreNotSame(clone, partition);
            Assert.AreEqual(clone.EnableSelfOverlaps, partition.EnableSelfOverlaps);
            Assert.AreEqual(clone.Filter, partition.Filter);
            Assert.AreEqual(0, clone.Count);

            clone.Add(0);
            Assert.AreEqual(4, partition.Count);
            Assert.AreEqual(1, clone.Count);
        }
Beispiel #8
0
        public void Infinite()
        {
            GlobalSettings.ValidationLevel = 0xff;

              var partition = new AabbTree<int>
              {
            EnableSelfOverlaps = true,
            GetAabbForItem = GetAabbForItem
              };

              partition.Add(1);
              partition.Add(0);
              partition.Add(2);
              partition.Add(3);

              Assert.AreEqual(new Aabb(new Vector3F(float.NegativeInfinity), new Vector3F(float.PositiveInfinity)), partition.Aabb);

              var overlaps = partition.GetOverlaps().ToArray();
              Assert.AreEqual(4, overlaps.Length);
              Assert.IsTrue(overlaps.Contains(new Pair<int>(0, 1)));
              Assert.IsTrue(overlaps.Contains(new Pair<int>(0, 2)));
              Assert.IsTrue(overlaps.Contains(new Pair<int>(0, 3)));
              Assert.IsTrue(overlaps.Contains(new Pair<int>(1, 2)));
        }
Beispiel #9
0
 protected override void Write(ContentWriter output, AabbTree <T> value)
 {
     output.Write(value.EnableSelfOverlaps);
     output.Write(value.BottomUpBuildThreshold);
     output.WriteSharedResource(value.Filter);
 }
Beispiel #10
0
        private float GetConcavity(int vertexLimit, bool sampleVertices, bool sampleCenters)
        {
            // Initially we assume that the new vertices are simply the union of the islands' vertices.
              Vertices = IslandA.Vertices.Union(IslandB.Vertices).ToArray();

              try
              {
            // Create hull mesh.

            // Incremental hull building.
            // Note: Commented out because this building the hull this way is less stable.
            //bool rebuild = true;
            //try
            //{
            //  if (IslandA.ConvexHullBuilder != null)
            //  {
            //    if (IslandB.ConvexHullBuilder == null || IslandA.Vertices.Length > IslandB.Vertices.Length)
            //    {
            //      ConvexHullBuilder = IslandA.ConvexHullBuilder.Clone();
            //      ConvexHullBuilder.Grow(IslandB.Vertices, vertexLimit, 0);
            //    }
            //    else
            //    {
            //      ConvexHullBuilder = IslandB.ConvexHullBuilder.Clone();
            //      ConvexHullBuilder.Grow(IslandA.Vertices, vertexLimit, 0);
            //    }
            //    rebuild = false;
            //  }
            //  else if (IslandB.ConvexHullBuilder != null)
            //  {
            //    ConvexHullBuilder = IslandB.ConvexHullBuilder.Clone();
            //    ConvexHullBuilder.Grow(IslandA.Vertices, vertexLimit, 0);
            //    rebuild = false;
            //  }
            //}
            //catch (GeometryException)
            //{
            //  rebuild = true;
            //}

            //if (rebuild)
            {
              try
              {
            ConvexHullBuilder = new ConvexHullBuilder();
            ConvexHullBuilder.Grow(Vertices, vertexLimit, 0);
              }
              catch (GeometryException)
              {
            // Hull building failed. Try again with a randomized order.
            var random = new Random(1234567);
            // Fisher-Yates shuffle:
            for (int i = Vertices.Length - 1; i >= 1; i--)
            {
              var v = Vertices[i];
              var j = random.NextInteger(0, i);
              Vertices[i] = Vertices[j];
              Vertices[j] = v;
            }
              }
            }

            var hullMesh = ConvexHullBuilder.Mesh.ToTriangleMesh();

            // Now, we have a reduced set of vertices.
            Vertices = hullMesh.Vertices.ToArray();

            // For larger meshes we create an AabbTree as acceleration structure.
            AabbTree<int> partition = null;
            if (hullMesh.NumberOfTriangles > 12)
            {
              partition = new AabbTree<int>
              {
            GetAabbForItem = i => hullMesh.GetTriangle(i).Aabb,
            BottomUpBuildThreshold = 0,
              };
              for (int i = 0; i < hullMesh.NumberOfTriangles; i++)
            partition.Add(i);

              partition.Update(true);
            }

            Aabb aabb = Aabb;
            float aabbExtent = aabb.Extent.Length;

            // Note: For a speed-up we could skip some ray tests in the next loop and only sample
            // a few vertices if there would be a lot of tests.

            // The next loop performs ray casts against the hull mesh to determine the maximum
            // concavity. We ensure that we make only one ray cast per vertex even if a vertex
            // is shared by many triangles.
            float maxConcavity = 0;
            foreach (var triangle in IslandA.Triangles.Union(IslandB.Triangles))
            {
              if (sampleVertices)
              {
            for (int i = 0; i < triangle.Vertices.Length; i++)
            {
              // Each vertex can be shared by several triangles of the current islands.
              // Therefore, we check the edges that contain this vertex. If an edge neighbor
              // is in the same island, we make sure that the vertex concavity is computed only once
              // in the triangle with the smallest Id.
              var neighbor0 = triangle.Neighbors[(i + 1) % 3];
              var neighbor1 = triangle.Neighbors[(i + 2) % 3];

              if (neighbor0 != null
                  && (neighbor0.Island == IslandA || neighbor0.Island == IslandB)
                  && triangle.Id > neighbor0.Id)
              {
                // No need to test: The neighbor is in the same islands and this triangle Id is larger.
                continue;
              }

              if (neighbor1 != null
                  && (neighbor1.Island == IslandA || neighbor1.Island == IslandB)
                  && triangle.Id > neighbor1.Id)
              {
                // No need to test: The neighbor is in the same islands and this triangle Id is larger.
                continue;
              }

              var position = triangle.Vertices[i];
              var normal = triangle.VertexNormals[i];

              // Degenerate triangles are ignored.
              if (normal.IsNumericallyZero)
                continue;

              // Shoot a ray from outside the hull mesh to the vertex.
              float hitDistance;
              Vector3F rayOrigin = position + normal * aabbExtent;
              float rayLength = (position - rayOrigin).Length;
              var ray = new Ray(rayOrigin, -normal, rayLength);
              if (partition != null)
              {
                // Use AABB tree for better performance.
                foreach (var triangleIndex in partition.GetOverlaps(ray))
                {
                  var candidateTriangle = hullMesh.GetTriangle(triangleIndex);
                  var hit = GeometryHelper.GetContact(ray, candidateTriangle, false, out hitDistance);
                  if (hit)
                  {
                    // The concavity is the distance from the hull to the vertex.
                    float concavity = rayLength - hitDistance;
                    maxConcavity = Math.Max(maxConcavity, concavity);
                    break;
                  }
                }
              }
              else
              {
                // No AABB tree.
                var hit = GeometryHelper.GetContact(hullMesh, ray, out hitDistance);
                if (hit)
                {
                  float concavity = rayLength - hitDistance;
                  maxConcavity = Math.Max(maxConcavity, concavity);
                }
              }
            }
              }

              if (sampleCenters)
              {
            // Test: Also shoot from the triangle centers.
            var center = (triangle.Vertices[0] + triangle.Vertices[1] + triangle.Vertices[2]) / 3;
            var normal = triangle.Normal;

            // Degenerate triangles are ignored.
            if (normal.IsNumericallyZero)
              continue;

            // Shoot a ray from outside the hull mesh to the vertex.
            float hitDistance;
            Vector3F rayOrigin = center + normal * aabbExtent;
            float rayLength = (center - rayOrigin).Length;
            var ray = new Ray(rayOrigin, -normal, rayLength);
            if (partition != null)
            {
              // Use AABBTree for better performance.
              foreach (var triangleIndex in partition.GetOverlaps(ray))
              {
                var candidateTriangle = hullMesh.GetTriangle(triangleIndex);
                var hit = GeometryHelper.GetContact(ray, candidateTriangle, false, out hitDistance);
                if (hit)
                {
                  // The concavity is the distance from the hull to the vertex.
                  float concavity = rayLength - hitDistance;
                  maxConcavity = Math.Max(maxConcavity, concavity);
                  break;
                }
              }
            }
            else
            {
              // No AABBTree.
              var hit = GeometryHelper.GetContact(hullMesh, ray, out hitDistance);
              if (hit)
              {
                float concavity = rayLength - hitDistance;
                maxConcavity = Math.Max(maxConcavity, concavity);
              }
            }
              }
            }

            return maxConcavity;
              }
              catch (GeometryException)
              {
            // Ouch, the convex hull generation failed. This can happen for degenerate inputs
            // and numerical problems in the convex hull builder.
            ConvexHullBuilder = null;
            return 0;
              }
        }
Beispiel #11
0
        private float GetConcavity(int vertexLimit, bool sampleVertices, bool sampleCenters)
        {
            // Initially we assume that the new vertices are simply the union of the islands' vertices.
            Vertices = IslandA.Vertices.Union(IslandB.Vertices).ToArray();

            try
            {
                // Create hull mesh.

                // Incremental hull building.
                // Note: Commented out because this building the hull this way is less stable.
                //bool rebuild = true;
                //try
                //{
                //  if (IslandA.ConvexHullBuilder != null)
                //  {
                //    if (IslandB.ConvexHullBuilder == null || IslandA.Vertices.Length > IslandB.Vertices.Length)
                //    {
                //      ConvexHullBuilder = IslandA.ConvexHullBuilder.Clone();
                //      ConvexHullBuilder.Grow(IslandB.Vertices, vertexLimit, 0);
                //    }
                //    else
                //    {
                //      ConvexHullBuilder = IslandB.ConvexHullBuilder.Clone();
                //      ConvexHullBuilder.Grow(IslandA.Vertices, vertexLimit, 0);
                //    }
                //    rebuild = false;
                //  }
                //  else if (IslandB.ConvexHullBuilder != null)
                //  {
                //    ConvexHullBuilder = IslandB.ConvexHullBuilder.Clone();
                //    ConvexHullBuilder.Grow(IslandA.Vertices, vertexLimit, 0);
                //    rebuild = false;
                //  }
                //}
                //catch (GeometryException)
                //{
                //  rebuild = true;
                //}

                //if (rebuild)
                {
                    try
                    {
                        ConvexHullBuilder = new ConvexHullBuilder();
                        ConvexHullBuilder.Grow(Vertices, vertexLimit, 0);
                    }
                    catch (GeometryException)
                    {
                        // Hull building failed. Try again with a randomized order.
                        var random = new Random(1234567);
                        // Fisher-Yates shuffle:
                        for (int i = Vertices.Length - 1; i >= 1; i--)
                        {
                            var v = Vertices[i];
                            var j = random.NextInteger(0, i);
                            Vertices[i] = Vertices[j];
                            Vertices[j] = v;
                        }
                    }
                }

                var hullMesh = ConvexHullBuilder.Mesh.ToTriangleMesh();

                // Now, we have a reduced set of vertices.
                Vertices = hullMesh.Vertices.ToArray();

                // For larger meshes we create an AabbTree as acceleration structure.
                AabbTree <int> partition = null;
                if (hullMesh.NumberOfTriangles > 12)
                {
                    partition = new AabbTree <int>
                    {
                        GetAabbForItem         = i => hullMesh.GetTriangle(i).Aabb,
                        BottomUpBuildThreshold = 0,
                    };
                    for (int i = 0; i < hullMesh.NumberOfTriangles; i++)
                    {
                        partition.Add(i);
                    }

                    partition.Update(true);
                }

                Aabb  aabb       = Aabb;
                float aabbExtent = aabb.Extent.Length;

                // Note: For a speed-up we could skip some ray tests in the next loop and only sample
                // a few vertices if there would be a lot of tests.

                // The next loop performs ray casts against the hull mesh to determine the maximum
                // concavity. We ensure that we make only one ray cast per vertex even if a vertex
                // is shared by many triangles.
                float maxConcavity = 0;
                foreach (var triangle in IslandA.Triangles.Union(IslandB.Triangles))
                {
                    if (sampleVertices)
                    {
                        for (int i = 0; i < triangle.Vertices.Length; i++)
                        {
                            // Each vertex can be shared by several triangles of the current islands.
                            // Therefore, we check the edges that contain this vertex. If an edge neighbor
                            // is in the same island, we make sure that the vertex concavity is computed only once
                            // in the triangle with the smallest Id.
                            var neighbor0 = triangle.Neighbors[(i + 1) % 3];
                            var neighbor1 = triangle.Neighbors[(i + 2) % 3];

                            if (neighbor0 != null &&
                                (neighbor0.Island == IslandA || neighbor0.Island == IslandB) &&
                                triangle.Id > neighbor0.Id)
                            {
                                // No need to test: The neighbor is in the same islands and this triangle Id is larger.
                                continue;
                            }

                            if (neighbor1 != null &&
                                (neighbor1.Island == IslandA || neighbor1.Island == IslandB) &&
                                triangle.Id > neighbor1.Id)
                            {
                                // No need to test: The neighbor is in the same islands and this triangle Id is larger.
                                continue;
                            }

                            var position = triangle.Vertices[i];
                            var normal   = triangle.VertexNormals[i];

                            // Degenerate triangles are ignored.
                            if (normal.IsNumericallyZero)
                            {
                                continue;
                            }

                            // Shoot a ray from outside the hull mesh to the vertex.
                            float    hitDistance;
                            Vector3F rayOrigin = position + normal * aabbExtent;
                            float    rayLength = (position - rayOrigin).Length;
                            var      ray       = new Ray(rayOrigin, -normal, rayLength);
                            if (partition != null)
                            {
                                // Use AABB tree for better performance.
                                foreach (var triangleIndex in partition.GetOverlaps(ray))
                                {
                                    var candidateTriangle = hullMesh.GetTriangle(triangleIndex);
                                    var hit = GeometryHelper.GetContact(ray, candidateTriangle, false, out hitDistance);
                                    if (hit)
                                    {
                                        // The concavity is the distance from the hull to the vertex.
                                        float concavity = rayLength - hitDistance;
                                        maxConcavity = Math.Max(maxConcavity, concavity);
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                // No AABB tree.
                                var hit = GeometryHelper.GetContact(hullMesh, ray, out hitDistance);
                                if (hit)
                                {
                                    float concavity = rayLength - hitDistance;
                                    maxConcavity = Math.Max(maxConcavity, concavity);
                                }
                            }
                        }
                    }

                    if (sampleCenters)
                    {
                        // Test: Also shoot from the triangle centers.
                        var center = (triangle.Vertices[0] + triangle.Vertices[1] + triangle.Vertices[2]) / 3;
                        var normal = triangle.Normal;

                        // Degenerate triangles are ignored.
                        if (normal.IsNumericallyZero)
                        {
                            continue;
                        }

                        // Shoot a ray from outside the hull mesh to the vertex.
                        float    hitDistance;
                        Vector3F rayOrigin = center + normal * aabbExtent;
                        float    rayLength = (center - rayOrigin).Length;
                        var      ray       = new Ray(rayOrigin, -normal, rayLength);
                        if (partition != null)
                        {
                            // Use AABBTree for better performance.
                            foreach (var triangleIndex in partition.GetOverlaps(ray))
                            {
                                var candidateTriangle = hullMesh.GetTriangle(triangleIndex);
                                var hit = GeometryHelper.GetContact(ray, candidateTriangle, false, out hitDistance);
                                if (hit)
                                {
                                    // The concavity is the distance from the hull to the vertex.
                                    float concavity = rayLength - hitDistance;
                                    maxConcavity = Math.Max(maxConcavity, concavity);
                                    break;
                                }
                            }
                        }
                        else
                        {
                            // No AABBTree.
                            var hit = GeometryHelper.GetContact(hullMesh, ray, out hitDistance);
                            if (hit)
                            {
                                float concavity = rayLength - hitDistance;
                                maxConcavity = Math.Max(maxConcavity, concavity);
                            }
                        }
                    }
                }

                return(maxConcavity);
            }
            catch (GeometryException)
            {
                // Ouch, the convex hull generation failed. This can happen for degenerate inputs
                // and numerical problems in the convex hull builder.
                ConvexHullBuilder = null;
                return(0);
            }
        }
Beispiel #12
0
        public void NaNWithValidation()
        {
            GlobalSettings.ValidationLevel = 0xff;

              var partition = new AabbTree<int>();
              partition.EnableSelfOverlaps = true;
              partition.GetAabbForItem = GetAabbForItem;

              partition.Add(1);
              partition.Add(4);
              partition.Add(2);
              partition.Add(3);

              // Full rebuild.
              Assert.Throws<GeometryException>(() => partition.Update(true));

              partition = new AabbTree<int>();
              partition.EnableSelfOverlaps = true;
              partition.GetAabbForItem = GetAabbForItem;

              partition.Add(1);
              partition.Add(2);
              partition.Add(3);
              partition.Update(true);
              partition.Add(4);

              // Partial rebuild.
              Assert.Throws<GeometryException>(() => partition.Update(false));
        }
        /// <summary>
        /// Compresses an AABB tree.
        /// </summary>
        /// <param name="compressedNodes">The list of compressed AABB nodes.</param>
        /// <param name="uncompressedNode">The root of the uncompressed AABB tree.</param>
        private void CompressTree(List<Node> compressedNodes, AabbTree<int>.Node uncompressedNode)
        {
            if (uncompressedNode.IsLeaf)
              {
            // Compress leaf node.
            Node node = new Node();
            node.Item = uncompressedNode.Item;
            SetAabb(ref node, uncompressedNode.Aabb);
            compressedNodes.Add(node);
              }
              else
              {
            // Node is internal node.
            int currentIndex = compressedNodes.Count;
            Node node = new Node();
            SetAabb(ref node, uncompressedNode.Aabb);
            compressedNodes.Add(node);

            // Compress child nodes.
            CompressTree(compressedNodes, uncompressedNode.LeftChild);
            CompressTree(compressedNodes, uncompressedNode.RightChild);

            // Set escape offset. (Escape offset = size of subtree)
            node.EscapeOffset = compressedNodes.Count - currentIndex;
            compressedNodes[currentIndex] = node;
              }
        }
 public static void RayCast(Vector3 from, Vector3 to, AabbTree <RayMarchedShape> .RayCastCallback callback)
 {
     s_tree.RayCast(from, to, callback);
 }
 public static void Query(Aabb bounds, AabbTree <RayMarchedShape> .QueryCallbcak callback)
 {
     s_tree.Query(bounds, callback);
 }