├── .gitignore ├── .travis.yml ├── doc ├── BUILD.txt ├── LICENSE.txt ├── README.txt └── TEST.txt ├── pom.xml ├── readme.md └── src ├── main ├── assembly │ └── with-dependencies-zip.xml ├── java │ └── net │ │ └── sf │ │ └── jsi │ │ ├── BuildProperties.java │ │ ├── Point.java │ │ ├── PriorityQueue.java │ │ ├── Rectangle.java │ │ ├── SpatialIndex.java │ │ └── rtree │ │ ├── Node.java │ │ ├── RTree.java │ │ └── SortedList.java └── resources │ └── build.properties ├── site ├── site.xml └── xdoc │ └── index.xml └── test ├── java ├── net │ └── sf │ │ └── jsi │ │ ├── DeleteAllEntriesTest.java │ │ ├── ListDecorator.java │ │ ├── MoveEntriesTest.java │ │ ├── NullIndex.java │ │ ├── PerformanceTest.java │ │ ├── RTreeWrapper.java │ │ ├── RectangleMaxValueTest.java │ │ ├── RectangleTest.java │ │ ├── ReferenceCompareTest.java │ │ ├── ReferenceCompareTest_1000.java │ │ ├── ReferenceCompareTest_10000.java │ │ ├── ReferenceCompareTest_100000.java │ │ ├── SILWrapper.java │ │ ├── Script.java │ │ ├── SimpleIndex.java │ │ ├── SortedListDecorator.java │ │ ├── SortedListTest.java │ │ └── SpatialIndexFactory.java └── sil │ ├── rtree │ ├── Index.java │ ├── Leaf.java │ ├── Node.java │ ├── RTree.java │ ├── Statistics.java │ └── makefile │ ├── spatialindex │ ├── IData.java │ ├── IEntry.java │ ├── INearestNeighborComparator.java │ ├── INode.java │ ├── INodeCommand.java │ ├── IQueryStrategy.java │ ├── IShape.java │ ├── ISpatialIndex.java │ ├── IStatistics.java │ ├── IVisitor.java │ ├── Point.java │ ├── RWLock.java │ ├── Region.java │ └── SpatialIndex.java │ └── storagemanager │ ├── Buffer.java │ ├── DiskStorageManager.java │ ├── IBuffer.java │ ├── IStorageManager.java │ ├── InvalidPageException.java │ ├── MemoryStorageManager.java │ ├── PropertySet.java │ ├── RandomEvictionsBuffer.java │ └── makefile └── resources ├── logback.xml └── test-inputs ├── test-allfunctions-100-in ├── test-allfunctions-1000-in ├── test-allfunctions-10000-in ├── test-allfunctions-100000-in ├── test-allqueries-10000-in ├── test-contains-100-in ├── test-contains-1000-in ├── test-contains-10000-in ├── test-contains-100000-in ├── test-delete-100-in ├── test-delete-1000-in ├── test-delete-10000-in ├── test-delete-100000-in ├── test-intersect-100-in ├── test-intersect-1000-in ├── test-intersect-10000-in ├── test-intersect-100000-in ├── test-intersect-1000000-in ├── test-intersect-10000000-in ├── test-nearest-100-in ├── test-nearest-1000-in ├── test-nearest-10000-in ├── test-nearest-100000-in ├── test-nearestN-100-in ├── test-nearestN-1000-in └── test-nearestN-10000-in /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .metadata 3 | .classpath 4 | .project 5 | .settings 6 | target 7 | *~ 8 | *.swp 9 | *.log 10 | *.iml 11 | *.ipr 12 | *.iws 13 | /.idea/ 14 | 15 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | -------------------------------------------------------------------------------- /doc/BUILD.txt: -------------------------------------------------------------------------------- 1 | To build the JSI library from source, install maven 3 and run the following: 2 | 3 | % cd 4 | % mvn package 5 | 6 | This will generate the binary package (jsi-x.y.z.jar) in the target subdirectory. 7 | 8 | The following is a list of useful maven targets: 9 | o eclipse:eclipse (generate eclipse project files; see below) 10 | o clean 11 | o compile 12 | o test 13 | o -Dtest=ReferenceCompareTest_10000 test 14 | o package 15 | o site 16 | o assembly:single (create package only) 17 | o site:deploy 18 | o deploy 19 | 20 | To import the project into eclipse, run mvn eclipse:eclipse, and then set the M2_REPO variable 21 | in Window -> Preferences -> Java -> Build Path -> Classpath Variables to point to your local 22 | maven repository (e.g. ~/.m2/repository) 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /doc/README.txt: -------------------------------------------------------------------------------- 1 | This is the Java Spatial Index library. 2 | 3 | For examples of usage, please see https://github.com/aled/jsi-examples -------------------------------------------------------------------------------- /doc/TEST.txt: -------------------------------------------------------------------------------- 1 | These are the steps needed to check that the JSI library is working correctly. 2 | Note this will take a very long time to run: 3 | 4 | % cd 5 | % mvn test [This runs a short and quick test] 6 | % mvn -Dtest=ReferenceCompareTest_1000 test [Long test] 7 | % mvn -Dtest=ReferenceCompareTest_10000 test [Very long test] 8 | % mvn -Dtest=ReferenceCompareTest_100000 test [Ridiculously long test] 9 | 10 | If any errors occur, please raise an issue at https://github.com/aled/jsi/issues 11 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | net.sf.jsi 6 | jsi 7 | 1.1.0-SNAPSHOT 8 | jar 9 | 10 | jsi 11 | Java Spatial Index library 12 | https://www.sourceforge.net/projects/jsi 13 | 14 | 15 | 16 | The GNU Lesser General Public License, Version 2.1 or later 17 | https://www.gnu.org/licenses/lgpl-2.1.txt 18 | 19 | 20 | 21 | 22 | 23 | Aled Morris 24 | aled@users.sourceforge.net 25 | https://github.com/aled/jsi 26 | 27 | 28 | 29 | 30 | scm:git:https://github.com/aled/jsi.git 31 | scm:git:https://github.com/aled/jsi.git 32 | https://github.com/aled/jsi.git 33 | 34 | 35 | 36 | UTF-8 37 | 38 | 39 | 40 | 41 | 42 | src/main/resources 43 | true 44 | 45 | build.properties 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | maven-compiler-plugin 54 | 2.3.2 55 | 56 | 1.5 57 | 1.5 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-surefire-plugin 63 | 2.10 64 | 65 | 66 | **/PerformanceTest.java 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.apache.maven.plugins 79 | maven-enforcer-plugin 80 | 1.1.1 81 | 82 | 83 | enforce-versions 84 | 85 | enforce 86 | 87 | 88 | 89 | 90 | [3.0.0,4.0.0) 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 123 | 124 | 125 | org.apache.maven.plugins 126 | maven-source-plugin 127 | 2.1.2 128 | 129 | 130 | attach-sources 131 | 132 | jar 133 | 134 | 135 | 136 | 137 | 138 | 139 | org.apache.maven.plugins 140 | maven-javadoc-plugin 141 | 2.8 142 | 143 | 144 | attach-javadocs 145 | 146 | jar 147 | 148 | 149 | 150 | 151 | 152 | 153 | org.apache.maven.plugins 154 | maven-dependency-plugin 155 | 2.4 156 | 157 | 158 | copy-dependencies 159 | package 160 | 161 | copy-dependencies 162 | 163 | 164 | ${project.build.directory}/dependencies 165 | compile 166 | 167 | 168 | 169 | 170 | copy-test-dependencies 171 | package 172 | 173 | copy-dependencies 174 | 175 | 176 | ${project.build.directory}/test-dependencies 177 | compile 178 | 179 | 180 | 181 | 182 | 183 | 203 | 204 | 205 | maven-deploy-plugin 206 | 2.7 207 | 208 | 209 | 210 | org.apache.maven.plugins 211 | maven-gpg-plugin 212 | 1.5 213 | 214 | 215 | sign-artifacts 216 | verify 217 | 218 | sign 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | org.apache.maven.wagon 228 | wagon-ssh 229 | 2.2 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | org.slf4j 238 | slf4j-api 239 | 1.6.3 240 | compile 241 | 242 | 243 | 244 | net.sf.trove4j 245 | trove4j 246 | 3.0.3 247 | compile 248 | 249 | 250 | 251 | 252 | ch.qos.logback 253 | logback-classic 254 | 1.2.0 255 | test 256 | 257 | 258 | 259 | ch.qos.logback 260 | logback-core 261 | 1.2.0 262 | test 263 | 264 | 265 | 266 | junit 267 | junit 268 | 4.13.1 269 | test 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | ossrh 278 | https://oss.sonatype.org/content/repositories/snapshots 279 | 280 | 281 | 282 | ossrh 283 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 284 | 285 | 286 | 289 | 290 | 291 | 295 | 296 | 297 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | jsi.sourceforge.net 308 | scp://shell.sourceforge.net/home/project-web/jsi/htdocs 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | org.apache.maven.plugins 317 | maven-javadoc-plugin 318 | 2.8 319 | 320 | 321 | 322 | 323 | 324 | 325 | docline-java8-disable 326 | 327 | [1.8,) 328 | 329 | 330 | 331 | 332 | 333 | org.apache.maven.plugins 334 | maven-javadoc-plugin 335 | 336 | -Xdoclint:none 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://www.travis-ci.org/aled/jsi.png?branch=master)](https://www.travis-ci.org/aled/jsi) 2 | 3 | Overview 4 | -------- 5 | The Java Spatial Index project aims to maintain a high performance Java version of the RTree spatial indexing algorithm as described in the 1984 paper "R-trees: A Dynamic Index Structure for Spatial Searching" by Antonin Guttman. (PDF on CiteSeerX) 6 | 7 | The JSI spatial index is deliberately limited in features, 8 | and does a small number of things well. It particular, it is fast. 9 | 10 | The code is open source, and released under the GNU Lesser General Public License, version 2.1 or later. 11 | 12 | Usage 13 | ----- 14 | It is highly recommended to start by looking at the jsi-examples repository at https://github.com/aled/jsi-examples. 15 | 16 | Briefly, you need to initialize the RTree like this: 17 | 18 | // Create and initialize an rtree 19 | SpatialIndex si = new RTree(); 20 | si.init(null); 21 | 22 | Then add some rectangles; each one has an ID. 23 | 24 | final Rectangle[] rects = new Rectangle[100]; 25 | rects[0] = new Rectangle(0, 10, 0, 10); 26 | rects[1] = new Rectangle(0, 11, 1, 20); 27 | si.add(rects[0], 0); 28 | si.add(rects[1], 1); 29 | ... 30 | 31 | and finally query for the 3 nearest rectangles to (36.3, 84.3) by calling the nearestN() method. 32 | 33 | si.nearestN( 34 | new Point(36.3f, 84.3f), // the point for which we want to find nearby rectangles 35 | new TIntProcedure() { // a procedure whose execute() method will be called with the results 36 | public boolean execute(int i) { 37 | log.info("Rectangle " + i + " " + rects[i] + ", distance=" + rects[i].distance(p)); 38 | return true; // return true here to continue receiving results 39 | } 40 | }, 41 | 3, // the number of nearby rectangles to find 42 | Float.MAX_VALUE // Don't bother searching further than this. MAX_VALUE means search everything 43 | ); 44 | 45 | A binary distribution that contains the JSI jar and all the runtime dependencies is available from http://sourceforge.net/projects/jsi/files. 46 | 47 | Alternatively, maven users can use this repository in their pom.xml: 48 | 49 | 50 | jsi.sourceforge.net 51 | sourceforge jsi repository 52 | http://sourceforge.net/projects/jsi/files/m2_repo 53 | 54 | 55 | 56 | net.sourceforge.jsi 57 | jsi 58 | 1.0.0 59 | 60 | 61 | Building 62 | ------- 63 | To build the JSI library from source, install maven 3 and run the following: 64 | 65 | % cd 66 | % mvn package 67 | 68 | This will generate the binary package (jsi-x.y.z.jar) in the target subdirectory. 69 | 70 | The following is a list of useful maven targets: 71 | 72 | eclipse:eclipse (generate eclipse project files; see below) 73 | clean 74 | compile 75 | test 76 | -Dtest=ReferenceCompareTest_10000 test 77 | package 78 | site 79 | assembly:single (create package only) 80 | site:deploy 81 | deploy 82 | 83 | To import the project into eclipse, run mvn eclipse:eclipse, and then set the `M2_REPO` variable 84 | in `Window -> Preferences -> Java -> Build Path -> Classpath Variables` to point to your local maven repository (e.g. `~/.m2/repository`) 85 | 86 | 87 | Testing 88 | ------- 89 | 90 | These are the steps needed to check that the JSI library is working correctly. 91 | Note this will take a very long time to run: 92 | 93 | % cd 94 | % mvn test [This runs a short and quick test] 95 | % mvn -Dtest=ReferenceCompareTest_1000 test [Long test] 96 | % mvn -Dtest=ReferenceCompareTest_10000 test [Very long test] 97 | % mvn -Dtest=ReferenceCompareTest_100000 test [Ridiculously long test] 98 | 99 | If any errors occur, please raise an issue at https://github.com/aled/jsi/issues 100 | 101 | -------------------------------------------------------------------------------- /src/main/assembly/with-dependencies-zip.xml: -------------------------------------------------------------------------------- 1 | 4 | with-dependencies 5 | 6 | zip 7 | 8 | 9 | 10 | ${project.basedir}/target/dependencies 11 | /lib 12 | 13 | *.jar 14 | 15 | 16 | 17 | ${project.basedir}/target 18 | / 19 | 20 | *.jar 21 | 22 | 23 | 24 | ${project.basedir}/doc 25 | / 26 | 27 | README.txt 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/main/java/net/sf/jsi/BuildProperties.java: -------------------------------------------------------------------------------- 1 | // BuildProperties.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2012 Aled Morris 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import java.io.IOException; 22 | import java.util.Properties; 23 | 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | /** 28 | * Allows build properties to be retrieved at runtime. Currently, version and 29 | * scmRevisionId are implemented. 30 | */ 31 | public class BuildProperties { 32 | private static final Logger log = LoggerFactory.getLogger(BuildProperties.class); 33 | private static final BuildProperties instance = new BuildProperties(); 34 | 35 | private String version = null; 36 | private String scmRevisionId = null; 37 | 38 | private BuildProperties() { 39 | Properties p = new Properties(); 40 | try { 41 | p.load(getClass().getClassLoader().getResourceAsStream("build.properties")); 42 | version = p.getProperty("version", ""); 43 | scmRevisionId = p.getProperty("scmRevisionId", ""); 44 | } catch (IOException e) { 45 | log.warn("Unable to read from build.properties"); 46 | } 47 | } 48 | 49 | /** 50 | * Version number as specified in pom.xml 51 | */ 52 | public static String getVersion() { 53 | return instance.version; 54 | } 55 | 56 | 57 | /** 58 | * SCM revision ID. This is the git commit ID. 59 | */ 60 | public static String getScmRevisionId() { 61 | return instance.scmRevisionId; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/net/sf/jsi/Point.java: -------------------------------------------------------------------------------- 1 | // Point.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | /** 22 | * Currently hardcoded to 2 dimensions, but could be extended. 23 | */ 24 | public class Point { 25 | /** 26 | * The (x, y) coordinates of the point. 27 | */ 28 | public float x, y; 29 | 30 | /** 31 | * Constructor. 32 | * 33 | * @param x The x coordinate of the point 34 | * @param y The y coordinate of the point 35 | */ 36 | public Point(float x, float y) { 37 | this.x = x; 38 | this.y = y; 39 | } 40 | 41 | /** 42 | * Copy from another point into this one 43 | */ 44 | public void set(Point other) { 45 | x = other.x; 46 | y = other.y; 47 | } 48 | 49 | /** 50 | * Print as a string in format "(x, y)" 51 | */ 52 | @Override 53 | public String toString() { 54 | return "(" + x + ", " + y + ")"; 55 | } 56 | 57 | /** 58 | * @return X coordinate rounded to an int 59 | */ 60 | public int xInt() { 61 | return Math.round(x); 62 | } 63 | 64 | /** 65 | * @return Y coordinate rounded to an int 66 | */ 67 | public int yInt() { 68 | return Math.round(y); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/net/sf/jsi/PriorityQueue.java: -------------------------------------------------------------------------------- 1 | // PriorityQueue.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2008 aled@users.sourceforge.net 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import java.io.Serializable; 22 | 23 | import gnu.trove.list.array.TIntArrayList; 24 | import gnu.trove.list.array.TFloatArrayList; 25 | 26 | /** 27 | *

28 | * Priority Queue that stores values as ints and priorities as floats. Uses a 29 | * Heap to sort the priorities; the values are sorted "in step" with the 30 | * priorities. 31 | *

32 | *

33 | * A Heap is simply an array that is kept semi sorted; in particular if the 34 | * elements of the array are arranged in a tree structure; ie 35 | *

36 | *
 37 |  *                                   00
 38 |  *                                 /     \
 39 |  *                             01          02
 40 |  *                            /  \        /  \
 41 |  *                          03    04    05    06
 42 |  *                          /\    /\    /\    /\
 43 |  *                        07 08 09 10 11 12 13 14
 44 |  * 
45 | *

46 | * then each parent is kept sorted with respect to it's immediate children. E.g. 47 | * 00 < 01, 00 < 02, 02 < 05, 02 < 06 48 | *

49 | *

50 | * This means that the array appears to be sorted, as long as we only ever look 51 | * at element 0. 52 | *

53 | *

54 | * Inserting new elements is much faster than if the entire array was kept 55 | * sorted; a new element is appended to the array, and then recursively swapped 56 | * with each parent to maintain the "parent is sorted w.r.t it's children" 57 | * property. 58 | *

59 | *

60 | * To return the "next" value it is necessary to remove the root element. The 61 | * last element in the array is placed in the root of the tree, and is 62 | * recursively swapped with one of it's children until the "parent is sorted 63 | * w.r.t it's children" property is restored. 64 | *

65 | *

66 | * Random access is slow (eg for deleting a particular value), and is not 67 | * implemented here - if this functionality is required, then a heap probably 68 | * isn't the right data structure. 69 | *

