/**
  * Creates the levels higher than the given level
  *
  * @param boundablesOfALevel the level to build on
  * @param level the level of the Boundables, or -1 if the boundables are item boundables (that is,
  *     below level 0)
  * @return the root, which may be a ParentNode or a LeafNode
  */
 private AbstractNode createHigherLevels(List boundablesOfALevel, int level) {
   Assert.isTrue(!boundablesOfALevel.isEmpty());
   List parentBoundables = createParentBoundables(boundablesOfALevel, level + 1);
   if (parentBoundables.size() == 1) {
     return (AbstractNode) parentBoundables.get(0);
   }
   return createHigherLevels(parentBoundables, level + 1);
 }
 private void query(Object searchBounds, AbstractNode node, ItemVisitor visitor) {
   List childBoundables = node.getChildBoundables();
   for (int i = 0; i < childBoundables.size(); i++) {
     Boundable childBoundable = (Boundable) childBoundables.get(i);
     if (!getIntersectsOp().intersects(childBoundable.getBounds(), searchBounds)) {
       continue;
     }
     if (childBoundable instanceof AbstractNode) {
       query(searchBounds, (AbstractNode) childBoundable, visitor);
     } else if (childBoundable instanceof ItemBoundable) {
       visitor.visitItem(((ItemBoundable) childBoundable).getItem());
     } else {
       Assert.shouldNeverReachHere();
     }
   }
 }
 protected AbstractNode lastNode(List nodes) {
   return (AbstractNode) nodes.get(nodes.size() - 1);
 }