/* XXL: The eXtensible and fleXible Library for data processing
Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger
Head of the Database Research Group
Department of Mathematics and Computer Science
University of Marburg
Germany
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; If not, see <http://www.gnu.org/licenses/>.
http://code.google.com/p/xxl/
*/
package xxl.core.indexStructures;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;
import xxl.core.cursors.Cursors;
import xxl.core.functions.AbstractFunction;
import xxl.core.spatial.rectangles.Rectangle;
/**
* An <tt>RTree</tt> implementing the split-strategy proposed by C.H. Ang and T.C.Tan
*
* For a detailed discussion see C.H. Ang and T.C.Tan:
* "New Linear Node Splitting Algorithm for R-trees",
* Proceedings of the 5th International Symposium on Advances in Spatial Databases 1997
* Pages: 339 - 349
*
*/
public class LinearRTreeAT extends RTree{
/**
*
*/
public Tree.Node createNode (int level) {
return new Node().initialize(level, new LinkedList());
}
/** A modification of {@link RTree.Node node} implementing the linear split-algorithm.
*
* @see RTree.Node
*/
public class Node extends RTree.Node{
/**
* When the deadlock occures the R*Tree split algorithm will be used
* instead of the original algorithm
*
* @param path the nodes already visited during this insert
* @return a <tt>SplitInfo</tt> containig all information needed about the split
*/
// TODO: outliers reinsert, falls stark geclustert
protected Tree.Node.SplitInfo split(final Stack path) {
final Node node = (Node)node(path);
final int dimensions = ((Rectangle)rootDescriptor()).dimensions();
// overflowed nodes MBR
final Rectangle nodesMBR = rectangle(((IndexEntry)indexEntry(path)).descriptor());
Distribution distribution = null;
// compute Distributions
List distributionList = new ArrayList();
for (int dim = 0; dim < dimensions; dim++ ){
final double left = nodesMBR.getCorner(false).getValue(dim);
final double right = nodesMBR.getCorner(true).getValue(dim);
List leftEntries = new ArrayList(); //L1
List rightEntries = new ArrayList();//L2
Iterator entriesIterator = node.entries();
Rectangle actuallEntry;
double leftActuall = 0d;
double rightActuall = 0d;
// compute first descriptors
Rectangle firstDescriptor = null;
Rectangle secondDescriptor = null;
int secondStart = 0;
while( entriesIterator.hasNext()){
Object entry = entriesIterator.next();
actuallEntry = rectangle(descriptor(entry));
leftActuall = actuallEntry.getCorner(false).getValue(dim);
rightActuall = actuallEntry.getCorner(true).getValue(dim);
if ( leftActuall - left < right - rightActuall){
//Insert in L1
leftEntries.add(entry);
firstDescriptor = (firstDescriptor == null) ? actuallEntry :
Descriptors.union(firstDescriptor, actuallEntry);
}else{
//Insert in L2
rightEntries.add(entry);
secondDescriptor = (secondDescriptor == null) ? actuallEntry :
Descriptors.union(secondDescriptor, actuallEntry);
}
}
secondStart = leftEntries.size();
leftEntries.addAll(rightEntries);
Object[] array = leftEntries.toArray();
Distribution distr = new Distribution(array , secondStart,
firstDescriptor, secondDescriptor, dimensions);
distributionList.add(distr);
}
Iterator distributions = distributionList.iterator();
//TODO
List evenNumberDistributions = (List)Cursors.minima(distributions,
new AbstractFunction(){
public Object invoke(Object distr){
Distribution actuallDistr = (Distribution)distr;
int secondStart = actuallDistr.secondStart;
int maxNumber = Math.max(secondStart, actuallDistr.entries.length - secondStart);
return new Integer(maxNumber);
}
}
);
// if one of descriptors == null start nativ R*Tree Split algorithmus
for (int i = 0; i < evenNumberDistributions.size(); i++ ){
Distribution distr = (Distribution)evenNumberDistributions.get(i);
if (distr.firstDescriptor == null
|| distr.secondDescriptor == null){
return super.split(path);
}
}
if (evenNumberDistributions.size() == 1){
distribution = (Distribution) evenNumberDistributions.get(0);
}
else{
List minOverlapDistributions = (List)Cursors.minima(evenNumberDistributions.iterator(),
new AbstractFunction(){
public Object invoke(Object distr){
Distribution actuallDistr = (Distribution)distr;
double groupOverlap = actuallDistr.overlapValue();
return new Double(groupOverlap);
}
}
);
if (minOverlapDistributions.size() == 1){
distribution = (Distribution) minOverlapDistributions.get(0);
}else{ //
distribution = (Distribution)Cursors.minima( minOverlapDistributions.iterator(),
new AbstractFunction(){
public Object invoke(Object distr){
Distribution actuallDistr = (Distribution)distr;
double groupArea = actuallDistr.marginValue();
// double groupArea = actuallDistr.areaValue();
return new Double(groupArea);
}
}
).getFirst();
}
}
node.entries.clear();
node.entries.addAll(distribution.entries(false));
entries.addAll(distribution.entries(true));
((IndexEntry)indexEntry(path)).descriptor = distribution.descriptor(false);
return new SplitInfo(path).initialize(distribution);
}
}
}