private Set<Entry<T>> validateChildrenSize() { boolean possibleMerge = true; Set<Entry<T>> childrenInLeaf = new HashSet<Entry<T>>(); if ( !isLeaf() ) { for ( int i = 0; i < children.length; ++i ) { QTree<T> n = children[i]; if ( n != null ) { if ( n.isLeaf() ) { // if one of the other children wasn't a leaf, don't bother getting the objects if ( possibleMerge ) { n.getObjects( n.envelope, childrenInLeaf ); } // the child is a leaf but does not contain any leafObjects, no need to keep it in memory. if ( n.leafObjects == null && n.objectsCoveringEnv == null ) { children[i] = null; } } else { // no merging, but check other children if they can be deleted. possibleMerge = false; } } } } return possibleMerge ? childrenInLeaf : null; }
/** * */ @Override public void clear() { if ( isLeaf() ) { if ( leafObjects != null ) { leafObjects.clear(); leafObjects = null; } } else { for ( QTree<T> n : children ) { if ( n != null ) { n.clear(); } } children = null; } }
@Override public String toString() { StringBuilder sb = new StringBuilder( "{min(" ); for ( int i = 0; i < getMaxOffset(); ++i ) { sb.append( entryEnv[i] ); if ( ( i + 1 ) < getMaxOffset() ) { sb.append( "," ); } } sb.append( "), max(" ); for ( int i = 0; i < getMaxOffset(); ++i ) { sb.append( entryEnv[getMaxOffset() + i] ); if ( ( i + 1 ) < getMaxOffset() ) { sb.append( "," ); } } sb.append( "), value:" + entryValue + "}" ); return sb.toString(); } }
/** * */ private void merge() { if ( !isLeaf() ) { Set<Entry<T>> mergableObjects = validateChildrenSize(); if ( mergableObjects != null ) { // calculate the size of the set, after removing duplicates ArrayList<Entry<T>> objects = new ArrayList<Entry<T>>( mergableObjects ); int size = mergableObjects.size() - duplicateEnvelopes( objects ); if ( size <= numberOfObjects ) { // we can merge the children. leafObjects = objects; // leafObjects.addAll( mergableObjects ); for ( QTree<T> n : children ) { if ( n != null ) { n.objectsCoveringEnv = null; n.leafObjects = null; n = null; } } children = null; } } } }
/** * @param entryEnv * @return the nodes the given envelope will intersect. */ final protected List<QTree<T>> getObjectNodes( float[] entryEnv ) { List<QTree<T>> list = new LinkedList<QTree<T>>(); // if the object covers the whole of this node if ( objectCoversEnvelope( entryEnv ) ) { list.add( this ); } else { if ( !isLeaf() ) { int[] indizes = getIndizes( entryEnv ); for ( int index : indizes ) { QTree<T> child = children[index]; // No children in that area create a new one if ( child == null ) { child = createNode( index ); children[index] = child; list.add( child ); } else { // traverse tree list.addAll( child.getObjectNodes( entryEnv ) ); } } } else { list.add( this ); } } return list; }
/** * remove the given object from the subtree of this node. * * @param object * to remove * @return true if the object could be removed from one of the subtrees. */ private boolean removeFromSubTree( T object ) { // only usable for not leafs; boolean result = false; if ( !isLeaf() ) { boolean tR = false; for ( QTree<T> node : children ) { if ( node != null ) { tR = node.removeObject( object ); if ( tR && !result ) { result = true; } } } if ( result ) { merge(); } } return result; }
private final void getObjects( float[] envelope, Set<Entry<T>> result ) { if ( intersects( this.envelope, envelope, maxOffset ) ) { if ( hasCoveringObjects() ) { result.addAll( objectsCoveringEnv ); } if ( isLeaf() ) { if ( leafObjects != null ) { for ( Entry<T> e : leafObjects ) { if ( intersects( envelope, e.entryEnv, maxOffset ) && !result.contains( e.entryValue ) ) { result.add( e ); } } } } else { for ( QTree<T> n : children ) { if ( n != null ) { n.getObjects( envelope, result ); } } } } }
/** * @param object */ private boolean removeObject( T object ) { boolean result = false; if ( objectsCoveringEnv != null ) { result = removeFromCovering( object ); } // none of the totally covering objects matched the given object, try the subtrees. if ( !result ) { if ( isLeaf() ) { result = removeFromLeaf( object ); } else { result = removeFromSubTree( object ); } } return result; }
/** * @param envelope * of the object * @param object * to insert * @return true if the object was inserted, false otherwise. */ @Override public boolean insert( float[] envelope, T object ) { if ( object != null ) { if ( intersects( this.envelope, envelope, maxOffset ) ) { Entry<T> obj = new Entry<T>( envelope, object ); if ( isLeaf() ) { addObject( obj ); } else { List<QTree<T>> treeNodes = getObjectNodes( obj.entryEnv ); for ( QTree<T> node : treeNodes ) { if ( node != null ) { node.addObject( obj ); } } } return true; } } return false; }
/** * @param out * @param id * @param level * @param sonID * @throws IOException */ public void outputAsDot( Writer out, String id, int level, int sonID ) throws IOException { if ( isLeaf() ) { GraphvizDot.writeVertex( id, getDotVertex( level, sonID, true ), out ); } else { GraphvizDot.writeVertex( id, getDotVertex( level, sonID, false ), out ); for ( int i = 0; i < 4; ++i ) { QTree<T> child = children[i]; if ( child != null ) { String newID = id + i; child.outputAsDot( out, newID, level + 1, i ); GraphvizDot.writeEdge( id, newID, null, out ); } } } }