70 | */ 71 | public class PriorityQueue implements Serializable { 72 | private static final long serialVersionUID = -5653506138757217673L; 73 | public static final boolean SORT_ORDER_ASCENDING = true; 74 | public static final boolean SORT_ORDER_DESCENDING = false; 75 | 76 | private TIntArrayList values = null; 77 | private TFloatArrayList priorities = null; 78 | private boolean sortOrder = SORT_ORDER_ASCENDING; 79 | 80 | private static boolean INTERNAL_CONSISTENCY_CHECKING = false; 81 | 82 | public PriorityQueue(boolean sortOrder) { 83 | this(sortOrder, 10); 84 | } 85 | 86 | public PriorityQueue(boolean sortOrder, int initialCapacity) { 87 | this.sortOrder = sortOrder; 88 | values = new TIntArrayList(initialCapacity); 89 | priorities = new TFloatArrayList(initialCapacity); 90 | } 91 | 92 | /** 93 | * @param p1 94 | * @param p2 95 | * @return true if p1 has an earlier sort order than p2. 96 | */ 97 | private boolean sortsEarlierThan(float p1, float p2) { 98 | if (sortOrder == SORT_ORDER_ASCENDING) { 99 | return p1 < p2; 100 | } 101 | return p2 < p1; 102 | } 103 | 104 | // to insert a value, append it to the arrays, then 105 | // reheapify by promoting it to the correct place. 106 | public void insert(int value, float priority) { 107 | values.add(value); 108 | priorities.add(priority); 109 | 110 | promote(values.size() - 1, value, priority); 111 | } 112 | 113 | private void promote(int index, int value, float priority) { 114 | // Consider the index to be a "hole"; i.e. don't swap priorities/values 115 | // when moving up the tree, simply copy the parent into the hole and 116 | // then consider the parent to be the hole. 117 | // Finally, copy the value/priority into the hole. 118 | while (index > 0) { 119 | int parentIndex = (index - 1) / 2; 120 | float parentPriority = priorities.get(parentIndex); 121 | 122 | if (sortsEarlierThan(parentPriority, priority)) { 123 | break; 124 | } 125 | 126 | // copy the parent entry into the current index. 127 | values.set(index, values.get(parentIndex)); 128 | priorities.set(index, parentPriority); 129 | index = parentIndex; 130 | } 131 | 132 | values.set(index, value); 133 | priorities.set(index, priority); 134 | 135 | if (INTERNAL_CONSISTENCY_CHECKING) { 136 | check(); 137 | } 138 | } 139 | 140 | public int size() { 141 | return values.size(); 142 | } 143 | 144 | public void clear() { 145 | values.clear(); 146 | priorities.clear(); 147 | } 148 | 149 | public void reset() { 150 | values.reset(); 151 | priorities.reset(); 152 | } 153 | 154 | public int getValue() { 155 | return values.get(0); 156 | } 157 | 158 | public float getPriority() { 159 | return priorities.get(0); 160 | } 161 | 162 | private void demote(int index, int value, float priority) { 163 | int childIndex = (index * 2) + 1; // left child 164 | 165 | while (childIndex < values.size()) { 166 | float childPriority = priorities.get(childIndex); 167 | 168 | if (childIndex + 1 < values.size()) { 169 | float rightPriority = priorities.get(childIndex + 1); 170 | if (sortsEarlierThan(rightPriority, childPriority)) { 171 | childPriority = rightPriority; 172 | childIndex++; // right child 173 | } 174 | } 175 | 176 | if (sortsEarlierThan(childPriority, priority)) { 177 | priorities.set(index, childPriority); 178 | values.set(index, values.get(childIndex)); 179 | index = childIndex; 180 | childIndex = (index * 2) + 1; 181 | } else { 182 | break; 183 | } 184 | } 185 | 186 | values.set(index, value); 187 | priorities.set(index, priority); 188 | } 189 | 190 | // get the value with the lowest priority 191 | // creates a "hole" at the root of the tree. 192 | // The algorithm swaps the hole with the appropriate child, until 193 | // the last entry will fit correctly into the hole (ie is lower 194 | // priority than its children) 195 | public int pop() { 196 | int ret = values.get(0); 197 | 198 | // record the value/priority of the last entry 199 | int lastIndex = values.size() - 1; 200 | int tempValue = values.get(lastIndex); 201 | float tempPriority = priorities.get(lastIndex); 202 | 203 | values.removeAt(lastIndex); 204 | priorities.removeAt(lastIndex); 205 | 206 | if (lastIndex > 0) { 207 | demote(0, tempValue, tempPriority); 208 | } 209 | 210 | if (INTERNAL_CONSISTENCY_CHECKING) { 211 | check(); 212 | } 213 | 214 | return ret; 215 | } 216 | 217 | public void setSortOrder(boolean sortOrder) { 218 | if (this.sortOrder != sortOrder) { 219 | this.sortOrder = sortOrder; 220 | // reheapify the arrays 221 | for (int i = (values.size() / 2) - 1; i >= 0; i--) { 222 | demote(i, values.get(i), priorities.get(i)); 223 | } 224 | } 225 | if (INTERNAL_CONSISTENCY_CHECKING) { 226 | check(); 227 | } 228 | } 229 | 230 | private void check() { 231 | // for each entry, check that the child entries have a lower or equal 232 | // priority 233 | int lastIndex = values.size() - 1; 234 | 235 | for (int i = 0; i < values.size() / 2; i++) { 236 | float currentPriority = priorities.get(i); 237 | 238 | int leftIndex = (i * 2) + 1; 239 | if (leftIndex <= lastIndex) { 240 | float leftPriority = priorities.get(leftIndex); 241 | if (sortsEarlierThan(leftPriority, currentPriority)) { 242 | System.err.println("Internal error in PriorityQueue"); 243 | } 244 | } 245 | 246 | int rightIndex = (i * 2) + 2; 247 | if (rightIndex <= lastIndex) { 248 | float rightPriority = priorities.get(rightIndex); 249 | if (sortsEarlierThan(rightPriority, currentPriority)) { 250 | System.err.println("Internal error in PriorityQueue"); 251 | } 252 | } 253 | } 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/main/java/net/sf/jsi/SpatialIndex.java: -------------------------------------------------------------------------------- 1 | // SpatialIndex.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import gnu.trove.procedure.TIntProcedure; 22 | 23 | import java.util.Properties; 24 | 25 | /** 26 | * Defines methods that must be implemented by all 27 | * spatial indexes. This includes the RTree and its variants. 28 | */ 29 | public interface SpatialIndex { 30 | 31 | /** 32 | * Initializes any implementation dependent properties 33 | * of the spatial index. For example, RTree implementations 34 | * will have a NodeSize property. 35 | * 36 | * @param props The set of properties used to initialize the spatial index. 37 | */ 38 | public void init(Properties props); 39 | 40 | /** 41 | * Adds a new rectangle to the spatial index 42 | * 43 | * @param r The rectangle to add to the spatial index. 44 | * @param id The ID of the rectangle to add to the spatial index. 45 | * The result of adding more than one rectangle with 46 | * the same ID is undefined. 47 | */ 48 | public void add(Rectangle r, int id); 49 | 50 | /** 51 | * Deletes a rectangle from the spatial index 52 | * 53 | * @param r The rectangle to delete from the spatial index 54 | * @param id The ID of the rectangle to delete from the spatial 55 | * index 56 | * 57 | * @return true if the rectangle was deleted 58 | * false if the rectangle was not found, or the 59 | * rectangle was found but with a different ID 60 | */ 61 | public boolean delete(Rectangle r, int id); 62 | 63 | /** 64 | * Finds the nearest rectangles to the passed rectangle and calls 65 | * v.execute(id) for each one. 66 | * 67 | * If multiple rectangles are equally near, they will 68 | * all be returned. 69 | * 70 | * @param p The point for which this method finds the 71 | * nearest neighbours. 72 | * 73 | * @param v The IntProcedure whose execute() method is is called 74 | * for each nearest neighbour. 75 | * 76 | * @param furthestDistance The furthest distance away from the rectangle 77 | * to search. Rectangles further than this will not be found. 78 | * 79 | * This should be as small as possible to minimise 80 | * the search time. 81 | * 82 | * Use Float.POSITIVE_INFINITY to guarantee that the nearest rectangle is found, 83 | * no matter how far away, although this will slow down the algorithm. 84 | */ 85 | public void nearest(Point p, TIntProcedure v, float furthestDistance); 86 | 87 | /** 88 | * Finds the N nearest rectangles to the passed rectangle, and calls 89 | * execute(id, distance) on each one, in order of increasing distance. 90 | * 91 | * Note that fewer than N rectangles may be found if fewer entries 92 | * exist within the specified furthest distance, or more if rectangles 93 | * N and N+1 have equal distances. 94 | * 95 | * @param p The point for which this method finds the 96 | * nearest neighbours. 97 | * 98 | * @param v The IntfloatProcedure whose execute() method is is called 99 | * for each nearest neighbour. 100 | * 101 | * @param n The desired number of rectangles to find (but note that 102 | * fewer or more may be returned) 103 | * 104 | * @param distance The furthest distance away from the rectangle 105 | * to search. Rectangles further than this will not be found. 106 | * 107 | * This should be as small as possible to minimise 108 | * the search time. 109 | * 110 | * Use Float.POSITIVE_INFINITY to guarantee that the nearest rectangle is found, 111 | * no matter how far away, although this will slow down the algorithm. 112 | */ 113 | public void nearestN(Point p, TIntProcedure v, int n, float distance); 114 | 115 | /** 116 | * Same as nearestN, except the found rectangles are not returned 117 | * in sorted order. This will be faster, if sorting is not required 118 | */ 119 | public void nearestNUnsorted(Point p, TIntProcedure v, int n, float distance); 120 | 121 | /** 122 | * Finds all rectangles that intersect the passed rectangle. 123 | * 124 | * @param r The rectangle for which this method finds 125 | * intersecting rectangles. 126 | * 127 | * @param ip The IntProcedure whose execute() method is is called 128 | * for each intersecting rectangle. 129 | */ 130 | public void intersects(Rectangle r, TIntProcedure ip); 131 | 132 | /** 133 | * Finds all rectangles contained by the passed rectangle. 134 | * 135 | * @param r The rectangle for which this method finds 136 | * contained rectangles. 137 | * 138 | * @param ip The procedure whose visit() method is is called 139 | * for each contained rectangle. 140 | */ 141 | public void contains(Rectangle r, TIntProcedure ip); 142 | 143 | /** 144 | * Returns the number of entries in the spatial index 145 | */ 146 | public int size(); 147 | 148 | 149 | /** 150 | * Returns the bounds of all the entries in the spatial index, 151 | * or null if there are no entries. 152 | */ 153 | public Rectangle getBounds(); 154 | 155 | /** 156 | * Returns a string identifying the type of 157 | * spatial index, and the version number, 158 | * eg "SimpleIndex-0.1" 159 | */ 160 | public String getVersion(); 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/net/sf/jsi/rtree/Node.java: -------------------------------------------------------------------------------- 1 | // Node.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited 4 | // Copyright (C) 2008-2010 aled@users.sourceforge.net 5 | // 6 | // This library is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU Lesser General Public 8 | // License as published by the Free Software Foundation; either 9 | // version 2.1 of the License, or (at your option) any later version. 10 | // 11 | // This library is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | // Lesser General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU Lesser General Public 17 | // License along with this library; if not, write to the Free Software 18 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 | 20 | package net.sf.jsi.rtree; 21 | 22 | import java.io.Serializable; 23 | 24 | /** 25 | *

Used by RTree. There are no public methods in this class.

26 | */ 27 | public class Node implements Serializable { 28 | private static final long serialVersionUID = -2823316966528817396L; 29 | int nodeId = 0; 30 | float mbrMinX = Float.MAX_VALUE; 31 | float mbrMinY = Float.MAX_VALUE; 32 | float mbrMaxX = -Float.MAX_VALUE; 33 | float mbrMaxY = -Float.MAX_VALUE; 34 | 35 | float[] entriesMinX = null; 36 | float[] entriesMinY = null; 37 | float[] entriesMaxX = null; 38 | float[] entriesMaxY = null; 39 | 40 | int[] ids = null; 41 | int level; 42 | int entryCount; 43 | 44 | Node(int nodeId, int level, int maxNodeEntries) { 45 | this.nodeId = nodeId; 46 | this.level = level; 47 | entriesMinX = new float[maxNodeEntries]; 48 | entriesMinY = new float[maxNodeEntries]; 49 | entriesMaxX = new float[maxNodeEntries]; 50 | entriesMaxY = new float[maxNodeEntries]; 51 | ids = new int[maxNodeEntries]; 52 | } 53 | 54 | void addEntry(float minX, float minY, float maxX, float maxY, int id) { 55 | ids[entryCount] = id; 56 | entriesMinX[entryCount] = minX; 57 | entriesMinY[entryCount] = minY; 58 | entriesMaxX[entryCount] = maxX; 59 | entriesMaxY[entryCount] = maxY; 60 | 61 | if (minX < mbrMinX) mbrMinX = minX; 62 | if (minY < mbrMinY) mbrMinY = minY; 63 | if (maxX > mbrMaxX) mbrMaxX = maxX; 64 | if (maxY > mbrMaxY) mbrMaxY = maxY; 65 | 66 | entryCount++; 67 | } 68 | 69 | // Return the index of the found entry, or -1 if not found 70 | int findEntry(float minX, float minY, float maxX, float maxY, int id) { 71 | for (int i = 0; i < entryCount; i++) { 72 | if (id == ids[i] && 73 | entriesMinX[i] == minX && entriesMinY[i] == minY && 74 | entriesMaxX[i] == maxX && entriesMaxY[i] == maxY) { 75 | return i; 76 | } 77 | } 78 | return -1; 79 | } 80 | 81 | // delete entry. This is done by setting it to null and copying the last entry into its space. 82 | void deleteEntry(int i) { 83 | int lastIndex = entryCount - 1; 84 | float deletedMinX = entriesMinX[i]; 85 | float deletedMinY = entriesMinY[i]; 86 | float deletedMaxX = entriesMaxX[i]; 87 | float deletedMaxY = entriesMaxY[i]; 88 | 89 | if (i != lastIndex) { 90 | entriesMinX[i] = entriesMinX[lastIndex]; 91 | entriesMinY[i] = entriesMinY[lastIndex]; 92 | entriesMaxX[i] = entriesMaxX[lastIndex]; 93 | entriesMaxY[i] = entriesMaxY[lastIndex]; 94 | ids[i] = ids[lastIndex]; 95 | } 96 | entryCount--; 97 | 98 | // adjust the MBR 99 | recalculateMBRIfInfluencedBy(deletedMinX, deletedMinY, deletedMaxX, deletedMaxY); 100 | } 101 | 102 | // deletedMin/MaxX/Y is a rectangle that has just been deleted or made smaller. 103 | // Thus, the MBR is only recalculated if the deleted rectangle influenced the old MBR 104 | void recalculateMBRIfInfluencedBy(float deletedMinX, float deletedMinY, float deletedMaxX, float deletedMaxY) { 105 | if (mbrMinX == deletedMinX || mbrMinY == deletedMinY || mbrMaxX == deletedMaxX || mbrMaxY == deletedMaxY) { 106 | recalculateMBR(); 107 | } 108 | } 109 | 110 | void recalculateMBR() { 111 | mbrMinX = entriesMinX[0]; 112 | mbrMinY = entriesMinY[0]; 113 | mbrMaxX = entriesMaxX[0]; 114 | mbrMaxY = entriesMaxY[0]; 115 | 116 | for (int i = 1; i < entryCount; i++) { 117 | if (entriesMinX[i] < mbrMinX) mbrMinX = entriesMinX[i]; 118 | if (entriesMinY[i] < mbrMinY) mbrMinY = entriesMinY[i]; 119 | if (entriesMaxX[i] > mbrMaxX) mbrMaxX = entriesMaxX[i]; 120 | if (entriesMaxY[i] > mbrMaxY) mbrMaxY = entriesMaxY[i]; 121 | } 122 | } 123 | 124 | /** 125 | * eliminate null entries, move all entries to the start of the source node 126 | */ 127 | void reorganize(RTree rtree) { 128 | int countdownIndex = rtree.maxNodeEntries - 1; 129 | for (int index = 0; index < entryCount; index++) { 130 | if (ids[index] == -1) { 131 | while (ids[countdownIndex] == -1 && countdownIndex > index) { 132 | countdownIndex--; 133 | } 134 | entriesMinX[index] = entriesMinX[countdownIndex]; 135 | entriesMinY[index] = entriesMinY[countdownIndex]; 136 | entriesMaxX[index] = entriesMaxX[countdownIndex]; 137 | entriesMaxY[index] = entriesMaxY[countdownIndex]; 138 | ids[index] = ids[countdownIndex]; 139 | ids[countdownIndex] = -1; 140 | } 141 | } 142 | } 143 | 144 | public int getEntryCount() { 145 | return entryCount; 146 | } 147 | 148 | public int getId(int index) { 149 | if (index < entryCount) { 150 | return ids[index]; 151 | } 152 | return -1; 153 | } 154 | 155 | boolean isLeaf() { 156 | return (level == 1); 157 | } 158 | 159 | public int getLevel() { 160 | return level; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/net/sf/jsi/rtree/SortedList.java: -------------------------------------------------------------------------------- 1 | // SortedList.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi.rtree; 20 | 21 | import java.io.Serializable; 22 | 23 | import gnu.trove.list.array.TFloatArrayList; 24 | import gnu.trove.list.array.TIntArrayList; 25 | import gnu.trove.procedure.TIntProcedure; 26 | 27 | /** 28 | *

29 | * Sorted List, backed by a TArrayList. 30 | * 31 | * The elements in the list are always ordered by priority. 32 | * Methods exists to remove elements with the highest and lowest priorities. 33 | * 34 | * If more than one element has the highest priority, they will 35 | * all be removed by calling removeHighest. Ditto for the lowest priority. 36 | * 37 | * The list has a preferred maximum size. If possible, entries with the lowest priority 38 | * will be removed to limit the maximum size. Note that entries with the lowest priority 39 | * will not be removed if this would leave fewer than the preferred maximum number 40 | * of entries. 41 | * 42 | * This class is not optimised for large values of preferredMaximumSize. Values greater than, 43 | * say, 5, are not recommended. 44 | *

45 | */ 46 | public class SortedList implements Serializable { 47 | private static final long serialVersionUID = -1549539544212731131L; 48 | 49 | private static final int DEFAULT_PREFERRED_MAXIMUM_SIZE = 10; 50 | 51 | private int preferredMaximumSize = 1; 52 | private TIntArrayList ids = null; 53 | private TFloatArrayList priorities = null; 54 | 55 | public void init(int preferredMaximumSize) { 56 | this.preferredMaximumSize = preferredMaximumSize; 57 | ids.clear(preferredMaximumSize); 58 | priorities.clear(preferredMaximumSize); 59 | } 60 | 61 | public void reset() { 62 | ids.reset(); 63 | priorities.reset(); 64 | } 65 | 66 | public SortedList() { 67 | ids = new TIntArrayList(DEFAULT_PREFERRED_MAXIMUM_SIZE); 68 | priorities = new TFloatArrayList(DEFAULT_PREFERRED_MAXIMUM_SIZE); 69 | } 70 | 71 | public void add(int id, float priority) { 72 | float lowestPriority = Float.NEGATIVE_INFINITY; 73 | 74 | if (priorities.size() > 0) { 75 | lowestPriority = priorities.get(priorities.size() - 1); 76 | } 77 | 78 | if ((priority == lowestPriority) || 79 | (priority < lowestPriority && ids.size() < preferredMaximumSize)) { 80 | // simply add the new entry at the lowest priority end 81 | ids.add(id); 82 | priorities.add(priority); 83 | } else if (priority > lowestPriority) { 84 | if (ids.size() >= preferredMaximumSize) { 85 | int lowestPriorityIndex = ids.size() - 1; 86 | while ((lowestPriorityIndex - 1 >= 0) && 87 | (priorities.get(lowestPriorityIndex - 1) == lowestPriority)) { 88 | lowestPriorityIndex--; 89 | } 90 | 91 | if (lowestPriorityIndex >= preferredMaximumSize - 1) { 92 | ids.remove(lowestPriorityIndex, ids.size() - lowestPriorityIndex); 93 | priorities.remove(lowestPriorityIndex, priorities.size() - lowestPriorityIndex); 94 | } 95 | } 96 | 97 | // put the new entry in the correct position. Could do a binary search here if the 98 | // preferredMaximumSize was large. 99 | int insertPosition = ids.size(); 100 | while (insertPosition - 1 >= 0 && priority > priorities.get(insertPosition - 1)) { 101 | insertPosition--; 102 | } 103 | 104 | ids.insert(insertPosition, id); 105 | priorities.insert(insertPosition, priority); 106 | } 107 | } 108 | 109 | /** 110 | * return the lowest priority currently stored, or float.NEGATIVE_INFINITY if no 111 | * entries are stored 112 | */ 113 | public float getLowestPriority() { 114 | float lowestPriority = Float.NEGATIVE_INFINITY; 115 | if (priorities.size() >= preferredMaximumSize) { 116 | lowestPriority = priorities.get(priorities.size() - 1); 117 | } 118 | return lowestPriority; 119 | } 120 | 121 | public void forEachId(TIntProcedure v) { 122 | for (int i = 0; i < ids.size(); i++) { 123 | if (!v.execute(ids.get(i))) { 124 | break; 125 | } 126 | } 127 | } 128 | 129 | public int[] toNativeArray() { 130 | return ids.toArray(); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/resources/build.properties: -------------------------------------------------------------------------------- 1 | # standard maven properties 2 | version=${version} 3 | 4 | # the scm revision id is set using the environment variable BUILD_VCS_NUMBER, which is set by teamcity. 5 | scmRevisionId=${env.BUILD_VCS_NUMBER} 6 | -------------------------------------------------------------------------------- /src/site/site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | org.apache.maven.skins 5 | maven-default-skin 6 | 1.1 7 | 8 | 9 | 10 | JSI (Java Spatial Index) RTree Library 11 | http://web.sourceforge.net/home/project-web/jsi/htdocs 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/site/xdoc/index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Aled Morris 4 | JSI (Java Spatial Index) RTree Library 5 | 6 | 7 |
8 |

The Java Spatial Index project aims to maintain a high performance Java version of the RTree spatial indexing algorithm. 9 | as described in the 1984 paper "R-trees: A Dynamic Index Structure for Spatial Searching" by Antonin Guttman. 10 | (PDF on CiteSeerX)

11 |

The code is open source, and released under the GNU Lesser General Public License, version 2.1 or later. 13 |

14 |

See the SourceForge project page for more information. 15 | Javadoc documentation is available online. 16 |

17 |
18 | 19 |
20 |

The JSI spatial index is deliberately limited in features, 21 | and does a small number of things well. It particular, it is fast. On a test 22 | machine, it takes about 500ms to add 10,000 entries 23 | to the spatial index. By comparison, an alternative implementation (that seems 24 | to be unmaintained now) takes over 6000ms (but it has more features). 25 |

26 | 27 |

The current release is 1.0.0, and binaries are available in a zip file at 28 | http://sourceforge.net/projects/jsi/files, or via a maven repository hosted 29 | at http://sourceforge.net/projects/jsi/files/m2_repo. 30 | See http://github.com/aled/jsi-examples for examples that use the 31 | JSI library via this maven repo. 32 |

33 |

The source is hosted at github, at http://github.com/aled/jsi. Feel 34 | free to send pull requests. To build the source or run tests, you will need maven 3 installed 35 | and a working internet connection. Note that the CVS and SVN repositories on sourceforge are well out of date. 36 |

37 | 38 |

The API includes the following operations: 39 |

    40 |
  • Add
  • 41 |
  • Delete
  • 42 |
  • Intersection query
  • 43 |
  • Nearest neighbour query
  • 44 |
  • Nearest N neighbours query
  • 45 |
  • Containment query
  • 46 |
47 |
SourceForge.net Logo 50 |
51 |

52 | 53 |

54 | YourKit is kindly supporting open source projects with its full-featured Java Profiler. 55 | YourKit, LLC is the creator of innovative and intelligent tools for profiling 56 | Java and .NET applications. Take a look at YourKit's leading software products: 57 | YourKit Java Profiler and 58 | YourKit .NET Profiler." 59 |

60 |
61 | 62 |
63 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/DeleteAllEntriesTest.java: -------------------------------------------------------------------------------- 1 | // DeleteAllEntriesTest.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2010 aled@users.sourceforge.net 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import gnu.trove.procedure.TIntProcedure; 22 | 23 | import java.util.Properties; 24 | import java.util.Random; 25 | 26 | import junit.framework.TestCase; 27 | 28 | import net.sf.jsi.rtree.RTree; 29 | 30 | public class DeleteAllEntriesTest extends TestCase { 31 | 32 | Rectangle[] rects = null; 33 | 34 | class Counter implements TIntProcedure { 35 | public int count = 0; 36 | public boolean execute(int arg0) { 37 | count++; 38 | return true; 39 | } 40 | }; 41 | 42 | public DeleteAllEntriesTest(String name) { 43 | super(name); 44 | } 45 | 46 | public void testDeleteAllEntries() { 47 | System.out.println("testDeleteAllEntries"); 48 | 49 | int numRects = 500; 50 | 51 | rects = new Rectangle[numRects]; 52 | Random r = new Random(); 53 | r.setSeed(0); 54 | for (int i = 0; i < numRects; i+=1) { 55 | rects[i] = new Rectangle(r.nextFloat(), r.nextFloat(), r.nextFloat(), r.nextFloat()); 56 | } 57 | 58 | run(1, 2, numRects); 59 | run(1, 3, numRects); 60 | run(2, 4, numRects); 61 | run(2, 5, numRects); 62 | run(2, 6, numRects); 63 | } 64 | 65 | private void run(int minNodeEntries, int maxNodeEntries, int numRects) { 66 | Properties p = new Properties(); 67 | p.setProperty("MinNodeEntries", Integer.toString(minNodeEntries)); 68 | p.setProperty("MaxNodeEntries", Integer.toString(maxNodeEntries)); 69 | RTree rtree = (RTree) SpatialIndexFactory.newInstance("rtree.RTree", p); 70 | 71 | for (int i = 0; i <= numRects; i+=100) { 72 | // add some entries 73 | for (int j = 0; j < i; j++) { 74 | rtree.add(rects[j], j); 75 | } 76 | assertTrue(rtree.checkConsistency()); 77 | 78 | // now delete them all 79 | for (int j = 0; j < i; j++) { 80 | rtree.delete(rects[j], j); 81 | } 82 | assertTrue(rtree.size() == 0); 83 | assertTrue(rtree.checkConsistency()); 84 | 85 | // check that we can make queries on an empty rtree without error. 86 | Rectangle testRect = new Rectangle(1,2,3,4); 87 | Point testPoint = new Point(1,2); 88 | 89 | Counter counter = new Counter(); 90 | rtree.intersects(testRect, counter); 91 | assertTrue(counter.count == 0); 92 | 93 | rtree.nearest(testPoint, counter, Float.MAX_VALUE); 94 | assertTrue(counter.count == 0); 95 | 96 | rtree.nearestN(testPoint, counter, 10, Float.MAX_VALUE); 97 | assertTrue(counter.count == 0); 98 | 99 | rtree.nearestNUnsorted(testPoint, counter, 10, Float.MAX_VALUE); 100 | assertTrue(counter.count == 0); 101 | 102 | rtree.contains(testRect, counter); 103 | assertTrue(counter.count == 0); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/ListDecorator.java: -------------------------------------------------------------------------------- 1 | // ListDecorator.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import gnu.trove.procedure.TIntProcedure; 22 | 23 | import java.util.ArrayList; 24 | import java.util.List; 25 | 26 | /** 27 | * ListDecorator 28 | */ 29 | public class ListDecorator { 30 | SpatialIndex m_si = null; 31 | 32 | public ListDecorator(SpatialIndex si) { 33 | m_si = si; 34 | } 35 | 36 | class AddToListProcedure implements TIntProcedure { 37 | private List m_list = new ArrayList(); 38 | 39 | public boolean execute(int id) { 40 | m_list.add(new Integer(id)); 41 | return true; 42 | } 43 | 44 | public List getList() { 45 | return m_list; 46 | } 47 | } 48 | 49 | /** 50 | * Finds all rectangles that are nearest to the passed 51 | * rectangle. 52 | * 53 | * @param p The p point which this method finds 54 | * the nearest neighbours. 55 | * 56 | * @return List of IDs of rectangles that are nearest 57 | * to the passed rectangle, ordered by distance (nearest first). 58 | */ 59 | public List nearest(Point p, float furthestDistance) { 60 | AddToListProcedure v = new AddToListProcedure(); 61 | m_si.nearest(p, v, furthestDistance); 62 | return v.getList(); 63 | } 64 | 65 | /** 66 | * Finds all rectangles that are nearest to the passed 67 | * rectangle. 68 | * 69 | * @param p The p point which this method finds 70 | * the nearest neighbours. 71 | * 72 | * @return List of IDs of rectangles that are nearest 73 | * to the passed rectangle, ordered by distance (nearest first). 74 | * If multiple rectangles have the same distance, order by ID. 75 | */ 76 | public List nearestN(Point p, int maxCount, float furthestDistance) { 77 | AddToListProcedure v = new AddToListProcedure(); 78 | m_si.nearestN(p, v, maxCount, furthestDistance); 79 | return v.getList(); 80 | } 81 | 82 | /** 83 | * Finds all rectangles that intersect the passed rectangle. 84 | * 85 | * @param r The rectangle for which this method finds 86 | * intersecting rectangles. 87 | * 88 | * @return List of IDs of rectangles that intersect the passed 89 | * rectangle. 90 | */ 91 | public List intersects(Rectangle r) { 92 | AddToListProcedure v = new AddToListProcedure(); 93 | m_si.intersects(r, v); 94 | return v.getList(); 95 | } 96 | 97 | /** 98 | * Finds all rectangles contained by the passed rectangle. 99 | * 100 | * @param r The rectangle for which this method finds 101 | * contained rectangles. 102 | * 103 | * @return Collection of IDs of rectangles that are contained by the 104 | * passed rectangle. 105 | */ 106 | public List contains(Rectangle r) { 107 | AddToListProcedure v = new AddToListProcedure(); 108 | m_si.contains(r, v); 109 | return v.getList(); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/MoveEntriesTest.java: -------------------------------------------------------------------------------- 1 | // MoveEntriesTest.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2011 Aled Morris 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import java.util.Properties; 22 | import java.util.Random; 23 | 24 | import net.sf.jsi.Rectangle; 25 | import net.sf.jsi.rtree.RTree; 26 | 27 | import junit.framework.TestCase; 28 | 29 | public class MoveEntriesTest extends TestCase { 30 | 31 | Random r = new Random(); 32 | 33 | public MoveEntriesTest(String name) { 34 | super(name); 35 | r.setSeed(0); 36 | } 37 | 38 | private Rectangle nextRect() { 39 | return new Rectangle(r.nextInt(100), r.nextInt(100), r.nextInt(100), r.nextInt(100)); 40 | } 41 | 42 | public void testMoveEntries() { 43 | run(4, 50, 4, 10); 44 | } 45 | 46 | private void run(int minNodeEntries, int maxNodeEntries, int numRects, int numMoves) { 47 | Properties p = new Properties(); 48 | p.setProperty("MinNodeEntries", Integer.toString(minNodeEntries)); 49 | p.setProperty("MaxNodeEntries", Integer.toString(maxNodeEntries)); 50 | RTree rtree = (RTree) SpatialIndexFactory.newInstance("rtree.RTree", p); 51 | 52 | Rectangle[] rects = new Rectangle[numRects]; 53 | 54 | // first add the rects 55 | for (int i = 0; i < numRects; i++) { 56 | rects[i] = nextRect(); 57 | rtree.add(rects[i], i); 58 | } 59 | 60 | // now move each one in turn 61 | for (int move = 0; move < numMoves; move++) { 62 | for (int i = 0; i < numRects; i++) { 63 | rtree.delete(rects[i], i); 64 | rects[i].set(nextRect()); 65 | rtree.add(rects[i], i); 66 | assertTrue(rtree.checkConsistency()); 67 | } 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/NullIndex.java: -------------------------------------------------------------------------------- 1 | // NullIndex.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import gnu.trove.procedure.TIntProcedure; 22 | 23 | import java.util.Properties; 24 | 25 | /** 26 | * An implementation of SpatialIndex that does absolutely nothing. 27 | * The purpose of this class is to measure the overhead of the 28 | * testing framework. 29 | */ 30 | public class NullIndex implements SpatialIndex { 31 | 32 | /** 33 | * @see net.sf.jsi.SpatialIndex#init(Properties) 34 | */ 35 | public void init(Properties props) { 36 | } 37 | 38 | /** 39 | * @see net.sf.jsi.SpatialIndex#nearest(Point, gnu.trove.TIntProcedure, float) 40 | */ 41 | public void nearest(Point p, TIntProcedure v, float distance) { 42 | } 43 | 44 | /** 45 | * @see net.sf.jsi.SpatialIndex#nearestN(Point, gnu.trove.TIntProcedure, int, float) 46 | */ 47 | public void nearestN(Point p, TIntProcedure v, int n, float distance) { 48 | } 49 | 50 | /** 51 | * @see net.sf.jsi.SpatialIndex#nearestNUnsorted(Point, gnu.trove.TIntProcedure, int, float) 52 | */ 53 | public void nearestNUnsorted(Point p, TIntProcedure v, int n, float distance) { 54 | } 55 | 56 | /** 57 | * @see net.sf.jsi.SpatialIndex#intersects(Rectangle, gnu.trove.TIntProcedure) 58 | */ 59 | public void intersects(Rectangle r, TIntProcedure ip) { 60 | } 61 | 62 | /** 63 | * @see net.sf.jsi.SpatialIndex#contains(Rectangle, gnu.trove.TIntProcedure) 64 | */ 65 | public void contains(Rectangle r, TIntProcedure ip) { 66 | } 67 | 68 | /** 69 | * @see net.sf.jsi.SpatialIndex#add(Rectangle, int) 70 | */ 71 | public void add(Rectangle r, int id) { 72 | } 73 | 74 | /** 75 | * @see net.sf.jsi.SpatialIndex#delete(Rectangle, int) 76 | */ 77 | public boolean delete(Rectangle r, int id) { 78 | return false; 79 | } 80 | 81 | /** 82 | * @see net.sf.jsi.SpatialIndex#size() 83 | */ 84 | public int size() { 85 | return 0; 86 | } 87 | 88 | /** 89 | * @see net.sf.jsi.SpatialIndex#getBounds() 90 | */ 91 | public Rectangle getBounds() { 92 | return null; 93 | } 94 | 95 | /** 96 | * @see net.sf.jsi.SpatialIndex#getVersion() 97 | */ 98 | public String getVersion() { 99 | return "NullIndex-" + BuildProperties.getVersion(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/PerformanceTest.java: -------------------------------------------------------------------------------- 1 | // PerformanceTest.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // Copyright (C) 2013 Aled Morris 5 | // 6 | // 7 | // This library is free software; you can redistribute it and/or 8 | // modify it under the terms of the GNU Lesser General Public 9 | // License as published by the Free Software Foundation; either 10 | // version 2.1 of the License, or (at your option) any later version. 11 | // 12 | // This library is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | // Lesser General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU Lesser General Public 18 | // License along with this library; if not, write to the Free Software 19 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 | 21 | package net.sf.jsi; 22 | 23 | import java.util.Properties; 24 | import java.util.Random; 25 | import java.util.concurrent.ExecutorService; 26 | import java.util.concurrent.Executors; 27 | import java.util.concurrent.TimeUnit; 28 | 29 | import net.sf.jsi.rtree.RTree; 30 | import gnu.trove.procedure.TIntProcedure; 31 | 32 | import org.junit.Test; 33 | import org.slf4j.Logger; 34 | import org.slf4j.LoggerFactory; 35 | 36 | /** 37 | * PerformanceTest 38 | * 39 | * Generates results used for comparing the performance of the Java Spatial 40 | * Index library against alternative implementations. 41 | * 42 | * The idea is for the raw data to be imported into a database, and results 43 | * extracted from that. 44 | * 45 | * This test requires 1024M memory (i.e. use -Xmx1024M) 46 | */ 47 | public class PerformanceTest { 48 | 49 | private static final Logger log = LoggerFactory.getLogger(PerformanceTest.class); 50 | private SpatialIndex si; 51 | 52 | private float randomFloat(Random r, float min, float max) { 53 | return (r.nextFloat() * (max - min)) + min; 54 | } 55 | 56 | protected Point randomPoint(Random r) { 57 | return new Point(randomFloat(r, 0, 100), randomFloat(r, 0, 100)); 58 | } 59 | 60 | private Rectangle randomRectangle(Random r, float size) { 61 | float x = randomFloat(r, 0, 100); 62 | float y = randomFloat(r, 0, 100); 63 | return new Rectangle(x, y, x + randomFloat(r, 0, size), y + randomFloat(r, 0, size)); 64 | } 65 | 66 | abstract class Operation { 67 | private final int count[] = new int[1]; 68 | private String description; 69 | public Random r; 70 | 71 | public Operation(String description, Random r) { 72 | this.description = description; 73 | this.r = r; 74 | } 75 | 76 | protected TIntProcedure countProc = new TIntProcedure() { 77 | public boolean execute(int value) { 78 | count[0]++; 79 | return true; 80 | } 81 | }; 82 | 83 | public int callbackCount() { 84 | return count[0]; 85 | } 86 | 87 | public String getDescription() { 88 | return description; 89 | } 90 | 91 | abstract void execute(SpatialIndex si, Random r); 92 | } 93 | 94 | private void benchmark(Operation o, int repetitions) { 95 | long duration = 0; 96 | long startTime = System.nanoTime(); 97 | for (int j = 0; j < repetitions; j++) o.execute(si, o.r); 98 | duration += (System.nanoTime() - startTime); 99 | 100 | log.info(o.getDescription() + ", " + 101 | "avg callbacks = " + ((float) o.callbackCount() / repetitions) + ", " + 102 | "avg time = " + (duration / repetitions) + " ns"); 103 | } 104 | 105 | /** 106 | * First attempt at a benchmark 107 | */ 108 | @Test 109 | public void benchmark_1() { 110 | Random rand = new Random(0); 111 | Properties p = new Properties(); 112 | p.setProperty("MinNodeEntries", "20"); 113 | p.setProperty("MaxNodeEntries", "50"); 114 | si = new RTree(); 115 | si.init(p); 116 | 117 | final int rectangleCount = 1000000; 118 | final Rectangle[] rects = new Rectangle[rectangleCount]; 119 | for (int i = 0; i < rectangleCount; i++) { 120 | rects[i] = randomRectangle(rand, 0.01f); 121 | } 122 | 123 | long duration; 124 | long startTime; 125 | 126 | for (int j = 0; j < 5; j++) { 127 | duration = 0; 128 | startTime = System.nanoTime(); 129 | for (int i = 0; i < rectangleCount; i++) { 130 | si.add(rects[i], i); 131 | } 132 | duration += (System.nanoTime() - startTime); 133 | log.info("add " + rectangleCount + " avg tme = " + (duration / rectangleCount) + " ns"); 134 | 135 | if (j == 4) break; // don't do the delete on the last iteration 136 | 137 | duration = 0; 138 | startTime = System.nanoTime(); 139 | for (int i = 0; i < rectangleCount; i++) { 140 | si.delete(rects[i], i); 141 | } 142 | duration += (System.nanoTime() - startTime); 143 | log.info("delete " + rectangleCount + " avg tme = " + (duration / rectangleCount) + " ns"); 144 | } 145 | 146 | ExecutorService exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); 147 | try { 148 | for (int i = 0; i < 100; i++) { 149 | exec.submit(new Runnable() {public void run() {benchmark(new Operation("nearest", new Random(0)) {void execute(SpatialIndex si, Random r) {si.nearest(randomPoint(r), countProc, 0.1f);}}, 100); }}); 150 | exec.submit(new Runnable() {public void run() {benchmark(new Operation("nearestNUnsorted", new Random(0)) {void execute(SpatialIndex si, Random r) {si.nearestNUnsorted(randomPoint(r), countProc, 10, 0.16f);}}, 100); }}); 151 | exec.submit(new Runnable() {public void run() {benchmark(new Operation("nearestN", new Random(0)) {void execute(SpatialIndex si, Random r) {si.nearestN(randomPoint(r), countProc, 10, 0.16f);}}, 100); }}); 152 | exec.submit(new Runnable() {public void run() {benchmark(new Operation("intersects", new Random(0)) {void execute(SpatialIndex si, Random r) {si.intersects(randomRectangle(r, 0.6f), countProc);}}, 100); }}); 153 | exec.submit(new Runnable() {public void run() {benchmark(new Operation("contains", new Random(0)) {void execute(SpatialIndex si, Random r) {si.contains(randomRectangle(r, 0.65f), countProc);}}, 100); }}); 154 | } 155 | try { exec.awaitTermination(1, TimeUnit.DAYS); } catch (Exception e) {} 156 | } 157 | finally { 158 | exec.shutdown(); 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/RTreeWrapper.java: -------------------------------------------------------------------------------- 1 | // RTreeWrapper.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import gnu.trove.procedure.TIntProcedure; 22 | 23 | import java.util.Properties; 24 | 25 | import net.sf.jsi.rtree.RTree; 26 | 27 | /** 28 | * A completely useless wrapper class for the RTree class. 29 | * 30 | * Actually the point to introduce the same overhead as 31 | * the SILWrapper class, so that performance comparisons 32 | * can be made. 33 | */ 34 | public class RTreeWrapper implements SpatialIndex { 35 | private RTree tree; 36 | 37 | class IntProcedure2 implements TIntProcedure { 38 | private TIntProcedure m_intProcedure = null; 39 | 40 | public IntProcedure2(TIntProcedure ip) { 41 | m_intProcedure = ip; 42 | } 43 | 44 | public boolean execute(int i) { 45 | return m_intProcedure.execute(i); 46 | } 47 | } 48 | 49 | /** 50 | * @see net.sf.jsi.SpatialIndex#init(Properties) 51 | */ 52 | public void init(Properties props) { 53 | // create a memory-based storage manager 54 | 55 | tree = new RTree(); 56 | tree.init(props); 57 | } 58 | 59 | /** 60 | * @see net.sf.jsi.SpatialIndex#nearest(Point, gnu.trove.TIntProcedure, float) 61 | */ 62 | public void nearest(Point p, TIntProcedure v, float furthestDistance) { 63 | tree.nearest(new Point(p.x, p.y), 64 | new IntProcedure2(v), 65 | Float.POSITIVE_INFINITY); 66 | } 67 | 68 | /** 69 | * @see net.sf.jsi.SpatialIndex#nearestN(Point, gnu.trove.TIntProcedure, int, float) 70 | */ 71 | public void nearestN(Point p, TIntProcedure v, int n, float furthestDistance) { 72 | tree.nearestN(new Point(p.x, p.y), 73 | new IntProcedure2(v), 74 | n, 75 | furthestDistance); 76 | } 77 | 78 | /** 79 | * @see net.sf.jsi.SpatialIndex#nearestNUnsorted(Point, gnu.trove.TIntProcedure, int, float) 80 | */ 81 | public void nearestNUnsorted(Point p, TIntProcedure v, int n, float furthestDistance) { 82 | tree.nearestNUnsorted(new Point(p.x, p.y), 83 | new IntProcedure2(v), 84 | n, 85 | furthestDistance); 86 | } 87 | 88 | /** 89 | * @see net.sf.jsi.SpatialIndex#intersects(Rectangle, gnu.trove.TIntProcedure) 90 | */ 91 | public void intersects(Rectangle r, TIntProcedure ip) { 92 | Rectangle r2 = new Rectangle(r.minX, r.minY, r.maxX, r.maxY); 93 | tree.intersects(r2, new IntProcedure2(ip)); 94 | } 95 | 96 | /** 97 | * @see net.sf.jsi.SpatialIndex#contains(Rectangle, gnu.trove.TIntProcedure) 98 | */ 99 | public void contains(Rectangle r, TIntProcedure ip) { 100 | Rectangle r2 = new Rectangle(r.minX, r.minY, r.maxX, r.maxY); 101 | tree.contains(r2, new IntProcedure2(ip)); 102 | } 103 | 104 | /** 105 | * @see net.sf.jsi.SpatialIndex#add(Rectangle, int) 106 | */ 107 | public void add(Rectangle r, int id) { 108 | Rectangle r2 = new Rectangle(r.minX, r.minY, r.maxX, r.maxY); 109 | tree.add(r2, id); 110 | } 111 | 112 | /** 113 | * @see net.sf.jsi.SpatialIndex#delete(Rectangle, int) 114 | */ 115 | public boolean delete(Rectangle r, int id) { 116 | Rectangle r2 = new Rectangle(r.minX, r.minY, r.maxX, r.maxY); 117 | return tree.delete(r2, id); 118 | } 119 | 120 | /** 121 | * @see net.sf.jsi.SpatialIndex#size() 122 | */ 123 | public int size() { 124 | return tree.size(); 125 | } 126 | 127 | /** 128 | * @see net.sf.jsi.SpatialIndex#getBounds() 129 | */ 130 | public Rectangle getBounds() { 131 | return tree.getBounds(); 132 | } 133 | 134 | /** 135 | * @see net.sf.jsi.SpatialIndex#getVersion() 136 | */ 137 | public String getVersion() { 138 | return "RTreeWrapper-" + BuildProperties.getVersion(); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/RectangleMaxValueTest.java: -------------------------------------------------------------------------------- 1 | package net.sf.jsi; 2 | 3 | import junit.framework.TestCase; 4 | 5 | import net.sf.jsi.Rectangle; 6 | import net.sf.jsi.rtree.RTree; 7 | 8 | public class RectangleMaxValueTest extends TestCase { 9 | public RectangleMaxValueTest(String name) { 10 | super(name); 11 | } 12 | 13 | public void testMaxValue() { 14 | RTree rTree = new RTree(); 15 | rTree.init(null); 16 | rTree.add(new Rectangle(8.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 1); 17 | rTree.add(new Rectangle(1.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 2); 18 | rTree.add(new Rectangle(10.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 3); 19 | rTree.add(new Rectangle(5.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 4); 20 | rTree.add(new Rectangle(6.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 6); 21 | rTree.add(new Rectangle(3.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 7); 22 | rTree.add(new Rectangle(9.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 8); 23 | rTree.add(new Rectangle(5.0f, 7.0f, Float.MAX_VALUE, Float.MAX_VALUE), 9); 24 | rTree.add(new Rectangle(2.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 10); 25 | rTree.add(new Rectangle(2.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 11); 26 | rTree.add(new Rectangle(5.0f, 3.0f, Float.MAX_VALUE, Float.MAX_VALUE), 14); 27 | rTree.add(new Rectangle(7.0f, 3.0f, Float.MAX_VALUE, Float.MAX_VALUE), 15); 28 | rTree.add(new Rectangle(6.0f, 3.0f, Float.MAX_VALUE, Float.MAX_VALUE), 16); 29 | rTree.delete(new Rectangle(9.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 8); 30 | rTree.add(new Rectangle(7.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 17); 31 | rTree.add(new Rectangle(3.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 18); 32 | rTree.delete(new Rectangle(5.0f, 7.0f, Float.MAX_VALUE, Float.MAX_VALUE), 9); 33 | rTree.add(new Rectangle(4.0f, 7.0f, Float.MAX_VALUE, Float.MAX_VALUE), 19); 34 | rTree.delete(new Rectangle(2.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 10); 35 | rTree.add(new Rectangle(2.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 20); 36 | rTree.add(new Rectangle(9.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 21); 37 | rTree.add(new Rectangle(7.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 22); 38 | rTree.delete(new Rectangle(10.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 3); 39 | rTree.add(new Rectangle(3.0f, 4.0f, Float.MAX_VALUE, Float.MAX_VALUE), 23); 40 | rTree.delete(new Rectangle(3.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 7); 41 | rTree.add(new Rectangle(3.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 24); 42 | rTree.delete(new Rectangle(8.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 1); 43 | rTree.add(new Rectangle(3.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 25); 44 | rTree.delete(new Rectangle(7.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 17); 45 | rTree.add(new Rectangle(7.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 26); 46 | rTree.delete(new Rectangle(2.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 20); 47 | rTree.add(new Rectangle(0.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 27); 48 | rTree.delete(new Rectangle(2.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 11); 49 | rTree.add(new Rectangle(2.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 28); 50 | rTree.delete(new Rectangle(5.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 4); 51 | rTree.add(new Rectangle(4.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 29); 52 | rTree.delete(new Rectangle(5.0f, 3.0f, Float.MAX_VALUE, Float.MAX_VALUE), 14); 53 | rTree.add(new Rectangle(5.0f, 3.0f, Float.MAX_VALUE, Float.MAX_VALUE), 30); 54 | rTree.add(new Rectangle(7.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 31); 55 | rTree.delete(new Rectangle(7.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 31); 56 | rTree.add(new Rectangle(7.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 32); 57 | rTree.add(new Rectangle(5.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 33); 58 | rTree.delete(new Rectangle(2.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 28); 59 | rTree.add(new Rectangle(1.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 34); 60 | rTree.delete(new Rectangle(0.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 27); 61 | rTree.add(new Rectangle(0.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 35); 62 | rTree.add(new Rectangle(8.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 36); 63 | rTree.delete(new Rectangle(3.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 18); 64 | rTree.add(new Rectangle(3.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 37); 65 | rTree.add(new Rectangle(8.0f, 7.0f, Float.MAX_VALUE, Float.MAX_VALUE), 39); 66 | rTree.delete(new Rectangle(7.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 22); 67 | rTree.add(new Rectangle(5.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 40); 68 | rTree.delete(new Rectangle(3.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 24); 69 | rTree.add(new Rectangle(3.0f, 0.0f, Float.MAX_VALUE, Float.MAX_VALUE), 41); 70 | rTree.delete(new Rectangle(7.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 26); 71 | rTree.add(new Rectangle(7.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 42); 72 | rTree.delete(new Rectangle(7.0f, 3.0f, Float.MAX_VALUE, Float.MAX_VALUE), 15); 73 | rTree.add(new Rectangle(3.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 43); 74 | rTree.delete(new Rectangle(4.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 29); 75 | rTree.add(new Rectangle(4.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 44); 76 | rTree.delete(new Rectangle(3.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 25); 77 | rTree.add(new Rectangle(3.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 45); 78 | rTree.delete(new Rectangle(3.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 43); 79 | rTree.add(new Rectangle(1.0f, 0.0f, Float.MAX_VALUE, Float.MAX_VALUE), 46); 80 | rTree.delete(new Rectangle(1.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 2); 81 | rTree.add(new Rectangle(1.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 47); 82 | rTree.delete(new Rectangle(9.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 21); 83 | rTree.add(new Rectangle(7.0f, 6.0f, Float.MAX_VALUE, Float.MAX_VALUE), 48); 84 | rTree.delete(new Rectangle(4.0f, 7.0f, Float.MAX_VALUE, Float.MAX_VALUE), 19); 85 | rTree.add(new Rectangle(4.0f, 0.0f, Float.MAX_VALUE, Float.MAX_VALUE), 49); 86 | rTree.delete(new Rectangle(5.0f, 3.0f, Float.MAX_VALUE, Float.MAX_VALUE), 30); 87 | rTree.add(new Rectangle(0.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 50); 88 | rTree.delete(new Rectangle(5.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 33); 89 | rTree.add(new Rectangle(4.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 51); 90 | rTree.delete(new Rectangle(3.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 45); 91 | rTree.add(new Rectangle(3.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 52); 92 | rTree.delete(new Rectangle(7.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 42); 93 | rTree.add(new Rectangle(7.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 53); 94 | rTree.delete(new Rectangle(5.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 40); 95 | rTree.add(new Rectangle(3.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 54); 96 | rTree.delete(new Rectangle(6.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 6); 97 | rTree.add(new Rectangle(6.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 55); 98 | rTree.delete(new Rectangle(4.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 51); 99 | rTree.add(new Rectangle(4.0f, 8.0f, Float.MAX_VALUE, Float.MAX_VALUE), 56); 100 | rTree.delete(new Rectangle(1.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 47); 101 | rTree.add(new Rectangle(1.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 57); 102 | rTree.delete(new Rectangle(0.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 50); 103 | rTree.add(new Rectangle(0.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 58); 104 | rTree.delete(new Rectangle(3.0f, 0.0f, Float.MAX_VALUE, Float.MAX_VALUE), 41); 105 | rTree.add(new Rectangle(3.0f, 0.0f, Float.MAX_VALUE, Float.MAX_VALUE), 59); 106 | rTree.delete(new Rectangle(7.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 53); 107 | rTree.add(new Rectangle(0.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 60); 108 | rTree.delete(new Rectangle(6.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 55); 109 | rTree.add(new Rectangle(2.0f, 1.0f, Float.MAX_VALUE, Float.MAX_VALUE), 61); 110 | rTree.delete(new Rectangle(7.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 32); 111 | rTree.add(new Rectangle(0.0f, 5.0f, Float.MAX_VALUE, Float.MAX_VALUE), 62); 112 | rTree.delete(new Rectangle(0.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 58); 113 | rTree.add(new Rectangle(0.0f, 2.0f, Float.MAX_VALUE, Float.MAX_VALUE), 63); 114 | rTree.delete(new Rectangle(3.0f, 4.0f, Float.MAX_VALUE, Float.MAX_VALUE), 23); 115 | rTree.add(new Rectangle(3.0f, 3.0f, Float.MAX_VALUE, Float.MAX_VALUE), 64); 116 | rTree.delete(new Rectangle(8.0f, 7.0f, Float.MAX_VALUE, Float.MAX_VALUE), 39); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/RectangleTest.java: -------------------------------------------------------------------------------- 1 | // RectangleTest.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import junit.framework.TestCase; 22 | 23 | import net.sf.jsi.Rectangle; 24 | 25 | /** 26 | * RectangleTest 27 | */ 28 | public class RectangleTest extends TestCase { 29 | public RectangleTest(String s) { 30 | super(s); 31 | } 32 | 33 | public void testContains() { 34 | 35 | } 36 | 37 | public void testDistance() { 38 | 39 | } 40 | 41 | public void testIntersects() { 42 | Rectangle r0_0_0_0 = new Rectangle (0, 0, 0, 0); 43 | Rectangle r1_1_1_1 = new Rectangle (1, 1, 1, 1); 44 | Rectangle r2_2_6_6 = new Rectangle (2, 2, 6, 6); 45 | Rectangle r3_3_7_5 = new Rectangle (3, 3, 7, 5); 46 | Rectangle r3_3_5_7 = new Rectangle (3, 3, 5, 7); 47 | Rectangle r1_3_5_5 = new Rectangle (1, 3, 5, 5); 48 | Rectangle r3_1_5_5 = new Rectangle (3, 1, 5, 5); 49 | 50 | // A rectangle always intersects itself 51 | assertTrue(r0_0_0_0.intersects(r0_0_0_0)); 52 | assertTrue(r2_2_6_6.intersects(r2_2_6_6)); 53 | 54 | assertTrue(r0_0_0_0.intersects(r1_1_1_1) == false); 55 | assertTrue(r1_1_1_1.intersects(r0_0_0_0) == false); 56 | 57 | // Rectangles that intersect only on the right-hand side 58 | assertTrue(r2_2_6_6.intersects(r3_3_7_5)); 59 | assertTrue(r3_3_7_5.intersects(r2_2_6_6)); 60 | 61 | // Rectangles that touch only on the right hand side 62 | //assertTrue(r 63 | 64 | // Rectangles that intersect only on the top side 65 | assertTrue(r2_2_6_6.intersects(r3_3_5_7)); 66 | assertTrue(r3_3_5_7.intersects(r2_2_6_6)); 67 | 68 | // Rectangles that intersect only on the left-hand side 69 | assertTrue(r2_2_6_6.intersects(r1_3_5_5)); 70 | assertTrue(r1_3_5_5.intersects(r2_2_6_6)); 71 | 72 | // Rectangles that intersect only on the bottom side 73 | assertTrue(r2_2_6_6.intersects(r3_1_5_5)); 74 | assertTrue(r3_1_5_5.intersects(r2_2_6_6)); 75 | 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/ReferenceCompareTest.java: -------------------------------------------------------------------------------- 1 | // ReferenceCompareTest.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import java.util.Properties; 22 | 23 | import junit.framework.TestCase; 24 | 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | /** 29 | * ReferenceCompareTest 30 | * 31 | * Generates results used for comparing the performance of the Java Spatial 32 | * Index library against alternative implementations. 33 | */ 34 | public class ReferenceCompareTest extends TestCase { 35 | 36 | private static final Logger log = LoggerFactory.getLogger(ReferenceCompareTest.class); 37 | 38 | private Script script = new Script(); 39 | private Properties linear_3_6 = props("Linear", 3, 6); 40 | private Properties linear_5_10 = props("Linear", 5, 10); 41 | private Properties rstar_1_13 = props("RStar", 1, 13); 42 | private Properties rstar_6_13 = props("RStar", 6, 13); 43 | 44 | protected int entriesToTest = 100; 45 | 46 | public ReferenceCompareTest(String s) { 47 | super(s); 48 | } 49 | 50 | public int GetNumEntriesToTest() { 51 | return 100; 52 | } 53 | 54 | public Properties props(String treeVariant, int minNodeEntries, int maxNodeEntries) { 55 | Properties p = new Properties(); 56 | p.setProperty("MinNodeEntries", Integer.toString(minNodeEntries)); 57 | p.setProperty("MaxNodeEntries", Integer.toString(maxNodeEntries)); 58 | p.setProperty("TreeVariant", treeVariant); 59 | return p; 60 | } 61 | 62 | private void runComparisonTest(String scriptName, String referenceType, Properties refProps, String testType, Properties testProps) { 63 | log.info(scriptName + " - creating reference test results"); 64 | script.run(referenceType, refProps, scriptName, Script.REFERENCE_GENERATE); 65 | 66 | log.info(scriptName + " - running comparison test"); 67 | script.run(testType, testProps, scriptName, Script.REFERENCE_COMPARISON); 68 | } 69 | 70 | 71 | // 100, 1000, 10,000 72 | // Reference results are generated by the SimpleIndex implementation. 73 | // Therefore, compare results for both SIL and JSI implementations. 74 | // 75 | // 100,000 76 | // Reference result generated by SIL, therefore compare results 77 | // for JSI only 78 | public void testReferenceCompareAllFunctions() { 79 | log.debug("testReferenceCompareAllFunctions()"); 80 | 81 | if (entriesToTest >= 100) { 82 | runComparisonTest("allfunctions-100", "SimpleIndex", null, "SILWrapper", linear_3_6); 83 | runComparisonTest("allfunctions-100", "SimpleIndex", null, "rtree.RTree", linear_3_6); 84 | } 85 | 86 | if (entriesToTest >= 1000) { 87 | runComparisonTest("allfunctions-1000", "SimpleIndex", null, "SILWrapper", linear_3_6); 88 | runComparisonTest("allfunctions-1000", "SimpleIndex", null, "rtree.RTree", linear_3_6); 89 | } 90 | 91 | if (entriesToTest >= 10000) { 92 | runComparisonTest("allfunctions-10000", "SimpleIndex", null, "SILWrapper", linear_3_6); 93 | runComparisonTest("allfunctions-10000", "SimpleIndex", null, "rtree.RTree", linear_3_6); 94 | } 95 | 96 | if (entriesToTest >= 100000) { 97 | runComparisonTest("allfunctions-100000", "SILWrapper", rstar_1_13, "rtree.RTree", linear_3_6); 98 | } 99 | } 100 | 101 | public void testReferenceCompareDelete() { 102 | log.debug("testReferenceCompareDelete()"); 103 | 104 | if (entriesToTest >= 100) { 105 | runComparisonTest("delete-100", "SimpleIndex", null, "SILWrapper", linear_3_6); 106 | runComparisonTest("delete-100", "SimpleIndex", null, "rtree.RTree", linear_3_6); 107 | } 108 | 109 | if (entriesToTest >= 1000) { 110 | runComparisonTest("delete-1000", "SimpleIndex", null, "SILWrapper", linear_3_6); 111 | runComparisonTest("delete-1000", "SimpleIndex", null, "rtree.RTree", linear_3_6); 112 | } 113 | 114 | if (entriesToTest >= 10000) { 115 | runComparisonTest("delete-10000", "SimpleIndex", null, "SILWrapper", linear_3_6); 116 | runComparisonTest("delete-10000", "SimpleIndex", null, "rtree.RTree", linear_3_6); 117 | } 118 | 119 | if (entriesToTest >= 100000) { 120 | runComparisonTest("delete-100000", "SILWrapper", rstar_1_13, "rtree.RTree", linear_3_6); 121 | } 122 | } 123 | 124 | public void testReferenceCompareIntersect() { 125 | log.debug("testReferenceCompareIntersect()"); 126 | 127 | if (entriesToTest >= 100) { 128 | runComparisonTest("intersect-100", "SimpleIndex", null, "SILWrapper", linear_5_10); 129 | runComparisonTest("intersect-100", "SimpleIndex", null, "rtree.RTree", linear_5_10); 130 | } 131 | 132 | if (entriesToTest >= 1000) { 133 | runComparisonTest("intersect-1000", "SimpleIndex", null, "SILWrapper", linear_5_10); 134 | runComparisonTest("intersect-1000", "SimpleIndex", null, "rtree.RTree", linear_5_10); 135 | } 136 | 137 | if (entriesToTest >= 10000) { 138 | runComparisonTest("intersect-10000", "SimpleIndex", null, "SILWrapper", linear_5_10); 139 | runComparisonTest("intersect-10000", "SimpleIndex", null, "rtree.RTree", linear_5_10); 140 | } 141 | 142 | if (entriesToTest >= 100000) { 143 | runComparisonTest("intersect-100000", "SILWrapper", rstar_1_13, "rtree.RTree", linear_5_10); 144 | } 145 | } 146 | 147 | public void testReferenceCompareNearest() { 148 | log.debug("testReferenceCompareNearest()"); 149 | 150 | if (entriesToTest >= 100) { 151 | runComparisonTest("nearest-100", "SimpleIndex", null, "SILWrapper", linear_5_10); 152 | runComparisonTest("nearest-100", "SimpleIndex", null, "rtree.RTree", linear_5_10); 153 | } 154 | 155 | if (entriesToTest >= 1000) { 156 | runComparisonTest("nearest-1000", "SimpleIndex", null, "SILWrapper", linear_5_10); 157 | runComparisonTest("nearest-1000", "SimpleIndex", null, "rtree.RTree", linear_5_10); 158 | } 159 | 160 | if (entriesToTest >= 10000) { 161 | runComparisonTest("nearest-10000", "SimpleIndex", null, "SILWrapper", linear_5_10); 162 | runComparisonTest("nearest-10000", "SimpleIndex", null, "rtree.RTree", linear_5_10); 163 | } 164 | 165 | if (entriesToTest >= 100000) { 166 | runComparisonTest("nearest-100000", "SILWrapper", rstar_1_13, "rtree.RTree", linear_5_10); 167 | } 168 | } 169 | 170 | public void testReferenceCompareNearestN() { 171 | log.debug("testReferenceCompareNearestN()"); 172 | 173 | if (entriesToTest >= 100) { 174 | runComparisonTest("nearestN-100", "SimpleIndex", null, "SILWrapper", linear_5_10); 175 | runComparisonTest("nearestN-100", "SimpleIndex", null, "rtree.RTree", linear_5_10); 176 | } 177 | 178 | if (entriesToTest >= 1000) { 179 | runComparisonTest("nearestN-1000", "SimpleIndex", null, "SILWrapper", linear_5_10); 180 | runComparisonTest("nearestN-1000", "SimpleIndex", null, "rtree.RTree", linear_5_10); 181 | } 182 | 183 | if (entriesToTest >= 10000) { 184 | runComparisonTest("nearestN-10000", "SimpleIndex", null, "SILWrapper", linear_5_10); 185 | runComparisonTest("nearestN-10000", "SimpleIndex", null, "rtree.RTree", linear_5_10); 186 | } 187 | 188 | if (entriesToTest >= 100000) { 189 | runComparisonTest("nearestN-100000", "SILWrapper", rstar_1_13, "rtree.RTree", linear_5_10); 190 | } 191 | } 192 | 193 | public void testReferenceCompareContains() { 194 | log.debug("testReferenceCompareContains()"); 195 | 196 | if (entriesToTest >= 100) { 197 | runComparisonTest("contains-100", "SimpleIndex", null, "SILWrapper", linear_5_10); 198 | runComparisonTest("contains-100", "SimpleIndex", null, "rtree.RTree", linear_5_10); 199 | } 200 | 201 | if (entriesToTest >= 1000) { 202 | runComparisonTest("contains-1000", "SimpleIndex", null, "SILWrapper", linear_5_10); 203 | runComparisonTest("contains-1000", "SimpleIndex", null, "rtree.RTree", linear_5_10); 204 | } 205 | 206 | if (entriesToTest >= 10000) { 207 | runComparisonTest("contains-10000", "SimpleIndex", null, "SILWrapper", linear_5_10); 208 | runComparisonTest("contains-10000", "SimpleIndex", null, "rtree.RTree", linear_5_10); 209 | } 210 | 211 | if (entriesToTest >= 100000) { 212 | runComparisonTest("contains-100000", "SILWrapper", rstar_6_13, "rtree.RTree", linear_5_10); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/ReferenceCompareTest_1000.java: -------------------------------------------------------------------------------- 1 | package net.sf.jsi; 2 | 3 | public class ReferenceCompareTest_1000 extends ReferenceCompareTest { 4 | public ReferenceCompareTest_1000(String s) { 5 | super(s); 6 | entriesToTest = 1000; 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/ReferenceCompareTest_10000.java: -------------------------------------------------------------------------------- 1 | package net.sf.jsi; 2 | 3 | public class ReferenceCompareTest_10000 extends ReferenceCompareTest { 4 | public ReferenceCompareTest_10000(String s) { 5 | super(s); 6 | entriesToTest = 10000; 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/ReferenceCompareTest_100000.java: -------------------------------------------------------------------------------- 1 | package net.sf.jsi; 2 | 3 | public class ReferenceCompareTest_100000 extends ReferenceCompareTest { 4 | public ReferenceCompareTest_100000(String s) { 5 | super(s); 6 | entriesToTest = 100000; 7 | } 8 | } 9 | 10 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/SILWrapper.java: -------------------------------------------------------------------------------- 1 | // SILWrapper.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import gnu.trove.procedure.TIntProcedure; 22 | 23 | import java.util.Properties; 24 | 25 | import org.slf4j.Logger; 26 | import org.slf4j.LoggerFactory; 27 | 28 | import sil.rtree.RTree; 29 | import sil.spatialindex.IData; 30 | import sil.spatialindex.INode; 31 | import sil.spatialindex.ISpatialIndex; 32 | import sil.spatialindex.IVisitor; 33 | import sil.spatialindex.Region; 34 | import sil.storagemanager.IStorageManager; 35 | import sil.storagemanager.MemoryStorageManager; 36 | import sil.storagemanager.PropertySet; 37 | 38 | /** 39 | * Wrapper class for the Spatial Index Library (v0.43b) written by 40 | * Marios Hadjieleftheriou (marioh@cs.ucr.edu), with minor modifications. 41 | * 42 | * Used to generate test results and performance comparisons. 43 | */ 44 | public class SILWrapper implements SpatialIndex { 45 | 46 | private static final Logger log = LoggerFactory.getLogger(SILWrapper.class); 47 | 48 | private IStorageManager storageManager = null; 49 | private ISpatialIndex tree = null; 50 | private int size = 0; 51 | 52 | class IntProcedureVisitor implements IVisitor { 53 | private TIntProcedure m_intProcedure = null; 54 | 55 | public IntProcedureVisitor(TIntProcedure ip) { 56 | m_intProcedure = ip; 57 | } 58 | 59 | public void visitNode(final INode n) { 60 | return; 61 | } 62 | 63 | public void visitData(final IData d) { 64 | m_intProcedure.execute(d.getIdentifier()); 65 | } 66 | } 67 | 68 | /** 69 | * @see net.sf.jsi.SpatialIndex#init(Properties) 70 | */ 71 | public void init(Properties props) { 72 | int minNodeEntries = Integer.parseInt(props.getProperty("MinNodeEntries", "0")); 73 | int maxNodeEntries = Integer.parseInt(props.getProperty("MaxNodeEntries", "0")); 74 | 75 | float fillFactor = (float) minNodeEntries / (float) maxNodeEntries; 76 | 77 | // create a memory-based storage manager 78 | storageManager = new MemoryStorageManager(); 79 | PropertySet propertySet = new PropertySet(); 80 | propertySet.setProperty("FillFactor", new Double(fillFactor)); 81 | propertySet.setProperty("IndexCapacity", new Integer(maxNodeEntries)); 82 | propertySet.setProperty("LeafCapacity", new Integer(maxNodeEntries)); 83 | propertySet.setProperty("Dimension", new Integer(2)); 84 | 85 | String strTreeVariant = props.getProperty("TreeVariant"); 86 | Integer intTreeVariant = null; 87 | if (strTreeVariant.equalsIgnoreCase("Linear")) { 88 | intTreeVariant = new Integer(sil.spatialindex.SpatialIndex.RtreeVariantLinear); 89 | } else if (strTreeVariant.equalsIgnoreCase("Quadratic")) { 90 | intTreeVariant = new Integer(sil.spatialindex.SpatialIndex.RtreeVariantQuadratic); 91 | } else { 92 | // default 93 | if (!strTreeVariant.equalsIgnoreCase("Rstar")) { 94 | log.error("Property key TreeVariant: invalid value " + strTreeVariant + ", defaulting to Rstar"); 95 | } 96 | intTreeVariant = new Integer(sil.spatialindex.SpatialIndex.RtreeVariantRstar); 97 | } 98 | propertySet.setProperty("TreeVariant", intTreeVariant); 99 | 100 | tree = new RTree(propertySet, storageManager); 101 | } 102 | 103 | /** 104 | * @see net.sf.jsi.SpatialIndex#nearest(Point p, gnu.trove.TIntProcedure ip, float) 105 | */ 106 | public void nearest(Point p, TIntProcedure v, float furthestDistance) { 107 | tree.nearestNeighborQuery(1, 108 | new sil.spatialindex.Point(new double[] {p.x, p.y}), 109 | new IntProcedureVisitor(v)); 110 | } 111 | 112 | /** 113 | * @see net.sf.jsi.SpatialIndex#nearestN(Point, gnu.trove.TIntProcedure, int, float) 114 | */ 115 | public void nearestN(Point p, TIntProcedure v, int n, float furthestDistance) { 116 | tree.nearestNeighborQuery(n, 117 | new sil.spatialindex.Point(new double[] {p.x, p.y}), 118 | new IntProcedureVisitor(v)); 119 | } 120 | 121 | /** 122 | * Same as nearestN 123 | * 124 | * @see net.sf.jsi.SpatialIndex#nearestNUnsorted(Point, gnu.trove.TIntProcedure, int, float) 125 | */ 126 | public void nearestNUnsorted(Point p, TIntProcedure v, int n, float furthestDistance) { 127 | nearestN(p, v, n, furthestDistance); 128 | } 129 | 130 | 131 | /** 132 | * @see net.sf.jsi.SpatialIndex#intersects(Rectangle, gnu.trove.TIntProcedure) 133 | */ 134 | public void intersects(Rectangle r, TIntProcedure v) { 135 | Region region = new Region(new double[] {r.minX, r.minY}, new double[] {r.maxX, r.maxY}); 136 | tree.intersectionQuery(region, new IntProcedureVisitor(v)); 137 | } 138 | 139 | /** 140 | * @see net.sf.jsi.SpatialIndex#contains(Rectangle, gnu.trove.TIntProcedure) 141 | */ 142 | public void contains(Rectangle r, TIntProcedure v) { 143 | Region region = new Region(new double[] {r.minX, r.minY}, new double[] {r.maxX, r.maxY}); 144 | tree.containmentQuery(region, new IntProcedureVisitor(v)); 145 | } 146 | 147 | /** 148 | * @see net.sf.jsi.SpatialIndex#add(Rectangle, int) 149 | */ 150 | public void add(Rectangle r, int id) { 151 | Region region = new Region(new double[] {r.minX, r.minY}, new double[] {r.maxX, r.maxY}); 152 | tree.insertData(null, region, (int)id); 153 | size++; 154 | } 155 | 156 | /** 157 | * @see net.sf.jsi.SpatialIndex#delete(Rectangle, int) 158 | */ 159 | public boolean delete(Rectangle r, int id) { 160 | Region region = new Region(new double[] {r.minX, r.minY}, new double[] {r.maxX, r.maxY}); 161 | if (tree.deleteData(region, (int)id)) { 162 | size--; 163 | return true; 164 | } 165 | return false; 166 | } 167 | 168 | /** 169 | * @see net.sf.jsi.SpatialIndex#size() 170 | */ 171 | public int size() { 172 | return size; 173 | } 174 | 175 | /** 176 | * @see net.sf.jsi.SpatialIndex#getBounds() 177 | */ 178 | public Rectangle getBounds() { 179 | return null; // operation not supported in Spatial Index Library 180 | } 181 | 182 | /** 183 | * @see net.sf.jsi.SpatialIndex#getVersion() 184 | */ 185 | public String getVersion() { 186 | return "SILWrapper-" + BuildProperties.getVersion(); 187 | } 188 | 189 | } 190 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/SimpleIndex.java: -------------------------------------------------------------------------------- 1 | // SimpleIndex.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import gnu.trove.list.array.TFloatArrayList; 22 | import gnu.trove.list.array.TIntArrayList; 23 | import gnu.trove.map.hash.TIntObjectHashMap; 24 | import gnu.trove.iterator.TIntObjectIterator; 25 | import gnu.trove.procedure.TIntProcedure; 26 | 27 | import java.util.Properties; 28 | 29 | /** 30 | * SimpleIndex 31 | * 32 | *

A very simple (and slow!) spatial index implementation, 33 | * intended only for generating test results.

34 | * 35 | *

All of the search methods, ie nearest(), contains() and intersects(), 36 | * run in linear time, so performance will be very slow with more 37 | * than 1000 or so entries.

38 | * 39 | *

On the other hand, the add() and delete() methods are very fast :-)

40 | */ 41 | public class SimpleIndex implements SpatialIndex { 42 | TIntObjectHashMap m_map = new TIntObjectHashMap(); 43 | 44 | /** 45 | * Does nothing. There are no implementation dependent properties for 46 | * the SimpleIndex spatial index. 47 | */ 48 | public void init(Properties p) { 49 | return; 50 | } 51 | 52 | /** 53 | * Nearest 54 | */ 55 | private TIntArrayList nearest(Point p, float furthestDistance) { 56 | TIntArrayList ret = new TIntArrayList(); 57 | float nearestDistance = furthestDistance; 58 | TIntObjectIterator i = m_map.iterator(); 59 | while (i.hasNext()) { 60 | i.advance(); 61 | int currentId = i.key(); 62 | Rectangle currentRectangle = i.value(); 63 | float distance = currentRectangle.distance(p); 64 | if (distance < nearestDistance) { 65 | nearestDistance = distance; 66 | ret.clear(); 67 | } 68 | if (distance <= nearestDistance) { 69 | ret.add(currentId); 70 | } 71 | } 72 | return ret; 73 | } 74 | 75 | /** 76 | * @see net.sf.jsi.SpatialIndex#nearest(Point, gnu.trove.TIntProcedure, float) 77 | */ 78 | public void nearest(Point p, final TIntProcedure v, float furthestDistance) { 79 | TIntArrayList nearestList = nearest(p, furthestDistance); 80 | nearestList.forEach(new TIntProcedure() { 81 | public boolean execute(int id) { 82 | v.execute(id); 83 | return true; 84 | } 85 | }); 86 | } 87 | 88 | private TIntArrayList nearestN(Point p, int n, float furthestDistance) { 89 | TIntArrayList ids = new TIntArrayList(); 90 | TFloatArrayList distances = new TFloatArrayList(); 91 | 92 | TIntObjectIterator iter = m_map.iterator(); 93 | while (iter.hasNext()) { 94 | iter.advance(); 95 | int currentId = iter.key(); 96 | Rectangle currentRectangle = iter.value(); 97 | float distance = currentRectangle.distance(p); 98 | 99 | if (distance <= furthestDistance) { 100 | int insertionIndex = 0; 101 | while (ids.size() > insertionIndex && distances.get(insertionIndex) <= distance) { 102 | insertionIndex++; 103 | } 104 | 105 | ids.insert(insertionIndex, currentId); 106 | distances.insert(insertionIndex, distance); 107 | 108 | // remove the entries with the greatest distance, if necessary. 109 | if (ids.size() > n) { 110 | // check that removing all entries with equal greatest distance 111 | // would leave at least N entries. 112 | int maxDistanceCount = 1; 113 | int currentIndex = distances.size() - 1; 114 | float maxDistance = distances.get(currentIndex); 115 | while (currentIndex - 1 >= 0 && distances.get(currentIndex - 1) == maxDistance) { 116 | currentIndex--; 117 | maxDistanceCount++; 118 | } 119 | if (ids.size() - maxDistanceCount >= n) { 120 | ids.remove(currentIndex, maxDistanceCount); 121 | distances.remove(currentIndex, maxDistanceCount); 122 | } 123 | } 124 | } 125 | } 126 | 127 | return ids; 128 | } 129 | 130 | /** 131 | * @see net.sf.jsi.SpatialIndex#nearestN(Point, gnu.trove.TIntProcedure, int, float) 132 | */ 133 | public void nearestN(Point p, final TIntProcedure v, int n, float furthestDistance) { 134 | TIntArrayList nearestList = nearestN(p, n, furthestDistance); 135 | nearestList.forEach(new TIntProcedure() { 136 | public boolean execute(int id) { 137 | v.execute(id); 138 | return true; 139 | } 140 | }); 141 | } 142 | 143 | /** 144 | * Same as nearestN 145 | * 146 | * @see net.sf.jsi.SpatialIndex#nearestNUnsorted(Point, gnu.trove.TIntProcedure, int, float) 147 | */ 148 | public void nearestNUnsorted(Point p, final TIntProcedure v, int n, float furthestDistance) { 149 | nearestN(p, v, n, furthestDistance); 150 | } 151 | 152 | /** 153 | * @see net.sf.jsi.SpatialIndex#intersects(Rectangle, gnu.trove.TIntProcedure) 154 | */ 155 | public void intersects(Rectangle r, TIntProcedure v) { 156 | TIntObjectIterator i = m_map.iterator(); 157 | while (i.hasNext()) { 158 | i.advance(); 159 | int currentId = i.key(); 160 | Rectangle currentRectangle = i.value(); 161 | if (r.intersects(currentRectangle)) { 162 | v.execute(currentId); 163 | } 164 | } 165 | } 166 | 167 | /** 168 | * @see net.sf.jsi.SpatialIndex#contains(Rectangle, gnu.trove.TIntProcedure) 169 | */ 170 | public void contains(Rectangle r, TIntProcedure v) { 171 | TIntObjectIterator i = m_map.iterator(); 172 | while (i.hasNext()) { 173 | i.advance(); 174 | int currentId = i.key(); 175 | Rectangle currentRectangle = i.value(); 176 | if (r.contains(currentRectangle)) { 177 | v.execute(currentId); 178 | } 179 | } 180 | return; 181 | } 182 | 183 | /** 184 | * @see net.sf.jsi.SpatialIndex#add(Rectangle, int) 185 | */ 186 | public void add(Rectangle r, int id) { 187 | m_map.put(id, r.copy()); 188 | } 189 | 190 | /** 191 | * @see net.sf.jsi.SpatialIndex#delete(Rectangle, int) 192 | */ 193 | public boolean delete(Rectangle r, int id) { 194 | Rectangle value = m_map.get(id); 195 | 196 | if (r.equals(value)) { 197 | m_map.remove(id); 198 | return true; 199 | } 200 | return false; 201 | } 202 | 203 | /** 204 | * @see net.sf.jsi.SpatialIndex#size() 205 | */ 206 | public int size() { 207 | return m_map.size(); 208 | } 209 | 210 | /** 211 | * @see net.sf.jsi.SpatialIndex#getBounds() 212 | */ 213 | public Rectangle getBounds() { 214 | Rectangle bounds = null; 215 | TIntObjectIterator i = m_map.iterator(); 216 | while (i.hasNext()) { 217 | i.advance(); 218 | Rectangle currentRectangle = i.value(); 219 | if (bounds == null) { 220 | bounds = currentRectangle.copy(); 221 | } else { 222 | bounds.add(currentRectangle); 223 | } 224 | } 225 | return bounds; 226 | } 227 | 228 | /** 229 | * @see net.sf.jsi.SpatialIndex#getVersion 230 | */ 231 | public String getVersion() { 232 | return "SimpleIndex-" + BuildProperties.getVersion(); 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/SortedListDecorator.java: -------------------------------------------------------------------------------- 1 | // SortedListDecorator.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import java.util.Collections; 22 | import java.util.List; 23 | 24 | import net.sf.jsi.Point; 25 | import net.sf.jsi.Rectangle; 26 | import net.sf.jsi.SpatialIndex; 27 | 28 | /** 29 | * SortedListDecorator 30 | */ 31 | public class SortedListDecorator extends ListDecorator { 32 | 33 | public SortedListDecorator(SpatialIndex si) { 34 | super(si); 35 | } 36 | 37 | private List sort(List l) { 38 | Collections.sort(l); 39 | return l; 40 | } 41 | 42 | public List nearestN(Point p, int maxCount, float furthestDistance) { 43 | return sort(super.nearestN(p, maxCount, furthestDistance)); 44 | } 45 | 46 | public List nearest(Point p, float furthestDistance) { 47 | return sort(super.nearest(p, furthestDistance)); 48 | } 49 | 50 | public List intersects(Rectangle r) { 51 | return sort(super.intersects(r)); 52 | } 53 | 54 | public List contains(Rectangle r) { 55 | return sort(super.contains(r)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/SortedListTest.java: -------------------------------------------------------------------------------- 1 | // SortedListTest.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import java.util.Arrays; 22 | 23 | import junit.framework.TestCase; 24 | 25 | import net.sf.jsi.rtree.SortedList; 26 | 27 | public class SortedListTest extends TestCase { 28 | 29 | public SortedListTest(String s) { 30 | super(s); 31 | } 32 | 33 | private boolean checkExpected(SortedList sl, int[] ids) { 34 | if (Arrays.equals(sl.toNativeArray(), ids)) { 35 | return true; 36 | } 37 | return false; 38 | } 39 | 40 | public void testSortedList() { 41 | SortedList sl = new SortedList(); 42 | sl.init(1); 43 | 44 | sl.add(10, 10.0F); 45 | checkExpected(sl, new int[] {10}); 46 | 47 | sl.add(9, 9.0F); 48 | checkExpected(sl, new int[] {10}); 49 | 50 | sl.init(3); 51 | 52 | // add in reverse priority order 53 | sl.add(10, 10.0F); 54 | checkExpected(sl, new int[] {10}); 55 | 56 | sl.add(9, 9.0F); 57 | checkExpected(sl, new int[] {10, 9}); 58 | 59 | sl.add(8, 8.0F); 60 | checkExpected(sl, new int[] {10, 9, 8}); 61 | 62 | // add elements with priority lower than lowest priority; 63 | // when current size = preferredMaxSize 64 | sl.add(7, 7.0F); 65 | checkExpected(sl, new int[] {10, 9, 8}); 66 | 67 | sl.add(6, 6.0F); 68 | checkExpected(sl, new int[] {10, 9, 8}); 69 | 70 | // add element with priority equal to lowest priority 71 | // when currentSize = preferredMaxSize 72 | sl.add(8, 8.0F); 73 | checkExpected(sl, new int[] {10, 9, 8, 8}); 74 | 75 | // add elements with priority lower than lowest priority; 76 | // when current size = preferredMaxSize + 1 77 | sl.add(7, 7.0F); 78 | checkExpected(sl, new int[] {10, 9, 8, 8}); 79 | 80 | // add element with priority equal to lowest priority 81 | // when current size = preferredMaxSize + 1 82 | sl.add(8, 8.0F); 83 | checkExpected(sl, new int[] {10, 9, 8, 8, 8}); 84 | 85 | // add elements with priority lower than lowest priority; 86 | // when current size = preferredMaxSize + 2 87 | sl.add(7, 7.0F); 88 | checkExpected(sl, new int[] {10, 9, 8, 8, 8}); 89 | 90 | // add element that will remove multiple entries of lowest priority 91 | sl.add(9, 9.0F); 92 | checkExpected(sl, new int[] {10, 9, 9}); 93 | 94 | 95 | // add in priority order 96 | sl.init(3); 97 | sl.add(1, 1.0F); 98 | checkExpected(sl, new int[] {1}); 99 | 100 | sl.add(2, 2.0F); 101 | checkExpected(sl, new int[] {2, 1}); 102 | 103 | sl.add(3, 3.0F); 104 | checkExpected(sl, new int[] {3, 2, 1}); 105 | 106 | sl.add(4, 4.0F); 107 | checkExpected(sl, new int[] {4, 3, 2}); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/net/sf/jsi/SpatialIndexFactory.java: -------------------------------------------------------------------------------- 1 | // SpatialIndexFactory.java 2 | // Java Spatial Index Library 3 | // Copyright (C) 2002-2005 Infomatiq Limited. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | 19 | package net.sf.jsi; 20 | 21 | import java.util.Properties; 22 | 23 | import org.slf4j.Logger; 24 | import org.slf4j.LoggerFactory; 25 | 26 | import net.sf.jsi.SpatialIndex; 27 | 28 | /** 29 | * Factory class used to create instances of spatial indexes 30 | */ 31 | public class SpatialIndexFactory { 32 | 33 | private final static Logger log = 34 | LoggerFactory.getLogger(SpatialIndexFactory.class); 35 | 36 | public static SpatialIndex newInstance(String type) { 37 | return newInstance(type, null); 38 | } 39 | 40 | public static SpatialIndex newInstance(String type, Properties props) { 41 | SpatialIndex si = null; 42 | String className = "net.sf.jsi." + type; 43 | try { 44 | si = (SpatialIndex) Class.forName(className).newInstance(); 45 | si.init(props); 46 | } catch (ClassNotFoundException cnfe) { 47 | log.error(cnfe.toString()); 48 | } catch (IllegalAccessException iae) { 49 | log.error(iae.toString()); 50 | } catch (InstantiationException ie) { 51 | log.error(ie.toString()); 52 | } 53 | 54 | return si; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/test/java/sil/rtree/Index.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License aint with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.rtree; 31 | 32 | import java.util.ArrayList; 33 | import java.util.Arrays; 34 | import java.util.Comparator; 35 | import java.util.Stack; 36 | 37 | import sil.spatialindex.SpatialIndex; 38 | import sil.spatialindex.Region; 39 | 40 | public class Index extends Node 41 | { 42 | public Index(RTree pTree, int id, int level) 43 | { 44 | super(pTree, id, level, pTree.m_indexCapacity); 45 | } 46 | 47 | protected Node chooseSubtree(Region mbr, int level, Stack pathBuffer) 48 | { 49 | if (m_level == level) return this; 50 | 51 | pathBuffer.push(new Integer(m_identifier)); 52 | 53 | int child = 0; 54 | 55 | switch (m_pTree.m_treeVariant) 56 | { 57 | case SpatialIndex.RtreeVariantLinear: 58 | case SpatialIndex.RtreeVariantQuadratic: 59 | child = findLeastEnlargement(mbr); 60 | break; 61 | case SpatialIndex.RtreeVariantRstar: 62 | if (m_level == 1) 63 | { 64 | // if this node points to leaves... 65 | child = findLeastOverlap(mbr); 66 | } 67 | else 68 | { 69 | child = findLeastEnlargement(mbr); 70 | } 71 | break; 72 | default: 73 | throw new IllegalStateException("Unknown RTree variant."); 74 | } 75 | 76 | Node n = m_pTree.readNode(m_pIdentifier[child]); 77 | Node ret = n.chooseSubtree(mbr, level, pathBuffer); 78 | 79 | return ret; 80 | } 81 | 82 | protected Leaf findLeaf(Region mbr, int id, Stack pathBuffer) 83 | { 84 | pathBuffer.push(new Integer(m_identifier)); 85 | 86 | for (int cChild = 0; cChild < m_children; cChild++) 87 | { 88 | if (m_pMBR[cChild].contains(mbr)) 89 | { 90 | Node n = m_pTree.readNode(m_pIdentifier[cChild]); 91 | Leaf l = n.findLeaf(mbr, id, pathBuffer); 92 | if (l != null) return l; 93 | } 94 | } 95 | 96 | pathBuffer.pop(); 97 | 98 | return null; 99 | } 100 | 101 | protected Node[] split(byte[] pData, Region mbr, int id) 102 | { 103 | m_pTree.m_stats.m_splits++; 104 | 105 | ArrayList g1 = new ArrayList(), g2 = new ArrayList(); 106 | 107 | switch (m_pTree.m_treeVariant) 108 | { 109 | case SpatialIndex.RtreeVariantLinear: 110 | case SpatialIndex.RtreeVariantQuadratic: 111 | rtreeSplit(pData, mbr, id, g1, g2); 112 | break; 113 | case SpatialIndex.RtreeVariantRstar: 114 | rstarSplit(pData, mbr, id, g1, g2); 115 | break; 116 | default: 117 | throw new IllegalStateException("Unknown RTree variant."); 118 | } 119 | 120 | Node left = new Index(m_pTree, m_identifier, m_level); 121 | Node right = new Index(m_pTree, -1, m_level); 122 | 123 | int cIndex; 124 | 125 | for (cIndex = 0; cIndex < g1.size(); cIndex++) 126 | { 127 | int i = ((Integer) g1.get(cIndex)).intValue(); 128 | left.insertEntry(null, m_pMBR[i], m_pIdentifier[i]); 129 | } 130 | 131 | for (cIndex = 0; cIndex < g2.size(); cIndex++) 132 | { 133 | int i = ((Integer) g2.get(cIndex)).intValue(); 134 | right.insertEntry(null, m_pMBR[i], m_pIdentifier[i]); 135 | } 136 | 137 | Node[] ret = new Node[2]; 138 | ret[0] = left; 139 | ret[1] = right; 140 | return ret; 141 | } 142 | 143 | protected int findLeastEnlargement(Region r) 144 | { 145 | double area = Double.POSITIVE_INFINITY; 146 | int best = -1; 147 | 148 | for (int cChild = 0; cChild < m_children; cChild++) 149 | { 150 | Region t = m_pMBR[cChild].combinedRegion(r); 151 | 152 | double a = m_pMBR[cChild].getArea(); 153 | double enl = t.getArea() - a; 154 | 155 | if (enl < area) 156 | { 157 | area = enl; 158 | best = cChild; 159 | } 160 | else if (enl == area) 161 | { 162 | if (a < m_pMBR[best].getArea()) best = cChild; 163 | } 164 | } 165 | 166 | return best; 167 | } 168 | 169 | protected int findLeastOverlap(Region r) 170 | { 171 | OverlapEntry[] entries = new OverlapEntry[m_children]; 172 | 173 | double leastOverlap = Double.POSITIVE_INFINITY; 174 | double me = Double.POSITIVE_INFINITY; 175 | int best = -1; 176 | 177 | // find combined region and enlargement of every entry and store it. 178 | for (int cChild = 0; cChild < m_children; cChild++) 179 | { 180 | OverlapEntry e = new OverlapEntry(); 181 | 182 | e.m_id = cChild; 183 | e.m_original = m_pMBR[cChild]; 184 | e.m_combined = m_pMBR[cChild].combinedRegion(r); 185 | e.m_oa = e.m_original.getArea(); 186 | e.m_ca = e.m_combined.getArea(); 187 | e.m_enlargement = e.m_ca - e.m_oa; 188 | entries[cChild] = e; 189 | 190 | if (e.m_enlargement < me) 191 | { 192 | me = e.m_enlargement; 193 | best = cChild; 194 | } 195 | else if (e.m_enlargement == me && e.m_oa < entries[best].m_oa) 196 | { 197 | best = cChild; 198 | } 199 | } 200 | 201 | if (me < SpatialIndex.EPSILON || me > SpatialIndex.EPSILON) 202 | { 203 | int cIterations; 204 | 205 | if (m_children > m_pTree.m_nearMinimumOverlapFactor) 206 | { 207 | // sort entries in increasing order of enlargement. 208 | Arrays.sort(entries, new OverlapEntryComparator()); 209 | cIterations = m_pTree.m_nearMinimumOverlapFactor; 210 | } 211 | else 212 | { 213 | cIterations = m_children; 214 | } 215 | 216 | // calculate overlap of most important original entries (near minimum overlap cost). 217 | for (int cIndex = 0; cIndex < cIterations; cIndex++) 218 | { 219 | double dif = 0.0; 220 | OverlapEntry e = entries[cIndex]; 221 | 222 | for (int cChild = 0; cChild < m_children; cChild++) 223 | { 224 | if (e.m_id != cChild) 225 | { 226 | double f = e.m_combined.getIntersectingArea(m_pMBR[cChild]); 227 | if (f != 0.0) dif += f - e.m_original.getIntersectingArea(m_pMBR[cChild]); 228 | } 229 | } // for (cChild) 230 | 231 | if (dif < leastOverlap) 232 | { 233 | leastOverlap = dif; 234 | best = cIndex; 235 | } 236 | else if (dif == leastOverlap) 237 | { 238 | if (e.m_enlargement == entries[best].m_enlargement) 239 | { 240 | // keep the one with least area. 241 | if (e.m_original.getArea() < entries[best].m_original.getArea()) best = cIndex; 242 | } 243 | else 244 | { 245 | // keep the one with least enlargement. 246 | if (e.m_enlargement < entries[best].m_enlargement) best = cIndex; 247 | } 248 | } 249 | } // for (cIndex) 250 | } 251 | 252 | return entries[best].m_id; 253 | } 254 | 255 | protected void adjustTree(Node n, Stack pathBuffer) 256 | { 257 | m_pTree.m_stats.m_adjustments++; 258 | 259 | // find entry pointing to old node; 260 | int child; 261 | for (child = 0; child < m_children; child++) 262 | { 263 | if (m_pIdentifier[child] == n.m_identifier) break; 264 | } 265 | 266 | // MBR needs recalculation if either: 267 | // 1. the NEW child MBR is not contained. 268 | // 2. the OLD child MBR is touching. 269 | boolean b = m_nodeMBR.contains(n.m_nodeMBR); 270 | boolean recalc = (! b) ? true : m_nodeMBR.touches(m_pMBR[child]); 271 | 272 | m_pMBR[child] = (Region) n.m_nodeMBR.clone(); 273 | 274 | if (recalc) 275 | { 276 | for (int cDim = 0; cDim < m_pTree.m_dimension; cDim++) 277 | { 278 | m_nodeMBR.m_pLow[cDim] = Double.POSITIVE_INFINITY; 279 | m_nodeMBR.m_pHigh[cDim] = Double.NEGATIVE_INFINITY; 280 | 281 | for (int cChild = 0; cChild < m_children; cChild++) 282 | { 283 | m_nodeMBR.m_pLow[cDim] = Math.min(m_nodeMBR.m_pLow[cDim], m_pMBR[cChild].m_pLow[cDim]); 284 | m_nodeMBR.m_pHigh[cDim] = Math.max(m_nodeMBR.m_pHigh[cDim], m_pMBR[cChild].m_pHigh[cDim]); 285 | } 286 | } 287 | } 288 | 289 | m_pTree.writeNode(this); 290 | 291 | if (recalc && ! pathBuffer.empty()) 292 | { 293 | int cParent = ((Integer) pathBuffer.pop()).intValue(); 294 | Index p = (Index) m_pTree.readNode(cParent); 295 | p.adjustTree(this, pathBuffer); 296 | } 297 | } 298 | 299 | protected void adjustTree(Node n1, Node n2, Stack pathBuffer, boolean[] overflowTable) 300 | { 301 | m_pTree.m_stats.m_adjustments++; 302 | 303 | // find entry pointing to old node; 304 | int child; 305 | for (child = 0; child < m_children; child++) 306 | { 307 | if (m_pIdentifier[child] == n1.m_identifier) break; 308 | } 309 | 310 | // MBR needs recalculation if either: 311 | // 1. the NEW child MBR is not contained. 312 | // 2. the OLD child MBR is touching. 313 | boolean b = m_nodeMBR.contains(n1.m_nodeMBR); 314 | boolean recalc = (! b) ? true : m_nodeMBR.touches(m_pMBR[child]); 315 | 316 | m_pMBR[child] = (Region) n1.m_nodeMBR.clone(); 317 | 318 | if (recalc) 319 | { 320 | for (int cDim = 0; cDim < m_pTree.m_dimension; cDim++) 321 | { 322 | m_nodeMBR.m_pLow[cDim] = Double.POSITIVE_INFINITY; 323 | m_nodeMBR.m_pHigh[cDim] = Double.NEGATIVE_INFINITY; 324 | 325 | for (int cChild = 0; cChild < m_children; cChild++) 326 | { 327 | m_nodeMBR.m_pLow[cDim] = Math.min(m_nodeMBR.m_pLow[cDim], m_pMBR[cChild].m_pLow[cDim]); 328 | m_nodeMBR.m_pHigh[cDim] = Math.max(m_nodeMBR.m_pHigh[cDim], m_pMBR[cChild].m_pHigh[cDim]); 329 | } 330 | } 331 | } 332 | 333 | // No write necessary here. insertData will write the node if needed. 334 | //m_pTree.writeNode(this); 335 | 336 | boolean adjusted = insertData(null, (Region) n2.m_nodeMBR.clone(), n2.m_identifier, pathBuffer, overflowTable); 337 | 338 | // if n2 is contained in the node and there was no split or reinsert, 339 | // we need to adjust only if recalculation took place. 340 | // In all other cases insertData above took care of adjustment. 341 | if (! adjusted && recalc && ! pathBuffer.empty()) 342 | { 343 | int cParent = ((Integer) pathBuffer.pop()).intValue(); 344 | Index p = (Index) m_pTree.readNode(cParent); 345 | p.adjustTree(this, pathBuffer); 346 | } 347 | } 348 | 349 | class OverlapEntry 350 | { 351 | int m_id; 352 | double m_enlargement; 353 | Region m_original; 354 | Region m_combined; 355 | double m_oa; 356 | double m_ca; 357 | } 358 | 359 | class OverlapEntryComparator implements Comparator 360 | { 361 | public int compare(Object o1, Object o2) 362 | { 363 | OverlapEntry e1 = (OverlapEntry) o1; 364 | OverlapEntry e2 = (OverlapEntry) o2; 365 | 366 | if (e1.m_enlargement < e2.m_enlargement) return -1; 367 | if (e1.m_enlargement > e2.m_enlargement) return 1; 368 | return 0; 369 | } 370 | } 371 | } 372 | -------------------------------------------------------------------------------- /src/test/java/sil/rtree/Leaf.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.rtree; 31 | 32 | import java.util.ArrayList; 33 | import java.util.Stack; 34 | 35 | import sil.spatialindex.Region; 36 | import sil.spatialindex.SpatialIndex; 37 | 38 | public class Leaf extends Node 39 | { 40 | public Leaf(RTree pTree, int id) 41 | { 42 | super(pTree, id, 0, pTree.m_leafCapacity); 43 | } 44 | 45 | protected Node chooseSubtree(Region mbr, int level, Stack pathBuffer) 46 | { 47 | return this; 48 | } 49 | 50 | protected Leaf findLeaf(Region mbr, int id, Stack pathBuffer) 51 | { 52 | for (int cChild = 0; cChild < m_children; cChild++) 53 | { 54 | if (m_pIdentifier[cChild] == id && mbr.equals(m_pMBR[cChild])) return this; 55 | } 56 | 57 | return null; 58 | } 59 | 60 | protected Node[] split(byte[] pData, Region mbr, int id) 61 | { 62 | m_pTree.m_stats.m_splits++; 63 | 64 | ArrayList g1 = new ArrayList(), g2 = new ArrayList(); 65 | 66 | switch (m_pTree.m_treeVariant) 67 | { 68 | case SpatialIndex.RtreeVariantLinear: 69 | case SpatialIndex.RtreeVariantQuadratic: 70 | rtreeSplit(pData, mbr, id, g1, g2); 71 | break; 72 | case SpatialIndex.RtreeVariantRstar: 73 | rstarSplit(pData, mbr, id, g1, g2); 74 | break; 75 | default: 76 | throw new IllegalStateException("Unknown RTree variant."); 77 | } 78 | 79 | Node left = new Leaf(m_pTree, -1); 80 | Node right = new Leaf(m_pTree, -1); 81 | 82 | int cIndex; 83 | 84 | for (cIndex = 0; cIndex < g1.size(); cIndex++) 85 | { 86 | int i = ((Integer) g1.get(cIndex)).intValue(); 87 | left.insertEntry(m_pData[i], m_pMBR[i], m_pIdentifier[i]); 88 | 89 | // we don't want to delete the data array from this node's destructor! 90 | m_pData[i] = null; 91 | } 92 | 93 | for (cIndex = 0; cIndex < g2.size(); cIndex++) 94 | { 95 | int i = ((Integer) g2.get(cIndex)).intValue(); 96 | right.insertEntry(m_pData[i], m_pMBR[i], m_pIdentifier[i]); 97 | 98 | // we don't want to delete the data array from this node's destructor! 99 | m_pData[i] = null; 100 | } 101 | 102 | Node[] ret = new Node[2]; 103 | ret[0] = left; 104 | ret[1] = right; 105 | return ret; 106 | } 107 | 108 | protected void deleteData(int id, Stack pathBuffer) 109 | { 110 | int child; 111 | for (child = 0; child < m_children; child++) 112 | { 113 | if (m_pIdentifier[child] == id) break; 114 | } 115 | 116 | deleteEntry(child); 117 | m_pTree.writeNode(this); 118 | 119 | Stack toReinsert = new Stack(); 120 | condenseTree(toReinsert, pathBuffer); 121 | 122 | // re-insert eliminated nodes. 123 | while (! toReinsert.empty()) 124 | { 125 | Node n = (Node) toReinsert.pop(); 126 | m_pTree.deleteNode(n); 127 | 128 | for (int cChild = 0; cChild < n.m_children; cChild++) 129 | { 130 | // keep this in the for loop. The tree height might change after insertions. 131 | boolean[] overflowTable = new boolean[m_pTree.m_stats.m_treeHeight]; 132 | for (int cLevel = 0; cLevel < m_pTree.m_stats.m_treeHeight; cLevel++) overflowTable[cLevel] = false; 133 | 134 | m_pTree.insertData_impl(n.m_pData[cChild], 135 | n.m_pMBR[cChild], n.m_pIdentifier[cChild], 136 | n.m_level, overflowTable); 137 | n.m_pData[cChild] = null; 138 | } 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/test/java/sil/rtree/Statistics.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.rtree; 31 | 32 | import java.util.ArrayList; 33 | 34 | import sil.spatialindex.IStatistics; 35 | 36 | public class Statistics implements IStatistics, Cloneable 37 | { 38 | protected long m_reads; 39 | protected long m_writes; 40 | protected long m_splits; 41 | protected long m_hits; 42 | protected long m_misses; 43 | protected long m_nodes; 44 | protected long m_adjustments; 45 | protected long m_queryResults; 46 | protected long m_data; 47 | protected int m_treeHeight; 48 | protected ArrayList m_nodesInLevel = new ArrayList(); 49 | 50 | public Statistics() 51 | { 52 | reset(); 53 | } 54 | 55 | public Statistics(Statistics s) 56 | { 57 | m_reads = s.m_reads; 58 | m_writes = s.m_writes; 59 | m_splits = s.m_splits; 60 | m_hits = s.m_hits; 61 | m_misses = s.m_misses; 62 | m_nodes = s.m_nodes; 63 | m_adjustments = s.m_adjustments; 64 | m_queryResults = s.m_queryResults; 65 | m_data = s.m_data; 66 | m_treeHeight = s.m_treeHeight; 67 | m_nodesInLevel = (ArrayList) s.m_nodesInLevel.clone(); 68 | } 69 | 70 | public long getReads() 71 | { 72 | return m_reads; 73 | } 74 | 75 | public long getWrites() 76 | { 77 | return m_writes; 78 | } 79 | 80 | public long getNumberOfNodes() 81 | { 82 | return m_nodes; 83 | } 84 | 85 | public long getNumberOfData() 86 | { 87 | return m_data; 88 | } 89 | 90 | public long getSplits() 91 | { 92 | return m_splits; 93 | } 94 | 95 | public long getHits() 96 | { 97 | return m_hits; 98 | } 99 | 100 | public long getMisses() 101 | { 102 | return m_misses; 103 | } 104 | 105 | public long getAdjustments() 106 | { 107 | return m_adjustments; 108 | } 109 | 110 | public long getQueryResults() 111 | { 112 | return m_queryResults; 113 | } 114 | 115 | public int getTreeHeight() 116 | { 117 | return m_treeHeight; 118 | } 119 | 120 | public int getNumberOfNodesInLevel(int l) throws IndexOutOfBoundsException 121 | { 122 | return ((Integer) m_nodesInLevel.get(l)).intValue(); 123 | } 124 | 125 | public void reset() 126 | { 127 | m_reads = 0; 128 | m_writes = 0; 129 | m_splits = 0; 130 | m_hits = 0; 131 | m_misses = 0; 132 | m_nodes = 0; 133 | m_adjustments = 0; 134 | m_queryResults = 0; 135 | m_data = 0; 136 | m_treeHeight = 0; 137 | m_nodesInLevel.clear(); 138 | } 139 | 140 | public String toString() 141 | { 142 | String s = "Reads: " + m_reads + "\n" + 143 | "Writes: " + m_writes + "\n" + 144 | "Hits: " + m_hits + "\n" + 145 | "Misses: " + m_misses + "\n" + 146 | "Tree height: " + m_treeHeight + "\n" + 147 | "Number of data: " + m_data + "\n" + 148 | "Number of nodes: " + m_nodes + "\n"; 149 | 150 | for (int cLevel = 0; cLevel < m_treeHeight; cLevel++) 151 | { 152 | s += "Level " + cLevel + " pages: " + ((Integer) m_nodesInLevel.get(cLevel)).intValue() + "\n"; 153 | } 154 | 155 | s += "Splits: " + m_splits + "\n" + 156 | "Adjustments: " + m_adjustments + "\n" + 157 | "Query results: " + m_queryResults; 158 | 159 | return s; 160 | } 161 | 162 | public Object clone() 163 | { 164 | return new Statistics(this); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/test/java/sil/rtree/makefile: -------------------------------------------------------------------------------- 1 | # Spatial Index Library 2 | # 3 | # Copyright (C) 2002 Navel Ltd. 4 | # 5 | # This library is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU Lesser General Public 7 | # License as published by the Free Software Foundation; either 8 | # version 2.1 of the License, or (at your option) any later version. 9 | # 10 | # This library is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # Lesser General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this library; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | # 19 | # Contact information: 20 | # Mailing address: 21 | # Marios Hadjieleftheriou 22 | # University of California, Riverside 23 | # Department of Computer Science 24 | # Surge Building, Room 310 25 | # Riverside, CA 92521 26 | # 27 | # Email: 28 | # marioh@cs.ucr.edu 29 | 30 | all: 31 | javac -source 1.4 -classpath ../lib -d ../lib -g:none *.java 32 | 33 | debug: 34 | javac -source 1.4 -classpath ../lib -d ../lib -g *.java 35 | 36 | clean: 37 | rm -rf ../lib/spatialindex/rtree 38 | 39 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/IData.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | public interface IData extends IEntry 33 | { 34 | public byte[] getData(); 35 | } // IData 36 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/IEntry.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | public interface IEntry 33 | { 34 | public int getIdentifier(); 35 | public IShape getShape(); 36 | } // IEntry 37 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/INearestNeighborComparator.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | public interface INearestNeighborComparator 33 | { 34 | public double getMinimumDistance(IShape query, IEntry e); 35 | } // INearestNeighborComparator 36 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/INode.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | public interface INode extends IEntry 33 | { 34 | public int getChildrenCount(); 35 | public int getChildIdentifier(int index) throws IndexOutOfBoundsException; 36 | public IShape getChildShape(int index) throws IndexOutOfBoundsException; 37 | public int getLevel(); 38 | public boolean isIndex(); 39 | public boolean isLeaf(); 40 | } // INode 41 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/INodeCommand.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | public interface INodeCommand 33 | { 34 | public void execute(INode n); 35 | } // INodeCommand 36 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/IQueryStrategy.java: -------------------------------------------------------------------------------- 1 | // 2 | // This library is free software; you can redistribute it and/or 3 | // modify it under the terms of the GNU Lesser General Public 4 | // License as published by the Free Software Foundation; either 5 | // version 2.1 of the License, or (at your option) any later version. 6 | // 7 | // This library is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | // Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public 13 | // License along with this library; if not, write to the Free Software 14 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | // 16 | // Contact information: 17 | // Mailing address: 18 | // Marios Hadjieleftheriou 19 | // University of California, Riverside 20 | // Department of Computer Science 21 | // Surge Building, Room 310 22 | // Riverside, CA 92521 23 | // 24 | // Email: 25 | // marioh@cs.ucr.edu 26 | 27 | package sil.spatialindex; 28 | 29 | public interface IQueryStrategy 30 | { 31 | public void getNextEntry(IEntry e, int[] nextEntry, boolean[] hasNext); 32 | } // IQueryStrategy 33 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/IShape.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | public interface IShape 33 | { 34 | public boolean intersects(final IShape s); 35 | public boolean contains(final IShape s); 36 | public boolean touches(final IShape s); 37 | public double[] getCenter(); 38 | public long getDimension(); 39 | public Region getMBR(); 40 | public double getArea(); 41 | public double getMinimumDistance(final IShape s); 42 | } // IShape 43 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/ISpatialIndex.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | import sil.storagemanager.PropertySet; 33 | 34 | public interface ISpatialIndex 35 | { 36 | public void flush() throws IllegalStateException; 37 | public void insertData(final byte[] data, final IShape shape, int id); 38 | public boolean deleteData(final IShape shape, int id); 39 | public void containmentQuery(final IShape query, final IVisitor v); 40 | public void intersectionQuery(final IShape query, final IVisitor v); 41 | public void pointLocationQuery(final IShape query, final IVisitor v); 42 | public void nearestNeighborQuery(int k, final IShape query, final IVisitor v, INearestNeighborComparator nnc); 43 | public void nearestNeighborQuery(int k, final IShape query, final IVisitor v); 44 | public void queryStrategy(final IQueryStrategy qs); 45 | public PropertySet getIndexProperties(); 46 | public void addWriteNodeCommand(INodeCommand nc); 47 | public void addReadNodeCommand(INodeCommand nc); 48 | public void addDeleteNodeCommand(INodeCommand nc); 49 | public boolean isIndexValid(); 50 | public IStatistics getStatistics(); 51 | } // ISpatialIndex 52 | 53 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/IStatistics.java: -------------------------------------------------------------------------------- 1 | // 2 | // This library is free software; you can redistribute it and/or 3 | // modify it under the terms of the GNU Lesser General Public 4 | // License as published by the Free Software Foundation; either 5 | // version 2.1 of the License, or (at your option) any later version. 6 | // 7 | // This library is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | // Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public 13 | // License along with this library; if not, write to the Free Software 14 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | // 16 | // Contact information: 17 | // Mailing address: 18 | // Marios Hadjieleftheriou 19 | // University of California, Riverside 20 | // Department of Computer Science 21 | // Surge Building, Room 310 22 | // Riverside, CA 92521 23 | // 24 | // Email: 25 | // marioh@cs.ucr.edu 26 | 27 | package sil.spatialindex; 28 | 29 | public interface IStatistics 30 | { 31 | public long getReads(); 32 | public long getWrites(); 33 | public long getNumberOfNodes(); 34 | public long getNumberOfData(); 35 | } // IStatistics 36 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/IVisitor.java: -------------------------------------------------------------------------------- 1 | // 2 | // This library is free software; you can redistribute it and/or 3 | // modify it under the terms of the GNU Lesser General Public 4 | // License as published by the Free Software Foundation; either 5 | // version 2.1 of the License, or (at your option) any later version. 6 | // 7 | // This library is distributed in the hope that it will be useful, 8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 10 | // Lesser General Public License for more details. 11 | // 12 | // You should have received a copy of the GNU Lesser General Public 13 | // License along with this library; if not, write to the Free Software 14 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 15 | // 16 | // Contact information: 17 | // Mailing address: 18 | // Marios Hadjieleftheriou 19 | // University of California, Riverside 20 | // Department of Computer Science 21 | // Surge Building, Room 310 22 | // Riverside, CA 92521 23 | // 24 | // Email: 25 | // marioh@cs.ucr.edu 26 | 27 | package sil.spatialindex; 28 | 29 | public interface IVisitor 30 | { 31 | public void visitNode(final INode n); 32 | public void visitData(final IData d); 33 | } // IVisitor 34 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/Point.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | public class Point implements IShape, Cloneable 33 | { 34 | public double[] m_pCoords = null; 35 | 36 | public Point(double[] pCoords) 37 | { 38 | m_pCoords = new double[pCoords.length]; 39 | System.arraycopy(pCoords, 0, m_pCoords, 0, pCoords.length); 40 | } 41 | 42 | public Point(final Point pt) 43 | { 44 | m_pCoords = new double[pt.m_pCoords.length]; 45 | System.arraycopy(pt.m_pCoords, 0, m_pCoords, 0, pt.m_pCoords.length); 46 | } 47 | 48 | public boolean equals(Object o) 49 | { 50 | if (o instanceof Point) 51 | { 52 | Point pt = (Point) o; 53 | 54 | if (pt.m_pCoords.length != m_pCoords.length) return false; 55 | 56 | for (int cIndex = 0; cIndex < m_pCoords.length; cIndex++) 57 | { 58 | if (m_pCoords[cIndex] < pt.m_pCoords[cIndex] - SpatialIndex.EPSILON || 59 | m_pCoords[cIndex] > pt.m_pCoords[cIndex] + SpatialIndex.EPSILON) return false; 60 | } 61 | 62 | return true; 63 | } 64 | 65 | return false; 66 | } 67 | 68 | // 69 | // Cloneable interface 70 | // 71 | 72 | public Object clone() 73 | { 74 | return new Point(m_pCoords); 75 | } 76 | 77 | // 78 | // IShape interface 79 | // 80 | 81 | public boolean intersects(final IShape s) 82 | { 83 | if (s instanceof Region) return ((Region) s).contains(this); 84 | 85 | return false; 86 | } 87 | 88 | public boolean contains(final IShape s) 89 | { 90 | return false; 91 | } 92 | 93 | public boolean touches(final IShape s) 94 | { 95 | if (s instanceof Point && this.equals(s)) return true; 96 | 97 | if (s instanceof Region) return ((Region) s).touches(this); 98 | 99 | return false; 100 | } 101 | 102 | public double[] getCenter() 103 | { 104 | double[] pCoords = new double[m_pCoords.length]; 105 | System.arraycopy(m_pCoords, 0, pCoords, 0, m_pCoords.length); 106 | return pCoords; 107 | } 108 | 109 | public long getDimension() 110 | { 111 | return m_pCoords.length; 112 | } 113 | 114 | public Region getMBR() 115 | { 116 | return new Region(m_pCoords, m_pCoords); 117 | } 118 | 119 | public double getArea() 120 | { 121 | return 0.0f; 122 | } 123 | 124 | public double getMinimumDistance(final IShape s) 125 | { 126 | if (s instanceof Region) return ((Region) s).getMinimumDistance(this); 127 | 128 | if (s instanceof Point) return getMinimumDistance((Point) s); 129 | 130 | throw new IllegalStateException("getMinimumDistance: Not implemented yet!"); 131 | } 132 | 133 | double getMinimumDistance(final Point p) 134 | { 135 | if (m_pCoords.length != p.m_pCoords.length) throw new IllegalArgumentException("getMinimumDistance: Shape has the wrong number of dimensions."); 136 | 137 | double ret = 0.0; 138 | 139 | for (int cIndex = 0; cIndex < m_pCoords.length; cIndex++) 140 | { 141 | ret += Math.pow(m_pCoords[cIndex] - p.m_pCoords[cIndex], 2.0); 142 | } 143 | 144 | return Math.sqrt(ret); 145 | } 146 | 147 | public double getCoord(int index) throws IndexOutOfBoundsException 148 | { 149 | if (index >= m_pCoords.length) throw new IndexOutOfBoundsException("" + index); 150 | return m_pCoords[index]; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/RWLock.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License aint with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | // Readers/Writers lock by Allen Holub 31 | 32 | package sil.spatialindex; 33 | 34 | import java.util.*; 35 | 36 | public class RWLock 37 | { 38 | private int active_readers; 39 | private int waiting_readers; 40 | private int active_writers; 41 | 42 | private final LinkedList writer_locks = new LinkedList(); 43 | 44 | public synchronized void read_lock() 45 | { 46 | if (active_writers == 0 && writer_locks.size() == 0) 47 | ++active_readers; 48 | else 49 | { 50 | ++waiting_readers; 51 | try{ wait(); } catch (InterruptedException e) {} 52 | } 53 | } 54 | 55 | public synchronized boolean read_lock_noblock() 56 | { 57 | if (active_writers == 0 && writer_locks.size() == 0) 58 | { 59 | ++active_readers; 60 | return true; 61 | } 62 | return false; 63 | } 64 | 65 | public synchronized void read_unlock() 66 | { 67 | if (--active_readers == 0) notify_writers(); 68 | } 69 | 70 | public void write_lock() 71 | { 72 | Object lock = new Object(); 73 | synchronized(lock) 74 | { 75 | synchronized(this) 76 | { 77 | boolean okay_to_write = writer_locks.size() == 0 && active_readers == 0 && active_writers == 0; 78 | if (okay_to_write) 79 | { 80 | ++active_writers; 81 | return; // the "return" jumps over the "wait" call 82 | } 83 | 84 | writer_locks.addLast(lock); 85 | } 86 | try { lock.wait(); } catch (InterruptedException e) {} 87 | } 88 | } 89 | 90 | synchronized public boolean write_lock_noblock() 91 | { 92 | if (writer_locks.size() == 0 && active_readers == 0 && active_writers == 0) 93 | { 94 | ++active_writers; 95 | return true; 96 | } 97 | return false; 98 | } 99 | 100 | public synchronized void write_unlock() 101 | { 102 | --active_writers; 103 | if (waiting_readers > 0) // priority to waiting readers 104 | notify_readers(); 105 | else 106 | notify_writers(); 107 | } 108 | 109 | private void notify_readers() // must be accessed from a 110 | { // synchronized method 111 | active_readers += waiting_readers; 112 | waiting_readers = 0; 113 | notifyAll(); 114 | } 115 | 116 | private void notify_writers() // must be accessed from a 117 | { // synchronized method 118 | if (writer_locks.size() > 0) 119 | { 120 | Object oldest = writer_locks.removeFirst(); 121 | ++active_writers; 122 | synchronized(oldest) { oldest.notify(); } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/Region.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | public class Region implements IShape 33 | { 34 | public double[] m_pLow = null; 35 | public double[] m_pHigh = null; 36 | 37 | public Region() 38 | { 39 | } 40 | 41 | public Region(final double[] pLow, final double[] pHigh) 42 | { 43 | if (pLow.length != pHigh.length) throw new IllegalArgumentException("Region: arguments have different number of dimensions."); 44 | 45 | m_pLow = new double[pLow.length]; 46 | System.arraycopy(pLow, 0, m_pLow, 0, pLow.length); 47 | 48 | m_pHigh = new double[pHigh.length]; 49 | System.arraycopy(pHigh, 0, m_pHigh, 0, pHigh.length); 50 | } 51 | 52 | public Region(final Point low, final Point high) 53 | { 54 | if (low.m_pCoords.length != high.m_pCoords.length) throw new IllegalArgumentException("Region: arguments have different number of dimensions."); 55 | 56 | m_pLow = new double[low.m_pCoords.length]; 57 | System.arraycopy(low.m_pCoords, 0, m_pLow, 0, low.m_pCoords.length); 58 | m_pHigh = new double[high.m_pCoords.length]; 59 | System.arraycopy(high.m_pCoords, 0, m_pHigh, 0, high.m_pCoords.length); 60 | } 61 | 62 | public Region(final Region r) 63 | { 64 | m_pLow = new double[r.m_pLow.length]; 65 | System.arraycopy(r.m_pLow, 0, m_pLow, 0, r.m_pLow.length); 66 | m_pHigh = new double[r.m_pHigh.length]; 67 | System.arraycopy(r.m_pHigh, 0, m_pHigh, 0, r.m_pHigh.length); 68 | } 69 | 70 | public boolean equals(Object o) 71 | { 72 | if (o instanceof Region) 73 | { 74 | Region r = (Region) o; 75 | 76 | if (r.m_pLow.length != m_pLow.length) return false; 77 | 78 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 79 | { 80 | if (m_pLow[cIndex] < r.m_pLow[cIndex] - SpatialIndex.EPSILON || m_pLow[cIndex] > r.m_pLow[cIndex] + SpatialIndex.EPSILON || 81 | m_pHigh[cIndex] < r.m_pHigh[cIndex] - SpatialIndex.EPSILON || m_pHigh[cIndex] > r.m_pHigh[cIndex] + SpatialIndex.EPSILON) 82 | return false; 83 | } 84 | return true; 85 | } 86 | return false; 87 | } 88 | 89 | // 90 | // Cloneable interface 91 | // 92 | 93 | public Object clone() 94 | { 95 | return new Region(m_pLow, m_pHigh); 96 | } 97 | 98 | // 99 | // IShape interface 100 | // 101 | 102 | public boolean intersects(final IShape s) 103 | { 104 | if (s instanceof Region) return intersects((Region) s); 105 | 106 | if (s instanceof Point) return contains((Point) s); 107 | 108 | throw new IllegalStateException("intersects: Not implemented yet!"); 109 | } 110 | 111 | public boolean contains(final IShape s) 112 | { 113 | if (s instanceof Region) return contains((Region) s); 114 | 115 | if (s instanceof Point) return contains((Point) s); 116 | 117 | throw new IllegalStateException("contains: Not implemented yet!"); 118 | } 119 | 120 | public boolean touches(final IShape s) 121 | { 122 | if (s instanceof Region) return touches((Region) s); 123 | 124 | if (s instanceof Point) return touches((Point) s); 125 | 126 | throw new IllegalStateException("touches: Not implemented yet!"); 127 | } 128 | 129 | public double[] getCenter() 130 | { 131 | double[] pCoords = new double[m_pLow.length]; 132 | 133 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 134 | { 135 | pCoords[cIndex] = (m_pLow[cIndex] + m_pHigh[cIndex]) / 2.0; 136 | } 137 | 138 | return pCoords; 139 | } 140 | 141 | public long getDimension() 142 | { 143 | return m_pLow.length; 144 | } 145 | 146 | public Region getMBR() 147 | { 148 | return new Region(m_pLow, m_pHigh); 149 | } 150 | 151 | public double getArea() 152 | { 153 | double area = 1.0; 154 | 155 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 156 | { 157 | area *= m_pHigh[cIndex] - m_pLow[cIndex]; 158 | } 159 | 160 | return area; 161 | } 162 | 163 | public double getMinimumDistance(final IShape s) 164 | { 165 | if (s instanceof Region) return getMinimumDistance((Region) s); 166 | 167 | if (s instanceof Point) return getMinimumDistance((Point) s); 168 | 169 | throw new IllegalStateException("getMinimumDistance: Not implemented yet!"); 170 | } 171 | 172 | public boolean intersects(final Region r) 173 | { 174 | if (m_pLow.length != r.m_pLow.length) throw new IllegalArgumentException("intersects: Shape has the wrong number of dimensions."); 175 | 176 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 177 | { 178 | if (m_pLow[cIndex] > r.m_pHigh[cIndex] || m_pHigh[cIndex] < r.m_pLow[cIndex]) return false; 179 | } 180 | return true; 181 | } 182 | 183 | public boolean contains(final Region r) 184 | { 185 | if (m_pLow.length != r.m_pLow.length) throw new IllegalArgumentException("contains: Shape has the wrong number of dimensions."); 186 | 187 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 188 | { 189 | if (m_pLow[cIndex] > r.m_pLow[cIndex] || m_pHigh[cIndex] < r.m_pHigh[cIndex]) return false; 190 | } 191 | return true; 192 | } 193 | 194 | public boolean touches(final Region r) 195 | { 196 | if (m_pLow.length != r.m_pLow.length) throw new IllegalArgumentException("touches: Shape has the wrong number of dimensions."); 197 | 198 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 199 | { 200 | if ((m_pLow[cIndex] > r.m_pLow[cIndex] - SpatialIndex.EPSILON && m_pLow[cIndex] < r.m_pLow[cIndex] + SpatialIndex.EPSILON) || 201 | (m_pHigh[cIndex] > r.m_pHigh[cIndex] - SpatialIndex.EPSILON && m_pHigh[cIndex] < r.m_pHigh[cIndex] + SpatialIndex.EPSILON)) 202 | return true; 203 | } 204 | return false; 205 | } 206 | 207 | public double getMinimumDistance(final Region r) 208 | { 209 | if (m_pLow.length != r.m_pLow.length) throw new IllegalArgumentException("getMinimumDistance: Shape has the wrong number of dimensions."); 210 | 211 | double ret = 0.0; 212 | 213 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 214 | { 215 | double x = 0.0; 216 | 217 | if (r.m_pHigh[cIndex] < m_pLow[cIndex]) 218 | { 219 | x = Math.abs(r.m_pHigh[cIndex] - m_pLow[cIndex]); 220 | } 221 | else if (m_pHigh[cIndex] < r.m_pLow[cIndex]) 222 | { 223 | x = Math.abs(r.m_pLow[cIndex] - m_pHigh[cIndex]); 224 | } 225 | 226 | ret += x * x; 227 | } 228 | 229 | return Math.sqrt(ret); 230 | } 231 | 232 | public boolean contains(final Point p) 233 | { 234 | if (m_pLow.length != p.m_pCoords.length) throw new IllegalArgumentException("contains: Shape has the wrong number of dimensions."); 235 | 236 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 237 | { 238 | if (m_pLow[cIndex] > p.m_pCoords[cIndex] || m_pHigh[cIndex] < p.m_pCoords[cIndex]) return false; 239 | } 240 | return true; 241 | } 242 | 243 | public boolean touches(final Point p) 244 | { 245 | if (m_pLow.length != p.m_pCoords.length) throw new IllegalArgumentException("touches: Shape has the wrong number of dimensions."); 246 | 247 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 248 | { 249 | if ((m_pLow[cIndex] > p.m_pCoords[cIndex] - SpatialIndex.EPSILON && m_pLow[cIndex] < p.m_pCoords[cIndex] + SpatialIndex.EPSILON) || 250 | (m_pHigh[cIndex] > p.m_pCoords[cIndex] - SpatialIndex.EPSILON && m_pHigh[cIndex] < p.m_pCoords[cIndex] + SpatialIndex.EPSILON)) 251 | return true; 252 | } 253 | return false; 254 | } 255 | 256 | public double getMinimumDistance(final Point p) 257 | { 258 | if (m_pLow.length != p.m_pCoords.length) throw new IllegalArgumentException("getMinimumDistance: Shape has the wrong number of dimensions."); 259 | 260 | double ret = 0.0; 261 | 262 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 263 | { 264 | if (p.m_pCoords[cIndex] < m_pLow[cIndex]) 265 | { 266 | ret += Math.pow(m_pLow[cIndex] - p.m_pCoords[cIndex], 2.0); 267 | } 268 | else if (p.m_pCoords[cIndex] > m_pHigh[cIndex]) 269 | { 270 | ret += Math.pow(p.m_pCoords[cIndex] - m_pHigh[cIndex], 2.0); 271 | } 272 | } 273 | 274 | return Math.sqrt(ret); 275 | } 276 | 277 | public double getIntersectingArea(final Region r) 278 | { 279 | if (m_pLow.length != r.m_pLow.length) throw new IllegalArgumentException("getIntersectingArea: Shape has the wrong number of dimensions."); 280 | 281 | int cIndex; 282 | 283 | // check for intersection. 284 | // marioh: avoid function call since this is called billions of times. 285 | for (cIndex = 0; cIndex < m_pLow.length; cIndex++) 286 | { 287 | if (m_pLow[cIndex] > r.m_pHigh[cIndex] || m_pHigh[cIndex] < r.m_pLow[cIndex]) return 0.0; 288 | } 289 | 290 | double ret = 1.0; 291 | double f1, f2; 292 | 293 | for (cIndex = 0; cIndex < m_pLow.length; cIndex++) 294 | { 295 | f1 = Math.max(m_pLow[cIndex], r.m_pLow[cIndex]); 296 | f2 = Math.min(m_pHigh[cIndex], r.m_pHigh[cIndex]); 297 | ret *= f2 - f1; 298 | } 299 | 300 | return ret; 301 | } 302 | 303 | public Region combinedRegion(final Region r) 304 | { 305 | if (m_pLow.length != r.m_pLow.length) throw new IllegalArgumentException("combinedRegion: Shape has the wrong number of dimensions."); 306 | 307 | double[] mn = new double[m_pLow.length]; 308 | double[] mx = new double[m_pLow.length]; 309 | 310 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 311 | { 312 | mn[cIndex] = Math.min(m_pLow[cIndex], r.m_pLow[cIndex]); 313 | mx[cIndex] = Math.max(m_pHigh[cIndex], r.m_pHigh[cIndex]); 314 | } 315 | 316 | return new Region(mn, mx); 317 | } 318 | 319 | public static Region combinedRegion(Region[] pRegions) 320 | { 321 | double[] mn = new double[pRegions[0].m_pLow.length]; 322 | double[] mx = new double[pRegions[0].m_pLow.length]; 323 | 324 | for (int cDim = 0; cDim < pRegions[0].m_pLow.length; cDim++) 325 | { 326 | mn[cDim] = Double.POSITIVE_INFINITY; 327 | mx[cDim] = Double.NEGATIVE_INFINITY; 328 | 329 | for (int cIndex = 0; cIndex < pRegions.length; cIndex++) 330 | { 331 | mn[cDim] = Math.min(mn[cDim], pRegions[cIndex].m_pLow[cDim]); 332 | mx[cDim] = Math.max(mx[cDim], pRegions[cIndex].m_pHigh[cDim]); 333 | } 334 | } 335 | 336 | return new Region(mn, mx); 337 | } 338 | 339 | // Modifies the first argument to include the second. 340 | public static void combinedRegion(Region pToModify, final Region pConst) 341 | { 342 | if (pToModify.m_pLow.length != pConst.m_pLow.length) throw new IllegalArgumentException("combineRegion: Shape has the wrong number of dimensions."); 343 | 344 | for (int cIndex = 0; cIndex < pToModify.m_pLow.length; cIndex++) 345 | { 346 | pToModify.m_pLow[cIndex] = Math.min(pToModify.m_pLow[cIndex], pConst.m_pLow[cIndex]); 347 | pToModify.m_pHigh[cIndex] = Math.max(pToModify.m_pHigh[cIndex], pConst.m_pHigh[cIndex]); 348 | } 349 | } 350 | 351 | // Returns the margin of a region. It is calcuated as the sum of 2^(d-1) * width in each dimension. 352 | public double getMargin() 353 | { 354 | double mul = Math.pow(2.0, ((double) m_pLow.length) - 1.0); 355 | double margin = 0.0; 356 | 357 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) 358 | { 359 | margin += (m_pHigh[cIndex] - m_pLow[cIndex]) * mul; 360 | } 361 | 362 | return margin; 363 | } 364 | 365 | public double getLow(int index) throws IndexOutOfBoundsException 366 | { 367 | if (index >= m_pLow.length) throw new IndexOutOfBoundsException("" + index); 368 | return m_pLow[index]; 369 | } 370 | 371 | public double getHigh(int index) throws IndexOutOfBoundsException 372 | { 373 | if (index >= m_pLow.length) throw new IndexOutOfBoundsException("" + index); 374 | return m_pHigh[index]; 375 | } 376 | 377 | public String toString() 378 | { 379 | String s = ""; 380 | 381 | for (int cIndex = 0; cIndex < m_pLow.length; cIndex++) s += m_pLow[cIndex] + " "; 382 | 383 | s += ": "; 384 | 385 | for (int cIndex = 0; cIndex < m_pHigh.length; cIndex++) s += m_pHigh[cIndex] + " "; 386 | 387 | return s; 388 | } 389 | } 390 | -------------------------------------------------------------------------------- /src/test/java/sil/spatialindex/SpatialIndex.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.spatialindex; 31 | 32 | import java.io.FileNotFoundException; 33 | import java.io.IOException; 34 | 35 | import sil.storagemanager.DiskStorageManager; 36 | import sil.storagemanager.IStorageManager; 37 | import sil.storagemanager.MemoryStorageManager; 38 | import sil.storagemanager.PropertySet; 39 | 40 | public class SpatialIndex 41 | { 42 | public static final String EMAIL = "marioh@cs.ucr.edu"; 43 | public static final String VERSION = "0.44.2b"; 44 | public static final String DATE = "27 July 2003"; 45 | 46 | public static final double EPSILON = 1.192092896e-07; 47 | 48 | public static final int RtreeVariantQuadratic = 1; 49 | public static final int RtreeVariantLinear = 2; 50 | public static final int RtreeVariantRstar = 3; 51 | 52 | public static final int PersistentIndex = 1; 53 | public static final int PersistentLeaf = 2; 54 | 55 | public static final int ContainmentQuery = 1; 56 | public static final int IntersectionQuery = 2; 57 | 58 | public static ISpatialIndex createRTree(PropertySet ps, IStorageManager sm) 59 | { 60 | return null; 61 | } 62 | 63 | public static IStorageManager createMemoryStorageManager(PropertySet ps) 64 | { 65 | IStorageManager sm = (IStorageManager) new MemoryStorageManager(); 66 | return sm; 67 | } 68 | 69 | public static IStorageManager createDiskStorageManager(PropertySet ps) 70 | throws SecurityException, NullPointerException, IOException, FileNotFoundException, IllegalArgumentException 71 | { 72 | IStorageManager sm = (IStorageManager) new DiskStorageManager(ps); 73 | return sm; 74 | } 75 | } // SpatialIndex 76 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/Buffer.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.storagemanager; 31 | 32 | import java.util.*; 33 | 34 | public abstract class Buffer implements IBuffer 35 | { 36 | int m_capacity = 10; 37 | boolean m_bWriteThrough = false; 38 | IStorageManager m_storageManager = null; 39 | HashMap m_buffer = new HashMap(); 40 | long m_hits = 0; 41 | 42 | abstract void addEntry(int id, Entry entry); 43 | abstract void removeEntry(); 44 | 45 | public Buffer(IStorageManager sm, int capacity, boolean bWriteThrough) 46 | { 47 | m_storageManager = sm; 48 | m_capacity = capacity; 49 | m_bWriteThrough = bWriteThrough; 50 | } 51 | 52 | public byte[] loadByteArray(final int id) 53 | { 54 | byte[] ret = null; 55 | Entry e = (Entry) m_buffer.get(new Integer(id)); 56 | 57 | if (e != null) 58 | { 59 | m_hits++; 60 | 61 | ret = new byte[e.m_data.length]; 62 | System.arraycopy(e.m_data, 0, ret, 0, e.m_data.length); 63 | } 64 | else 65 | { 66 | ret = m_storageManager.loadByteArray(id); 67 | e = new Entry(ret); 68 | addEntry(id, e); 69 | } 70 | 71 | return ret; 72 | } 73 | public int storeByteArray(final int id, final byte[] data) 74 | { 75 | int ret = id; 76 | 77 | if (id == NewPage) 78 | { 79 | ret = m_storageManager.storeByteArray(id, data); 80 | Entry e = new Entry(data); 81 | addEntry(ret, e); 82 | } 83 | else 84 | { 85 | if (m_bWriteThrough) 86 | { 87 | m_storageManager.storeByteArray(id, data); 88 | } 89 | 90 | Entry e = (Entry) m_buffer.get(new Integer(id)); 91 | if (e != null) 92 | { 93 | e.m_data = new byte[data.length]; 94 | System.arraycopy(data, 0, e.m_data, 0, data.length); 95 | 96 | if (m_bWriteThrough == false) 97 | { 98 | e.m_bDirty = true; 99 | m_hits++; 100 | } 101 | else 102 | { 103 | e.m_bDirty = false; 104 | } 105 | } 106 | else 107 | { 108 | e = new Entry(data); 109 | if (m_bWriteThrough == false) e.m_bDirty = true; 110 | addEntry(id, e); 111 | } 112 | } 113 | 114 | return ret; 115 | } 116 | public void deleteByteArray(final int id) 117 | { 118 | Integer ID = new Integer(id); 119 | Entry e = (Entry) m_buffer.get(ID); 120 | if (e != null) 121 | { 122 | m_buffer.remove(ID); 123 | } 124 | 125 | m_storageManager.deleteByteArray(id); 126 | } 127 | 128 | public void flush() 129 | { 130 | Iterator it = m_buffer.entrySet().iterator(); 131 | 132 | while (it.hasNext()) 133 | { 134 | Map.Entry me = (Map.Entry) it.next(); 135 | Entry e = (Entry) me.getValue(); 136 | int id = ((Integer) me.getKey()).intValue(); 137 | if (e.m_bDirty) m_storageManager.storeByteArray(id, e.m_data); 138 | } 139 | 140 | m_storageManager.flush(); 141 | } 142 | public void clear() 143 | { 144 | Iterator it = m_buffer.entrySet().iterator(); 145 | 146 | while (it.hasNext()) 147 | { 148 | Map.Entry me = (Map.Entry) it.next(); 149 | Entry e = (Entry) me.getValue(); 150 | 151 | if (e.m_bDirty) 152 | { 153 | int id = ((Integer) me.getKey()).intValue(); 154 | m_storageManager.storeByteArray(id, e.m_data); 155 | } 156 | } 157 | 158 | m_buffer.clear(); 159 | m_hits = 0; 160 | } 161 | 162 | public long getHits() 163 | { 164 | return m_hits; 165 | } 166 | 167 | class Entry 168 | { 169 | byte[] m_data = null; 170 | boolean m_bDirty = false; 171 | 172 | Entry(final byte[] d) 173 | { 174 | m_data = new byte[d.length]; 175 | System.arraycopy(d, 0, m_data, 0, d.length); 176 | } 177 | }; // Entry 178 | 179 | } // Buffer 180 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/DiskStorageManager.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.storagemanager; 31 | 32 | import java.util.*; 33 | import java.io.*; 34 | 35 | public class DiskStorageManager implements IStorageManager 36 | { 37 | private RandomAccessFile m_dataFile = null; 38 | private RandomAccessFile m_indexFile = null; 39 | private int m_pageSize = 0; 40 | private int m_nextPage = -1; 41 | private TreeSet m_emptyPages = new TreeSet(); 42 | private HashMap m_pageIndex = new HashMap(); 43 | private byte[] m_buffer = null; 44 | 45 | public DiskStorageManager(PropertySet ps) 46 | throws SecurityException, NullPointerException, IOException, FileNotFoundException, IllegalArgumentException 47 | { 48 | Object var; 49 | 50 | // Open/Create flag. 51 | boolean bOverwrite = false; 52 | var = ps.getProperty("Overwrite"); 53 | 54 | if (var != null) 55 | { 56 | if (! (var instanceof Boolean)) throw new IllegalArgumentException("Property Overwrite must be a Boolean"); 57 | bOverwrite = ((Boolean) var).booleanValue(); 58 | } 59 | 60 | // storage filename. 61 | var = ps.getProperty("FileName"); 62 | 63 | if (var != null) 64 | { 65 | if (! (var instanceof String)) throw new IllegalArgumentException("Property FileName must be a String"); 66 | 67 | File indexFile = new File((String) var + ".idx"); 68 | File dataFile = new File((String) var + ".dat"); 69 | 70 | // check if files exist. 71 | if (bOverwrite == false && (! indexFile.exists() || ! dataFile.exists())) bOverwrite = true; 72 | 73 | if (bOverwrite) 74 | { 75 | if (indexFile.exists()) indexFile.delete(); 76 | if (dataFile.exists()) dataFile.delete(); 77 | 78 | boolean b = indexFile.createNewFile(); 79 | if (b == false) throw new IOException("Index file cannot be opened."); 80 | 81 | b = dataFile.createNewFile(); 82 | if (b == false) throw new IOException("Data file cannot be opened."); 83 | } 84 | 85 | m_indexFile = new RandomAccessFile(indexFile, "rw"); 86 | m_dataFile = new RandomAccessFile(dataFile, "rw"); 87 | } 88 | else 89 | { 90 | throw new IllegalArgumentException("Property FileName was not specified."); 91 | } 92 | 93 | // find page size. 94 | if (bOverwrite == true) 95 | { 96 | var = ps.getProperty("PageSize"); 97 | 98 | if (var != null) 99 | { 100 | if (! (var instanceof Integer)) throw new IllegalArgumentException("Property PageSize must be an Integer"); 101 | m_pageSize = ((Integer) var).intValue(); 102 | m_nextPage = 0; 103 | } 104 | else 105 | { 106 | throw new IllegalArgumentException("Property PageSize was not specified."); 107 | } 108 | } 109 | else 110 | { 111 | try 112 | { 113 | m_pageSize = m_indexFile.readInt(); 114 | } 115 | catch (EOFException ex) 116 | { 117 | throw new IllegalStateException("Failed reading pageSize."); 118 | } 119 | 120 | try 121 | { 122 | m_nextPage = m_indexFile.readInt(); 123 | } 124 | catch (EOFException ex) 125 | { 126 | throw new IllegalStateException("Failed reading nextPage."); 127 | } 128 | } 129 | 130 | // create buffer. 131 | m_buffer = new byte[m_pageSize]; 132 | 133 | if (bOverwrite == false) 134 | { 135 | int count, id, page; 136 | 137 | // load empty pages in memory. 138 | try 139 | { 140 | count = m_indexFile.readInt(); 141 | 142 | for (int cCount = 0; cCount < count; cCount++) 143 | { 144 | page = m_indexFile.readInt(); 145 | m_emptyPages.add(new Integer(page)); 146 | } 147 | 148 | // load index table in memory. 149 | count = m_indexFile.readInt(); 150 | 151 | for (int cCount = 0; cCount < count; cCount++) 152 | { 153 | Entry e = new Entry(); 154 | 155 | id = m_indexFile.readInt(); 156 | e.m_length = m_indexFile.readInt(); 157 | 158 | int count2 = m_indexFile.readInt(); 159 | 160 | for (int cCount2 = 0; cCount2 < count2; cCount2++) 161 | { 162 | page = m_indexFile.readInt(); 163 | e.m_pages.add(new Integer(page)); 164 | } 165 | m_pageIndex.put(new Integer(id), e); 166 | } 167 | } 168 | catch (EOFException ex) 169 | { 170 | throw new IllegalStateException("Corrupted index file."); 171 | } 172 | } 173 | } 174 | 175 | public void flush() 176 | { 177 | try 178 | { 179 | m_indexFile.seek(0l); 180 | 181 | m_indexFile.writeInt(m_pageSize); 182 | m_indexFile.writeInt(m_nextPage); 183 | 184 | int id, page; 185 | int count = m_emptyPages.size(); 186 | 187 | m_indexFile.writeInt(count); 188 | 189 | Iterator it = m_emptyPages.iterator(); 190 | while (it.hasNext()) 191 | { 192 | page = ((Integer) it.next()).intValue(); 193 | m_indexFile.writeInt(page); 194 | } 195 | 196 | count = m_pageIndex.size(); 197 | m_indexFile.writeInt(count); 198 | 199 | it = m_pageIndex.entrySet().iterator(); 200 | 201 | while (it.hasNext()) 202 | { 203 | Map.Entry me = (Map.Entry) it.next(); 204 | id = ((Integer) me.getKey()).intValue(); 205 | m_indexFile.writeInt(id); 206 | 207 | Entry e = (Entry) me.getValue(); 208 | count = e.m_length; 209 | m_indexFile.writeInt(count); 210 | 211 | count = e.m_pages.size(); 212 | m_indexFile.writeInt(count); 213 | 214 | for (int cIndex = 0; cIndex < count; cIndex++) 215 | { 216 | page = ((Integer) e.m_pages.get(cIndex)).intValue(); 217 | m_indexFile.writeInt(page); 218 | } 219 | } 220 | } 221 | catch (IOException ex) 222 | { 223 | throw new IllegalStateException("Corrupted index file."); 224 | } 225 | } 226 | 227 | public byte[] loadByteArray(final int id) 228 | { 229 | Entry e = (Entry) m_pageIndex.get(new Integer(id)); 230 | if (e == null) throw new InvalidPageException(id); 231 | 232 | int cNext = 0; 233 | int cTotal = e.m_pages.size(); 234 | 235 | byte[] data = new byte[e.m_length]; 236 | int cIndex = 0; 237 | int cLen; 238 | int cRem = e.m_length; 239 | 240 | do 241 | { 242 | try 243 | { 244 | m_dataFile.seek(((Integer) e.m_pages.get(cNext)).intValue() * m_pageSize); 245 | int bytesread = m_dataFile.read(m_buffer); 246 | if (bytesread != m_pageSize) throw new IllegalStateException("Corrupted data file."); 247 | } 248 | catch (IOException ex) 249 | { 250 | throw new IllegalStateException("Corrupted data file."); 251 | } 252 | 253 | cLen = (cRem > m_pageSize) ? m_pageSize : cRem; 254 | System.arraycopy(m_buffer, 0, data, cIndex, cLen); 255 | 256 | cIndex += cLen; 257 | cRem -= cLen; 258 | cNext++; 259 | } 260 | while (cNext < cTotal); 261 | 262 | return data; 263 | } 264 | 265 | public int storeByteArray(final int id, final byte[] data) 266 | { 267 | if (id == NewPage) 268 | { 269 | Entry e = new Entry(); 270 | e.m_length = data.length; 271 | 272 | int cIndex = 0; 273 | int cPage; 274 | int cRem = data.length; 275 | int cLen; 276 | 277 | while (cRem > 0) 278 | { 279 | if (! m_emptyPages.isEmpty()) 280 | { 281 | Integer i = (Integer) m_emptyPages.first(); 282 | m_emptyPages.remove(i); 283 | cPage = i.intValue(); 284 | } 285 | else 286 | { 287 | cPage = m_nextPage; 288 | m_nextPage++; 289 | } 290 | 291 | cLen = (cRem > m_pageSize) ? m_pageSize : cRem; 292 | System.arraycopy(data, cIndex, m_buffer, 0, cLen); 293 | 294 | try 295 | { 296 | m_dataFile.seek(cPage * m_pageSize); 297 | m_dataFile.write(m_buffer); 298 | } 299 | catch (IOException ex) 300 | { 301 | throw new IllegalStateException("Corrupted data file."); 302 | } 303 | 304 | cIndex += cLen; 305 | cRem -= cLen; 306 | e.m_pages.add(new Integer(cPage)); 307 | } 308 | 309 | Integer i = (Integer) e.m_pages.get(0); 310 | m_pageIndex.put(i, e); 311 | 312 | return i.intValue(); 313 | } 314 | else 315 | { 316 | // find the entry. 317 | Entry oldEntry = (Entry) m_pageIndex.get(new Integer(id)); 318 | if (oldEntry == null) throw new InvalidPageException(id); 319 | 320 | m_pageIndex.remove(new Integer(id)); 321 | 322 | Entry e = new Entry(); 323 | e.m_length = data.length; 324 | 325 | int cIndex = 0; 326 | int cPage; 327 | int cRem = data.length; 328 | int cLen, cNext = 0; 329 | 330 | while (cRem > 0) 331 | { 332 | if (cNext < oldEntry.m_pages.size()) 333 | { 334 | cPage = ((Integer) oldEntry.m_pages.get(cNext)).intValue(); 335 | cNext++; 336 | } 337 | else if (! m_emptyPages.isEmpty()) 338 | { 339 | Integer i = (Integer) m_emptyPages.first(); 340 | m_emptyPages.remove(i); 341 | cPage = i.intValue(); 342 | } 343 | else 344 | { 345 | cPage = m_nextPage; 346 | m_nextPage++; 347 | } 348 | 349 | cLen = (cRem > m_pageSize) ? m_pageSize : cRem; 350 | System.arraycopy(data, cIndex, m_buffer, 0, cLen); 351 | 352 | try 353 | { 354 | m_dataFile.seek(cPage * m_pageSize); 355 | m_dataFile.write(m_buffer); 356 | } 357 | catch (IOException ex) 358 | { 359 | throw new IllegalStateException("Corrupted data file."); 360 | } 361 | 362 | cIndex += cLen; 363 | cRem -= cLen; 364 | e.m_pages.add(new Integer(cPage)); 365 | } 366 | 367 | while (cNext < oldEntry.m_pages.size()) 368 | { 369 | m_emptyPages.add(oldEntry.m_pages.get(cNext)); 370 | cNext++; 371 | } 372 | 373 | Integer i = (Integer) e.m_pages.get(0); 374 | m_pageIndex.put(i, e); 375 | 376 | return i.intValue(); 377 | } 378 | } 379 | 380 | public void deleteByteArray(final int id) 381 | { 382 | // find the entry. 383 | Entry e = (Entry) m_pageIndex.get(new Integer(id)); 384 | if (e == null) throw new InvalidPageException(id); 385 | 386 | m_pageIndex.remove(new Integer(id)); 387 | 388 | for (int cIndex = 0; cIndex < e.m_pages.size(); cIndex++) 389 | { 390 | m_emptyPages.add(e.m_pages.get(cIndex)); 391 | } 392 | } 393 | 394 | public void close() 395 | { 396 | flush(); 397 | } 398 | 399 | class Entry 400 | { 401 | int m_length = 0; 402 | ArrayList m_pages = new ArrayList(); 403 | } 404 | } 405 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/IBuffer.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.storagemanager; 31 | 32 | public interface IBuffer extends IStorageManager 33 | { 34 | public long getHits(); 35 | public void clear(); 36 | public void flush(); 37 | } // IBuffer 38 | 39 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/IStorageManager.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.storagemanager; 31 | 32 | public interface IStorageManager 33 | { 34 | public static final int NewPage = -1; 35 | 36 | public void flush(); 37 | public byte[] loadByteArray(final int id); 38 | public int storeByteArray(final int id, final byte[] data); 39 | public void deleteByteArray(final int id); 40 | } // IStorageManager 41 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/InvalidPageException.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.storagemanager; 31 | 32 | public class InvalidPageException extends RuntimeException 33 | { 34 | public InvalidPageException(int id) 35 | { 36 | super("" + id); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/MemoryStorageManager.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.storagemanager; 31 | 32 | import java.util.*; 33 | 34 | public class MemoryStorageManager implements IStorageManager 35 | { 36 | private ArrayList m_buffer = new ArrayList(); 37 | private Stack m_emptyPages = new Stack(); 38 | 39 | public void flush() 40 | { 41 | } 42 | 43 | public byte[] loadByteArray(final int id) 44 | { 45 | Entry e = null; 46 | 47 | try 48 | { 49 | e = (Entry) m_buffer.get(id); 50 | } 51 | catch (IndexOutOfBoundsException ex) 52 | { 53 | throw new InvalidPageException(id); 54 | } 55 | 56 | byte[] ret = new byte[e.m_pData.length]; 57 | System.arraycopy(e.m_pData, 0, ret, 0, e.m_pData.length); 58 | return ret; 59 | } 60 | 61 | public int storeByteArray(final int id, final byte[] data) 62 | { 63 | int ret = id; 64 | Entry e = new Entry(data); 65 | 66 | if (id == NewPage) 67 | { 68 | if (m_emptyPages.empty()) 69 | { 70 | m_buffer.add(e); 71 | ret = m_buffer.size() - 1; 72 | } 73 | else 74 | { 75 | ret = ((Integer) m_emptyPages.pop()).intValue(); 76 | m_buffer.set(ret, e); 77 | } 78 | } 79 | else 80 | { 81 | if (id < 0 || id >= m_buffer.size()) throw new InvalidPageException(id); 82 | m_buffer.set(id, e); 83 | } 84 | 85 | return ret; 86 | } 87 | 88 | public void deleteByteArray(final int id) 89 | { 90 | Entry e = null; 91 | try 92 | { 93 | e = (Entry) m_buffer.get(id); 94 | } 95 | catch (IndexOutOfBoundsException ex) 96 | { 97 | throw new InvalidPageException(id); 98 | } 99 | 100 | m_buffer.set(id, null); 101 | m_emptyPages.push(new Integer(id)); 102 | } 103 | 104 | class Entry 105 | { 106 | byte[] m_pData; 107 | 108 | Entry(final byte[] d) 109 | { 110 | m_pData = new byte[d.length]; 111 | System.arraycopy(d, 0, m_pData, 0, d.length); 112 | } 113 | } // Entry 114 | } 115 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/PropertySet.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.storagemanager; 31 | 32 | import java.util.*; 33 | 34 | public class PropertySet 35 | { 36 | private HashMap m_propertySet = new HashMap(); 37 | 38 | public Object getProperty(String property) 39 | { 40 | return m_propertySet.get(property); 41 | } 42 | 43 | public void setProperty(String property, Object o) 44 | { 45 | m_propertySet.put(property, o); 46 | } 47 | } // PropertySet 48 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/RandomEvictionsBuffer.java: -------------------------------------------------------------------------------- 1 | // Spatial Index Library 2 | // 3 | // Copyright (C) 2002 Navel Ltd. 4 | // 5 | // This library is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU Lesser General Public 7 | // License as published by the Free Software Foundation; either 8 | // version 2.1 of the License, or (at your option) any later version. 9 | // 10 | // This library is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | // Lesser General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU Lesser General Public 16 | // License along with this library; if not, write to the Free Software 17 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | // 19 | // Contact information: 20 | // Mailing address: 21 | // Marios Hadjieleftheriou 22 | // University of California, Riverside 23 | // Department of Computer Science 24 | // Surge Building, Room 310 25 | // Riverside, CA 92521 26 | // 27 | // Email: 28 | // marioh@cs.ucr.edu 29 | 30 | package sil.storagemanager; 31 | 32 | import java.util.*; 33 | 34 | public class RandomEvictionsBuffer extends Buffer 35 | { 36 | Random m_random = new Random(); 37 | 38 | public RandomEvictionsBuffer(IStorageManager sm, int capacity, boolean bWriteThrough) 39 | { 40 | super(sm, capacity, bWriteThrough); 41 | } 42 | 43 | void addEntry(int id, Entry e) 44 | { 45 | // assert m_buffer.size() <= m_capacity; 46 | 47 | if (m_buffer.size() == m_capacity) removeEntry(); 48 | m_buffer.put(new Integer(id), e); 49 | } 50 | 51 | void removeEntry() 52 | { 53 | if (m_buffer.size() == 0) return; 54 | 55 | int entry = m_random.nextInt(m_buffer.size()); 56 | 57 | Iterator it = m_buffer.entrySet().iterator(); 58 | for (int cIndex = 0; cIndex < entry - 1; cIndex++) it.next(); 59 | 60 | Map.Entry me = (Map.Entry) it.next(); 61 | Entry e = (Entry) me.getValue(); 62 | int id = ((Integer) me.getKey()).intValue(); 63 | 64 | if (e.m_bDirty) 65 | { 66 | m_storageManager.storeByteArray(id, e.m_data); 67 | } 68 | 69 | m_buffer.remove(new Integer(id)); 70 | } 71 | } // RandomEvictionsBuffer 72 | -------------------------------------------------------------------------------- /src/test/java/sil/storagemanager/makefile: -------------------------------------------------------------------------------- 1 | # Spatial Index Library 2 | # 3 | # Copyright (C) 2002 Navel Ltd. 4 | # 5 | # This library is free software; you can redistribute it and/or 6 | # modify it under the terms of the GNU Lesser General Public 7 | # License as published by the Free Software Foundation; either 8 | # version 2.1 of the License, or (at your option) any later version. 9 | # 10 | # This library is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | # Lesser General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public 16 | # License along with this library; if not, write to the Free Software 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 | # 19 | # Contact information: 20 | # Mailing address: 21 | # Marios Hadjieleftheriou 22 | # University of California, Riverside 23 | # Department of Computer Science 24 | # Surge Building, Room 310 25 | # Riverside, CA 92521 26 | # 27 | # Email: 28 | # marioh@cs.ucr.edu 29 | 30 | all: 31 | javac -source 1.4 -classpath ../lib -d ../lib -g:none *.java 32 | 33 | debug: 34 | javac -source 1.4 -classpath ../lib -d ../lib -g *.java 35 | 36 | clean: 37 | rm -rf ../lib/spatialindex/storagemanager 38 | 39 | -------------------------------------------------------------------------------- /src/test/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | [%level] %msg%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-allfunctions-100-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 40 0 20000 3 | randomize 1 4 | deleteRandom 20 0 20000 5 | # 6 | randomize 2 7 | addRandom 40 40 20000 8 | randomize 2 9 | deleteRandom 20 40 20000 10 | # 11 | randomize 3 12 | addRandom 40 80 20000 13 | randomize 3 14 | deleteRandom 20 80 20000 15 | # 16 | randomize 4 17 | addRandom 40 120 20000 18 | randomize 4 19 | deleteRandom 20 120 20000 20 | # 21 | randomize 5 22 | addRandom 40 160 20000 23 | randomize 5 24 | deleteRandom 20 160 20000 25 | # 26 | randomize 6 27 | intersectRandom 100 20000 28 | # 29 | randomize 7 30 | nearestRandom 100 31 | # 32 | randomize 8 33 | nearestNRandom 100 5 34 | # 35 | randomize 9 36 | containsRandom 100 100000 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-allfunctions-1000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 400 0 100 3 | randomize 1 4 | deleteRandom 200 0 100 5 | # 6 | randomize 2 7 | addRandom 400 400 200 8 | randomize 2 9 | deleteRandom 200 400 200 10 | # 11 | randomize 3 12 | addRandom 400 800 400 13 | randomize 3 14 | deleteRandom 200 800 400 15 | # 16 | randomize 4 17 | addRandom 400 1200 800 18 | randomize 4 19 | deleteRandom 200 1200 800 20 | # 21 | randomize 5 22 | addRandom 400 1600 1600 23 | randomize 5 24 | deleteRandom 200 1600 1600 25 | # 26 | randomize 6 27 | intersectRandom 200 100 28 | intersectRandom 200 200 29 | intersectRandom 200 400 30 | intersectRandom 200 800 31 | intersectRandom 200 1600 32 | # 33 | randomize 7 34 | nearestRandom 200 100 35 | nearestRandom 200 200 36 | nearestRandom 200 400 37 | nearestRandom 200 800 38 | nearestRandom 200 1600 39 | # 40 | randomize 8 41 | nearestNRandom 200 1000 42 | nearestNRandom 200 2000 43 | nearestNRandom 200 4000 44 | nearestNRandom 200 8000 45 | nearestNRandom 200 16000 46 | # 47 | randomize 9 48 | containsRandom 200 100 49 | containsRandom 200 200 50 | containsRandom 200 400 51 | containsRandom 200 800 52 | containsRandom 200 1600 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-allfunctions-10000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 4000 0 100 3 | randomize 1 4 | deleteRandom 2000 0 100 5 | # 6 | randomize 2 7 | addRandom 4000 4000 200 8 | randomize 2 9 | deleteRandom 2000 4000 200 10 | # 11 | randomize 3 12 | addRandom 4000 8000 400 13 | randomize 3 14 | deleteRandom 2000 8000 400 15 | # 16 | randomize 4 17 | addRandom 4000 12000 800 18 | randomize 4 19 | deleteRandom 2000 12000 800 20 | # 21 | randomize 5 22 | addRandom 4000 16000 1600 23 | randomize 5 24 | deleteRandom 2000 16000 1600 25 | # 26 | randomize 6 27 | intersectRandom 2000 100 28 | intersectRandom 2000 200 29 | intersectRandom 2000 400 30 | intersectRandom 2000 800 31 | intersectRandom 2000 1600 32 | # 33 | randomize 7 34 | nearestRandom 2000 100 35 | nearestRandom 2000 200 36 | nearestRandom 2000 400 37 | nearestRandom 2000 800 38 | nearestRandom 2000 1600 39 | # 40 | randomize 8 41 | nearestNRandom 2000 10000 42 | nearestNRandom 2000 20000 43 | nearestNRandom 2000 40000 44 | nearestNRandom 2000 80000 45 | nearestNRandom 2000 160000 46 | # 47 | randomize 9 48 | containsRandom 2000 100 49 | containsRandom 2000 200 50 | containsRandom 2000 400 51 | containsRandom 2000 800 52 | containsRandom 2000 1600 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-allfunctions-100000-in: -------------------------------------------------------------------------------- 1 | # Full test script. Add 200 entries. After 40 have been added delete 20. 2 | # Use a range of scales from 100 to 1600 3 | randomize 1 4 | addRandom 4000 0 100 5 | randomize 1 6 | deleteRandom 2000 0 100 7 | # 8 | randomize 2 9 | addRandom 4000 40000 200 10 | randomize 2 11 | deleteRandom 2000 40000 200 12 | # 13 | randomize 3 14 | addRandom 40000 80000 400 15 | randomize 3 16 | deleteRandom 20000 80000 400 17 | # 18 | randomize 4 19 | addRandom 40000 120000 800 20 | randomize 4 21 | deleteRandom 20000 120000 800 22 | # 23 | randomize 5 24 | addRandom 40000 160000 1600 25 | randomize 5 26 | deleteRandom 20000 160000 1600 27 | # 28 | randomize 6 29 | intersectRandom 20000 100 30 | intersectRandom 20000 200 31 | intersectRandom 20000 400 32 | intersectRandom 20000 800 33 | intersectRandom 20000 1600 34 | # 35 | randomize 7 36 | nearestRandom 20000 100 37 | nearestRandom 20000 200 38 | nearestRandom 20000 400 39 | nearestRandom 20000 800 40 | nearestRandom 20000 1600 41 | # 42 | randomize 8 43 | nearestNRandom 20000 100000 44 | nearestNRandom 20000 200000 45 | nearestNRandom 20000 400000 46 | nearestNRandom 20000 800000 47 | nearestNRandom 20000 1600000 48 | # 49 | randomize 9 50 | containsRandom 20000 100 51 | containsRandom 20000 200 52 | containsRandom 20000 400 53 | containsRandom 20000 800 54 | containsRandom 20000 1600 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-allqueries-10000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 10000 0 5000 3 | 4 | randomize 2 5 | #intersectRandom 10000 5000 6 | 7 | randomize 3 8 | nearestRandom 10000 10 9 | 10 | randomize 4 11 | #nearestNRandom 10000 5 6000 12 | 13 | randomize 5 14 | #containsRandom 10000 15000 15 | 16 | # deletion test - delete all of the entries 17 | randomize 1 18 | #deleteRandom 10000 0 5000 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-contains-100-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 100 0 5 3 | containsRandom 100 5 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-contains-1000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 1000 0 60 3 | containsRandom 1000 60 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-contains-10000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 10000 0 280 3 | containsRandom 10000 280 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-contains-100000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 100000 0 800 3 | containsRandom 100000 800 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-delete-100-in: -------------------------------------------------------------------------------- 1 | # specific test to isolate bug whereby tree was not shrunk correctly 2 | deleteAllRandom 1 100 0 235.4 3 | 4 | # original tests 5 | #randomize 1 6 | #addRandom 200 0 235.4 7 | #randomize 1 8 | #deleteRandom 100 0 235.4 9 | #randomize 123456 10 | #deleteRandom 100 0 235.4 11 | #randomize 2 12 | #intersectRandom 100 0 235.4 13 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-delete-1000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 2000 0 646.8 3 | randomize 1 4 | deleteRandom 1000 0 646.8 5 | randomize 123456 6 | deleteRandom 1000 0 646.8 7 | randomize 2 8 | intersectRandom 1000 0 646.8 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-delete-10000-in: -------------------------------------------------------------------------------- 1 | # 1000 = 43 2 | # 1500 = 21.8101 3 | # 1800 = 15 4 | # 2100 = 11.9093 5 | # 2200 = 10.969 6 | # 2300 = 10.2979 7 | # 2400 = 9.7034 8 | randomize 1 9 | addRandom 20000 0 2350 10 | randomize 1 11 | deleteRandom 10000 0 2350 12 | randomize 123456 13 | deleteRandom 10000 0 2350 14 | randomize 2 15 | intersectRandom 10000 0 2350 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-delete-100000-in: -------------------------------------------------------------------------------- 1 | #4995=15.77595 2 | randomize 1 3 | addRandom 200000 0 5500 4 | randomize 1 5 | deleteRandom 100000 0 5500 6 | randomize 123456 7 | deleteRandom 100000 0 5500 8 | randomize 2 9 | intersectRandom 100000 0 5500 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-intersect-100-in: -------------------------------------------------------------------------------- 1 | # scale chosen by trial-and-error to give about 10 intersects per query. 2 | randomize 1 3 | addRandom 100 0 129.7 4 | intersectRandom 100 129.7 5 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-intersect-1000-in: -------------------------------------------------------------------------------- 1 | # scale chosen by trial-and-error to give an average of 10 intersects per query. 2 | # 435.7 = 10.001 3 | randomize 1 4 | addRandom 1000 0 435.7 5 | intersectRandom 1000 435.7 6 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-intersect-10000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 10000 0 1463 3 | intersectRandom 10000 1463 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-intersect-100000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 100000 0 4917 3 | intersectRandom 100000 4917 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-intersect-1000000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 1000000 0 1000000 3 | intersectRandom 1000000 1000000 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-intersect-10000000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 10000000 0 10000000 3 | intersectRandom 10000000 10000000 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-nearest-100-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 100 0 1000 3 | nearestRandom 100 1000 4 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-nearest-1000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 1000 0 3162 3 | nearestRandom 1000 3162 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-nearest-10000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 10000 0 10000 3 | nearestRandom 10000 10000 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-nearest-100000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 100000 0 31623 3 | nearestRandom 100000 31623 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-nearestN-100-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 50 0 1000 3 | nearestNRandom 100 1 1000 4 | nearestNRandom 100 2 1000 5 | nearestNRandom 100 8 1000 6 | nearestNRandom 100 32 1000 7 | 8 | distanceQuantizer 10000 9 | addRandom 50 50 1000 10 | nearestNRandom 100 1 1000 11 | nearestNRandom 100 2 1000 12 | nearestNRandom 100 8 1000 13 | nearestNRandom 100 64 1000 14 | -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-nearestN-1000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 500 0 3162 3 | nearestNRandom 1000 1 3162 4 | nearestNRandom 1000 2 3162 5 | nearestNRandom 1000 8 3162 6 | nearestNRandom 1000 32 3162 7 | nearestNRandom 1000 256 3162 8 | 9 | distanceQuantizer 10000 10 | addRandom 500 500 3162 11 | nearestNRandom 1000 1 3162 12 | nearestNRandom 1000 2 3162 13 | nearestNRandom 1000 64 3162 14 | nearestNRandom 1000 512 3162 -------------------------------------------------------------------------------- /src/test/resources/test-inputs/test-nearestN-10000-in: -------------------------------------------------------------------------------- 1 | randomize 1 2 | addRandom 5000 0 10000 3 | nearestNRandom 10000 1 10000 4 | nearestNRandom 10000 2 10000 5 | nearestNRandom 10000 8 10000 6 | nearestNRandom 10000 32 10000 7 | nearestNRandom 10000 256 10000 8 | 9 | distanceQuantizer 10000 10 | addRandom 5000 5000 10000 11 | nearestNRandom 10000 1 10000 12 | nearestNRandom 10000 2 10000 13 | nearestNRandom 10000 64 10000 14 | nearestNRandom 10000 512 10000 --------------------------------------------------------------------------------