/** * @param son * one of {@link QTree#LOWER_LEFT},{@link QTree#LOWER_RIGHT},{@link QTree#UP_LEFT},{@link QTree#UP_RIGHT} * @return a new QTree created from the given index. */ protected QTree<T> createNode( int son ) { float[] newEnv = bboxForSon( son ); return new QTree<T>( numberOfObjects, newEnv, (byte) ( currentDepth + 1 ) ); }
/** * Calculate the indices of the sons touching this envelope * * @param envelope * @return the indices of the sons touching the envelope */ private final int[] getIndizes( float[] envelope ) { int min = getIndex( envelope, 0 ); int max = getIndex( envelope, maxOffset ); return analyzeIndizes( envelope, min, max ); }
private final boolean hasDuplicateLocation( final float[] objectEnvelope ) { for ( Entry<T> obj : leafObjects ) { float[] second = obj.entryEnv; double minD = calcDist( objectEnvelope, second, 0, maxOffset ); double maxD = calcDist( objectEnvelope, second, maxOffset, maxOffset ); // if min and max have distance 0, then just count as one because they are equals, this might // prevent a stack overflow if ( ( minD < SPLIT_CRITERIA_EPSILON && maxD < SPLIT_CRITERIA_EPSILON ) ) { return true; } } return false; }
/** * @param object * to insert * @return true if the object was inserted, false otherwise. */ public boolean insert( T object ) { if ( object == null ) { return false; } this.maxError = Math.max( object.getErrorScalar(), maxError ); return super.insert( object.getModelBBox(), object ); }
/** * @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; }
@SuppressWarnings("unchecked") @Override public boolean insert( float[] insertBox, T object ) { if ( root == null || hasNullEntries( root ) ) { NodeEntry newEntry = new NodeEntry(); newEntry.bbox = insertBox; newEntry.entryValue = object; newEntry.next = null; root = new RTree.NodeEntry[bigM + 1]; root[0] = newEntry; return true; } insertNode( insertBox, object, root ); return true; }
@Override public void insertBulk( List<Pair<float[], T>> listOfObjects ) { for ( Pair<float[], T> p : listOfObjects ) { if ( p != null ) { insert( p.first, p.second ); } } }
/** * @param insertBox */ private double calculateAreaOverlap( float[] box1, float[] box2, float[] insertBox ) { double area1; try { area1 = calculateArea( calculateIntersection( mbbIncludeInsertBox( box1, insertBox ), box2 ) ) - calculateArea( calculateIntersection( box1, box2 ) ); } catch ( NoOverlapException e ) { area1 = 0.0; } double area2; try { area2 = calculateArea( calculateIntersection( box1, box2 ) ); } catch ( NoOverlapException e ) { area2 = 0.0; } return area1 - area2; }
/** * Find the right leaf node in which to insert * * @param insertBox * @param entries */ private NodeEntry<T>[] chooseLeaf( float[] insertBox, NodeEntry<T>[] entries, List<TraceCell<T>> trace ) { if ( entries[0].next == null ) { return entries; } int index = chooseSubtree( entries, insertBox ); trace.add( new TraceCell<T>( entries, index ) ); return chooseLeaf( insertBox, entries[index].next, trace ); }
/** * @param env * to get the leafObjects for. * @return the leafObjects which intersect with this node and or it's children, or the empty list. */ @Override public List<T> query( float[] env ) { Set<Entry<T>> r = new HashSet<Entry<T>>(); getObjects( env, r ); return getEntrySetAsResult( r ); }
/** * Calculate how much does the bbox of an entry needs to be enlarged so that it contains the bbox of the objext to * be inserted * * @param entryBbox * the bbox of the entry already in the tree * @param insertBbox * the bbox of object to be inserted * @return the area of enlargement */ private double calculateEnlargement( float[] entryBbox, float[] insertBbox ) { return calculateArea( mbbIncludeInsertBox( entryBbox, insertBbox ) ) - calculateArea( entryBbox ); }
@SuppressWarnings("unchecked") private final void split() { children = new QTree[4]; for ( Entry<T> e : leafObjects ) { List<QTree<T>> treeNodes = getObjectNodes( e.entryEnv ); for ( QTree<T> node : treeNodes ) { node.addObject( e ); } } objectsInLeaf = 0; leafObjects = null; }
private final int getIndex( float[] position, int start ) { return ( ( ( position[start] < getHalfWidth() ) ? 0 : 1 ) + ( ( position[start + 1] < getHalfHeight() ) ? 0 : 2 ) ); }
/** * Calculate "maximum perimeter" constant for a node to be split: 2 times the perimeter of the minimum bounding box * of all bigM + 1 bboxes minus the shortest axis length * * @param boxes */ private double calculatePerimMax( float[][] boxes ) { float[] overfilledBox = mbb( boxes ); double result = 2 * calculatePerimeter( overfilledBox ); double xLength = 2 * ( overfilledBox[2] - overfilledBox[0] ); double yLength = 2 * ( overfilledBox[3] - overfilledBox[1] ); if ( xLength < yLength ) { return result - xLength; } return result - yLength; }
/** * @return the number of all objects in this node, e.g. the leafObjects and the objects covering the entire * envelope. */ private final int totalSize() { return size() + ( ( objectsCoveringEnv == null ) ? 0 : ( objectsCoveringEnv.size() - duplicateEnvelopes( objectsCoveringEnv ) ) ); }
/** * Uses a QTree as a spatial index. * * @param domain * @param rasterReference * @param objectsInLeaf */ public IndexedMemoryTileContainer( Envelope domain, RasterGeoReference rasterReference, int objectsInLeaf ) { this.rasterReference = rasterReference; this.index = new QTree<AbstractRaster>( createEnvelope( domain ), objectsInLeaf ); this.domain = domain; }
/** * @param object * to remove * @return true if the object was inserted, false otherwise. */ @Override public boolean remove( T object ) { if ( object != null ) { return removeObject( object ); } return false; }
/** * @return true if the number of objects in the leaf without the duplicate envelopes are larger than the allowed * number of objects in a leaf */ private boolean splitCriteria() { return ( size() > numberOfObjects ) && ( ( currentDepth + 1 ) < MAX_DEPTH ); }
/** * Builds the index from the given objects with their envelope. * * @param listOfObjects */ @SuppressWarnings("unchecked") @Override public void insertBulk( List<Pair<float[], T>> listOfObjects ) { root = buildTree( (List) listOfObjects ); }
/** * @return the leafObjects which intersect with this node and or it's children, or the empty list. */ public List<T> getObjects() { Set<Entry<T>> r = new HashSet<Entry<T>>(); getObjects( envelope, r ); return getEntrySetAsResult( r ); }