Example #1
0
 private void Query(object searchBounds,
                    AbstractNode node, ArrayList matches)
 {
     for (IEnumerator i = node.ChildBoundables.GetEnumerator(); i.MoveNext();)
     {
         IBoundable childBoundable = (IBoundable)i.Current;
         if (!GetIntersectsOp().Intersects(childBoundable.Bounds, searchBounds))
         {
             continue;
         }
         AbstractNode abstractNode = childBoundable as AbstractNode;
         if (abstractNode != null)
         {
             Query(searchBounds, abstractNode, matches);
         }
         else
         {
             ItemBoundable objItem = childBoundable as ItemBoundable;
             if (objItem != null)
             {
                 matches.Add(objItem.Item);
             }
             else
             {
                 Debug.Assert(false, "Should never reach here");
             }
         }
     }
 }
Example #2
0
        /// <summary>
        /// Calculates the bounding box, in world space, for the given path to a DomNode.
        /// Typically this comes from a selection set.</summary>
        /// <param name="path">Path</param>
        /// <returns>The bounding box in world space, or a new empty uninitialized box
        /// if no IBoundable could be found</returns>
        public static Box CalcWorldBoundingBox(Path <DomNode> path)
        {
            // Find the lowest level IBoundable in the given path.
            int        startIndex = path.Count;
            IBoundable boundable  = null;

            while (--startIndex >= 0)
            {
                if (path[startIndex] != null)
                {
                    boundable = path[startIndex].As <IBoundable>();

                    if (boundable != null)
                    {
                        break;
                    }
                }
            }
            if (boundable == null)
            {
                return(new Box());
            }

            // startIndex is the index of the lowest-level IBoundable that we could find.
            //  But we want to calculate the transform down to boundable's parent because
            //  the bounding box needs to be transformed by the parent's transform, not
            //  boundable's transform (if any).
            Matrix4F localToWorld = CalcPathTransform(path, startIndex - 1);

            Box box = boundable.BoundingBox;

            box.Transform(localToWorld);
            return(box);
        }
Example #3
0
        /// <summary>
        /// Sorts the childBoundables then divides them into groups of size M, where
        /// M is the node capacity.
        /// </summary>
        protected virtual ArrayList CreateParentBoundables(ArrayList childBoundables,
                                                           int newLevel)
        {
            Debug.Assert(!(childBoundables.Count == 0));

            ArrayList parentBoundables = new ArrayList();

            parentBoundables.Add(CreateNode(newLevel));

            ArrayList sortedChildBoundables = new ArrayList(childBoundables);

            sortedChildBoundables.Sort(Comparator);

            for (IEnumerator i = sortedChildBoundables.GetEnumerator(); i.MoveNext();)
            {
                IBoundable childBoundable = (IBoundable)i.Current;
                if (LastNode(parentBoundables).ChildBoundables.Count == NodeCapacity)
                {
                    parentBoundables.Add(CreateNode(newLevel));
                }

                LastNode(parentBoundables).AddChildBoundable(childBoundable);
            }

            return(parentBoundables);
        }
Example #4
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="level">-1 to get items.</param>
 /// <param name="top"></param>
 /// <param name="boundables"></param>
 private void BoundablesAtLevel(int level, AbstractNode top, ref IList boundables)
 {
     Assert.IsTrue(level > -2);
     if (top.Level == level)
     {
         boundables.Add(top);
         return;
     }
     for (IEnumerator i = top.ChildBoundables.GetEnumerator(); i.MoveNext();)
     {
         IBoundable boundable = (IBoundable)i.Current;
         if (boundable is AbstractNode)
         {
             BoundablesAtLevel(level, (AbstractNode)boundable, ref boundables);
         }
         else
         {
             Assert.IsTrue(boundable is ItemBoundable);
             if (level == -1)
             {
                 boundables.Add(boundable);
             }
         }
     }
     return;
 }
        /// <summary>
        /// Computes the distance between two <see cref="IGeometry"/> items,
        /// using the <see cref="IGeometry.Distance(IGeometry)"/> method.
        /// </summary>
        /// <param name="item1">An item which is a geometry.</param>
        /// <param name="item2">An item which is a geometry.</param>
        /// <exception cref="InvalidCastException">if either item is not a Geometry</exception>
        /// <returns>The distance between the two items.</returns>
        public double Distance(IBoundable <Envelope, IGeometry> item1, IBoundable <Envelope, IGeometry> item2)
        {
            var g1 = item1.Item;
            var g2 = item2.Item;

            return(g1.Distance(g2));
        }
