private boolean remove(Object searchBounds, AbstractNode node, Object item) {
    // first try removing item from this node
    boolean found = removeItem(node, item);
    if (found) return true;

    AbstractNode childToPrune = null;
    // next try removing item from lower nodes
    for (Iterator i = node.getChildBoundables().iterator(); i.hasNext(); ) {
      Boundable childBoundable = (Boundable) i.next();
      if (!getIntersectsOp().intersects(childBoundable.getBounds(), searchBounds)) {
        continue;
      }
      if (childBoundable instanceof AbstractNode) {
        found = remove(searchBounds, (AbstractNode) childBoundable, item);
        // if found, record child for pruning and exit
        if (found) {
          childToPrune = (AbstractNode) childBoundable;
          break;
        }
      }
    }
    // prune child if possible
    if (childToPrune != null) {
      if (childToPrune.getChildBoundables().isEmpty()) {
        node.getChildBoundables().remove(childToPrune);
      }
    }
    return found;
  }
 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();
     }
   }
 }