Example #1
0
        public void getOverlappingNodes_Test(double min, double max, int[] result)
        {
            AABBTree tree = getInitData1();

            Assert.NotNull(tree);

            List <AABBExternalNode> overlappingNodes = new List <AABBExternalNode>();
            var queryExtents = new AABBBox(new Point3(min, min, min), new Point3(max, max, max));
            var actualCount  = tree.getOverlappingNodes(queryExtents, overlappingNodes);

            Assert.Equal(result.Length, actualCount);
            var actualRes = overlappingNodes.Select(n => (int)n.Data).ToList();

            actualRes.Sort();
            Assert.Equal(result, actualRes);
        }
Example #2
0
        public void add(AABBExternalNode externalNode, AABBBox extents)
        {
            var endNode = this.getNodeCount();

            externalNode.spatialIndex = endNode - 1;

            var node = new AABBTreeNode(new AABBBox(), 1, null);

            node.escapeNodeOffset = 1;
            node.externalNode     = externalNode;
            var copyExtents = node.extents;

            copyExtents[0] = extents[0];
            copyExtents[1] = extents[1];
            copyExtents[2] = extents[2];
            copyExtents[3] = extents[3];
            copyExtents[4] = extents[4];
            copyExtents[5] = extents[5];

            this.nodes.Add(node);
            this.needsRebuild      = true;
            this.numAdds          += 1;
            this.numExternalNodes += 1;
        }
Example #3
0
 public int getOverlappingNodes(AABBBox queryExtents, List <AABBExternalNode> overlappingNodes)
 {
     if (this.numExternalNodes > 0)
     {
         var          queryMinX    = queryExtents[0];
         var          queryMinY    = queryExtents[1];
         var          queryMinZ    = queryExtents[2];
         var          queryMaxX    = queryExtents[3];
         var          queryMaxY    = queryExtents[4];
         var          queryMaxZ    = queryExtents[5];
         var          nodes        = this.nodes;
         var          endNodeIndex = this.getNodeCount();
         AABBTreeNode node;
         AABBBox      extents;
         int          endChildren;
         var          numOverlappingNodes = 0;
         var          nodeIndex           = 0;
         for (; ;)
         {
             node    = nodes[nodeIndex];
             extents = node.extents;
             var minX = extents[0];
             var minY = extents[1];
             var minZ = extents[2];
             var maxX = extents[3];
             var maxY = extents[4];
             var maxZ = extents[5];
             if (queryMinX <= maxX &&
                 queryMinY <= maxY &&
                 queryMinZ <= maxZ &&
                 queryMaxX >= minX &&
                 queryMaxY >= minY &&
                 queryMaxZ >= minZ)
             {
                 if (node.externalNode != null) // Is leaf
                 {
                     overlappingNodes.Add(node.externalNode);
                     numOverlappingNodes += 1;
                     nodeIndex           += 1;
                     if (nodeIndex >= endNodeIndex)
                     {
                         break;
                     }
                 }
                 else
                 {
                     if (queryMaxX >= maxX &&
                         queryMaxY >= maxY &&
                         queryMaxZ >= maxZ &&
                         queryMinX <= minX &&
                         queryMinY <= minY &&
                         queryMinZ <= minZ)
                     {
                         endChildren = (nodeIndex + node.escapeNodeOffset);
                         nodeIndex  += 1;
                         do
                         {
                             node = nodes[nodeIndex];
                             if (node.externalNode != null) // Is leaf
                             {
                                 overlappingNodes.Add(node.externalNode);
                                 numOverlappingNodes += 1;
                             }
                             nodeIndex += 1;
                         }while (nodeIndex < endChildren);
                         if (nodeIndex >= endNodeIndex)
                         {
                             break;
                         }
                     }
                     else
                     {
                         nodeIndex += 1;
                     }
                 }
             }
             else
             {
                 nodeIndex += node.escapeNodeOffset;
                 if (nodeIndex >= endNodeIndex)
                 {
                     break;
                 }
             }
         }
         return(numOverlappingNodes);
     }
     else
     {
         return(0);
     }
 }