Example #6
0
        /// <summary>
        /// Sorts the childBoundables then divides them into groups of size M, where
        /// M is the node capacity.
        /// </summary>
        /// <param name="childBoundables"></param>
        /// <param name="newLevel"></param>
        /// <returns></returns>
        protected virtual ArrayList CreateParentBoundables(ArrayList childBoundables, int newLevel)
        {
            //Assert.isTrue(!childBoundables.isEmpty());
            if (childBoundables.Count == 0)
            {
                throw new InvalidOperationException("childBoundables is empty.");
            }
            ArrayList parentBoundables = new ArrayList();

            parentBoundables.Add(CreateNode(newLevel));
            ArrayList sortedChildBoundables = new ArrayList(childBoundables);

            sortedChildBoundables.Sort(GetComparator());
            //for (Iterator i = sortedChildBoundables.iterator(); i.hasNext(); )
            foreach (object obj in sortedChildBoundables)
            {
                IBoundable childBoundable = (IBoundable)obj;
                if (LastNode(parentBoundables).GetChildBoundables().Count == _nodeCapacity)
                {
                    parentBoundables.Add(CreateNode(newLevel));
                }
                LastNode(parentBoundables).AddChildBoundable(childBoundable);
            }
            return(parentBoundables);
        }
Example #7
0
 /**
  * @param level -1 to get items
  */
 private void BoundablesAtLevel(int level, AbstractNode top, ArrayList boundables)
 {
     //Assert.isTrue(level > -2);
     if (level <= -2)
     {
         throw new InvalidOperationException();
     }
     if (top.GetLevel() == level)
     {
         boundables.Add(top);
         return;
     }
     //for (Iterator i = top.GetChildBoundables().iterator(); i.hasNext(); )
     foreach (object obj in top.GetChildBoundables())
     {
         IBoundable boundable = (IBoundable)obj;
         if (boundable is AbstractNode)
         {
             BoundablesAtLevel(level, (AbstractNode)boundable, boundables);
         }
         else
         {
             //Assert.isTrue(boundable is ItemBoundable);
             if (!(boundable is ItemBoundable))
             {
                 throw new InvalidOperationException();
             }
             if (level == -1)
             {
                 boundables.Add(boundable);
             }
         }
     }
     return;
 }
Example #8
0
 private void Query(object searchBounds, AbstractNode node, ArrayList matches)
 {
     //for (Iterator i = node.getChildBoundables().iterator(); i.hasNext(); )
     foreach (object obj in node.GetChildBoundables())
     {
         IBoundable childBoundable = (IBoundable)obj;
         if (!GetIntersectsOp().Intersects(childBoundable.GetBounds(), searchBounds))
         {
             continue;
         }
         if (childBoundable is AbstractNode)
         {
             Query(searchBounds, (AbstractNode)childBoundable, matches);
         }
         else if (childBoundable is ItemBoundable)
         {
             matches.Add(((ItemBoundable)childBoundable).GetItem());
         }
         else
         {
             //Assert.shouldNeverReachHere();
             throw new InvalidOperationException("Should never reach here.");
         }
     }
 }
Example #9
0
 private void Query(object searchBounds, AbstractNode node,
                    ISpatialIndexVisitor visitor)
 {
     for (IEnumerator i = node.ChildBoundables.GetEnumerator();
          i.MoveNext();)
     {
         IBoundable childBoundable = (IBoundable)i.Current;
         if (!GetIntersectsOp().Intersects(childBoundable.Bounds, searchBounds))
         {
             continue;
         }
         if (childBoundable is AbstractNode)
         {
             Query(searchBounds, (AbstractNode)childBoundable, visitor);
         }
         else if (childBoundable is ItemBoundable)
         {
             visitor.VisitItem(((ItemBoundable)childBoundable).Item);
         }
         else
         {
             Debug.Assert(true);
         }
     }
 }
