X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Frouting%2Fspatial%2FRTree.java;fp=bundles%2Forg.simantics.g2d%2Fsrc%2Forg%2Fsimantics%2Fg2d%2Frouting%2Fspatial%2FRTree.java;h=1334f797c020fff4795756e94a710ac5cbda88c0;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hp=ed3cfd3ac74a8bdf7a9063243915bd51506866fe;hpb=24e2b34260f219f0d1644ca7a138894980e25b14;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.g2d/src/org/simantics/g2d/routing/spatial/RTree.java b/bundles/org.simantics.g2d/src/org/simantics/g2d/routing/spatial/RTree.java index ed3cfd3ac..1334f797c 100644 --- a/bundles/org.simantics.g2d/src/org/simantics/g2d/routing/spatial/RTree.java +++ b/bundles/org.simantics.g2d/src/org/simantics/g2d/routing/spatial/RTree.java @@ -1,635 +1,635 @@ -/******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management - * in Industry THTH ry. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: - * VTT Technical Research Centre of Finland - initial API and implementation - *******************************************************************************/ -package org.simantics.g2d.routing.spatial; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Random; - -import org.simantics.g2d.routing.algorithm1.Rectangle; - -/* - * 2-dimensional R-tree - */ -public class RTree { - - public static final int MAX_ENTRIES = 7; - public static final int MIN_ENTRIES = 3; - public static final int MAX_ENTRIES_AFTER_SPLIT = MAX_ENTRIES - MIN_ENTRIES + 1; - - static interface INode { - void search(Rectangle rect, IRectangleProcedure proc); - boolean intersects(Rectangle rect); - Split add(Rectangle rect, Object value); - - double[] getRectangles(); - Object[] getChildren(); - void setCount(int count); - - Rectangle findBounds(); - } - - static class Split { - double oldX0, oldY0, oldX1, oldY1; - double newX0, newY0, newX1, newY1; - INode newNode; - - public Split(double oldX0, double oldY0, double oldX1, double oldY1, - double newX0, double newY0, double newX1, double newY1, - INode newNode) { - this.oldX0 = oldX0; - this.oldY0 = oldY0; - this.oldX1 = oldX1; - this.oldY1 = oldY1; - this.newX0 = newX0; - this.newY0 = newY0; - this.newX1 = newX1; - this.newY1 = newY1; - this.newNode = newNode; - } - - } - - class Node implements INode { - double[] rectangles = new double[MAX_ENTRIES*4]; - INode[] children = new INode[MAX_ENTRIES]; - int count = 0; - - public void search(Rectangle rect, IRectangleProcedure proc) { - double x0 = rect.x0; - double y0 = rect.y0; - double x1 = rect.x1; - double y1 = rect.y1; - for(int i=0,ad=0;i= rectangles[ad] && x0 <= rectangles[ad+2] && - y1 >= rectangles[ad+1] && y0 <= rectangles[ad+3]) - children[i].search(rect, proc); - } - - public boolean intersects(Rectangle rect) { - double x0 = rect.x0; - double y0 = rect.y0; - double x1 = rect.x1; - double y1 = rect.y1; - for(int i=0,ad=0;i= rectangles[ad] && x0 <= rectangles[ad+2] && - y1 >= rectangles[ad+1] && y0 <= rectangles[ad+3]) - if(children[i].intersects(rect)) - return true; - return false; - } - - @Override - public Split add(Rectangle rect, Object value) { - double x0 = rect.x0; - double y0 = rect.y0; - double x1 = rect.x1; - double y1 = rect.y1; - - int bestId = -1; - double bestArea = 0.0; - double bestAddition = Double.POSITIVE_INFINITY; - for(int i=0,ad=0;i x1b) x1b = x1; - if(y1 > y1b) y1b = y1; - double addition = (x1b-x0b)*(y1b-y0b) - area; - if(addition < bestAddition || (addition==bestAddition && area < bestArea)) { - bestId = i; - bestArea = area; - bestAddition = addition; - } - } - Split split = children[bestId].add(rect, value); - if(split == null) { - if(bestAddition > 0.0) { - int ad = bestId * 4; - rectangles[ad] = Math.min(rectangles[ad], x0); ++ad; - rectangles[ad] = Math.min(rectangles[ad], y0); ++ad; - rectangles[ad] = Math.max(rectangles[ad], x1); ++ad; - rectangles[ad] = Math.max(rectangles[ad], y1); - } - } - else { - int ad = bestId * 4; - rectangles[ad] = split.oldX0; ++ad; - rectangles[ad] = split.oldY0; ++ad; - rectangles[ad] = split.oldX1; ++ad; - rectangles[ad] = split.oldY1; - if(count < children.length) { - ad = count * 4; - rectangles[ad] = split.newX0; ++ad; - rectangles[ad] = split.newY0; ++ad; - rectangles[ad] = split.newX1; ++ad; - rectangles[ad] = split.newY1; - children[count++] = split.newNode; - } - else { - Node newNode = new Node(); - findNodeSeeds(rectangles, children, - new Rectangle(split.newX0, split.newY0, split.newX1, split.newY1), - split.newNode, newNode.rectangles, newNode.children); - return splitNode(this, newNode); - } - - } - return null; - } - - @Override - public Object[] getChildren() { - return children; - } - - @Override - public double[] getRectangles() { - return rectangles; - } - - @Override - public void setCount(int count) { - this.count = count; - } - - @Override - public Rectangle findBounds() { - double x0 = Double.POSITIVE_INFINITY; - double y0 = Double.POSITIVE_INFINITY; - double x1 = Double.NEGATIVE_INFINITY; - double y1 = Double.NEGATIVE_INFINITY; - for(int i=0;i= rectangles[ad] && x0 <= rectangles[ad+2] && - y1 >= rectangles[ad+1] && y0 <= rectangles[ad+3]) - proc.call( - rectangles[ad], rectangles[ad+1], - rectangles[ad+2], rectangles[ad+3], - children[i]); - } - - public boolean intersects(Rectangle rect) { - double x0 = rect.x0; - double y0 = rect.y0; - double x1 = rect.x1; - double y1 = rect.y1; - for(int i=0,ad=0;i= rectangles[ad] && x0 <= rectangles[ad+2] && - y1 >= rectangles[ad+1] && y0 <= rectangles[ad+3]) - return true; - return false; - } - - @Override - public Split add(Rectangle rect, Object value) { - if(count < children.length) { - int ad = count*4; - rectangles[ad++] = rect.x0; - rectangles[ad++] = rect.y0; - rectangles[ad++] = rect.x1; - rectangles[ad] = rect.y1; - children[count++] = value; - return null; - } - else { - Leaf newLeaf = new Leaf(); - findNodeSeeds(rectangles, children, rect, value, newLeaf.rectangles, newLeaf.children); - return splitNode(this, newLeaf); - } - } - - @Override - public Object[] getChildren() { - return children; - } - - @Override - public double[] getRectangles() { - return rectangles; - } - - @Override - public void setCount(int count) { - this.count = count; - } - - @Override - public Rectangle findBounds() { - double x0 = Double.POSITIVE_INFINITY; - double y0 = Double.POSITIVE_INFINITY; - double x1 = Double.NEGATIVE_INFINITY; - double y1 = Double.NEGATIVE_INFINITY; - for(int i=0;i bestDiff) { - bestI = i; - bestDiff = diff; - bestToB = db < da || (db==da && bCount < aCount); - } - } - - if(bestToB) { - rotate2(bRectangles, bValues, bCount, aRectangles, aValues, firstUnassigned, bestI); - x0b = Math.min(x0b, bRectangles[4*bCount]); - y0b = Math.min(y0b, bRectangles[4*bCount+1]); - x1b = Math.max(x1b, bRectangles[4*bCount+2]); - y1b = Math.max(y1b, bRectangles[4*bCount+3]); - ++bCount; - ++firstUnassigned; - if(bCount == MAX_ENTRIES_AFTER_SPLIT) { - while(firstUnassigned < aValues.length) { - move(aRectangles, aValues, aCount, firstUnassigned); - x0a = Math.min(x0a, aRectangles[4*aCount]); - y0a = Math.min(y0a, aRectangles[4*aCount+1]); - x1a = Math.max(x1a, aRectangles[4*aCount+2]); - y1a = Math.max(y1a, aRectangles[4*aCount+3]); - ++aCount; - ++firstUnassigned; - } - break loop; - } - } - else { - //System.out.println(aRectangles.length + " " + aValues.length + " " + aCount + " " + bCount + " " + firstUnassigned + " " + bestI); - rotate(aRectangles, aValues, aCount, firstUnassigned, bestI); - x0a = Math.min(x0a, aRectangles[4*aCount]); - y0a = Math.min(y0a, aRectangles[4*aCount+1]); - x1a = Math.max(x1a, aRectangles[4*aCount+2]); - y1a = Math.max(y1a, aRectangles[4*aCount+3]); - ++aCount; - ++firstUnassigned; - if(aCount == MAX_ENTRIES_AFTER_SPLIT) { - while(firstUnassigned < aValues.length) { - move2(bRectangles, bValues, bCount, aRectangles, aValues, firstUnassigned); - x0b = Math.min(x0b, bRectangles[4*bCount]); - y0b = Math.min(y0b, bRectangles[4*bCount+1]); - x1b = Math.max(x1b, bRectangles[4*bCount+2]); - y1b = Math.max(y1b, bRectangles[4*bCount+3]); - ++bCount; - ++firstUnassigned; - } - break loop; - } - } - - } - a.setCount(aCount); - b.setCount(bCount); - return new Split(x0a, y0a, x1a, y1a, x0b, y0b, x1b, y1b, b); - } - - static void move(double[] array, Object[] oArray, int a, int b) { - assert(a != b); - oArray[a] = oArray[b]; - oArray[b] = null; - a *= 4; - b *= 4; - for(int i=0;i<4;++i) - array[a++] = array[b++]; - } - - static void move2(double[] array, Object[] oArray, int a, double[] array2, Object[] oArray2, int b) { - oArray[a] = oArray2[b]; - oArray2[b] = null; - a *= 4; - b *= 4; - for(int i=0;i<4;++i) - array[a++] = array2[b++]; - } - - static void rotate(double[] array, Object[] oArray, int a, int b, int c) { - if(a==b) { - if(b==c) - return; - { - Object temp = oArray[a]; - oArray[a] = oArray[c]; - oArray[c] = temp; - } - - a *= 4; - c *= 4; - for(int i=0;i<4;++i) { - double temp = array[a]; - array[a] = array[c]; - array[c] = temp; - ++a; ++c; - } - - } - else if(b==c) { - { - Object temp = oArray[a]; - oArray[a] = oArray[c]; - oArray[c] = temp; - } - - a *= 4; - c *= 4; - for(int i=0;i<4;++i) { - double temp = array[a]; - array[a] = array[c]; - array[c] = temp; - ++a; ++c; - } - } - else { - { - Object temp = oArray[b]; - oArray[b] = oArray[a]; - oArray[a] = oArray[c]; - oArray[c] = temp; - } - - a *= 4; - b *= 4; - c *= 4; - for(int i=0;i<4;++i) { - double temp = array[b]; - array[b] = array[a]; - array[a] = array[c]; - array[c] = temp; - ++a; ++b; ++c; - } - } - } - - static void rotate2(double[] array, Object[] oArray, int a, double[] array2, Object[] oArray2, int b, int c) { - { - oArray[a] = oArray2[c]; - oArray2[c] = oArray2[b]; - oArray2[b] = null; - } - - a *= 4; - b *= 4; - c *= 4; - for(int i=0;i<4;++i) { - array[a] = array2[c]; - array2[c] = array2[b]; - array2[b] = 0.0; - ++a; ++b; ++c; - } - } - - static void findNodeSeeds(double[] rectangles, Object[] values, Rectangle rect, Object value, - double[] newRectangles, Object[] newValues) { - int bestI = -1; - int bestJ = -1; - double bestInefficiency = Double.NEGATIVE_INFINITY; - for(int j=0;j<=rectangles.length;j+=4) { - double x0b, y0b, x1b, y1b; - if(j < rectangles.length) { - x0b = rectangles[j]; - y0b = rectangles[j+1]; - x1b = rectangles[j+2]; - y1b = rectangles[j+3]; - } - else { - x0b = rect.x0; - y0b = rect.y0; - x1b = rect.x1; - y1b = rect.y1; - } - double areaB = (x1b-x0b) * (y1b-y0b); - for(int i=0;i bestInefficiency) { - bestI = i-4; - bestJ = j; - bestInefficiency = inefficiency; - } - } - } - if(bestJ==rectangles.length) { - newRectangles[0] = rect.x0; - newRectangles[1] = rect.y0; - newRectangles[2] = rect.x1; - newRectangles[3] = rect.y1; - newValues[0] = value; - } - else { - newValues[0] = values[bestJ/4]; - values[bestJ/4] = value; - - newRectangles[0] = rectangles[bestJ++]; - newRectangles[1] = rectangles[bestJ++]; - newRectangles[2] = rectangles[bestJ++]; - newRectangles[3] = rectangles[bestJ]; - - bestJ -= 3; - rectangles[bestJ++] = rect.x0; - rectangles[bestJ++] = rect.y0; - rectangles[bestJ++] = rect.x1; - rectangles[bestJ] = rect.y1; - - } - - if(bestI > 0) { - Object temp2 = values[0]; - values[0] = values[bestI/4]; - values[bestI/4] = temp2; - - double temp; - temp = rectangles[0]; - rectangles[0] = rectangles[bestI]; - rectangles[bestI++] = temp; - temp = rectangles[1]; - rectangles[1] = rectangles[bestI]; - rectangles[bestI++] = temp; - temp = rectangles[2]; - rectangles[2] = rectangles[bestI]; - rectangles[bestI++] = temp; - temp = rectangles[3]; - rectangles[3] = rectangles[bestI]; - rectangles[bestI++] = temp; - } - } - - INode root = new Leaf(); - - public void search(Rectangle rect, IRectangleProcedure proc) { - root.search(rect, proc); - } - - public boolean intersects(Rectangle rect) { - return root.intersects(rect); - } - - public void add(Rectangle rect, Object obj) { - Split split = root.add(rect, obj); - if(split != null) { - Node node = new Node(); - node.rectangles[0] = split.oldX0; - node.rectangles[1] = split.oldY0; - node.rectangles[2] = split.oldX1; - node.rectangles[3] = split.oldY1; - node.rectangles[4] = split.newX0; - node.rectangles[5] = split.newY0; - node.rectangles[6] = split.newX1; - node.rectangles[7] = split.newY1; - node.children[0] = root; - node.children[1] = split.newNode; - node.count = 2; - - root = node; - } - } - - static Random random = new Random(); - - public static Rectangle randomRectangle() { - double x = random.nextDouble(); - double y = random.nextDouble(); - double w = random.nextDouble()*0.1; - double h = random.nextDouble()*0.1; - return new Rectangle(x, y, x+w, y+h); - } - - public static void main(String[] args) { - Collection rects = new ArrayList(); - - for(int i=0;i<1000;++i) - rects.add(randomRectangle()); - - RTree tree = new RTree(); - for(Rectangle rect : rects) { - tree.add(rect, rect); - tree.root.findBounds(); - } - - - - for(int i=0;i<100;++i) { - final Rectangle q = randomRectangle(); - - int iCount = 0; - for(Rectangle rect : rects) - if(q.intersects(rect)) - ++iCount; - - final int[] iCount2 = new int[] { 0 }; - tree.search(q, new IRectangleProcedure() { - - @Override - public void call(double x0, double y0, double x1, double y1, - Object value) { - ++iCount2[0]; - Rectangle r = (Rectangle)value; - if(!r.intersects(q)) - System.out.println("Not really intersecting!"); - if( x0 != r.x0 - ||y0 != r.y0 - ||x1 != r.x1 - ||y1 != r.y1) - System.out.println("Value and key differ!" + - "(" + x0 + " " + y0 + " " + x1 + " " + y1 + ") " + - "(" + r.x0 + " " + r.y0 + " " + r.x1 + " " + r.y1 + ")"); - } - - }); - if(iCount != iCount2[0]) - System.out.println("Different iCount: " + iCount + " " + iCount2[0]); - } - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.g2d.routing.spatial; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Random; + +import org.simantics.g2d.routing.algorithm1.Rectangle; + +/* + * 2-dimensional R-tree + */ +public class RTree { + + public static final int MAX_ENTRIES = 7; + public static final int MIN_ENTRIES = 3; + public static final int MAX_ENTRIES_AFTER_SPLIT = MAX_ENTRIES - MIN_ENTRIES + 1; + + static interface INode { + void search(Rectangle rect, IRectangleProcedure proc); + boolean intersects(Rectangle rect); + Split add(Rectangle rect, Object value); + + double[] getRectangles(); + Object[] getChildren(); + void setCount(int count); + + Rectangle findBounds(); + } + + static class Split { + double oldX0, oldY0, oldX1, oldY1; + double newX0, newY0, newX1, newY1; + INode newNode; + + public Split(double oldX0, double oldY0, double oldX1, double oldY1, + double newX0, double newY0, double newX1, double newY1, + INode newNode) { + this.oldX0 = oldX0; + this.oldY0 = oldY0; + this.oldX1 = oldX1; + this.oldY1 = oldY1; + this.newX0 = newX0; + this.newY0 = newY0; + this.newX1 = newX1; + this.newY1 = newY1; + this.newNode = newNode; + } + + } + + class Node implements INode { + double[] rectangles = new double[MAX_ENTRIES*4]; + INode[] children = new INode[MAX_ENTRIES]; + int count = 0; + + public void search(Rectangle rect, IRectangleProcedure proc) { + double x0 = rect.x0; + double y0 = rect.y0; + double x1 = rect.x1; + double y1 = rect.y1; + for(int i=0,ad=0;i= rectangles[ad] && x0 <= rectangles[ad+2] && + y1 >= rectangles[ad+1] && y0 <= rectangles[ad+3]) + children[i].search(rect, proc); + } + + public boolean intersects(Rectangle rect) { + double x0 = rect.x0; + double y0 = rect.y0; + double x1 = rect.x1; + double y1 = rect.y1; + for(int i=0,ad=0;i= rectangles[ad] && x0 <= rectangles[ad+2] && + y1 >= rectangles[ad+1] && y0 <= rectangles[ad+3]) + if(children[i].intersects(rect)) + return true; + return false; + } + + @Override + public Split add(Rectangle rect, Object value) { + double x0 = rect.x0; + double y0 = rect.y0; + double x1 = rect.x1; + double y1 = rect.y1; + + int bestId = -1; + double bestArea = 0.0; + double bestAddition = Double.POSITIVE_INFINITY; + for(int i=0,ad=0;i x1b) x1b = x1; + if(y1 > y1b) y1b = y1; + double addition = (x1b-x0b)*(y1b-y0b) - area; + if(addition < bestAddition || (addition==bestAddition && area < bestArea)) { + bestId = i; + bestArea = area; + bestAddition = addition; + } + } + Split split = children[bestId].add(rect, value); + if(split == null) { + if(bestAddition > 0.0) { + int ad = bestId * 4; + rectangles[ad] = Math.min(rectangles[ad], x0); ++ad; + rectangles[ad] = Math.min(rectangles[ad], y0); ++ad; + rectangles[ad] = Math.max(rectangles[ad], x1); ++ad; + rectangles[ad] = Math.max(rectangles[ad], y1); + } + } + else { + int ad = bestId * 4; + rectangles[ad] = split.oldX0; ++ad; + rectangles[ad] = split.oldY0; ++ad; + rectangles[ad] = split.oldX1; ++ad; + rectangles[ad] = split.oldY1; + if(count < children.length) { + ad = count * 4; + rectangles[ad] = split.newX0; ++ad; + rectangles[ad] = split.newY0; ++ad; + rectangles[ad] = split.newX1; ++ad; + rectangles[ad] = split.newY1; + children[count++] = split.newNode; + } + else { + Node newNode = new Node(); + findNodeSeeds(rectangles, children, + new Rectangle(split.newX0, split.newY0, split.newX1, split.newY1), + split.newNode, newNode.rectangles, newNode.children); + return splitNode(this, newNode); + } + + } + return null; + } + + @Override + public Object[] getChildren() { + return children; + } + + @Override + public double[] getRectangles() { + return rectangles; + } + + @Override + public void setCount(int count) { + this.count = count; + } + + @Override + public Rectangle findBounds() { + double x0 = Double.POSITIVE_INFINITY; + double y0 = Double.POSITIVE_INFINITY; + double x1 = Double.NEGATIVE_INFINITY; + double y1 = Double.NEGATIVE_INFINITY; + for(int i=0;i= rectangles[ad] && x0 <= rectangles[ad+2] && + y1 >= rectangles[ad+1] && y0 <= rectangles[ad+3]) + proc.call( + rectangles[ad], rectangles[ad+1], + rectangles[ad+2], rectangles[ad+3], + children[i]); + } + + public boolean intersects(Rectangle rect) { + double x0 = rect.x0; + double y0 = rect.y0; + double x1 = rect.x1; + double y1 = rect.y1; + for(int i=0,ad=0;i= rectangles[ad] && x0 <= rectangles[ad+2] && + y1 >= rectangles[ad+1] && y0 <= rectangles[ad+3]) + return true; + return false; + } + + @Override + public Split add(Rectangle rect, Object value) { + if(count < children.length) { + int ad = count*4; + rectangles[ad++] = rect.x0; + rectangles[ad++] = rect.y0; + rectangles[ad++] = rect.x1; + rectangles[ad] = rect.y1; + children[count++] = value; + return null; + } + else { + Leaf newLeaf = new Leaf(); + findNodeSeeds(rectangles, children, rect, value, newLeaf.rectangles, newLeaf.children); + return splitNode(this, newLeaf); + } + } + + @Override + public Object[] getChildren() { + return children; + } + + @Override + public double[] getRectangles() { + return rectangles; + } + + @Override + public void setCount(int count) { + this.count = count; + } + + @Override + public Rectangle findBounds() { + double x0 = Double.POSITIVE_INFINITY; + double y0 = Double.POSITIVE_INFINITY; + double x1 = Double.NEGATIVE_INFINITY; + double y1 = Double.NEGATIVE_INFINITY; + for(int i=0;i bestDiff) { + bestI = i; + bestDiff = diff; + bestToB = db < da || (db==da && bCount < aCount); + } + } + + if(bestToB) { + rotate2(bRectangles, bValues, bCount, aRectangles, aValues, firstUnassigned, bestI); + x0b = Math.min(x0b, bRectangles[4*bCount]); + y0b = Math.min(y0b, bRectangles[4*bCount+1]); + x1b = Math.max(x1b, bRectangles[4*bCount+2]); + y1b = Math.max(y1b, bRectangles[4*bCount+3]); + ++bCount; + ++firstUnassigned; + if(bCount == MAX_ENTRIES_AFTER_SPLIT) { + while(firstUnassigned < aValues.length) { + move(aRectangles, aValues, aCount, firstUnassigned); + x0a = Math.min(x0a, aRectangles[4*aCount]); + y0a = Math.min(y0a, aRectangles[4*aCount+1]); + x1a = Math.max(x1a, aRectangles[4*aCount+2]); + y1a = Math.max(y1a, aRectangles[4*aCount+3]); + ++aCount; + ++firstUnassigned; + } + break loop; + } + } + else { + //System.out.println(aRectangles.length + " " + aValues.length + " " + aCount + " " + bCount + " " + firstUnassigned + " " + bestI); + rotate(aRectangles, aValues, aCount, firstUnassigned, bestI); + x0a = Math.min(x0a, aRectangles[4*aCount]); + y0a = Math.min(y0a, aRectangles[4*aCount+1]); + x1a = Math.max(x1a, aRectangles[4*aCount+2]); + y1a = Math.max(y1a, aRectangles[4*aCount+3]); + ++aCount; + ++firstUnassigned; + if(aCount == MAX_ENTRIES_AFTER_SPLIT) { + while(firstUnassigned < aValues.length) { + move2(bRectangles, bValues, bCount, aRectangles, aValues, firstUnassigned); + x0b = Math.min(x0b, bRectangles[4*bCount]); + y0b = Math.min(y0b, bRectangles[4*bCount+1]); + x1b = Math.max(x1b, bRectangles[4*bCount+2]); + y1b = Math.max(y1b, bRectangles[4*bCount+3]); + ++bCount; + ++firstUnassigned; + } + break loop; + } + } + + } + a.setCount(aCount); + b.setCount(bCount); + return new Split(x0a, y0a, x1a, y1a, x0b, y0b, x1b, y1b, b); + } + + static void move(double[] array, Object[] oArray, int a, int b) { + assert(a != b); + oArray[a] = oArray[b]; + oArray[b] = null; + a *= 4; + b *= 4; + for(int i=0;i<4;++i) + array[a++] = array[b++]; + } + + static void move2(double[] array, Object[] oArray, int a, double[] array2, Object[] oArray2, int b) { + oArray[a] = oArray2[b]; + oArray2[b] = null; + a *= 4; + b *= 4; + for(int i=0;i<4;++i) + array[a++] = array2[b++]; + } + + static void rotate(double[] array, Object[] oArray, int a, int b, int c) { + if(a==b) { + if(b==c) + return; + { + Object temp = oArray[a]; + oArray[a] = oArray[c]; + oArray[c] = temp; + } + + a *= 4; + c *= 4; + for(int i=0;i<4;++i) { + double temp = array[a]; + array[a] = array[c]; + array[c] = temp; + ++a; ++c; + } + + } + else if(b==c) { + { + Object temp = oArray[a]; + oArray[a] = oArray[c]; + oArray[c] = temp; + } + + a *= 4; + c *= 4; + for(int i=0;i<4;++i) { + double temp = array[a]; + array[a] = array[c]; + array[c] = temp; + ++a; ++c; + } + } + else { + { + Object temp = oArray[b]; + oArray[b] = oArray[a]; + oArray[a] = oArray[c]; + oArray[c] = temp; + } + + a *= 4; + b *= 4; + c *= 4; + for(int i=0;i<4;++i) { + double temp = array[b]; + array[b] = array[a]; + array[a] = array[c]; + array[c] = temp; + ++a; ++b; ++c; + } + } + } + + static void rotate2(double[] array, Object[] oArray, int a, double[] array2, Object[] oArray2, int b, int c) { + { + oArray[a] = oArray2[c]; + oArray2[c] = oArray2[b]; + oArray2[b] = null; + } + + a *= 4; + b *= 4; + c *= 4; + for(int i=0;i<4;++i) { + array[a] = array2[c]; + array2[c] = array2[b]; + array2[b] = 0.0; + ++a; ++b; ++c; + } + } + + static void findNodeSeeds(double[] rectangles, Object[] values, Rectangle rect, Object value, + double[] newRectangles, Object[] newValues) { + int bestI = -1; + int bestJ = -1; + double bestInefficiency = Double.NEGATIVE_INFINITY; + for(int j=0;j<=rectangles.length;j+=4) { + double x0b, y0b, x1b, y1b; + if(j < rectangles.length) { + x0b = rectangles[j]; + y0b = rectangles[j+1]; + x1b = rectangles[j+2]; + y1b = rectangles[j+3]; + } + else { + x0b = rect.x0; + y0b = rect.y0; + x1b = rect.x1; + y1b = rect.y1; + } + double areaB = (x1b-x0b) * (y1b-y0b); + for(int i=0;i bestInefficiency) { + bestI = i-4; + bestJ = j; + bestInefficiency = inefficiency; + } + } + } + if(bestJ==rectangles.length) { + newRectangles[0] = rect.x0; + newRectangles[1] = rect.y0; + newRectangles[2] = rect.x1; + newRectangles[3] = rect.y1; + newValues[0] = value; + } + else { + newValues[0] = values[bestJ/4]; + values[bestJ/4] = value; + + newRectangles[0] = rectangles[bestJ++]; + newRectangles[1] = rectangles[bestJ++]; + newRectangles[2] = rectangles[bestJ++]; + newRectangles[3] = rectangles[bestJ]; + + bestJ -= 3; + rectangles[bestJ++] = rect.x0; + rectangles[bestJ++] = rect.y0; + rectangles[bestJ++] = rect.x1; + rectangles[bestJ] = rect.y1; + + } + + if(bestI > 0) { + Object temp2 = values[0]; + values[0] = values[bestI/4]; + values[bestI/4] = temp2; + + double temp; + temp = rectangles[0]; + rectangles[0] = rectangles[bestI]; + rectangles[bestI++] = temp; + temp = rectangles[1]; + rectangles[1] = rectangles[bestI]; + rectangles[bestI++] = temp; + temp = rectangles[2]; + rectangles[2] = rectangles[bestI]; + rectangles[bestI++] = temp; + temp = rectangles[3]; + rectangles[3] = rectangles[bestI]; + rectangles[bestI++] = temp; + } + } + + INode root = new Leaf(); + + public void search(Rectangle rect, IRectangleProcedure proc) { + root.search(rect, proc); + } + + public boolean intersects(Rectangle rect) { + return root.intersects(rect); + } + + public void add(Rectangle rect, Object obj) { + Split split = root.add(rect, obj); + if(split != null) { + Node node = new Node(); + node.rectangles[0] = split.oldX0; + node.rectangles[1] = split.oldY0; + node.rectangles[2] = split.oldX1; + node.rectangles[3] = split.oldY1; + node.rectangles[4] = split.newX0; + node.rectangles[5] = split.newY0; + node.rectangles[6] = split.newX1; + node.rectangles[7] = split.newY1; + node.children[0] = root; + node.children[1] = split.newNode; + node.count = 2; + + root = node; + } + } + + static Random random = new Random(); + + public static Rectangle randomRectangle() { + double x = random.nextDouble(); + double y = random.nextDouble(); + double w = random.nextDouble()*0.1; + double h = random.nextDouble()*0.1; + return new Rectangle(x, y, x+w, y+h); + } + + public static void main(String[] args) { + Collection rects = new ArrayList(); + + for(int i=0;i<1000;++i) + rects.add(randomRectangle()); + + RTree tree = new RTree(); + for(Rectangle rect : rects) { + tree.add(rect, rect); + tree.root.findBounds(); + } + + + + for(int i=0;i<100;++i) { + final Rectangle q = randomRectangle(); + + int iCount = 0; + for(Rectangle rect : rects) + if(q.intersects(rect)) + ++iCount; + + final int[] iCount2 = new int[] { 0 }; + tree.search(q, new IRectangleProcedure() { + + @Override + public void call(double x0, double y0, double x1, double y1, + Object value) { + ++iCount2[0]; + Rectangle r = (Rectangle)value; + if(!r.intersects(q)) + System.out.println("Not really intersecting!"); + if( x0 != r.x0 + ||y0 != r.y0 + ||x1 != r.x1 + ||y1 != r.y1) + System.out.println("Value and key differ!" + + "(" + x0 + " " + y0 + " " + x1 + " " + y1 + ") " + + "(" + r.x0 + " " + r.y0 + " " + r.x1 + " " + r.y1 + ")"); + } + + }); + if(iCount != iCount2[0]) + System.out.println("Different iCount: " + iCount + " " + iCount2[0]); + } + } + +}