Example #4
0
        public void update(AABBExternalNode externalNode, AABBBox extents)
        {
            var index = externalNode.spatialIndex;

            if (index >= 0)
            {
                var min0 = extents[0];
                var min1 = extents[1];
                var min2 = extents[2];
                var max0 = extents[3];
                var max1 = extents[4];
                var max2 = extents[5];

                var needsRebuild = this.needsRebuild;
                var needsRebound = this.needsRebound;
                var nodes        = this.nodes;
                var node         = nodes[index];
                Debug.Assert(node.externalNode == externalNode);
                var nodeExtents = node.extents;

                var doUpdate = (needsRebuild ||
                                needsRebound ||
                                nodeExtents[0] > min0 ||
                                nodeExtents[1] > min1 ||
                                nodeExtents[2] > min2 ||
                                nodeExtents[3] < max0 ||
                                nodeExtents[4] < max1 ||
                                nodeExtents[5] < max2);

                nodeExtents[0] = min0;
                nodeExtents[1] = min1;
                nodeExtents[2] = min2;
                nodeExtents[3] = max0;
                nodeExtents[4] = max1;
                nodeExtents[5] = max2;

                if (doUpdate)
                {
                    if (!needsRebuild && 1 < nodes.Count)
                    {
                        this.numUpdates += 1;
                        if (this.startUpdate > index)
                        {
                            this.startUpdate = index;
                            if (this.endUpdate < index)
                            {
                                this.endUpdate = index;
                                if (!needsRebound)
                                {
                                    // force a rebound when things change too much
                                    if ((2 * this.numUpdates) > this.numExternalNodes)
                                    {
                                        this.needsRebound = true;
                                    }
                                    else
                                    {
                                        var parent        = this.findParent(index);
                                        var parentExtents = parent.extents;
                                        if (parentExtents[0] > min0 ||
                                            parentExtents[1] > min1 ||
                                            parentExtents[2] > min2 ||
                                            parentExtents[3] < max0 ||
                                            parentExtents[4] < max1 ||
                                            parentExtents[5] < max2)
                                        {
                                            this.needsRebound = true;
                                        }
                                    }
                                }
                                else
                                {
                                    // force a rebuild when things change too much
                                    if (this.numUpdates > (3 * this.numExternalNodes))
                                    {
                                        this.needsRebuild = true;
                                        this.numAdds      = this.numUpdates;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        this.add(externalNode, extents);
                    }
                }
            }
        }
Example #5
0
        // evaluate distance factor to a node's extents from ray origin, along direction
        // use this to induce an ordering on which nodes to check.
        double?distanceExtents(AABBTreeRay ray, AABBBox extents, double upperBound)
        {
            var origin    = ray.origin;
            var direction = ray.direction;

            // values used throughout calculations.
            var o0  = origin[0];
            var o1  = origin[1];
            var o2  = origin[2];
            var d0  = direction[0];
            var d1  = direction[1];
            var d2  = direction[2];
            var id0 = 1 / d0;
            var id1 = 1 / d1;
            var id2 = 1 / d2;

            var min0 = extents[0];
            var min1 = extents[1];
            var min2 = extents[2];
            var max0 = extents[3];
            var max1 = extents[4];
            var max2 = extents[5];

            // treat origin internal to extents as 0 distance.
            if (min0 <= o0 && o0 <= max0 &&
                min1 <= o1 && o1 <= max1 &&
                min2 <= o2 && o2 <= max2)
            {
                return(0.0);
            }

            double tmin, tmax;
            double tymin, tymax;
            double del;

            if (d0 >= 0)
            {
                // Deal with cases where d0 == 0
                del  = (min0 - o0);
                tmin = ((del == 0) ? 0 : (del * id0));
                del  = (max0 - o0);
                tmax = ((del == 0) ? 0 : (del * id0));
            }
            else
            {
                tmin = ((max0 - o0) * id0);
                tmax = ((min0 - o0) * id0);
            }

            if (d1 >= 0)
            {
                // Deal with cases where d1 == 0
                del   = (min1 - o1);
                tymin = ((del == 0) ? 0 : (del * id1));
                del   = (max1 - o1);
                tymax = ((del == 0) ? 0 : (del * id1));
            }
            else
            {
                tymin = ((max1 - o1) * id1);
                tymax = ((min1 - o1) * id1);
            }

            if ((tmin > tymax) || (tymin > tmax))
            {
                return(null);
            }

            if (tymin > tmin)
            {
                tmin = tymin;
            }

            if (tymax < tmax)
            {
                tmax = tymax;
            }

            double tzmin, tzmax;

            if (d2 >= 0)
            {
                // Deal with cases where d2 == 0
                del   = (min2 - o2);
                tzmin = ((del == 0) ? 0 : (del * id2));
                del   = (max2 - o2);
                tzmax = ((del == 0) ? 0 : (del * id2));
            }
            else
            {
                tzmin = ((max2 - o2) * id2);
                tzmax = ((min2 - o2) * id2);
            }

            if ((tmin > tzmax) || (tzmin > tmax))
            {
                return(null);
            }

            if (tzmin > tmin)
            {
                tmin = tzmin;
            }

            if (tzmax < tmax)
            {
                tmax = tzmax;
            }

            if (tmin < 0)
            {
                tmin = tmax;
            }

            if (0 <= tmin && tmin < upperBound)
            {
                return(tmin);
            }

            return(null);
        }
Example #6
0
        static void Main(string[] args)
        {
            // build tree
            var tree = new AABBTree(true);

            tree.add(new AABBExternalNode()
            {
                Data = 1
            }, new AABBBox(new Point3(0, 0, 0), new Point3(10, 10, 10)));
            tree.add(new AABBExternalNode()
            {
                Data = 2
            }, new AABBBox(new Point3(5, 5, 5), new Point3(15, 15, 15)));
            tree.add(new AABBExternalNode()
            {
                Data = 3
            }, new AABBBox(new Point3(20, 20, 20), new Point3(30, 30, 30)));
            tree.add(new AABBExternalNode()
            {
                Data = 4
            }, new AABBBox(new Point3(40, 40, 40), new Point3(50, 50, 50)));
            var node = new AABBExternalNode()
            {
                Data = 6
            };

            tree.add(node, new AABBBox(new Point3(50, 50, 50), new Point3(60, 60, 60)));
            var lastNode = new AABBExternalNode()
            {
                Data = 5
            };

            tree.add(lastNode, new AABBBox(new Point3(51, 51, 51), new Point3(60, 60, 60)));

            tree.finalize();

            // remove
            tree.remove(node);
            tree.update(lastNode, new AABBBox(new Point3(51, 51, 51), new Point3(61, 61, 61)));
            tree.finalize();

            // get parent
            var parent   = tree.findParent(lastNode.spatialIndex);
            var children = tree.findChildren(1);

            // get all the overlapping pairs
            List <AABBExternalNode> overlappingNodes = new List <AABBExternalNode>();
            var count = tree.getOverlappingPairs(overlappingNodes);

            Console.WriteLine($"Node Count:{count}");
            overlappingNodes.ForEach(node => node.Print());
            overlappingNodes.Clear();

            // find overlapping nodes by bounding box
            var queryExtents = new AABBBox(new Point3(-40, -40, -40), new Point3(40, 40, 40));

            count = tree.getOverlappingNodes(queryExtents, overlappingNodes);
            Console.WriteLine($"Node Count:{count}");
            overlappingNodes.ForEach(node => node.Print());
            overlappingNodes.Clear();

            // find overlapping nodes by sphere
            count = tree.getSphereOverlappingNodes(new Point3(20, 20, 20), 21, overlappingNodes);
            Console.WriteLine($"Node Count:{count}");
            overlappingNodes.ForEach(node => node.Print());
            overlappingNodes.Clear();

            // find nodes by planes
            var normal = new Vector3(0, 0, 1);
            var plane  = new Plane3(normal.X, normal.Y, normal.Z, -20);

            count = tree.getVisibleNodes(new Plane3[] { plane }, overlappingNodes);
            Console.WriteLine($"Node Count:{count}");
            overlappingNodes.ForEach(node => node.Print());
            overlappingNodes.Clear();

            // TODO: ray test
            var ray = new AABBTreeRay()
            {
                direction = new Vector3(1, 1, 1), origin = new Point3(), maxFactor = 30
            };
            var testRes = new AABBTreeRayTest().rayTest(new AABBTree[] { tree }, ray);

            tree.clear();
        }
Example #7
0
        public AABBBox extents;               // bounding box

        public AABBTreeNode(AABBBox extents, int escapeNodeOffset, AABBExternalNode externalNode)
        {
            this.escapeNodeOffset = escapeNodeOffset;
            this.externalNode     = externalNode;
            this.extents          = extents;
        }