Example #10
0
        /// <param name="level">-1 to get items</param>
        private void BoundablesAtLevel(int level, AbstractNode top, ArrayList boundables)
        {
            Debug.Assert(level > -2);
            if (top.Level == level)
            {
                boundables.Add(top);
                return;
            }

            for (IEnumerator i = top.ChildBoundables.GetEnumerator(); i.MoveNext();)
            {
                IBoundable   boundable    = (IBoundable)i.Current;
                AbstractNode abstractNode = boundable as AbstractNode;
                if (abstractNode != null)
                {
                    BoundablesAtLevel(level, abstractNode, boundables);
                }
                else
                {
                    Debug.Assert(boundable is ItemBoundable);
                    if (level == -1)
                    {
                        boundables.Add(boundable);
                    }
                }
            }
            return;
        }
Example #11
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="childBoundables">Must be sorted by the x-value of the envelope midpoints.</param>
        /// <param name="sliceCount"></param>
        protected IList[] VerticalSlices(IList childBoundables, int sliceCount)
        {
            int sliceCapacity = (int)Math.Ceiling(childBoundables.Count / (double)sliceCount);

            IList[]     slices = new IList[sliceCount];
            IEnumerator i      = childBoundables.GetEnumerator();

            for (int j = 0; j < sliceCount; j++)
            {
                slices[j] = new ArrayList();
                int boundablesAddedToSlice = 0;

                /*
                 *          Diego Guidi says:
                 *          the line below introduce an error:
                 *          the first element at the iteration (not the first) is lost!
                 *          This is simply a different implementation of Iteration in .NET against Java
                 */
                // while (i.MoveNext() && boundablesAddedToSlice < sliceCapacity)
                while (boundablesAddedToSlice < sliceCapacity && i.MoveNext())
                {
                    IBoundable childBoundable = (IBoundable)i.Current;
                    slices[j].Add(childBoundable);
                    boundablesAddedToSlice++;
                }
            }
            return(slices);
        }
Example #12
0
        private void Expand(IBoundable <Envelope, TItem> bndComposite, IBoundable <Envelope, TItem> bndOther, bool isFlipped,
                            PriorityQueue <BoundablePair <TItem> > priQ, double minDistance)
        {
            var children = ((AbstractNode <Envelope, TItem>)bndComposite).ChildBoundables;

            foreach (var child in children)
            {
                BoundablePair <TItem> bp;
                if (isFlipped)
                {
                    bp = new BoundablePair <TItem>(bndOther, child, _itemDistance);
                }
                else
                {
                    bp = new BoundablePair <TItem>(child, bndOther, _itemDistance);
                }

                // only add to queue if this pair might contain the closest points
                // MD - it's actually faster to construct the object rather than called distance(child, bndOther)!
                if (bp.Distance < minDistance)
                {
                    priQ.Add(bp);
                }
            }
        }
