├── LICENSE ├── Makefile ├── README.md ├── RStarBoundingBox.h ├── RStarDiscardedCode.txt ├── RStarTree.h ├── RStarVisitor.h ├── main.cpp ├── rstartree.sln ├── rstartree.vcproj └── test.cpp /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 489 | 490 | Also add information on how to contact you by electronic and paper mail. 491 | 492 | You should also get your employer (if you work as a programmer) or your 493 | school, if any, to sign a "copyright disclaimer" for the library, if 494 | necessary. Here is a sample; alter the names: 495 | 496 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 497 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 498 | 499 | , 1 April 1990 500 | Ty Coon, President of Vice 501 | 502 | That's all there is to it! 503 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | HDR = RStarVisitor.h RStarBoundingBox.h RStarTree.h 4 | SRC = main.cpp 5 | EXE = rstar 6 | CC = g++ 7 | OBJ = ${SRC:.cpp=.o} 8 | CPPFLAGS = -ggdb -Wall -Werror 9 | #CPPFLAGS = -O2 -Wall 10 | 11 | .DEFAULT : all 12 | 13 | all : ${EXE} 14 | 15 | ${EXE} : ${OBJ} 16 | ${CC} ${CPPFLAGS} -o $@ ${OBJ} 17 | 18 | .SUFFIXES : .o .cxx 19 | 20 | .cpp.o: 21 | ${CC} ${CPPFLAGS} -c $< 22 | 23 | 24 | .PHONY : clean 25 | clean : 26 | -rm -f all ${OBJ} ${EXE} *~ Depends 27 | 28 | 29 | .PHONY : exec run 30 | run exec : all 31 | ./${EXE} 32 | 33 | 34 | .PHONY : depend 35 | .PHONY : Depends 36 | Depends depend : 37 | ifneq (${MAKECMDGOALS},clean) 38 | @echo "Creating dependencies..." 39 | @${CC} -E -MM ${SRC} > Depends 40 | endif 41 | 42 | -include Depends 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | R* Tree for C++ 2 | =============== 3 | 4 | In 2008 I created this R* Tree implementation in C++. My goal for this 5 | implementation was as follows: 6 | 7 | * Simple API – Most existing implementations I’ve seen are far from simple 8 | * Generic enough to use with most types, with low overhead 9 | * N dimensions for bounding boxes 10 | * Take advantage of modern C++ features to get decent performance 11 | 12 | This is a header-only implementation of an R tree with an R* index, and makes 13 | heavy use of templates, STL, and STL-style functors; but it should work in any 14 | relatively modern C++ compiler. To do searching for nodes, this implementation 15 | uses the Visitor pattern via functors — there are examples and documentation in 16 | RStarVisitor.h. 17 | 18 | Maintenance 19 | =========== 20 | 21 | I do not use or update this code anymore, but I welcome pull requests. 22 | 23 | License 24 | ======= 25 | 26 | GNU Lesser Public License v2.1 27 | 28 | Author 29 | ====== 30 | 31 | Dustin Spicuzza (dustin@virtualroadside.com) -------------------------------------------------------------------------------- /RStarBoundingBox.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Dustin Spicuzza 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2.1 of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation. 7 | * 8 | * This library is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public 14 | * License along with this library; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | */ 17 | 18 | 19 | #ifndef RStarBoundingBox_H 20 | #define RStarBoundingBox_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | 29 | template 30 | struct RStarBoundingBox { 31 | 32 | // edges[x].first is low value, edges[x].second is high value 33 | std::pair edges[dimensions]; 34 | 35 | // forces all edges to their extremes so we can stretch() it 36 | void reset() 37 | { 38 | for (std::size_t axis = 0; axis < dimensions; axis++) 39 | { 40 | edges[axis].first = std::numeric_limits::max(); 41 | edges[axis].second = std::numeric_limits::min(); 42 | } 43 | } 44 | 45 | // returns a new bounding box that has the maximum boundaries 46 | static RStarBoundingBox MaximumBounds() 47 | { 48 | RStarBoundingBox bound; 49 | bound.reset(); 50 | return bound; 51 | } 52 | 53 | 54 | // fits another box inside of this box, returns true if a stretch occured 55 | bool stretch(const RStarBoundingBox &bb) 56 | { 57 | bool ret = false; 58 | 59 | for (std::size_t axis = 0; axis < dimensions; axis++) 60 | { 61 | 62 | if (edges[axis].first > bb.edges[axis].first) 63 | { 64 | edges[axis].first = bb.edges[axis].first; 65 | ret = true; 66 | } 67 | 68 | if (edges[axis].second < bb.edges[axis].second) 69 | { 70 | edges[axis].second = bb.edges[axis].second; 71 | ret = true; 72 | } 73 | } 74 | 75 | return ret; 76 | } 77 | 78 | // the sum of all deltas between edges 79 | inline int edgeDeltas() const 80 | { 81 | int distance = 0; 82 | for (std::size_t axis = 0; axis < dimensions; axis++) 83 | distance += edges[axis].second - edges[axis].first; 84 | 85 | return distance; 86 | } 87 | 88 | // calculates the area of a bounding box 89 | inline double area() const 90 | { 91 | double area = 1; 92 | for (std::size_t axis = 0; axis < dimensions; axis++) 93 | area *= (double)(edges[axis].second - edges[axis].first); 94 | 95 | return area; 96 | } 97 | 98 | // this determines if a bounding box is fully contained within this bounding box 99 | inline bool encloses(const RStarBoundingBox& bb) const 100 | { 101 | // if (y1 < x1 || x2 < y2) 102 | for (std::size_t axis = 0; axis < dimensions; axis++) 103 | if (bb.edges[axis].first < edges[axis].first || edges[axis].second < bb.edges[axis].second) 104 | return false; 105 | 106 | return true; 107 | } 108 | 109 | // a quicker way to determine if two bounding boxes overlap 110 | inline bool overlaps(const RStarBoundingBox& bb) const 111 | { 112 | // do it this way so theres no equal signs (in case of doubles) 113 | // if (!(x1 < y2) && !(x2 > y1)) 114 | for (std::size_t axis = 0; axis < dimensions; axis++) 115 | { 116 | if (!(edges[axis].first < bb.edges[axis].second) || !(bb.edges[axis].first < edges[axis].second)) 117 | return false; 118 | } 119 | 120 | return true; 121 | } 122 | 123 | // calculates the total overlapping area of two boxes 124 | double overlap(const RStarBoundingBox& bb) const 125 | { 126 | double area = 1.0; 127 | for (std::size_t axis = 0; area && axis < dimensions; axis++) 128 | { 129 | // this makes it easier to understand 130 | const int x1 = edges[axis].first; 131 | const int x2 = edges[axis].second; 132 | const int y1 = bb.edges[axis].first; 133 | const int y2 = bb.edges[axis].second; 134 | 135 | // left edge outside left edge 136 | if (x1 < y1) 137 | { 138 | // and right edge inside left edge 139 | if (y1 < x2) 140 | { 141 | // right edge outside right edge 142 | if (y2 < x2) 143 | area *= (double)( y2 - y1 ); 144 | else 145 | area *= (double)( x2 - y1 ); 146 | 147 | continue; 148 | } 149 | } 150 | // right edge inside left edge 151 | else if (x1 < y2) 152 | { 153 | // right edge outside right edge 154 | if (x2 < y2) 155 | area *= (double)( x2 - x1 ); 156 | else 157 | area *= (double)( y2 - x1 ); 158 | 159 | continue; 160 | } 161 | 162 | // if we get here, there is no overlap 163 | return 0.0; 164 | } 165 | 166 | return area; 167 | } 168 | 169 | // sums the total distances from the center of another bounding box 170 | double distanceFromCenter(const RStarBoundingBox& bb) const 171 | { 172 | double distance = 0, t; 173 | for (std::size_t axis = 0; axis < dimensions; axis++) 174 | { 175 | t = ((double)edges[axis].first + (double)edges[axis].second + 176 | (double)bb.edges[axis].first + (double)bb.edges[axis].second) 177 | /2.0; 178 | distance += t*t; 179 | } 180 | 181 | return distance; 182 | } 183 | 184 | // determines if two bounding boxes are identical 185 | bool operator==(const RStarBoundingBox& bb) 186 | { 187 | for (std::size_t axis = 0; axis < dimensions; axis++) 188 | if (edges[axis].first != bb.edges[axis].first || edges[axis].second != bb.edges[axis].second) 189 | return false; 190 | 191 | return true; 192 | } 193 | 194 | 195 | // very slow, use for debugging only 196 | std::string ToString() const 197 | { 198 | std::stringstream name(""); 199 | name << "["; 200 | for (std::size_t axis = 0; axis < dimensions; axis++) 201 | { 202 | name << "(" << edges[axis].first << "," << edges[axis].second << ")"; 203 | if (axis != dimensions -1) 204 | name << ","; 205 | } 206 | name << "]"; 207 | 208 | return name.str(); 209 | } 210 | }; 211 | 212 | 213 | 214 | template 215 | struct RStarBoundedItem { 216 | typedef RStarBoundingBox BoundingBox; 217 | 218 | BoundingBox bound; 219 | }; 220 | 221 | 222 | /********************************************************** 223 | * Functor used to iterate over a set and stretch a 224 | * bounding box 225 | **********************************************************/ 226 | 227 | // for_each(items.begin(), items.end(), StretchBoundedItem::BoundingBox(bound)); 228 | template 229 | struct StretchBoundingBox 230 | { 231 | typename BoundedItem::BoundingBox * m_bound; 232 | explicit StretchBoundingBox(typename BoundedItem::BoundingBox * bound) : m_bound(bound) {} 233 | 234 | void operator() (const BoundedItem * const item) 235 | { 236 | m_bound->stretch(item->bound); 237 | } 238 | }; 239 | 240 | 241 | /********************************************************** 242 | * R* Tree related functors used for sorting BoundedItems 243 | * 244 | * TODO: Take advantage of type traits 245 | **********************************************************/ 246 | 247 | template 248 | struct SortBoundedItemsByFirstEdge 249 | { 250 | const std::size_t m_axis; 251 | explicit SortBoundedItemsByFirstEdge (const std::size_t axis) : m_axis(axis) {} 252 | 253 | bool operator() (const BoundedItem * const bi1, const BoundedItem * const bi2) const 254 | { 255 | return bi1->bound.edges[m_axis].first < bi2->bound.edges[m_axis].first; 256 | } 257 | }; 258 | 259 | template 260 | struct SortBoundedItemsBySecondEdge 261 | { 262 | const std::size_t m_axis; 263 | explicit SortBoundedItemsBySecondEdge (const std::size_t axis) : m_axis(axis) {} 264 | 265 | bool operator() (const BoundedItem * const bi1, const BoundedItem * const bi2) const 266 | { 267 | return bi1->bound.edges[m_axis].second < bi2->bound.edges[m_axis].second; 268 | } 269 | }; 270 | 271 | 272 | template 273 | struct SortBoundedItemsByDistanceFromCenter 274 | { 275 | const typename BoundedItem::BoundingBox * const m_center; 276 | explicit SortBoundedItemsByDistanceFromCenter(const typename BoundedItem::BoundingBox * const center) : m_center(center) {} 277 | 278 | bool operator() (const BoundedItem * const bi1, const BoundedItem * const bi2) const 279 | { 280 | return bi1->bound.distanceFromCenter(*m_center) < bi2->bound.distanceFromCenter(*m_center); 281 | } 282 | }; 283 | 284 | template 285 | struct SortBoundedItemsByAreaEnlargement 286 | { 287 | const double area; 288 | explicit SortBoundedItemsByAreaEnlargement(const typename BoundedItem::BoundingBox * center) : area(center->area()) {} 289 | 290 | bool operator() (const BoundedItem * const bi1, const BoundedItem * const bi2) const 291 | { 292 | return area - bi1->bound.area() < area - bi2->bound.area(); 293 | } 294 | }; 295 | 296 | template 297 | struct SortBoundedItemsByOverlapEnlargement 298 | { 299 | const typename BoundedItem::BoundingBox * const m_center; 300 | explicit SortBoundedItemsByOverlapEnlargement(const typename BoundedItem::BoundingBox * const center) : m_center(center) {} 301 | 302 | bool operator() (const BoundedItem * const bi1, const BoundedItem * const bi2) const 303 | { 304 | return bi1->bound.overlap(*m_center) < bi2->bound.overlap(*m_center); 305 | } 306 | }; 307 | 308 | 309 | #endif 310 | -------------------------------------------------------------------------------- /RStarDiscardedCode.txt: -------------------------------------------------------------------------------- 1 | 2 | // strictly speaking, these should be implemented as visitors... 3 | 4 | // testing only: traverse the tree and print it out in a graphviz format 5 | void Print(std::string digraph = "rstartree") const 6 | { 7 | int id = 1; 8 | std::ofstream file; 9 | file.open((digraph + ".dot").c_str(), std::ifstream::trunc); 10 | 11 | file << "digraph " << digraph << " {\n"; 12 | 13 | if (m_root) 14 | PrintSubtree(file, "\"root " + m_root->bound.ToString() + "\"", m_root, "", id-1, id); 15 | 16 | file << "}\n"; 17 | file.close(); 18 | } 19 | 20 | void PrintSubtree(std::ofstream &output, std::string parent, Node * node, std::string level, int parent_id, int &id) const 21 | { 22 | level += " "; 23 | 24 | typename std::vector< BoundedItem* >::iterator it = node->items.begin(); 25 | for (; it != node->items.end(); it++) 26 | { 27 | output << level << parent << " -> "; 28 | 29 | if (node->hasLeaves) 30 | { 31 | Leaf * leaf = static_cast(*it); 32 | output << "\"" << leaf->leaf << " " << leaf->bound.ToString() << "\"" << std::endl; 33 | } 34 | else 35 | { 36 | std::stringstream my_name(""); 37 | my_name << "\"N" << id++ << " " << (*it)->bound.ToString() << "\""; 38 | output << my_name.str() << std::endl; 39 | 40 | PrintSubtree(output, my_name.str(), static_cast(*it), level, id-1, id); 41 | } 42 | } 43 | } 44 | 45 | void PrintStats() 46 | { 47 | // output any information that would be interesting to output here.. 48 | } 49 | 50 | 51 | /* 52 | // searches through a tree for items in a bounding box 53 | // 54 | // This is here in case it ever becomes useful, but I think the other way of doing searching 55 | // works out better. Maybe. We'll see. 56 | 57 | class Searcher { 58 | public: 59 | 60 | Searcher(RStarTree * tree, _BoundingBox searchBound) : 61 | m_tree(tree), 62 | m_searchBound(searchBound), 63 | m_curnode(tree->m_root) 64 | { 65 | if (tree->m_root) 66 | m_it = m_root->items.begin(); 67 | } 68 | 69 | // returns true if an item was found. The parameters (bound, leaf) are 70 | // modified if an item is found 71 | // I'm not 100% sold on using this mechanism for searching, but it seems 72 | // like it beats a recursive visitor pattern... 73 | bool Next(_BoundingBox &bound, LeafType &leaf) 74 | { 75 | // pick up where we were before 76 | while (m_curnode) 77 | { 78 | if (node->hasLeaves) 79 | { 80 | for (; m_it != m_curnode->items.end(); m_it++) 81 | if (m_searchBound.overlaps((*m_it).bound)) 82 | { 83 | Leaf * l = static_cast(*m_it); 84 | bound = l->bound; 85 | leaf = l->leaf; 86 | 87 | // return indicating that an item was found 88 | m_it++; 89 | return true; 90 | } 91 | } 92 | else 93 | { 94 | // if it has kids, then thats slightly different 95 | for (; m_it != m_curnode->items.end(); m_it++) 96 | { 97 | if (m_searchBound.overlaps((*m_it).bound)) 98 | { 99 | // save current node, setup for new level 100 | nodes.push(m_curnode); 101 | m_curnode = static_cast(*m_it); 102 | 103 | // save iterator for this level, setup for new level 104 | iterators.push(++m_it); 105 | m_it = m_curnode->items.begin(); 106 | break; 107 | } 108 | } 109 | } 110 | 111 | // if we reach the end of a loop, then traverse back up the tree 112 | if (m_it == m_curnode->items.end()) 113 | { 114 | if (nodes.empty()) 115 | m_curnode = NULL; 116 | else 117 | { 118 | m_nodes.pop(); 119 | m_iterators.pop(); 120 | 121 | // traverse back up 122 | m_curnode = nodes.top(); 123 | m_it = iterators.top(); 124 | } 125 | } 126 | } 127 | 128 | // done searching 129 | return false; 130 | } 131 | 132 | private: 133 | Searcher(){} 134 | 135 | RStarTree * m_tree; 136 | _BoundingBox m_searchBound; 137 | 138 | std::stack::Node*> nodes; 139 | std::stack< vector::iterator > iterators; 140 | 141 | // current node, iterator 142 | Node * curnode; 143 | vector::iterator it; 144 | 145 | }; 146 | */ 147 | -------------------------------------------------------------------------------- /RStarTree.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Dustin Spicuzza 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2.1 of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation. 7 | * 8 | * This library is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public 14 | * License along with this library; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | */ 17 | 18 | 19 | /* 20 | * This is intended to be a templated implementation of an R* Tree, designed 21 | * to create an efficient and (relatively) small indexing container in N 22 | * dimensions. At the moment, it is a memory-based container instead of disk 23 | * based. 24 | * 25 | * Based on "The R*-Tree: An Efficient and Robust Access Method for Points 26 | * and Rectangles" by N. Beckmann, H.P. Kriegel, R. Schneider, and B. Seeger 27 | */ 28 | 29 | 30 | #ifndef RSTARTREE_H 31 | #define RSTARTREE_H 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #include "RStarBoundingBox.h" 45 | 46 | // R* tree parameters 47 | #define RTREE_REINSERT_P 0.30 48 | #define RTREE_CHOOSE_SUBTREE_P 32 49 | 50 | // template definition: 51 | #define RSTAR_TEMPLATE 52 | 53 | 54 | // definition of an leaf 55 | template 56 | struct RStarLeaf : BoundedItem { 57 | 58 | typedef LeafType leaf_type; 59 | LeafType leaf; 60 | }; 61 | 62 | // definition of a node 63 | template 64 | struct RStarNode : BoundedItem { 65 | std::vector< BoundedItem* > items; 66 | bool hasLeaves; 67 | }; 68 | 69 | #include "RStarVisitor.h" 70 | 71 | 72 | /** 73 | \class RStarTree 74 | \brief Implementation of an RTree with an R* index 75 | 76 | @tparam LeafType type of leaves stored in the tree 77 | @tparam dimensions number of dimensions the bounding boxes are described in 78 | @tparam min_child_items m, in the range 2 <= m < M 79 | @tparam max_child_items M, in the range 2 <= m < M 80 | @tparam RemoveLeaf A functor used to remove leaves from the tree 81 | */ 82 | template < 83 | typename LeafType, 84 | std::size_t dimensions, std::size_t min_child_items, std::size_t max_child_items 85 | > 86 | class RStarTree { 87 | public: 88 | 89 | // shortcuts 90 | typedef RStarBoundedItem BoundedItem; 91 | typedef typename BoundedItem::BoundingBox BoundingBox; 92 | 93 | typedef RStarNode Node; 94 | typedef RStarLeaf Leaf; 95 | 96 | // acceptors 97 | typedef RStarAcceptOverlapping AcceptOverlapping; 98 | typedef RStarAcceptEnclosing AcceptEnclosing; 99 | typedef RStarAcceptAny AcceptAny; 100 | 101 | // predefined visitors 102 | typedef RStarRemoveLeaf RemoveLeaf; 103 | typedef RStarRemoveSpecificLeaf RemoveSpecificLeaf; 104 | 105 | 106 | // default constructor 107 | RStarTree() : m_root(NULL), m_size(0) 108 | { 109 | assert(1 <= min_child_items && min_child_items <= max_child_items/2); 110 | } 111 | 112 | // destructor 113 | ~RStarTree() { 114 | Remove( 115 | AcceptAny(), 116 | RemoveLeaf() 117 | ); 118 | } 119 | 120 | // Single insert function, adds a new item to the tree 121 | void Insert(LeafType leaf, const BoundingBox &bound) 122 | { 123 | // ID1: Invoke Insert starting with the leaf level as a 124 | // parameter, to Insert a new data rectangle 125 | Leaf * newLeaf = new Leaf(); 126 | newLeaf->bound = bound; 127 | newLeaf->leaf = leaf; 128 | 129 | // create a new root node if necessary 130 | if (!m_root) 131 | { 132 | m_root = new Node(); 133 | m_root->hasLeaves = true; 134 | 135 | // reserve memory 136 | m_root->items.reserve(min_child_items); 137 | m_root->items.push_back(newLeaf); 138 | m_root->bound = bound; 139 | } 140 | else 141 | // start the insertion process 142 | InsertInternal(newLeaf, m_root); 143 | 144 | m_size += 1; 145 | } 146 | 147 | 148 | /* 149 | This is an interpretation of the bulk insert algorithm described 150 | in "Improving Performance with Bulk-Inserts in Oracle R-Trees" 151 | by N. An, R. Kanth, V. Kothuri, and S. Ravada 152 | 153 | I think this is essentially right, since if you think about it for too 154 | long then it makes sense ;) The idea is to work your way down to the 155 | bottom of the tree, make some child nodes, perform a split, and work 156 | your way back up continually. The bounding boxes have to be adjusted 157 | on the way up the tree, and not on the way down. 158 | 159 | Entries * BulkInsert(Node * node, Node * buddy, vector &entries) 160 | { 161 | if (entries.empty() && !buddy) 162 | return node; 163 | 164 | if (node->hasLeaves) 165 | child_entries = node.items + buddy.items + entries; 166 | else 167 | { 168 | combine items in node and buddy; 169 | 170 | for each item in entries? 171 | for each possible partition in entries 172 | { 173 | pick ci and bi using choose subtree, where 174 | ci is not null, bi can be null 175 | 176 | each entry can only be in one partition 177 | 178 | child_entries += BulkInsert(ci, bi, entries); 179 | } 180 | } 181 | 182 | // this part builds up the tree from the ground up, and then 183 | // passes it back to the parent to be split more until we reach 184 | // the root node 185 | 186 | // create new nodes: the split algorithm generalized to N 187 | 188 | return rtreeCluster(child_entries); 189 | 190 | } 191 | */ 192 | 193 | /** 194 | \brief Touches each node using the visitor pattern 195 | 196 | You must specify an acceptor functor that takes a BoundingBox and a 197 | visitor that takes a BoundingBox and a const LeafType&. 198 | 199 | See RStarVisitor.h for more information about the various visitor 200 | types available. 201 | 202 | @param acceptor An acceptor functor that returns true if this 203 | branch or leaf of the tree should be considered for visitation. 204 | 205 | @param visitor A visitor functor that does the visiting 206 | 207 | @return This will return the Visitor object, so you can retrieve whatever 208 | data it has in it if needed (for example, to get the count of items 209 | visited). It returns by value, so ensure that the copy is cheap 210 | for decent performance. 211 | */ 212 | template 213 | Visitor Query(const Acceptor &accept, Visitor visitor) 214 | { 215 | if (m_root) 216 | { 217 | QueryFunctor query(accept, visitor); 218 | query(m_root); 219 | } 220 | 221 | return visitor; 222 | } 223 | 224 | 225 | /** 226 | \brief Removes item(s) from the tree. 227 | 228 | See RStarVisitor.h for more information about the various visitor 229 | types available. 230 | 231 | @param acceptor A node acceptor functor that returns true if this 232 | branch or leaf of the tree should be considered for deletion 233 | (it does not delete it, however. That is what the LeafRemover does). 234 | 235 | @param leafRemover A visitor functor that decides whether that 236 | individual item should be removed from the tree. If it returns true, 237 | then the node holding that item will be deleted. 238 | 239 | See also RemoveBoundedArea, RemoveItem for examples of how this 240 | function can be called. 241 | */ 242 | template 243 | void Remove( const Acceptor &accept, LeafRemover leafRemover) 244 | { 245 | std::list itemsToReinsert; 246 | 247 | if (!m_root) 248 | return; 249 | 250 | RemoveFunctor remove(accept, leafRemover, &itemsToReinsert, &m_size); 251 | remove(m_root, true); 252 | 253 | if (!itemsToReinsert.empty()) 254 | { 255 | // reinsert anything that needs to be reinserted 256 | typename std::list< Leaf* >::iterator it = itemsToReinsert.begin(); 257 | typename std::list< Leaf* >::iterator end = itemsToReinsert.end(); 258 | 259 | // TODO: do this whenever that actually works.. 260 | // BulkInsert(itemsToReinsert, m_root); 261 | 262 | for(;it != end; it++) 263 | InsertInternal(*it, m_root); 264 | } 265 | } 266 | 267 | // stub that removes any items contained in an specified area 268 | void RemoveBoundedArea( const BoundingBox &bound ) 269 | { 270 | Remove(AcceptEnclosing(bound), RemoveLeaf()); 271 | } 272 | 273 | // removes a specific item. If removeDuplicates is true, only the first 274 | // item found will be removed 275 | void RemoveItem( const LeafType &item, bool removeDuplicates = true ) 276 | { 277 | Remove( AcceptAny(), RemoveSpecificLeaf(item, removeDuplicates)); 278 | } 279 | 280 | 281 | std::size_t GetSize() const { return m_size; } 282 | std::size_t GetDimensions() const { return dimensions; } 283 | 284 | 285 | protected: 286 | 287 | // choose subtree: only pass this items that do not have leaves 288 | // I took out the loop portion of this algorithm, so it only 289 | // picks a subtree at that particular level 290 | Node * ChooseSubtree(Node * node, const BoundingBox * bound) 291 | { 292 | // If the child pointers in N point to leaves 293 | if (static_cast(node->items[0])->hasLeaves) 294 | { 295 | // determine the minimum overlap cost 296 | if (max_child_items > (RTREE_CHOOSE_SUBTREE_P*2)/3 && node->items.size() > RTREE_CHOOSE_SUBTREE_P) 297 | { 298 | // ** alternative algorithm: 299 | // Sort the rectangles in N in increasing order of 300 | // then area enlargement needed to include the new 301 | // data rectangle 302 | 303 | // Let A be the group of the first p entrles 304 | std::partial_sort( node->items.begin(), node->items.begin() + RTREE_CHOOSE_SUBTREE_P, node->items.end(), 305 | SortBoundedItemsByAreaEnlargement(bound)); 306 | 307 | // From the items in A, considering all items in 308 | // N, choose the leaf whose rectangle needs least 309 | // overlap enlargement 310 | 311 | return static_cast(* std::min_element(node->items.begin(), node->items.begin() + RTREE_CHOOSE_SUBTREE_P, 312 | SortBoundedItemsByOverlapEnlargement(bound))); 313 | } 314 | 315 | // choose the leaf in N whose rectangle needs least 316 | // overlap enlargement to include the new data 317 | // rectangle Resolve ties by choosmg the leaf 318 | // whose rectangle needs least area enlargement, then 319 | // the leaf with the rectangle of smallest area 320 | 321 | return static_cast(* std::min_element(node->items.begin(), node->items.end(), 322 | SortBoundedItemsByOverlapEnlargement(bound))); 323 | } 324 | 325 | // if the chlld pointers in N do not point to leaves 326 | 327 | // [determine the minimum area cost], 328 | // choose the leaf in N whose rectangle needs least 329 | // area enlargement to include the new data 330 | // rectangle. Resolve ties by choosing the leaf 331 | // with the rectangle of smallest area 332 | 333 | return static_cast(* std::min_element( node->items.begin(), node->items.end(), 334 | SortBoundedItemsByAreaEnlargement(bound))); 335 | } 336 | 337 | 338 | // inserts nodes recursively. As an optimization, the algorithm steps are 339 | // way out of order. :) If this returns something, then that item should 340 | // be added to the caller's level of the tree 341 | Node * InsertInternal(Leaf * leaf, Node * node, bool firstInsert = true) 342 | { 343 | // I4: Adjust all covering rectangles in the insertion path 344 | // such that they are minimum bounding boxes 345 | // enclosing the children rectangles 346 | node->bound.stretch(leaf->bound); 347 | 348 | 349 | // CS2: If we're at a leaf, then use that level 350 | if (node->hasLeaves) 351 | { 352 | // I2: If N has less than M items, accommodate E in N 353 | node->items.push_back(leaf); 354 | } 355 | else 356 | { 357 | // I1: Invoke ChooseSubtree. with the level as a parameter, 358 | // to find an appropriate node N, m which to place the 359 | // new leaf E 360 | 361 | // of course, this already does all of that recursively. we just need to 362 | // determine whether we need to split the overflow or not 363 | Node * tmp_node = InsertInternal( leaf, ChooseSubtree(node, &leaf->bound), firstInsert ); 364 | 365 | if (!tmp_node) 366 | return NULL; 367 | 368 | // this gets joined to the list of items at this level 369 | node->items.push_back(tmp_node); 370 | } 371 | 372 | 373 | // If N has M+1 items. invoke OverflowTreatment with the 374 | // level of N as a parameter [for reinsertion or split] 375 | if (node->items.size() > max_child_items ) 376 | { 377 | 378 | // I3: If OverflowTreatment was called and a split was 379 | // performed, propagate OverflowTreatment upwards 380 | // if necessary 381 | 382 | // This is implicit, the rest of the algorithm takes place in there 383 | return OverflowTreatment(node, firstInsert); 384 | } 385 | 386 | return NULL; 387 | } 388 | 389 | 390 | // TODO: probably could just merge this in with InsertInternal() 391 | Node * OverflowTreatment(Node * level, bool firstInsert) 392 | { 393 | // OT1: If the level is not the root level AND this is the first 394 | // call of OverflowTreatment in the given level during the 395 | // insertion of one data rectangle, then invoke Reinsert 396 | if (level != m_root && firstInsert) 397 | { 398 | Reinsert(level); 399 | return NULL; 400 | } 401 | 402 | Node * splitItem = Split(level); 403 | 404 | // If OverflowTreatment caused a split of the root, create a new root 405 | if (level == m_root) 406 | { 407 | Node * newRoot = new Node(); 408 | newRoot->hasLeaves = false; 409 | 410 | // reserve memory 411 | newRoot->items.reserve(min_child_items); 412 | newRoot->items.push_back(m_root); 413 | newRoot->items.push_back(splitItem); 414 | 415 | // Do I4 here for the new root item 416 | newRoot->bound.reset(); 417 | for_each(newRoot->items.begin(), newRoot->items.end(), StretchBoundingBox(&newRoot->bound)); 418 | 419 | // and we're done 420 | m_root = newRoot; 421 | return NULL; 422 | } 423 | 424 | // propagate it upwards 425 | return splitItem; 426 | } 427 | 428 | // this combines Split, ChooseSplitAxis, and ChooseSplitIndex into 429 | // one function as an optimization (they all share data structures, 430 | // so it would be pointless to do all of that copying) 431 | // 432 | // This returns a node, which should be added to the items of the 433 | // passed node's parent 434 | Node * Split(Node * node) 435 | { 436 | Node * newNode = new Node(); 437 | newNode->hasLeaves = node->hasLeaves; 438 | 439 | const std::size_t n_items = node->items.size(); 440 | const std::size_t distribution_count = n_items - 2*min_child_items + 1; 441 | 442 | std::size_t split_axis = dimensions+1, split_edge = 0, split_index = 0; 443 | int split_margin = 0; 444 | 445 | BoundingBox R1, R2; 446 | 447 | // these should always hold true 448 | assert(n_items == max_child_items + 1); 449 | assert(distribution_count > 0); 450 | assert(min_child_items + distribution_count-1 <= n_items); 451 | 452 | // S1: Invoke ChooseSplitAxis to determine the axis, 453 | // perpendicular to which the split 1s performed 454 | // S2: Invoke ChooseSplitIndex to determine the best 455 | // distribution into two groups along that axis 456 | 457 | // NOTE: We don't compare against node->bound, so it gets overwritten 458 | // at the end of the loop 459 | 460 | // CSA1: For each axis 461 | for (std::size_t axis = 0; axis < dimensions; axis++) 462 | { 463 | // initialize per-loop items 464 | int margin = 0; 465 | double overlap = 0, dist_area, dist_overlap; 466 | std::size_t dist_edge = 0, dist_index = 0; 467 | 468 | dist_area = dist_overlap = std::numeric_limits::max(); 469 | 470 | 471 | // Sort the items by the lower then by the upper 472 | // edge of their bounding box on this particular axis and 473 | // determine all distributions as described . Compute S. the 474 | // sum of all margin-values of the different 475 | // distributions 476 | 477 | // lower edge == 0, upper edge = 1 478 | for (std::size_t edge = 0; edge < 2; edge++) 479 | { 480 | // sort the items by the correct key (upper edge, lower edge) 481 | if (edge == 0) 482 | std::sort(node->items.begin(), node->items.end(), SortBoundedItemsByFirstEdge(axis)); 483 | else 484 | std::sort(node->items.begin(), node->items.end(), SortBoundedItemsBySecondEdge(axis)); 485 | 486 | // Distributions: pick a point m in the middle of the thing, call the left 487 | // R1 and the right R2. Calculate the bounding box of R1 and R2, then 488 | // calculate the margins. Then do it again for some more points 489 | for (std::size_t k = 0; k < distribution_count; k++) 490 | { 491 | double area = 0; 492 | 493 | // calculate bounding box of R1 494 | R1.reset(); 495 | for_each(node->items.begin(), node->items.begin()+(min_child_items+k), StretchBoundingBox(&R1)); 496 | 497 | // then do the same for R2 498 | R2.reset(); 499 | for_each(node->items.begin()+(min_child_items+k+1), node->items.end(), StretchBoundingBox(&R2)); 500 | 501 | 502 | // calculate the three values 503 | margin += R1.edgeDeltas() + R2.edgeDeltas(); 504 | area += R1.area() + R2.area(); // TODO: need to subtract.. overlap? 505 | overlap = R1.overlap(R2); 506 | 507 | 508 | // CSI1: Along the split axis, choose the distribution with the 509 | // minimum overlap-value. Resolve ties by choosing the distribution 510 | // with minimum area-value. 511 | if (overlap < dist_overlap || (overlap == dist_overlap && area < dist_area)) 512 | { 513 | // if so, store the parameters that allow us to recreate it at the end 514 | dist_edge = edge; 515 | dist_index = min_child_items+k; 516 | dist_overlap = overlap; 517 | dist_area = area; 518 | } 519 | } 520 | } 521 | 522 | // CSA2: Choose the axis with the minimum S as split axis 523 | if (split_axis == dimensions+1 || split_margin > margin ) 524 | { 525 | split_axis = axis; 526 | split_margin = margin; 527 | split_edge = dist_edge; 528 | split_index = dist_index; 529 | } 530 | } 531 | 532 | // S3: Distribute the items into two groups 533 | 534 | // ok, we're done, and the best distribution on the selected split 535 | // axis has been recorded, so we just have to recreate it and 536 | // return the correct index 537 | 538 | if (split_edge == 0) 539 | std::sort(node->items.begin(), node->items.end(), SortBoundedItemsByFirstEdge(split_axis)); 540 | 541 | // only reinsert the sort key if we have to 542 | else if (split_axis != dimensions-1) 543 | std::sort(node->items.begin(), node->items.end(), SortBoundedItemsBySecondEdge(split_axis)); 544 | 545 | // distribute the end of the array to the new node, then erase them from the original node 546 | newNode->items.assign(node->items.begin() + split_index, node->items.end()); 547 | node->items.erase(node->items.begin() + split_index, node->items.end()); 548 | 549 | // adjust the bounding box for each 'new' node 550 | node->bound.reset(); 551 | std::for_each(node->items.begin(), node->items.end(), StretchBoundingBox(&node->bound)); 552 | 553 | newNode->bound.reset(); 554 | std::for_each(newNode->items.begin(), newNode->items.end(), StretchBoundingBox(&newNode->bound)); 555 | 556 | return newNode; 557 | } 558 | 559 | // This routine is used to do the opportunistic reinsertion that the 560 | // R* algorithm calls for 561 | void Reinsert(Node * node) 562 | { 563 | std::vector< BoundedItem* > removed_items; 564 | 565 | const std::size_t n_items = node->items.size(); 566 | const std::size_t p = (std::size_t)((double)n_items * RTREE_REINSERT_P) > 0 ? (std::size_t)((double)n_items * RTREE_REINSERT_P) : 1; 567 | 568 | // RI1 For all M+l items of a node N, compute the distance 569 | // between the centers of their rectangles and the center 570 | // of the bounding rectangle of N 571 | assert(n_items == max_child_items + 1); 572 | 573 | // RI2: Sort the items in increasing order of their distances 574 | // computed in RI1 575 | std::partial_sort(node->items.begin(), node->items.end() - p, node->items.end(), 576 | SortBoundedItemsByDistanceFromCenter(&node->bound)); 577 | 578 | // RI3.A: Remove the last p items from N 579 | removed_items.assign(node->items.end() - p, node->items.end()); 580 | node->items.erase(node->items.end() - p, node->items.end()); 581 | 582 | // RI3.B: adjust the bounding rectangle of N 583 | node->bound.reset(); 584 | for_each(node->items.begin(), node->items.end(), StretchBoundingBox(&node->bound)); 585 | 586 | // RI4: In the sort, defined in RI2, starting with the 587 | // minimum distance (= close reinsert), invoke Insert 588 | // to reinsert the items 589 | for (typename std::vector< BoundedItem* >::iterator it = removed_items.begin(); it != removed_items.end(); it++) 590 | InsertInternal( static_cast(*it), m_root, false); 591 | } 592 | 593 | /**************************************************************** 594 | * These are used to implement walking the entire R* tree in a 595 | * conditional way 596 | ****************************************************************/ 597 | 598 | // visits a node if necessary 599 | template 600 | struct VisitFunctor { 601 | 602 | const Acceptor &accept; 603 | Visitor &visit; 604 | 605 | explicit VisitFunctor(const Acceptor &a, Visitor &v) : accept(a), visit(v) {} 606 | 607 | void operator()( BoundedItem * item ) 608 | { 609 | Leaf * leaf = static_cast(item); 610 | 611 | if (accept(leaf)) 612 | visit(leaf); 613 | } 614 | }; 615 | 616 | 617 | // this functor recursively walks the tree 618 | template 619 | struct QueryFunctor { 620 | const Acceptor &accept; 621 | Visitor &visitor; 622 | 623 | explicit QueryFunctor(const Acceptor &a, Visitor &v) : accept(a), visitor(v) {} 624 | 625 | void operator()(BoundedItem * item) 626 | { 627 | Node * node = static_cast(item); 628 | 629 | if (visitor.ContinueVisiting && accept(node)) 630 | { 631 | if (node->hasLeaves) 632 | for_each(node->items.begin(), node->items.end(), VisitFunctor(accept, visitor)); 633 | else 634 | for_each(node->items.begin(), node->items.end(), *this); 635 | } 636 | } 637 | }; 638 | 639 | 640 | /**************************************************************** 641 | * Used to remove items from the tree 642 | * 643 | * At some point, the complexity just gets ridiculous. I'm pretty 644 | * sure that the remove functions are close to that by now... 645 | ****************************************************************/ 646 | 647 | 648 | 649 | // determines whether a leaf should be deleted or not 650 | template 651 | struct RemoveLeafFunctor 652 | { 653 | const Acceptor &accept; 654 | LeafRemover &remove; 655 | std::size_t * size; 656 | 657 | explicit RemoveLeafFunctor(const Acceptor &a, LeafRemover &r, std::size_t * s) : 658 | accept(a), remove(r), size(s) {} 659 | 660 | bool operator()(BoundedItem * item ) const { 661 | Leaf * leaf = static_cast(item); 662 | 663 | if (accept(leaf) && remove(leaf)) 664 | { 665 | --(*size); 666 | delete leaf; 667 | return true; 668 | } 669 | 670 | return false; 671 | } 672 | }; 673 | 674 | 675 | template 676 | struct RemoveFunctor 677 | { 678 | const Acceptor &accept; 679 | LeafRemover &remove; 680 | 681 | // parameters that are passed in 682 | std::list * itemsToReinsert; 683 | std::size_t * m_size; 684 | 685 | // the third parameter is a list that the items that need to be reinserted 686 | // are put into 687 | explicit RemoveFunctor(const Acceptor &na, LeafRemover &lr, std::list* ir, std::size_t * size) 688 | : accept(na), remove(lr), itemsToReinsert(ir), m_size(size) {} 689 | 690 | bool operator()(BoundedItem * item, bool isRoot = false) 691 | { 692 | Node * node = static_cast(item); 693 | 694 | if (accept(node)) 695 | { 696 | // this is the easy part: remove nodes if they need to be removed 697 | if (node->hasLeaves) 698 | node->items.erase(std::remove_if(node->items.begin(), node->items.end(), RemoveLeafFunctor(accept, remove, m_size)), node->items.end()); 699 | else 700 | node->items.erase(std::remove_if(node->items.begin(), node->items.end(), *this), node->items.end() ); 701 | 702 | if (!isRoot) 703 | { 704 | if (node->items.empty()) 705 | { 706 | // tell parent to remove us if theres nothing left 707 | delete node; 708 | return true; 709 | } 710 | else if (node->items.size() < min_child_items) 711 | { 712 | // queue up the items that need to be reinserted 713 | QueueItemsToReinsert(node); 714 | return true; 715 | } 716 | } 717 | else if (node->items.empty()) 718 | { 719 | // if the root node is empty, setting these won't hurt 720 | // anything, since the algorithms don't actually require 721 | // the nodes to have anything in them. 722 | node->hasLeaves = true; 723 | node->bound.reset(); 724 | } 725 | } 726 | 727 | // anything else, don't remove it 728 | return false; 729 | 730 | } 731 | 732 | // theres probably a better way to do this, but this 733 | // traverses and finds any leaves, and adds them to a 734 | // list of items that will later be reinserted 735 | void QueueItemsToReinsert(Node * node) 736 | { 737 | typename std::vector< BoundedItem* >::iterator it = node->items.begin(); 738 | typename std::vector< BoundedItem* >::iterator end = node->items.end(); 739 | 740 | if (node->hasLeaves) 741 | { 742 | for(; it != end; it++) 743 | itemsToReinsert->push_back(static_cast(*it)); 744 | } 745 | else 746 | for (; it != end; it++) 747 | QueueItemsToReinsert(static_cast(*it)); 748 | 749 | delete node; 750 | } 751 | }; 752 | 753 | 754 | private: 755 | Node * m_root; 756 | 757 | std::size_t m_size; 758 | }; 759 | 760 | #undef RSTAR_TEMPLATE 761 | 762 | #undef RTREE_SPLIT_M 763 | #undef RTREE_REINSERT_P 764 | #undef RTREE_CHOOSE_SUBTREE_P 765 | 766 | 767 | 768 | 769 | #endif 770 | 771 | -------------------------------------------------------------------------------- /RStarVisitor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Dustin Spicuzza 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2.1 of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation. 7 | * 8 | * This library is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public 14 | * License along with this library; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | */ 17 | 18 | #ifndef RSTARVISITOR_H 19 | #define RSTARVISITOR_H 20 | 21 | #include "RStarBoundingBox.h" 22 | 23 | /** 24 | \file 25 | 26 | I'm not convinced that these are really the best way to implement 27 | this, but it works so I'll stick with it for the moment 28 | 29 | It should be noted that all of these items are typedef'ed inside 30 | of the RStarTree class, so you shouldn't generally need to 31 | directly use them. 32 | */ 33 | 34 | 35 | /******************************************************************** 36 | * These are all 'acceptor' functors used for queries and removals, 37 | * which will have the following characteristics: 38 | * 39 | * template 40 | * 41 | * bool operator()(const Node * node) 42 | * -- returns true if this branch should be visited 43 | * 44 | * bool operator()(const Leaf * leaf) 45 | * -- returns true if this leaf should be visited 46 | * 47 | * This class of functions should be easy to copy, and are expected 48 | * to be const. They are only used to determine whether something 49 | * should be visited, and not do the actual visiting. 50 | * 51 | ********************************************************************/ 52 | 53 | // returns true if the node overlaps the specified bound 54 | template 55 | struct RStarAcceptOverlapping 56 | { 57 | const typename Node::BoundingBox &m_bound; 58 | explicit RStarAcceptOverlapping(const typename Node::BoundingBox &bound) : m_bound(bound) {} 59 | 60 | bool operator()(const Node * const node) const 61 | { 62 | return m_bound.overlaps(node->bound); 63 | } 64 | 65 | bool operator()(const Leaf * const leaf) const 66 | { 67 | return m_bound.overlaps(leaf->bound); 68 | } 69 | 70 | private: RStarAcceptOverlapping(){} 71 | }; 72 | 73 | 74 | // returns true if the compared boundary is within the specified bound 75 | template 76 | struct RStarAcceptEnclosing 77 | { 78 | const typename Node::BoundingBox &m_bound; 79 | explicit RStarAcceptEnclosing(const typename Node::BoundingBox &bound) : m_bound(bound) {} 80 | 81 | bool operator()(const Node * const node) const 82 | { 83 | return m_bound.overlaps(node->bound); 84 | } 85 | 86 | bool operator()(const Leaf * const leaf) const 87 | { 88 | return m_bound.encloses(leaf->bound); 89 | } 90 | 91 | private: RStarAcceptEnclosing(){} 92 | }; 93 | 94 | 95 | // will always return true, no matter what 96 | template 97 | struct RStarAcceptAny 98 | { 99 | bool operator()(const Node * const node) const { return true; } 100 | bool operator()(const Leaf * const leaf) const { return true; } 101 | }; 102 | 103 | 104 | /******************************************************************** 105 | * These are all 'visitor' styled functions -- even though these are 106 | * specifically targeted for removal tasks, visitor classes are 107 | * specified exactly the same way. 108 | * 109 | * bool operator()(RStarLeaf * leaf) 110 | * -- Removal: if returns true, then remove the node 111 | * -- Visitor: return can actually be void, not used 112 | * 113 | * bool ContinueVisiting; (not a function) 114 | * -- if false, then the query will end as soon as possible. It 115 | * is not guaranteed that the operator() will not be called, so 116 | * items may be removed/visited after this is set to false 117 | * 118 | * You may modify the items that the leaf points to, but under no 119 | * circumstance should the bounds of the item be modified (since 120 | * that would screw up the tree). 121 | * 122 | ********************************************************************/ 123 | 124 | 125 | /* 126 | Default functor used to delete nodes from the R* tree. You can specify 127 | a different functor to use, as long as it has the same signature as this. 128 | */ 129 | template 130 | struct RStarRemoveLeaf{ 131 | 132 | const bool ContinueVisiting; 133 | RStarRemoveLeaf() : ContinueVisiting(true) {} 134 | 135 | bool operator()(const Leaf * const leaf) const 136 | { 137 | return true; 138 | } 139 | }; 140 | 141 | 142 | // returns true if the specific leaf is matched. If remove duplicates is true, 143 | // then it searches for all possible instances of the item 144 | template 145 | struct RStarRemoveSpecificLeaf 146 | { 147 | mutable bool ContinueVisiting; 148 | bool m_remove_duplicates; 149 | const typename Leaf::leaf_type &m_leaf; 150 | 151 | explicit RStarRemoveSpecificLeaf(const typename Leaf::leaf_type &leaf, bool remove_duplicates = false) : 152 | ContinueVisiting(true), m_remove_duplicates(remove_duplicates), m_leaf(leaf) {} 153 | 154 | bool operator()(const Leaf * const leaf) const 155 | { 156 | if (ContinueVisiting && m_leaf == leaf->leaf) 157 | { 158 | if (!m_remove_duplicates) 159 | ContinueVisiting = false; 160 | return true; 161 | } 162 | return false; 163 | } 164 | 165 | private: RStarRemoveSpecificLeaf(){} 166 | }; 167 | 168 | 169 | #endif 170 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008 Dustin Spicuzza 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of version 2.1 of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation. 7 | * 8 | * This library is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | * Lesser General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU Lesser General Public 14 | * License along with this library; if not, write to the Free Software 15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 16 | */ 17 | 18 | 19 | #include 20 | #include 21 | 22 | #include 23 | #include "RStarTree.h" 24 | 25 | #define RANDOM_DATASET 26 | //#define GUTTMAN_DATASET 27 | 28 | #ifdef RANDOM_DATASET 29 | typedef RStarTree RTree; 30 | #else 31 | typedef RStarTree RTree; 32 | #endif 33 | 34 | typedef RTree::BoundingBox BoundingBox; 35 | 36 | 37 | BoundingBox bounds(int x, int y, int w, int h) 38 | { 39 | BoundingBox bb; 40 | 41 | bb.edges[0].first = x; 42 | bb.edges[0].second = x + w; 43 | 44 | bb.edges[1].first = y; 45 | bb.edges[1].second = y + h; 46 | 47 | return bb; 48 | } 49 | 50 | 51 | struct Visitor { 52 | int count; 53 | bool ContinueVisiting; 54 | 55 | Visitor() : count(0), ContinueVisiting(true) {}; 56 | 57 | void operator()(const RTree::Leaf * const leaf) 58 | { 59 | #if defined( RANDOM_DATASET ) 60 | //std::cout << "Visiting " << count << std::endl; 61 | #elif defined( GUTTMAN_DATASET ) 62 | std::cout << "#" << count << ": visited " << leaf->leaf << " with bound " << leaf->bound.ToString() << std::endl; 63 | #else 64 | #error "Undefined dataset" 65 | #endif 66 | count++; 67 | } 68 | }; 69 | 70 | 71 | 72 | int main(int argc, char ** argv) 73 | { 74 | RTree tree; 75 | Visitor x; 76 | 77 | // insert a bunch of items into the tree 78 | // Note: this dataset is the one shown on Guttman's original paper 79 | #ifdef GUTTMAN_DATASET 80 | tree.Insert( "R8" , bounds( 1,5 , 3,2 )); 81 | //tree.Print("I1"); 82 | 83 | tree.Insert( "R9", bounds( 6,1 , 2,2 )); 84 | //tree.Print("I2"); 85 | 86 | tree.Insert( "R10", bounds( 6,4 , 2,2 )); 87 | //tree.Print("I3"); 88 | 89 | tree.Insert( "R11", bounds( 9,0 , 2,14 )); 90 | //tree.Print("I4"); 91 | 92 | tree.Insert( "R13", bounds( 13,1 , 1,9 )); 93 | //tree.Print("I5"); 94 | 95 | tree.Insert( "R14", bounds( 12,5 , 2,2 )); 96 | //tree.Print("I6"); 97 | 98 | tree.Insert( "R15", bounds( 0,16 , 2,2 )); 99 | //tree.Print("I7"); 100 | 101 | tree.Insert( "R16", bounds( 3,11 , 6,7 )); 102 | //tree.Print("I8"); 103 | 104 | tree.Insert( "R17", bounds( 14,10 , 7,4 )); 105 | //tree.Print("I9"); 106 | 107 | tree.Insert( "R18", bounds( 16,8 , 2,9 )); 108 | //tree.Print("I10"); 109 | 110 | tree.Insert( "R19", bounds( 17,12 , 3,3 )); 111 | //tree.Print("I11"); 112 | 113 | BoundingBox bound = bounds( 5,10, 5,5 ); 114 | 115 | std::cout << "Searching in " << bound.ToString() << std::endl; 116 | x = tree.Query(RTree::AcceptOverlapping(bound), Visitor()); 117 | std::cout << "Visited " << x.count << " nodes." << std::endl; 118 | 119 | tree.RemoveBoundedArea(bound); 120 | 121 | // stretch the bounds a bit 122 | 123 | std::cout << "Searching in " << bound.ToString() << std::endl; 124 | x = tree.Query(RTree::AcceptOverlapping(bound), Visitor()); 125 | std::cout << "Visited " << x.count << " nodes." << std::endl; 126 | 127 | BoundingBox bound2 = bounds(0,10, 10,10); 128 | std::cout << "Removing enclosed area " << bound2.ToString() << std::endl; 129 | tree.RemoveBoundedArea(bound2); 130 | 131 | std::cout << "Searching in " << bound.ToString() << std::endl; 132 | x = tree.Query(RTree::AcceptOverlapping(bound), Visitor()); 133 | std::cout << "Visited " << x.count << " nodes." << std::endl; 134 | 135 | 136 | Visitor y = tree.Query(RTree::AcceptAny(), Visitor()); 137 | std::cout << "Visited " << y.count << " nodes." << std::endl; 138 | 139 | 140 | #endif 141 | 142 | 143 | #ifdef RANDOM_DATASET 144 | srand(time(0)); 145 | 146 | #define nodes 20000 147 | 148 | for (int i = 0; i < nodes/2; i++) 149 | tree.Insert(i, bounds( rand() % 1000, rand() % 1000, rand() % 10, rand() % 10)); 150 | 151 | for (int i = 0; i < nodes/2; i++) 152 | tree.Insert(i, bounds( rand() % 1000, rand() % 1000, rand() % 20, rand() % 20)); 153 | 154 | BoundingBox bound = bounds( 100,100, 300,400 ); 155 | 156 | x = tree.Query(RTree::AcceptAny(), Visitor()); 157 | std::cout << "AcceptAny: " << x.count << " nodes visited (" << tree.GetSize() << " nodes in tree)" << std::endl; 158 | 159 | 160 | std::cout << "Searching in " << bound.ToString() << std::endl; 161 | x = tree.Query(RTree::AcceptEnclosing(bound), Visitor()); 162 | std::cout << "Visited " << x.count << " nodes (" << tree.GetSize() << " nodes in tree)" << std::endl; 163 | 164 | std::cout << "Removing enclosed area " << bound.ToString() << std::endl; 165 | tree.RemoveBoundedArea(bound); 166 | 167 | std::cout << "Searching in " << bound.ToString() << std::endl; 168 | x = tree.Query(RTree::AcceptEnclosing(bound), Visitor()); 169 | std::cout << "Visited " << x.count << " nodes. (" << tree.GetSize() << " nodes in tree)" << std::endl; 170 | 171 | //tree.Print(); 172 | 173 | #endif 174 | 175 | 176 | 177 | return 0; 178 | } 179 | 180 | 181 | /* 182 | 183 | http://donar.umiacs.umd.edu/quadtree/rectangles/cifquad.html 184 | 185 | 1.0 5.0 3.0 2.0 186 | 6.0 1.0 2.0 2.0 187 | 6.0 4.0 2.0 2.0 188 | 9.0 0.0 2.0 14.0 189 | 13.0 1.0 1.0 9.0 190 | 12.0 5.0 2.0 2.0 191 | 0.0 16.0 2.0 2.0 192 | 3.0 11.0 6.0 7.0 193 | 14.0 10.0 7.0 4.0 194 | 16.0 8.0 2.0 9.0 195 | 17.0 12.0 3.0 3.0 196 | 197 | 198 | 199 | Insert-BoundingBox{(1.0,5.0)(4.0,7.0)} 200 | Insert-BoundingBox{(6.0,1.0)(8.0,3.0)} 201 | Insert-BoundingBox{(6.0,4.0)(8.0,6.0)} 202 | Insert-BoundingBox{(9.0,0.0)(11.0,14.0)} 203 | Insert-BoundingBox{(13.0,1.0)(14.0,1.0)} 204 | Insert-BoundingBox{(12.0,5.0)(14.0,7.0)} 205 | Insert-BoundingBox{(0.0,16.0)(2.0,18.0)} 206 | Insert-BoundingBox{(3.0,11.0)(9.0,18.0)} 207 | Insert-BoundingBox{(14.0,10.0)(21.0,14.0)} 208 | Insert-BoundingBox{(16.0,8.0)(18.0,17.0)} 209 | Insert-BoundingBox{(17.0,12.0)(20.0,15.0)} 210 | 211 | */ 212 | 213 | 214 | -------------------------------------------------------------------------------- /rstartree.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual Studio 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rstartree", "rstartree.vcproj", "{40690B39-DB1D-4A94-B18F-EC6C5B9A0E3A}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {40690B39-DB1D-4A94-B18F-EC6C5B9A0E3A}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {40690B39-DB1D-4A94-B18F-EC6C5B9A0E3A}.Debug|Win32.Build.0 = Debug|Win32 14 | {40690B39-DB1D-4A94-B18F-EC6C5B9A0E3A}.Release|Win32.ActiveCfg = Release|Win32 15 | {40690B39-DB1D-4A94-B18F-EC6C5B9A0E3A}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /rstartree.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 25 | 28 | 31 | 34 | 37 | 40 | 53 | 56 | 59 | 62 | 71 | 74 | 77 | 80 | 83 | 86 | 89 | 92 | 95 | 96 | 104 | 107 | 110 | 113 | 116 | 119 | 128 | 131 | 134 | 137 | 146 | 149 | 152 | 155 | 158 | 161 | 164 | 167 | 170 | 171 | 172 | 173 | 174 | 175 | 180 | 183 | 184 | 185 | 190 | 193 | 194 | 197 | 198 | 201 | 202 | 203 | 208 | 209 | 210 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /test.cpp: -------------------------------------------------------------------------------- 1 | /* Verifies correctness of the bounding box TODO: Add OK/FAIL messages to verify correctness automatically */ #include #include "BoundingBox.h" #include int main(int argc, char ** argv) { int x = 0; RStarBoundingBox<1> b[20]; // line tests b[x++].edges[0] = std::make_pair(0, 2); b[x++].edges[0] = std::make_pair(1, 3); b[x++].edges[0] = std::make_pair(0, 4); b[x++].edges[0] = std::make_pair(1, 3); b[x++].edges[0] = std::make_pair(0, 1); b[x++].edges[0] = std::make_pair(1, 3); b[x++].edges[0] = std::make_pair(0, 1); b[x++].edges[0] = std::make_pair(2, 3); b[x++].edges[0] = std::make_pair(0, 1); b[x++].edges[0] = std::make_pair(0, 1); // point tests b[x++].edges[0] = std::make_pair(0, 0); b[x++].edges[0] = std::make_pair(1, 3); b[x++].edges[0] = std::make_pair(1, 1); b[x++].edges[0] = std::make_pair(1, 3); b[x++].edges[0] = std::make_pair(2, 2); b[x++].edges[0] = std::make_pair(1, 3); b[x++].edges[0] = std::make_pair(3, 3); b[x++].edges[0] = std::make_pair(1, 3); b[x++].edges[0] = std::make_pair(4, 4); b[x++].edges[0] = std::make_pair(1, 3); for (int i = 0; i < x/2; i++) { int i1 = i*2, i2 = i*2+1; printf("%s %s %s\n", b[i1].ToString().c_str(), b[i1].encloses(b[i2]) ? "encloses" : "does not enclose", b[i2].ToString().c_str()); printf("%s %s %s\n", b[i2].ToString().c_str(), b[i2].encloses(b[i1]) ? "encloses" : "does not enclose", b[i1].ToString().c_str()); printf("%s %s %s (%f)\n", b[i1].ToString().c_str(), b[i1].overlaps(b[i2]) ? "overlaps" : "does not overlap", b[i2].ToString().c_str(), b[i1].overlap(b[i2])); printf("%s %s %s (%f)\n\n", b[i2].ToString().c_str(), b[i2].overlaps(b[i1]) ? "overlaps" : "does not overlap", b[i1].ToString().c_str(), b[i2].overlap(b[i1])); } } --------------------------------------------------------------------------------