Example #13
0
        //private double _maxDistance = -1.0;

        /// <summary>
        /// Creates an instance of this class with the given <see cref="IBoundable{Envelope, TItem}"/>s and the <see cref="IItemDistance{Envelope, TItem}"/> function.
        /// </summary>
        /// <param name="boundable1">The first boundable</param>
        /// <param name="boundable2">The second boundable</param>
        /// <param name="itemDistance">The item distance function</param>
        public BoundablePair(IBoundable <Envelope, TItem> boundable1, IBoundable <Envelope, TItem> boundable2, IItemDistance <Envelope, TItem> itemDistance)
        {
            _boundable1   = boundable1;
            _boundable2   = boundable2;
            _itemDistance = itemDistance;
            _distance     = GetDistance();
        }
 public static void DrawBorder(this IBoundable boundable, SpriteBatch b)
 {
     b.Draw(AssetManager.SquareTexture, new Rectangle(boundable.Bounds.X - StaticTextElement.HighlightWidth, boundable.Bounds.Y - StaticTextElement.HighlightWidth, StaticTextElement.HighlightWidth / 2, boundable.Bounds.Height + StaticTextElement.HighlightWidth), Color.White);
     b.Draw(AssetManager.SquareTexture, new Rectangle(boundable.Bounds.X - StaticTextElement.HighlightWidth, boundable.Bounds.Y - StaticTextElement.HighlightWidth, boundable.Bounds.Width + StaticTextElement.HighlightWidth, StaticTextElement.HighlightWidth / 2), Color.White);
     b.Draw(AssetManager.SquareTexture, new Rectangle(boundable.Bounds.X + boundable.Bounds.Width, boundable.Bounds.Y - StaticTextElement.HighlightWidth, StaticTextElement.HighlightWidth / 2, boundable.Bounds.Height + StaticTextElement.HighlightWidth), Color.White);
     b.Draw(AssetManager.SquareTexture, new Rectangle(boundable.Bounds.X - StaticTextElement.HighlightWidth, boundable.Bounds.Y + boundable.Bounds.Height, boundable.Bounds.Width + (int)(StaticTextElement.HighlightWidth * 1.5), StaticTextElement.HighlightWidth / 2), Color.White);
 }
 public RadiusSearchQuery(int Radius, IBoundable Mapbound, ISearchable tree)
 {
     _radius  = Radius;
     _width   = _height = _radius;
     MapBound = Mapbound;
     Tree     = tree;
 }
        private IEnumerable <Vector3> _GetVolumePoints()
        {
            foreach (var obj in _objects)
            {
                IBoundable bound = obj as IBoundable;
                if (bound == null)
                {
                    continue;
                }

                var boundingBox    = bound.BoundingBox;
                var boundingSphere = bound.BoundingSphere;
                if (boundingBox != null)
                {
                    BoxBuilder box = new BoxBuilder(2, 2, 2);

                    for (int i = 0; i < box.Vertices.Length; i++)
                    {
                        var mat = Matrix.Scale(boundingBox.Extends) * boundingBox.GlobalPose;
                        yield return(Vector3.Transform(box.Vertices[i].Position, mat));
                    }
                }
                else if (boundingSphere.Radius > 0)
                {
                    SphereBuilder sphere = new SphereBuilder(16, 16, boundingSphere.Radius);
                    for (int i = 0; i < sphere.Vertices.Length; i++)
                    {
                        var mat = Matrix.Translate(boundingSphere.Center);
                        yield return(Vector3.Transform(sphere.Vertices[i].Position, mat));
                    }
                }
            }
        }
Example #17
0
        private DomNode CreatePrefab(IEnumerable <IGameObject> gobs)
        {
            UniqueNamer uniqueNamer = new UniqueNamer();

            DomNode[]          temp     = new DomNode[1];
            List <IGameObject> copyList = new List <IGameObject>();
            AABB bound = new AABB();

            foreach (IGameObject gameObject in SelectedGobs)
            {
                IBoundable boundable = gameObject.As <IBoundable>();
                bound.Extend(boundable.BoundingBox);
                Matrix4F world = TransformUtils.ComputeWorldTransform(gameObject);
                temp[0] = gameObject.As <DomNode>();
                DomNode[] copies = DomNode.Copy(temp);
                copies[0].InitializeExtensions();
                IGameObject copy = copies[0].As <IGameObject>();
                copy.Name = uniqueNamer.Name(copy.Name);
                TransformUtils.SetTransform(copy, world);
                copyList.Add(copy);
            }

            DomNode prefab = new DomNode(Schema.prefabType.Type, Schema.prefabRootElement);
            var     list   = prefab.GetChildList(Schema.prefabType.gameObjectChild);
            Vec3F   center = bound.Center;

            foreach (IGameObject gob in copyList)
            {
                gob.Translation = gob.Translation - center;
                gob.UpdateTransform();
                list.Add(gob.As <DomNode>());
            }
            return(prefab);
        }
Example #18
0
        /// <summary>
        /// Adds a game object to those being tracked by the
        /// axis list
        /// </summary>
        /// <param name="gameObject">The game object to track</param>
        public void AddGameObject(IBoundable gameObject)
        {
            var box = new Box()
            {
                GameObject = gameObject
            };
            EndPoint start = new EndPoint()
            {
                Box     = box,
                IsStart = true,
                Value   = gameObject.Bounds.X
            };

            box.Start = start;
            EndPoint end = new EndPoint()
            {
                Box     = box,
                IsStart = false,
                Value   = gameObject.Bounds.X + gameObject.Bounds.Width
            };

            box.End = end;
            boxes.Add(gameObject, box);
            endPoints.Add(start);
            endPoints.Add(end);
            Sort();
        }
Example #19
0
        public void RemoveGameObject(IBoundable gameObject)
        {
            var box = boxes[gameObject];

            endPoints.Remove(box.Start);
            endPoints.Remove(box.End);
            //boxes[gameObject] = null;
        }
Example #20
0
        /// <summary>
        /// Updates the provided game object's position in the axis list
        /// </summary>
        /// <param name="gameObject">The updated game object</param>
        public void UpdateGameObject(IBoundable gameObject)
        {
            var box = boxes[gameObject];

            box.Start.Value = gameObject.bounds.Y;
            box.End.Value   = gameObject.bounds.Y + gameObject.bounds.Height;
            Sort();
        }
Example #21
0
        /// <summary>
        /// Updates the provided game object's position in the axis list
        /// </summary>
        /// <param name="gameObject">The updated game object</param>
        public void UpdateGameObject(IBoundable gameObject)
        {
            var box = boxes[gameObject];

            box.Start.Value = gameObject.Bounds.X;
            box.End.Value   = gameObject.Bounds.X + gameObject.Bounds.Width;
            Sort();
        }
Example #22
0
            public double Distance(IBoundable <Envelope, FacetSequence> b1, IBoundable <Envelope, FacetSequence> b2)
            {
                var fs1 = b1.Item;
                var fs2 = b2.Item;

                _minDist = Double.MaxValue;
                return(Distance(fs1, fs2));
            }
Example #23
0
 /// <summary>
 /// childBoundable  either a Node or an ItemBoundable
 /// </summary>
 /// <param name="childBoundable"></param>
 public void AddChildBoundable(IBoundable childBoundable)
 {
     //Assert.isTrue(bounds == null);
     if (_bounds == null)
     {
         throw new InvalidOperationException("Bounds cannot be null.");
     }
     _childBoundables.Add(childBoundable);
 }
Example #24
0
        private void DrawSelectionRect(IBoundable r)
        {
            var g = Context.D2DTarget;

            g.Transform = SharpDX.Matrix.Translation(r.Bounds.Left, r.Bounds.Top, 0);
            Context.SolidBrush.Color = Color.DeepSkyBlue;
            g.DrawRectangle(new RectangleF(-2, -2, r.Bounds.Width + 4, r.Bounds.Height + 4), Context.SolidBrush, 1);
            g.Transform = SharpDX.Matrix.Identity;
        }
Example #25
0
        private DomNode CreatePrototype(IEnumerable <IGameObject> gobs)
        {
            DomNode[] originals = new DomNode[1];

            List <IGameObject> copyList = new List <IGameObject>();
            AABB bound = new AABB();

            foreach (IGameObject gameObject in SelectedGobs)
            {
                IBoundable boundable = gameObject.As <IBoundable>();
                bound.Extend(boundable.BoundingBox);
                Matrix4F world = TransformUtils.ComputeWorldTransform(gameObject);
                originals[0] = gameObject.As <DomNode>();
                DomNode[]   copies = DomNode.Copy(originals);
                IGameObject copy   = copies[0].As <IGameObject>();
                TransformUtils.SetTransform(copy, world);
                copyList.Add(copy);
            }

            DomNode gobchild = null;

            if (copyList.Count > 1)
            {// create group
                IGame            game     = m_contextRegistry.GetActiveContext <IGame>();
                IGameObjectGroup gobgroup = game.CreateGameObjectGroup();
                gobgroup.Translation = bound.Center;
                gobgroup.UpdateTransform();
                Matrix4F worldInv = new Matrix4F();
                worldInv.Invert(gobgroup.Transform);
                foreach (IGameObject gob in copyList)
                {
                    Vec3F translate = gob.Translation;
                    worldInv.Transform(ref translate);
                    gob.Translation = translate;
                    gob.UpdateTransform();
                    gobgroup.GameObjects.Add(gob);
                }
                gobchild = gobgroup.As <DomNode>();
            }
            else
            {
                gobchild = copyList[0].As <DomNode>();
            }

            gobchild.InitializeExtensions();
            gobchild.As <IGameObject>().Translation = new Vec3F(0, 0, 0);

            DomNode prototype = null;

            if (gobchild != null)
            {
                prototype = new DomNode(Schema.prototypeType.Type, Schema.prototypeRootElement);
                prototype.SetChild(Schema.prototypeType.gameObjectChild, gobchild);
            }
            return(prototype);
        }
Example #26
0
 public VectorSearchQuery(IBoundable mapBound, ISearchable tree, Occupant occupant,
                          IMovementVectorProvider lightsToactivate)
 {
     MapBound          = mapBound;
     Tree              = tree;
     _occupant         = occupant;
     _width            = 30;
     _height           = 60;
     _lightsToActivate = lightsToactivate;
 }
Example #27
0
        public void RemoveGameObject(IBoundable gameObject)
        {
            var box = boxes[gameObject];

            box.Start.Value = gameObject.bounds.Y;
            box.End.Value   = gameObject.bounds.Y + gameObject.bounds.Height;

            boxes.Remove(gameObject);
            endPoints.Remove(box.Start);
            endPoints.Remove(box.End);
        }
Example #28
0
        private DomNode CreatePrefab(IEnumerable <object> gobs)
        {
            UniqueNamer uniqueNamer = new UniqueNamer();

            DomNode[] temp     = new DomNode[1];
            var       copyList = new List <object>();
            AABB      bound    = new AABB();

            foreach (var gameObject in SelectedGobs)
            {
                IBoundable boundable = gameObject.As <IBoundable>();
                bound.Extend(boundable.BoundingBox);

                var trans = gameObject.As <ITransformable>();
                var world = (trans != null) ? TransformUtils.ComputeWorldTransform(trans) : Matrix4F.Identity;

                temp[0] = gameObject.As <DomNode>();
                DomNode[] copies = DomNode.Copy(temp);
                copies[0].InitializeExtensions();

                var nameable = copies[0].As <INameable>();
                if (nameable != null)
                {
                    nameable.Name = uniqueNamer.Name(nameable.Name);
                }

                var copyTrans = copies[0].As <ITransformable>();
                if (copyTrans != null)
                {
                    TransformUtils.SetTransform(copyTrans, world);
                }
                copyList.Add(copies[0]);
            }

            DomNode prefab = new DomNode(Schema.prefabType.Type, Schema.prefabRootElement);
            var     list   = prefab.GetChildList(Schema.prefabType.gameObjectChild);
            Vec3F   center = bound.Center;

            foreach (var gob in copyList)
            {
                var trans = gob.As <ITransformable>();
                if (trans != null)
                {
                    trans.Translation = trans.Translation - center;
                    trans.UpdateTransform();
                }
                var node = gob.As <DomNode>();
                if (node != null)
                {
                    list.Add(node);
                }
            }
            return(prefab);
        }
Example #29
0
 private void DrawSelectionRect(Group g)
 {
     foreach (var d in g.Childs)
     {
         IBoundable r = d as IBoundable;
         if (r != null)
         {
             DrawSelectionRect(r);
         }
     }
 }
Example #30
0
            public int Compare(IBoundable <Interval, TItem> o1, IBoundable <Interval, TItem> o2)
            {
                double c1 = o1.Bounds.Centre;
                double c2 = o2.Bounds.Centre;

                return(c1.CompareTo(c2));

                /*
                 * return CompareDoubles(((Interval)((IBoundable)o1).Bounds).Centre,
                 *                    ((Interval)((IBoundable)o2).Bounds).Centre);
                 */
            }
        private static void addBounds(IBoundable<Envelope, IGeometry> bnd, List<IGeometry>  bounds,
            IGeometryFactory factory)
        {
            // don't include bounds of leaf nodes
            if (!(bnd is AbstractNode<Envelope, IGeometry>)) return;

            var env = (Envelope)bnd.Bounds;
            bounds.Add(factory.ToGeometry(env));
            if (bnd is AbstractNode<Envelope, IGeometry>) {
                var node = (AbstractNode<Envelope, IGeometry>)bnd;
                var children = node.ChildBoundables;
                foreach (var child in children)
                {
                    addBounds(child, bounds, factory);
                }
            }
        }
Example #32
0
 /// <summary>
 /// Adds either an AbstractNode, or if this is a leaf node, a data object
 /// (wrapped in an ItemBoundable).
 /// </summary>
 /// <param name="childBoundable"></param>
 public virtual void AddChildBoundable(IBoundable childBoundable)
 {
     Assert.IsTrue(_bounds == null);
     _childBoundables.Add(childBoundable);
 }
Example #33
0
 /// <summary>
 /// Adds either an AbstractNode, or if this is a leaf node, a data object
 /// (wrapped in an ItemBoundable).
 /// </summary>
 /// <param name="childBoundable"></param>
 public void AddChildBoundable(IBoundable childBoundable) 
 {
     Assert.IsTrue(bounds == null);
     childBoundables.Add(childBoundable);
 }