├── .envrc ├── .gitignore ├── AUTHORS ├── CMakeLists.txt ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── Makefile.in ├── NEWS ├── README.Python ├── README.md ├── TODO ├── autogen.sh ├── config.h.in ├── configure ├── configure.ac ├── default.nix ├── doc ├── Doxyfile └── index.txt ├── examples ├── .gitignore ├── CMakeLists.txt ├── Makefile ├── test_find_within_range.cpp ├── test_hayne.cpp └── test_kdtree.cpp ├── flake.lock ├── flake.nix ├── install-sh ├── kdtree++ ├── allocator.hpp ├── function.hpp ├── iterator.hpp ├── kdtree.hpp ├── node.hpp └── region.hpp ├── libkdtree.nix ├── missing ├── pkgconfig └── libkdtree++.pc.in ├── python-bindings ├── CMakeLists.txt ├── Makefile ├── gen-swig-hpp.py ├── py-kdtree.hpp.tmpl ├── py-kdtree.i.tmpl ├── py-kdtree_test.cpp └── py-kdtree_test.py └── shell.nix /.envrc: -------------------------------------------------------------------------------- 1 | use flake -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.in 3 | aclocal.m4 4 | autom4te.cache 5 | config.h 6 | config.h.in 7 | config.log 8 | config.status 9 | configure 10 | install-sh 11 | missing 12 | stamp-h1 13 | 14 | .direnv 15 | .DS_Store 16 | result -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Martin F. Krafft 2 | Paul Harris 3 | Sylvain Bougerel 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8.12) 2 | project (libkdtree CXX) 3 | 4 | option (BUILD_PYTHON_BINDINGS "Build Python bindings (requires SWIG)") 5 | 6 | if (WIN32) 7 | 8 | # Maximum warning level 9 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") 10 | 11 | # Be strict about warnings... make them errors 12 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") 13 | 14 | # Detect 64-bit portability issues 15 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wp64") 16 | 17 | else (WIN32) 18 | 19 | # Maximum warning level 20 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") 21 | 22 | # turn on debugging 23 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") 24 | 25 | endif (WIN32) 26 | 27 | if (BUILD_PYTHON_BINDINGS) 28 | add_subdirectory (python-bindings) 29 | endif (BUILD_PYTHON_BINDINGS) 30 | 31 | include_directories (${PROJECT_SOURCE_DIR}) 32 | 33 | add_subdirectory(examples) 34 | 35 | file (GLOB KDTREE_HEADERS kdtree++/*.hpp) 36 | install (FILES ${KDTREE_HEADERS} DESTINATION ${CMAKE_INSTALL_PREFIX}/include) 37 | 38 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | "The Artistic Licence 2.0" 2 | Copyright (c) 2000-2006, The Perl Foundation. 3 | http://www.perlfoundation.org/legal/licenses/artistic-2_0.html 4 | 5 | Everyone is permitted to copy and distribute verbatim copies of this license 6 | document, but changing it is not allowed. 7 | 8 | Preamble 9 | ~~~~~~~~ 10 | This license establishes the terms under which a given free software Package 11 | may be copied, modified, distributed, and/or redistributed. The intent is that 12 | the Copyright Holder maintains some artistic control over the development of 13 | that Package while still keeping the Package available as open source and free 14 | software. 15 | 16 | You are always permitted to make arrangements wholly outside of this license 17 | directly with the Copyright Holder of a given Package. If the terms of this 18 | license do not permit the full use that you propose to make of the Package, 19 | you should contact the Copyright Holder and seek a different licensing 20 | arrangement. 21 | 22 | Definitions 23 | ~~~~~~~~~~~ 24 | "Copyright Holder" means the individual(s) or organization(s) named in the 25 | copyright notice for the entire Package. 26 | 27 | "Contributor" means any party that has contributed code or other material to 28 | the Package, in accordance with the Copyright Holder's procedures. 29 | 30 | "You" and "your" means any person who would like to copy, distribute, or 31 | modify the Package. 32 | 33 | "Package" means the collection of files distributed by the Copyright Holder, 34 | and derivatives of that collection and/or of those files. A given Package may 35 | consist of either the Standard Version, or a Modified Version. 36 | 37 | "Distribute" means providing a copy of the Package or making it accessible to 38 | anyone else, or in the case of a company or organization, to others outside of 39 | your company or organization. 40 | 41 | "Distributor Fee" means any fee that you charge for Distributing this Package 42 | or providing support for this Package to another party. It does not mean 43 | licensing fees. 44 | 45 | "Standard Version" refers to the Package if it has not been modified, or has 46 | been modified only in ways explicitly requested by the Copyright Holder. 47 | 48 | "Modified Version" means the Package, if it has been changed, and such changes 49 | were not explicitly requested by the Copyright Holder. 50 | 51 | "Original License" means this Artistic License as Distributed with the 52 | Standard Version of the Package, in its current version or as it may be 53 | modified by The Perl Foundation in the future. 54 | 55 | "Source" form means the source code, documentation source, and configuration 56 | files for the Package. 57 | 58 | "Compiled" form means the compiled bytecode, object code, binary, or any other 59 | form resulting from mechanical transformation or translation of the Source 60 | form. 61 | 62 | Permission for Use and Modification Without Distribution 63 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 64 | (1) You are permitted to use the Standard Version and create and use Modified 65 | Versions for any purpose without restriction, provided that you do not 66 | Distribute the Modified Version. 67 | 68 | Permissions for Redistribution of the Standard Version 69 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 70 | (2) You may Distribute verbatim copies of the Source form of the Standard 71 | Version of this Package in any medium without restriction, either gratis or 72 | for a Distributor Fee, provided that you duplicate all of the original 73 | copyright notices and associated disclaimers. At your discretion, such 74 | verbatim copies may or may not include a Compiled form of the Package. 75 | 76 | (3) You may apply any bug fixes, portability changes, and other modifications 77 | made available from the Copyright Holder. The resulting Package will still be 78 | considered the Standard Version, and as such will be subject to the Original 79 | License. 80 | 81 | Distribution of Modified Versions of the Package as Source 82 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 83 | (4) You may Distribute your Modified Version as Source (either gratis or for 84 | a Distributor Fee, and with or without a Compiled form of the Modified 85 | Version) provided that you clearly document how it differs from the Standard 86 | Version, including, but not limited to, documenting any non-standard features, 87 | executables, or modules, and provided that you do at least ONE of the 88 | following: 89 | 90 | (a) make the Modified Version available to the Copyright Holder of the 91 | Standard Version, under the Original License, so that the Copyright 92 | Holder may include your modifications in the Standard Version. 93 | (b) ensure that installation of your Modified Version does not prevent the 94 | user installing or running the Standard Version. In addition, the 95 | Modified Version must bear a name that is different from the name of 96 | the Standard Version. 97 | (c) allow anyone who receives a copy of the Modified Version to make the 98 | Source form of the Modified Version available to others under 99 | (i) the Original License or 100 | (ii) a license that permits the licensee to freely copy, modify and 101 | redistribute the Modified Version using the same licensing terms 102 | that apply to the copy that the licensee received, and requires 103 | that the Source form of the Modified Version, and of any works 104 | derived from it, be made freely available in that license fees 105 | are prohibited but Distributor Fees are allowed. 106 | 107 | Distribution of Compiled Forms of the Standard Version or Modified Versions 108 | without the Source 109 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 110 | (5) You may Distribute Compiled forms of the Standard Version without the 111 | Source, provided that you include complete instructions on how to get the 112 | Source of the Standard Version. Such instructions must be valid at the time of 113 | your distribution. If these instructions, at any time while you are carrying 114 | out such distribution, become invalid, you must provide new instructions on 115 | demand or cease further distribution. If you provide valid instructions or 116 | cease distribution within thirty days after you become aware that the 117 | instructions are invalid, then you do not forfeit any of your rights under 118 | this license. 119 | 120 | (6) You may Distribute a Modified Version in Compiled form without the Source, 121 | provided that you comply with Section 4 with respect to the Source of the 122 | Modified Version. 123 | 124 | Aggregating or Linking the Package 125 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 126 | (7) You may aggregate the Package (either the Standard Version or Modified 127 | Version) with other packages and Distribute the resulting aggregation provided 128 | that you do not charge a licensing fee for the Package. Distributor Fees are 129 | permitted, and licensing fees for other components in the aggregation are 130 | permitted. The terms of this license apply to the use and Distribution of the 131 | Standard or Modified Versions as included in the aggregation. 132 | 133 | (8) You are permitted to link Modified and Standard Versions with other works, 134 | to embed the Package in a larger work of your own, or to build stand-alone 135 | binary or bytecode versions of applications that include the Package, and 136 | Distribute the result without restriction, provided the result does not expose 137 | a direct interface to the Package. 138 | 139 | Items That are Not Considered Part of a Modified Version 140 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 141 | (9) Works (including, but not limited to, modules and scripts) that merely 142 | extend or make use of the Package, do not, by themselves, cause the Package to 143 | be a Modified Version. In addition, such works are not considered parts of the 144 | Package itself, and are not subject to the terms of this license. 145 | 146 | General Provisions 147 | ~~~~~~~~~~~~~~~~~~ 148 | (10) Any use, modification, and distribution of the Standard or Modified 149 | Versions is governed by this Artistic License. By using, modifying or 150 | distributing the Package, you accept this license. Do not use, modify, or 151 | distribute the Package, if you do not accept this license. 152 | 153 | (11) If your Modified Version has been derived from a Modified Version made by 154 | someone other than you, you are nevertheless required to ensure that your 155 | Modified Version complies with the requirements of this license. 156 | 157 | (12) This license does not grant you the right to use any trademark, service 158 | mark, tradename, or logo of the Copyright Holder. 159 | 160 | (13) This license includes the non-exclusive, worldwide, free-of-charge patent 161 | license to make, have made, use, offer to sell, sell, import and otherwise 162 | transfer the Package with respect to any patent claims licensable by the 163 | Copyright Holder that are necessarily infringed by the Package. If you 164 | institute patent litigation (including a cross-claim or counterclaim) against 165 | any party alleging that the Package constitutes direct or contributory patent 166 | infringement, then this Artistic License to you shall terminate on the date 167 | that such litigation is filed. 168 | 169 | (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER 170 | AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE 171 | IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 172 | NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. 173 | UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR 174 | ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY 175 | OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 176 | DAMAGE. 177 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | libkdtree++ ChangeLog 2 | ===================== 3 | 4 | 2008-11-17 Sylvain Bougerel 5 | 6 | - Added #include in order to compile 'printf' statements in the 7 | file 'examples/test_find_within_range.cpp'. 8 | - Added patch from Max Fellermann in order to compile libkdtree++ with 9 | clang++. 10 | 11 | 2009-02-10 Paul Harris 12 | 13 | - Bug fix: was incorrectly casting a pointer when the search key type 14 | was different to the stored type. 15 | 16 | 2008-12-30 Paul Harris 17 | 18 | - New function: efficient_replace_and_optimise(). 19 | Yes, its a long name. Sylvain doesn't like it. 20 | The reason for the long name is that it is a dangerous function, 21 | and it will resort whatever vector<> of data that you pass it. 22 | So I wanted the user to really know what they were doing before 23 | they called this function. 24 | - Now calls sqrt() when required in order to search for items 25 | in 'real' distance units... And so it will accept and return distance 26 | in 'real' units (as opposed to squared units). 27 | This is not an ideal solution, we have all sorts of ideas to improve 28 | kdtree which will include less calls to sqrt() for more speed, and 29 | the ability to change the standard euclidean distance measurements 30 | for distance-on-a-sphere or whatever the user wants. 31 | - Changed from using std::sort() to std::nth_element() when optimising 32 | the tree. Performance boost. 33 | - Added lots of tests to check that the find functions are working 34 | correctly when fed edge-cases, including: 35 | - Items that are exactly 'max' distance away from the target. 36 | - When there are no value items to find. 37 | - Templated the find functions so that the target/center point can be 38 | anything that can be accessed via the Accessor. 39 | - Fixes to make it compile. 40 | 41 | - And, a Python wrapper ! See README.Python 42 | 43 | - CMake support now can build the python wrapper and install the headers 44 | and the python wrapper to a destination folder. Its simple, but neat. 45 | Does not install python module into the python site packages or anything 46 | like that. 47 | 48 | 2008-11-17 Sylvain Bougerel 49 | 50 | - The version number of the library is now part of the headers. 51 | - Fixed a bug with assignment operator. 52 | - Fixed uninitialized memory problem with valgrind, when printing the 53 | content of the tree. Due to the fact the _M_header was a _Link_type 54 | instead of a _Node_base type and _M_root was a _Base_ptr type instead of 55 | a _Link_type. 56 | - Paul Harris fixed find() by ensuring that the correct node is being 57 | matched during a find(). Thus, fixed a similar problem in erase. Paul 58 | also added a new test courtesy of Hayne. 59 | - Paul Harris augmented test_kdtree with various test on copy 60 | construction, assignment, and formatting operator. 61 | - Paul Harris added support for CMake, which should suit not only 62 | MSVC users but others too. 63 | - Paul Harris fixed bug with compiling with MSVC2005 with the 64bit 64 | warnings turned on. 65 | 66 | 2008-11-12 Sylvain Bougerel 67 | 68 | - Fix segfault on the regular iterator when _M_header->_M_right == 69 | _M_root. Fix segfault on the reverse iterator when _M_header->_M_left == 70 | _M_root. 71 | 72 | Besides, it also change the behavior when iterating past the end() or 73 | rend(). Previously this would result in segfaults, now it makes the 74 | iterator points to an undetermined location in the tree, similarly to 75 | the current implementation of GNU libstdc++. 76 | 77 | 2008-11-10 Sylvain Bougerel 78 | 79 | - kdtree++/iterator.hpp (KDTree): the decrement iterator was 80 | ill-written. Its buggy behavior, and the use of non-standard 81 | reverse_iterator initialiser needed to be fixed. These error were do to 82 | a previous failed attempt by me at fixing the reverse_iterator. 83 | 84 | This time, I believe I got it right, however it needed the kdtree 85 | structure to be modified. The reason is that without modification it is 86 | not possible to distinguish the "header" from the "root" within the 87 | iterator. This is required for the reverse_iterator to work properly. 88 | 89 | Now the kdtree has an additional pointer that points directly to the 90 | root. The parent pointer of the header is permanently null. And 91 | therefore the header can be distinguished from the root within the 92 | iterator by checking the parent of the current node: if it is null, we 93 | are at the header. 94 | 95 | 96 | 2008-11-10 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com) 97 | 98 | - patch from Martin Shreiber to make libkdtree to compile with newer 99 | version of g++-4.2 and g++4.3. 100 | 101 | - patch from Paul Harris to make libkdtree more exception transparent. 102 | 103 | 2007-12-08 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com) 104 | 105 | - fix bug where find_nearest() could return the wrong value if a 106 | maximum distance greater than the root distance to the target value 107 | was given in argument to the function. 108 | 109 | - find_nearest() still returns SQUARED value of the distance. You still 110 | have to use sqrt() on the second member of the iterator. 111 | 112 | - find_nearest() behavior was slightly changed: if many nodes are at 113 | the same distance from the target value, the node with the lowest 114 | memory address will be returned. This is to catter for the 115 | reimplementation of find_exact() coming soon. 116 | 117 | 2007-12-02 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com) 118 | 119 | - find_nearest() now returned the SQUARED value of the distance for 120 | euclidean space calculation (the default). You have to use sqrt() on 121 | the returned distance (i.e. iterator->second) if you want to read the 122 | absolute distance returned by find_nearest. My apologies for not 123 | making highlighting this beforehand. 124 | 125 | - Increased the performance of find and find_nearest/find_nearest_if by 126 | about 50x to 100x depending on your compilation flags. 127 | 128 | - KDTree are not defined as: 129 | KDTree<__K, _Val, _Acc, _Cmp, _Alloc> 130 | but as: 131 | KDTree<__K, _Val, _Acc, _Dist, _Cmp, _Alloc> 132 | So pay attention to the _Dist functor. The distance functor calculate 133 | the squared difference between 2 elements returned by the accessor. You 134 | might have to change your code to reflect the new definition, or it wont 135 | compile if you have set custom accessor and comparison functors. 136 | 137 | - The following functors are now accessible in the tree: 138 | - the comparison functor, accessible by copy only 139 | - the accessor functor, accessible by copy only 140 | - the distance functor, accessible read-write, this means that 141 | you can modify the behavior of find, find_nearest, 142 | find_nearest_if within the same KDTree object. 143 | 144 | - find_exact has not be modified and retained the code of the former, 145 | slower algorithm. I have to write some more code to do this. Pls wait a 146 | little more. 147 | 148 | - The file accessor.hpp was renamed as function.hpp for it now boast 149 | more than just the KDTree accessor 150 | 151 | 2007-11-25 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com) 152 | 153 | - fixed the reverse_iterator. Now it can be used. 154 | 155 | 2007-10-24 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com) 156 | 157 | - Removal of all the warnings that are yield by the compiler when 158 | using the following flags: 159 | -Wall -pedantic -ansi 160 | Do not hesitate to suggest any flags for additional code checking. 161 | 162 | This release also feature numerous of enhancements by Paul Harris 163 | (paulharris@computer.org): 164 | - const kdtrees can be searched 165 | - find_nearest_if() enforce validation of a predicate 166 | - visit_within_range() walk the tree and calls 167 | Visitor::operator() on template argument for 168 | each node within the range 169 | - find_exact() matches an kdtree::value_type by location and by 170 | calling kdtree::value_type::operator==() (in case two different 171 | items have the same location find_exact() will not return the 172 | wrong item) 173 | - erase_exact() is to erase() what find_exact() is to find() 174 | - check_tree() and num_dist_calcs for debugging purpose plus 175 | additional improvements on erase and region intersection 176 | 177 | 2004-11-26 Paul Harris (paulharris@computer.org) 178 | 179 | - New feature: find_nearest() 180 | - Accessors can now be initialised with the tree, so ptr_fun() 181 | or functors can be used to access datapoints. 182 | - Accessors now much more generic, so you can use the same 183 | accessor to access multiple types. 184 | - Range-constructors now optimise() automatically, simplifying 185 | the construction of a filled tree. 186 | - _Range is now more easy to construct. 187 | 188 | 2004-11-15 Martin F. Krafft (libkdtree@pobox.madduck.net) 189 | 190 | - fixed numerous little bugs that led to compilation problems 191 | - changed code to compile cleanly with GCC 3.4 and GCC 4.0 192 | 193 | 2004-11-06 Martin F. Krafft (libkdtree@pobox.madduck.net) 194 | 195 | - reverted to optimise() to prevent API change, and added an optimize() 196 | passthrough method with an appropriate comment. 197 | 198 | 2004-11-05 Paul Harris (paulharris@computer.org) 199 | 200 | - Renamed optimise() to optimize(). 201 | - Added a full set of range constructors and insert(range) methods. 202 | it now works with inserter(tree,tree.begin()) 203 | - Target type no longer needs a default constructor. This also fixes 204 | problems with empty trees (would crash if optimized). 205 | - Some code cleanup (removed inlines, switched from const_iterator to 206 | iterator, added this-> to ensure the methods are called). 207 | - Added a new method: count_within_range(). 208 | - Fixed bug in rend(). 209 | 210 | 2004-11-04 Martin F. Krafft (libkdtree@pobox.madduck.net) 211 | 212 | - Integrated patch by Paul Harris to fix a logic error pertaining to 213 | OutputIterators in find_within_range. find_within_range() now 214 | returns the output iterator instead of a count. Thanks, Paul! 215 | - Added another fix by Paul Harris to _M_get_j_max, which would cause 216 | a dimensional overflow for trees with depths >= K. Thanks (again) Paul! 217 | - Made some improvements to the autotools files. 218 | 219 | 2004-05-11 Martin F. Krafft (libkdtree@pobox.madduck.net) 220 | 221 | - Fixed CFlags and Libs entries in pkgconfig file. 222 | 223 | 2004-05-11 Martin F. Krafft (libkdtree@pobox.madduck.net) 224 | 225 | - Initial release. 226 | 227 | 228 | COPYRIGHT -- 229 | libkdtree++ is (c) 2004-2007 Martin F. Krafft and 230 | Sylvain Bougerel and distributed under the 231 | terms of the Artistic License 2.0. See the ./COPYING file in the source tree 232 | root for more information. 233 | 234 | THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, 235 | INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND 236 | FITNESS FOR A PARTICULAR PURPOSE. 237 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Installation Instructions 2 | ************************* 3 | 4 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 5 | 2006 Free Software Foundation, Inc. 6 | 7 | This file is free documentation; the Free Software Foundation gives 8 | unlimited permission to copy, distribute and modify it. 9 | 10 | Basic Installation 11 | ================== 12 | 13 | Briefly, the shell commands `./configure; make; make install' should 14 | configure, build, and install this package. The following 15 | more-detailed instructions are generic; see the `README' file for 16 | instructions specific to this package. 17 | 18 | The `configure' shell script attempts to guess correct values for 19 | various system-dependent variables used during compilation. It uses 20 | those values to create a `Makefile' in each directory of the package. 21 | It may also create one or more `.h' files containing system-dependent 22 | definitions. Finally, it creates a shell script `config.status' that 23 | you can run in the future to recreate the current configuration, and a 24 | file `config.log' containing compiler output (useful mainly for 25 | debugging `configure'). 26 | 27 | It can also use an optional file (typically called `config.cache' 28 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 29 | the results of its tests to speed up reconfiguring. Caching is 30 | disabled by default to prevent problems with accidental use of stale 31 | cache files. 32 | 33 | If you need to do unusual things to compile the package, please try 34 | to figure out how `configure' could check whether to do them, and mail 35 | diffs or instructions to the address given in the `README' so they can 36 | be considered for the next release. If you are using the cache, and at 37 | some point `config.cache' contains results you don't want to keep, you 38 | may remove or edit it. 39 | 40 | The file `configure.ac' (or `configure.in') is used to create 41 | `configure' by a program called `autoconf'. You need `configure.ac' if 42 | you want to change it or regenerate `configure' using a newer version 43 | of `autoconf'. 44 | 45 | The simplest way to compile this package is: 46 | 47 | 1. `cd' to the directory containing the package's source code and type 48 | `./configure' to configure the package for your system. 49 | 50 | Running `configure' might take a while. While running, it prints 51 | some messages telling which features it is checking for. 52 | 53 | 2. Type `make' to compile the package. 54 | 55 | 3. Optionally, type `make check' to run any self-tests that come with 56 | the package. 57 | 58 | 4. Type `make install' to install the programs and any data files and 59 | documentation. 60 | 61 | 5. You can remove the program binaries and object files from the 62 | source code directory by typing `make clean'. To also remove the 63 | files that `configure' created (so you can compile the package for 64 | a different kind of computer), type `make distclean'. There is 65 | also a `make maintainer-clean' target, but that is intended mainly 66 | for the package's developers. If you use it, you may have to get 67 | all sorts of other programs in order to regenerate files that came 68 | with the distribution. 69 | 70 | Compilers and Options 71 | ===================== 72 | 73 | Some systems require unusual options for compilation or linking that the 74 | `configure' script does not know about. Run `./configure --help' for 75 | details on some of the pertinent environment variables. 76 | 77 | You can give `configure' initial values for configuration parameters 78 | by setting variables in the command line or in the environment. Here 79 | is an example: 80 | 81 | ./configure CC=c99 CFLAGS=-g LIBS=-lposix 82 | 83 | *Note Defining Variables::, for more details. 84 | 85 | Compiling For Multiple Architectures 86 | ==================================== 87 | 88 | You can compile the package for more than one kind of computer at the 89 | same time, by placing the object files for each architecture in their 90 | own directory. To do this, you can use GNU `make'. `cd' to the 91 | directory where you want the object files and executables to go and run 92 | the `configure' script. `configure' automatically checks for the 93 | source code in the directory that `configure' is in and in `..'. 94 | 95 | With a non-GNU `make', it is safer to compile the package for one 96 | architecture at a time in the source code directory. After you have 97 | installed the package for one architecture, use `make distclean' before 98 | reconfiguring for another architecture. 99 | 100 | Installation Names 101 | ================== 102 | 103 | By default, `make install' installs the package's commands under 104 | `/usr/local/bin', include files under `/usr/local/include', etc. You 105 | can specify an installation prefix other than `/usr/local' by giving 106 | `configure' the option `--prefix=PREFIX'. 107 | 108 | You can specify separate installation prefixes for 109 | architecture-specific files and architecture-independent files. If you 110 | pass the option `--exec-prefix=PREFIX' to `configure', the package uses 111 | PREFIX as the prefix for installing programs and libraries. 112 | Documentation and other data files still use the regular prefix. 113 | 114 | In addition, if you use an unusual directory layout you can give 115 | options like `--bindir=DIR' to specify different values for particular 116 | kinds of files. Run `configure --help' for a list of the directories 117 | you can set and what kinds of files go in them. 118 | 119 | If the package supports it, you can cause programs to be installed 120 | with an extra prefix or suffix on their names by giving `configure' the 121 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 122 | 123 | Optional Features 124 | ================= 125 | 126 | Some packages pay attention to `--enable-FEATURE' options to 127 | `configure', where FEATURE indicates an optional part of the package. 128 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 129 | is something like `gnu-as' or `x' (for the X Window System). The 130 | `README' should mention any `--enable-' and `--with-' options that the 131 | package recognizes. 132 | 133 | For packages that use the X Window System, `configure' can usually 134 | find the X include and library files automatically, but if it doesn't, 135 | you can use the `configure' options `--x-includes=DIR' and 136 | `--x-libraries=DIR' to specify their locations. 137 | 138 | Specifying the System Type 139 | ========================== 140 | 141 | There may be some features `configure' cannot figure out automatically, 142 | but needs to determine by the type of machine the package will run on. 143 | Usually, assuming the package is built to be run on the _same_ 144 | architectures, `configure' can figure that out, but if it prints a 145 | message saying it cannot guess the machine type, give it the 146 | `--build=TYPE' option. TYPE can either be a short name for the system 147 | type, such as `sun4', or a canonical name which has the form: 148 | 149 | CPU-COMPANY-SYSTEM 150 | 151 | where SYSTEM can have one of these forms: 152 | 153 | OS KERNEL-OS 154 | 155 | See the file `config.sub' for the possible values of each field. If 156 | `config.sub' isn't included in this package, then this package doesn't 157 | need to know the machine type. 158 | 159 | If you are _building_ compiler tools for cross-compiling, you should 160 | use the option `--target=TYPE' to select the type of system they will 161 | produce code for. 162 | 163 | If you want to _use_ a cross compiler, that generates code for a 164 | platform different from the build platform, you should specify the 165 | "host" platform (i.e., that on which the generated programs will 166 | eventually be run) with `--host=TYPE'. 167 | 168 | Sharing Defaults 169 | ================ 170 | 171 | If you want to set default values for `configure' scripts to share, you 172 | can create a site shell script called `config.site' that gives default 173 | values for variables like `CC', `cache_file', and `prefix'. 174 | `configure' looks for `PREFIX/share/config.site' if it exists, then 175 | `PREFIX/etc/config.site' if it exists. Or, you can set the 176 | `CONFIG_SITE' environment variable to the location of the site script. 177 | A warning: not all `configure' scripts look for a site script. 178 | 179 | Defining Variables 180 | ================== 181 | 182 | Variables not defined in a site shell script can be set in the 183 | environment passed to `configure'. However, some packages may run 184 | configure again during the build, and the customized values of these 185 | variables may be lost. In order to avoid this problem, you should set 186 | them in the `configure' command line, using `VAR=value'. For example: 187 | 188 | ./configure CC=/usr/local2/bin/gcc 189 | 190 | causes the specified `gcc' to be used as the C compiler (unless it is 191 | overridden in the site shell script). 192 | 193 | Unfortunately, this technique does not work for `CONFIG_SHELL' due to 194 | an Autoconf bug. Until the bug is fixed you can use this workaround: 195 | 196 | CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash 197 | 198 | `configure' Invocation 199 | ====================== 200 | 201 | `configure' recognizes the following options to control how it operates. 202 | 203 | `--help' 204 | `-h' 205 | Print a summary of the options to `configure', and exit. 206 | 207 | `--version' 208 | `-V' 209 | Print the version of Autoconf used to generate the `configure' 210 | script, and exit. 211 | 212 | `--cache-file=FILE' 213 | Enable the cache: use and save the results of the tests in FILE, 214 | traditionally `config.cache'. FILE defaults to `/dev/null' to 215 | disable caching. 216 | 217 | `--config-cache' 218 | `-C' 219 | Alias for `--cache-file=config.cache'. 220 | 221 | `--quiet' 222 | `--silent' 223 | `-q' 224 | Do not print messages saying which checks are being made. To 225 | suppress all normal output, redirect it to `/dev/null' (any error 226 | messages will still be shown). 227 | 228 | `--srcdir=DIR' 229 | Look for the package's source code in directory DIR. Usually 230 | `configure' can determine that directory automatically. 231 | 232 | `configure' also accepts some other, not widely useful, options. Run 233 | `configure --help' for more details. 234 | 235 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | nobase_include_HEADERS = \ 2 | kdtree++/allocator.hpp \ 3 | kdtree++/function.hpp \ 4 | kdtree++/iterator.hpp \ 5 | kdtree++/kdtree.hpp \ 6 | kdtree++/node.hpp \ 7 | kdtree++/region.hpp 8 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.10.1 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 5 | # 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 6 | # This Makefile.in is free software; the Free Software Foundation 7 | # gives unlimited permission to copy and/or distribute it, 8 | # with or without modifications, as long as this notice is preserved. 9 | 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 12 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 13 | # PARTICULAR PURPOSE. 14 | 15 | @SET_MAKE@ 16 | 17 | VPATH = @srcdir@ 18 | pkgdatadir = $(datadir)/@PACKAGE@ 19 | pkglibdir = $(libdir)/@PACKAGE@ 20 | pkgincludedir = $(includedir)/@PACKAGE@ 21 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 22 | install_sh_DATA = $(install_sh) -c -m 644 23 | install_sh_PROGRAM = $(install_sh) -c 24 | install_sh_SCRIPT = $(install_sh) -c 25 | INSTALL_HEADER = $(INSTALL_DATA) 26 | transform = $(program_transform_name) 27 | NORMAL_INSTALL = : 28 | PRE_INSTALL = : 29 | POST_INSTALL = : 30 | NORMAL_UNINSTALL = : 31 | PRE_UNINSTALL = : 32 | POST_UNINSTALL = : 33 | subdir = . 34 | DIST_COMMON = README $(am__configure_deps) $(nobase_include_HEADERS) \ 35 | $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ 36 | $(srcdir)/config.h.in $(top_srcdir)/configure AUTHORS COPYING \ 37 | ChangeLog INSTALL NEWS TODO install-sh missing 38 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 39 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 40 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 41 | $(ACLOCAL_M4) 42 | am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ 43 | configure.lineno config.status.lineno 44 | mkinstalldirs = $(install_sh) -d 45 | CONFIG_HEADER = config.h 46 | CONFIG_CLEAN_FILES = 47 | SOURCES = 48 | DIST_SOURCES = 49 | am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; 50 | am__vpath_adj = case $$p in \ 51 | $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ 52 | *) f=$$p;; \ 53 | esac; 54 | am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; 55 | am__installdirs = "$(DESTDIR)$(includedir)" 56 | nobase_includeHEADERS_INSTALL = $(install_sh_DATA) 57 | HEADERS = $(nobase_include_HEADERS) 58 | ETAGS = etags 59 | CTAGS = ctags 60 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 61 | distdir = $(PACKAGE)-$(VERSION) 62 | top_distdir = $(distdir) 63 | am__remove_distdir = \ 64 | { test ! -d $(distdir) \ 65 | || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ 66 | && rm -fr $(distdir); }; } 67 | DIST_ARCHIVES = $(distdir).tar.gz 68 | GZIP_ENV = --best 69 | distuninstallcheck_listfiles = find . -type f -print 70 | distcleancheck_listfiles = find . -type f -print 71 | ACLOCAL = @ACLOCAL@ 72 | AMTAR = @AMTAR@ 73 | AUTOCONF = @AUTOCONF@ 74 | AUTOHEADER = @AUTOHEADER@ 75 | AUTOMAKE = @AUTOMAKE@ 76 | AWK = @AWK@ 77 | CC = @CC@ 78 | CCDEPMODE = @CCDEPMODE@ 79 | CFLAGS = @CFLAGS@ 80 | CPP = @CPP@ 81 | CPPFLAGS = @CPPFLAGS@ 82 | CXX = @CXX@ 83 | CXXDEPMODE = @CXXDEPMODE@ 84 | CXXFLAGS = @CXXFLAGS@ 85 | CYGPATH_W = @CYGPATH_W@ 86 | DEFS = @DEFS@ 87 | DEPDIR = @DEPDIR@ 88 | ECHO_C = @ECHO_C@ 89 | ECHO_N = @ECHO_N@ 90 | ECHO_T = @ECHO_T@ 91 | EGREP = @EGREP@ 92 | EXEEXT = @EXEEXT@ 93 | GREP = @GREP@ 94 | INSTALL = @INSTALL@ 95 | INSTALL_DATA = @INSTALL_DATA@ 96 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 97 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 98 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 99 | LDFLAGS = @LDFLAGS@ 100 | LIBOBJS = @LIBOBJS@ 101 | LIBS = @LIBS@ 102 | LTLIBOBJS = @LTLIBOBJS@ 103 | MAKEINFO = @MAKEINFO@ 104 | MKDIR_P = @MKDIR_P@ 105 | OBJEXT = @OBJEXT@ 106 | PACKAGE = @PACKAGE@ 107 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 108 | PACKAGE_NAME = @PACKAGE_NAME@ 109 | PACKAGE_STRING = @PACKAGE_STRING@ 110 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 111 | PACKAGE_VERSION = @PACKAGE_VERSION@ 112 | PATH_SEPARATOR = @PATH_SEPARATOR@ 113 | SET_MAKE = @SET_MAKE@ 114 | SHELL = @SHELL@ 115 | STRIP = @STRIP@ 116 | VERSION = @VERSION@ 117 | abs_builddir = @abs_builddir@ 118 | abs_srcdir = @abs_srcdir@ 119 | abs_top_builddir = @abs_top_builddir@ 120 | abs_top_srcdir = @abs_top_srcdir@ 121 | ac_ct_CC = @ac_ct_CC@ 122 | ac_ct_CXX = @ac_ct_CXX@ 123 | am__include = @am__include@ 124 | am__leading_dot = @am__leading_dot@ 125 | am__quote = @am__quote@ 126 | am__tar = @am__tar@ 127 | am__untar = @am__untar@ 128 | bindir = @bindir@ 129 | build_alias = @build_alias@ 130 | builddir = @builddir@ 131 | datadir = @datadir@ 132 | datarootdir = @datarootdir@ 133 | docdir = @docdir@ 134 | dvidir = @dvidir@ 135 | exec_prefix = @exec_prefix@ 136 | host_alias = @host_alias@ 137 | htmldir = @htmldir@ 138 | includedir = @includedir@ 139 | infodir = @infodir@ 140 | install_sh = @install_sh@ 141 | libdir = @libdir@ 142 | libexecdir = @libexecdir@ 143 | localedir = @localedir@ 144 | localstatedir = @localstatedir@ 145 | mandir = @mandir@ 146 | mkdir_p = @mkdir_p@ 147 | oldincludedir = @oldincludedir@ 148 | pdfdir = @pdfdir@ 149 | prefix = @prefix@ 150 | program_transform_name = @program_transform_name@ 151 | psdir = @psdir@ 152 | sbindir = @sbindir@ 153 | sharedstatedir = @sharedstatedir@ 154 | srcdir = @srcdir@ 155 | sysconfdir = @sysconfdir@ 156 | target_alias = @target_alias@ 157 | top_build_prefix = @top_build_prefix@ 158 | top_builddir = @top_builddir@ 159 | top_srcdir = @top_srcdir@ 160 | nobase_include_HEADERS = \ 161 | kdtree++/allocator.hpp \ 162 | kdtree++/function.hpp \ 163 | kdtree++/iterator.hpp \ 164 | kdtree++/kdtree.hpp \ 165 | kdtree++/node.hpp \ 166 | kdtree++/region.hpp 167 | 168 | all: config.h 169 | $(MAKE) $(AM_MAKEFLAGS) all-am 170 | 171 | .SUFFIXES: 172 | am--refresh: 173 | @: 174 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 175 | @for dep in $?; do \ 176 | case '$(am__configure_deps)' in \ 177 | *$$dep*) \ 178 | echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ 179 | cd $(srcdir) && $(AUTOMAKE) --gnu \ 180 | && exit 0; \ 181 | exit 1;; \ 182 | esac; \ 183 | done; \ 184 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ 185 | cd $(top_srcdir) && \ 186 | $(AUTOMAKE) --gnu Makefile 187 | .PRECIOUS: Makefile 188 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 189 | @case '$?' in \ 190 | *config.status*) \ 191 | echo ' $(SHELL) ./config.status'; \ 192 | $(SHELL) ./config.status;; \ 193 | *) \ 194 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ 195 | cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ 196 | esac; 197 | 198 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 199 | $(SHELL) ./config.status --recheck 200 | 201 | $(top_srcdir)/configure: $(am__configure_deps) 202 | cd $(srcdir) && $(AUTOCONF) 203 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 204 | cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) 205 | 206 | config.h: stamp-h1 207 | @if test ! -f $@; then \ 208 | rm -f stamp-h1; \ 209 | $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ 210 | else :; fi 211 | 212 | stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status 213 | @rm -f stamp-h1 214 | cd $(top_builddir) && $(SHELL) ./config.status config.h 215 | $(srcdir)/config.h.in: $(am__configure_deps) 216 | cd $(top_srcdir) && $(AUTOHEADER) 217 | rm -f stamp-h1 218 | touch $@ 219 | 220 | distclean-hdr: 221 | -rm -f config.h stamp-h1 222 | install-nobase_includeHEADERS: $(nobase_include_HEADERS) 223 | @$(NORMAL_INSTALL) 224 | test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" 225 | @$(am__vpath_adj_setup) \ 226 | list='$(nobase_include_HEADERS)'; for p in $$list; do \ 227 | if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ 228 | $(am__vpath_adj) \ 229 | echo " $(nobase_includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \ 230 | $(nobase_includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \ 231 | done 232 | 233 | uninstall-nobase_includeHEADERS: 234 | @$(NORMAL_UNINSTALL) 235 | @$(am__vpath_adj_setup) \ 236 | list='$(nobase_include_HEADERS)'; for p in $$list; do \ 237 | $(am__vpath_adj) \ 238 | echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \ 239 | rm -f "$(DESTDIR)$(includedir)/$$f"; \ 240 | done 241 | 242 | ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) 243 | list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ 244 | unique=`for i in $$list; do \ 245 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 246 | done | \ 247 | $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ 248 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 249 | mkid -fID $$unique 250 | tags: TAGS 251 | 252 | TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ 253 | $(TAGS_FILES) $(LISP) 254 | tags=; \ 255 | here=`pwd`; \ 256 | list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ 257 | unique=`for i in $$list; do \ 258 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 259 | done | \ 260 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ 261 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 262 | if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ 263 | test -n "$$unique" || unique=$$empty_fix; \ 264 | $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ 265 | $$tags $$unique; \ 266 | fi 267 | ctags: CTAGS 268 | CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ 269 | $(TAGS_FILES) $(LISP) 270 | tags=; \ 271 | list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ 272 | unique=`for i in $$list; do \ 273 | if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ 274 | done | \ 275 | $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ 276 | END { if (nonempty) { for (i in files) print i; }; }'`; \ 277 | test -z "$(CTAGS_ARGS)$$tags$$unique" \ 278 | || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ 279 | $$tags $$unique 280 | 281 | GTAGS: 282 | here=`$(am__cd) $(top_builddir) && pwd` \ 283 | && cd $(top_srcdir) \ 284 | && gtags -i $(GTAGS_ARGS) $$here 285 | 286 | distclean-tags: 287 | -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags 288 | 289 | distdir: $(DISTFILES) 290 | $(am__remove_distdir) 291 | test -d $(distdir) || mkdir $(distdir) 292 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 293 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 294 | list='$(DISTFILES)'; \ 295 | dist_files=`for file in $$list; do echo $$file; done | \ 296 | sed -e "s|^$$srcdirstrip/||;t" \ 297 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 298 | case $$dist_files in \ 299 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 300 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 301 | sort -u` ;; \ 302 | esac; \ 303 | for file in $$dist_files; do \ 304 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 305 | if test -d $$d/$$file; then \ 306 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 307 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 308 | cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ 309 | fi; \ 310 | cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ 311 | else \ 312 | test -f $(distdir)/$$file \ 313 | || cp -p $$d/$$file $(distdir)/$$file \ 314 | || exit 1; \ 315 | fi; \ 316 | done 317 | -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ 318 | ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ 319 | ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ 320 | ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ 321 | || chmod -R a+r $(distdir) 322 | dist-gzip: distdir 323 | tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz 324 | $(am__remove_distdir) 325 | 326 | dist-bzip2: distdir 327 | tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 328 | $(am__remove_distdir) 329 | 330 | dist-lzma: distdir 331 | tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma 332 | $(am__remove_distdir) 333 | 334 | dist-tarZ: distdir 335 | tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z 336 | $(am__remove_distdir) 337 | 338 | dist-shar: distdir 339 | shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz 340 | $(am__remove_distdir) 341 | 342 | dist-zip: distdir 343 | -rm -f $(distdir).zip 344 | zip -rq $(distdir).zip $(distdir) 345 | $(am__remove_distdir) 346 | 347 | dist dist-all: distdir 348 | tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz 349 | $(am__remove_distdir) 350 | 351 | # This target untars the dist file and tries a VPATH configuration. Then 352 | # it guarantees that the distribution is self-contained by making another 353 | # tarfile. 354 | distcheck: dist 355 | case '$(DIST_ARCHIVES)' in \ 356 | *.tar.gz*) \ 357 | GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ 358 | *.tar.bz2*) \ 359 | bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ 360 | *.tar.lzma*) \ 361 | unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ 362 | *.tar.Z*) \ 363 | uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ 364 | *.shar.gz*) \ 365 | GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ 366 | *.zip*) \ 367 | unzip $(distdir).zip ;;\ 368 | esac 369 | chmod -R a-w $(distdir); chmod a+w $(distdir) 370 | mkdir $(distdir)/_build 371 | mkdir $(distdir)/_inst 372 | chmod a-w $(distdir) 373 | dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ 374 | && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ 375 | && cd $(distdir)/_build \ 376 | && ../configure --srcdir=.. --prefix="$$dc_install_base" \ 377 | $(DISTCHECK_CONFIGURE_FLAGS) \ 378 | && $(MAKE) $(AM_MAKEFLAGS) \ 379 | && $(MAKE) $(AM_MAKEFLAGS) dvi \ 380 | && $(MAKE) $(AM_MAKEFLAGS) check \ 381 | && $(MAKE) $(AM_MAKEFLAGS) install \ 382 | && $(MAKE) $(AM_MAKEFLAGS) installcheck \ 383 | && $(MAKE) $(AM_MAKEFLAGS) uninstall \ 384 | && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ 385 | distuninstallcheck \ 386 | && chmod -R a-w "$$dc_install_base" \ 387 | && ({ \ 388 | (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ 389 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ 390 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ 391 | && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ 392 | distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ 393 | } || { rm -rf "$$dc_destdir"; exit 1; }) \ 394 | && rm -rf "$$dc_destdir" \ 395 | && $(MAKE) $(AM_MAKEFLAGS) dist \ 396 | && rm -rf $(DIST_ARCHIVES) \ 397 | && $(MAKE) $(AM_MAKEFLAGS) distcleancheck 398 | $(am__remove_distdir) 399 | @(echo "$(distdir) archives ready for distribution: "; \ 400 | list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ 401 | sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' 402 | distuninstallcheck: 403 | @cd $(distuninstallcheck_dir) \ 404 | && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ 405 | || { echo "ERROR: files left after uninstall:" ; \ 406 | if test -n "$(DESTDIR)"; then \ 407 | echo " (check DESTDIR support)"; \ 408 | fi ; \ 409 | $(distuninstallcheck_listfiles) ; \ 410 | exit 1; } >&2 411 | distcleancheck: distclean 412 | @if test '$(srcdir)' = . ; then \ 413 | echo "ERROR: distcleancheck can only run from a VPATH build" ; \ 414 | exit 1 ; \ 415 | fi 416 | @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ 417 | || { echo "ERROR: files left in build directory after distclean:" ; \ 418 | $(distcleancheck_listfiles) ; \ 419 | exit 1; } >&2 420 | check-am: all-am 421 | check: check-am 422 | all-am: Makefile $(HEADERS) config.h 423 | installdirs: 424 | for dir in "$(DESTDIR)$(includedir)"; do \ 425 | test -z "$$dir" || $(MKDIR_P) "$$dir"; \ 426 | done 427 | install: install-am 428 | install-exec: install-exec-am 429 | install-data: install-data-am 430 | uninstall: uninstall-am 431 | 432 | install-am: all-am 433 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 434 | 435 | installcheck: installcheck-am 436 | install-strip: 437 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 438 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 439 | `test -z '$(STRIP)' || \ 440 | echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install 441 | mostlyclean-generic: 442 | 443 | clean-generic: 444 | 445 | distclean-generic: 446 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 447 | 448 | maintainer-clean-generic: 449 | @echo "This command is intended for maintainers to use" 450 | @echo "it deletes files that may require special tools to rebuild." 451 | clean: clean-am 452 | 453 | clean-am: clean-generic mostlyclean-am 454 | 455 | distclean: distclean-am 456 | -rm -f $(am__CONFIG_DISTCLEAN_FILES) 457 | -rm -f Makefile 458 | distclean-am: clean-am distclean-generic distclean-hdr distclean-tags 459 | 460 | dvi: dvi-am 461 | 462 | dvi-am: 463 | 464 | html: html-am 465 | 466 | info: info-am 467 | 468 | info-am: 469 | 470 | install-data-am: install-nobase_includeHEADERS 471 | 472 | install-dvi: install-dvi-am 473 | 474 | install-exec-am: 475 | 476 | install-html: install-html-am 477 | 478 | install-info: install-info-am 479 | 480 | install-man: 481 | 482 | install-pdf: install-pdf-am 483 | 484 | install-ps: install-ps-am 485 | 486 | installcheck-am: 487 | 488 | maintainer-clean: maintainer-clean-am 489 | -rm -f $(am__CONFIG_DISTCLEAN_FILES) 490 | -rm -rf $(top_srcdir)/autom4te.cache 491 | -rm -f Makefile 492 | maintainer-clean-am: distclean-am maintainer-clean-generic 493 | 494 | mostlyclean: mostlyclean-am 495 | 496 | mostlyclean-am: mostlyclean-generic 497 | 498 | pdf: pdf-am 499 | 500 | pdf-am: 501 | 502 | ps: ps-am 503 | 504 | ps-am: 505 | 506 | uninstall-am: uninstall-nobase_includeHEADERS 507 | 508 | .MAKE: install-am install-strip 509 | 510 | .PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ 511 | clean-generic ctags dist dist-all dist-bzip2 dist-gzip \ 512 | dist-lzma dist-shar dist-tarZ dist-zip distcheck distclean \ 513 | distclean-generic distclean-hdr distclean-tags distcleancheck \ 514 | distdir distuninstallcheck dvi dvi-am html html-am info \ 515 | info-am install install-am install-data install-data-am \ 516 | install-dvi install-dvi-am install-exec install-exec-am \ 517 | install-html install-html-am install-info install-info-am \ 518 | install-man install-nobase_includeHEADERS install-pdf \ 519 | install-pdf-am install-ps install-ps-am install-strip \ 520 | installcheck installcheck-am installdirs maintainer-clean \ 521 | maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ 522 | pdf-am ps ps-am tags uninstall uninstall-am \ 523 | uninstall-nobase_includeHEADERS 524 | 525 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 526 | # Otherwise a system limit (for SysV at least) may be exceeded. 527 | .NOEXPORT: 528 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | libkdtree++ NEWS 2 | ================ 3 | 4 | 17 Nov 2008: 5 | Again, it's almost Christmas. Recently a whole lot of bug have been fixed in 6 | version 0.6.3 of the library. You can find a summary of the fixes in the 7 | Changelog. For short: 8 | - you can now assign an existing tree to another tree without an ugly bug if 9 | your tree required parameters for the accessor, 10 | - now you can finally use the reverse iterator, 11 | - find() and erase() work properly based on the location given in argument, 12 | - the project is compatible with MSVC2005 13 | - many more... 14 | 15 | 02 Dec 2007: 16 | It's Christmas, and libkdtree++ packs in more power for the find 17 | and find_nearest functions. Performance improvement should be 18 | carried on with other part of the interface in the coming months. 19 | 20 | As a result of these modification, KDTree definition has been a 21 | little altered. The new definition includes a template for a 22 | distance calculator. This functor by default calcultes the square 23 | of th difference between two elements returned by the accessor. 24 | 25 | 29 Sep 2007: 26 | Sylvain Bougerel spent some time cleaning up the code and build 27 | infrastructure of the code from Sourceforge, and I imported the 28 | results of his work to a git repository on git.debian.org today. 29 | 30 | http://git.debian.org/?p=libkdtree/libkdtree.git;a=summary 31 | 32 | Martin F. Krafft 33 | -------------------------------------------------------------------------------- /README.Python: -------------------------------------------------------------------------------- 1 | Stand-alone Python bindings, contributed by Willi Richert 2 | 3 | To make them: 4 | $ cd python-bindings 5 | $ make 6 | You will find then two files kdtree.py _kdtree.so in the current directory. 7 | These are all you need to use libkdtree++. 8 | Please examine the test files to get a grip to the usage. 9 | 10 | To run the tests, type: 11 | python py-kdtree_test.py 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nvmd/libkdtree/1dda4a212c8e1e6059b59648b41a08eec076c612/README.md -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | libkdtree++ TODO list 2 | ===================== 3 | 4 | - DOCUMENTATION 5 | - automated unit testing 6 | - performance improvement 7 | - keep tree balanced in insert() and erase(). 8 | - erase(range) 9 | - add swap() to allow vectors of KDTree to be sorted 10 | - add policies/traits 11 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | 3 | #libtoolize --force &> /dev/null 4 | aclocal 5 | autoheader 6 | automake --add-missing --no-force 7 | autoconf 8 | # To be run by the library users 9 | #exec ./configure $@ 10 | 11 | # COPYRIGHT -- 12 | # 13 | # This file is part of libkdtree++, a C++ template KD-Tree sorting container. 14 | # libkdtree++ is (c) 2004-2007 Martin F. Krafft 15 | # and distributed under the terms of the Artistic License 2.0. 16 | # See the ./COPYING file in the source tree root for more information. 17 | # 18 | # THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 19 | # WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 20 | # OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 21 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_INTTYPES_H 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_MEMORY_H 8 | 9 | /* Define to 1 if you have the `pow' function. */ 10 | #undef HAVE_POW 11 | 12 | /* Define to 1 if the system has the type `ptrdiff_t size_t'. */ 13 | #undef HAVE_PTRDIFF_T_SIZE_T 14 | 15 | /* Define to 1 if you have the `sqrt' function. */ 16 | #undef HAVE_SQRT 17 | 18 | /* Define to 1 if stdbool.h conforms to C99. */ 19 | #undef HAVE_STDBOOL_H 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_STDINT_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_STDLIB_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_STRINGS_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_STRING_H 32 | 33 | /* Define to 1 if you have the header file. */ 34 | #undef HAVE_SYS_STAT_H 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #undef HAVE_SYS_TYPES_H 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_UNISTD_H 41 | 42 | /* Define to 1 if the system has the type `_Bool'. */ 43 | #undef HAVE__BOOL 44 | 45 | /* Name of package */ 46 | #undef PACKAGE 47 | 48 | /* Define to the address where bug reports for this package should be sent. */ 49 | #undef PACKAGE_BUGREPORT 50 | 51 | /* Define to the full name of this package. */ 52 | #undef PACKAGE_NAME 53 | 54 | /* Define to the full name and version of this package. */ 55 | #undef PACKAGE_STRING 56 | 57 | /* Define to the one symbol short name of this package. */ 58 | #undef PACKAGE_TARNAME 59 | 60 | /* Define to the version of this package. */ 61 | #undef PACKAGE_VERSION 62 | 63 | /* Define to 1 if you have the ANSI C header files. */ 64 | #undef STDC_HEADERS 65 | 66 | /* Version number of package */ 67 | #undef VERSION 68 | 69 | /* Define to empty if `const' does not conform to ANSI C. */ 70 | #undef const 71 | 72 | /* Define to `__inline__' or `__inline' if that's what the C compiler 73 | calls it, or to nothing if 'inline' is not supported under any name. */ 74 | #ifndef __cplusplus 75 | #undef inline 76 | #endif 77 | 78 | /* Define to `unsigned int' if does not define. */ 79 | #undef size_t 80 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ(2.61) 5 | AC_INIT([libkdtree++], [0.7.1], http://alioth.debian.org/projects/libkdtree/) 6 | AC_CONFIG_SRCDIR([kdtree++/kdtree.hpp]) 7 | AC_CONFIG_HEADER([config.h]) 8 | 9 | # Makefile initialization. 10 | AM_INIT_AUTOMAKE([-Wall -Werror]) 11 | 12 | # Checks for programs. 13 | AC_PROG_CXX 14 | 15 | # Checks for libraries. 16 | 17 | # Checks for header files. 18 | 19 | # Checks for typedefs, structures, and compiler characteristics. 20 | AC_HEADER_STDBOOL 21 | AC_C_CONST 22 | AC_C_INLINE 23 | AC_TYPE_SIZE_T 24 | AC_CHECK_TYPES([ptrdiff_t size_t]) 25 | 26 | # Checks for library functions. 27 | AC_CHECK_FUNCS([pow sqrt]) 28 | 29 | AC_CONFIG_FILES([Makefile]) 30 | AC_OUTPUT 31 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | (import 2 | ( 3 | let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in 4 | fetchTarball { 5 | url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; 6 | sha256 = lock.nodes.flake-compat.locked.narHash; 7 | } 8 | ) 9 | { src = ./.; } 10 | ).defaultNix -------------------------------------------------------------------------------- /doc/index.txt: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | @mainpage libkdtree++: a C++ template container for KD-Tree sorting 4 | 5 | Author: Martin F. Krafft 6 | 7 | Source: 8 | https://github.com/nvmd/libkdtree 9 | 10 | git clone https://github.com/nvmd/libkdtree.git 11 | 12 | License: Artistic License 2.0 13 | 14 | Homepage: https://github.com/nvmd/libkdtree 15 | 16 | This library is still undocumented. If you would like to document it, please 17 | feel free (but use Doxygen). 18 | 19 | */ 20 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | test_kdtree 2 | test_kdtree-gcc3.4 3 | test_kdtree-gcc4.3 4 | test_kdtree-gcc4.2 5 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable (test_hayne test_hayne.cpp) 2 | add_executable (test_kdtree test_kdtree.cpp) 3 | add_executable (test_find_within_range test_find_within_range.cpp) 4 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | all: test_kdtree test_hayne 2 | 3 | test_kdtree: test_kdtree.cpp 4 | g++ -I.. -Wall -ansi -pedantic -g -O2 -o test_kdtree test_kdtree.cpp 5 | 6 | test_hayne: test_hayne.cpp 7 | g++ -I.. -Wall -ansi -pedantic -g -O2 -o test_hayne test_hayne.cpp 8 | 9 | all_gcc: test_kdtree-gcc3.4 test_kdtree-gcc4.3 test_kdtree-gcc4.2 10 | 11 | test_kdtree-gcc3.4: test_kdtree.cpp 12 | g++-3.4 -I.. -Wall -ansi -pedantic -g -O2 -o test_kdtree-gcc3.4 test_kdtree.cpp 13 | 14 | test_kdtree-gcc4.2: test_kdtree.cpp 15 | g++-4.2 -I.. -Wall -ansi -pedantic -g -O2 -o test_kdtree-gcc4.2 test_kdtree.cpp 16 | 17 | test_kdtree-gcc4.3: test_kdtree.cpp 18 | g++-4.3 -I.. -Wall -ansi -pedantic -g -O2 -o test_kdtree-gcc4.3 test_kdtree.cpp 19 | 20 | clean: 21 | rm -f test_kdtree 22 | 23 | .PHONY: clean 24 | -------------------------------------------------------------------------------- /examples/test_find_within_range.cpp: -------------------------------------------------------------------------------- 1 | // Thanks to James Remillard 2 | // 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | struct kdtreeNode 12 | { 13 | typedef double value_type; 14 | 15 | double xyz[3]; 16 | size_t index; 17 | 18 | value_type operator[](size_t n) const 19 | { 20 | return xyz[n]; 21 | } 22 | 23 | double distance( const kdtreeNode &node) 24 | { 25 | double x = xyz[0] - node.xyz[0]; 26 | double y = xyz[1] - node.xyz[1]; 27 | double z = xyz[2] - node.xyz[2]; 28 | 29 | // this is not correct return sqrt( x*x+y*y+z*z); 30 | 31 | // this is what kdtree checks with find_within_range() 32 | // the "manhattan distance" from the search point. 33 | // effectively, distance is the maximum distance in any one dimension. 34 | return max(fabs(x),max(fabs(y),fabs(z))); 35 | 36 | } 37 | }; 38 | 39 | int main(int argc,char *argv[]) 40 | { 41 | vector pts; 42 | 43 | typedef KDTree::KDTree<3,kdtreeNode> treeType; 44 | 45 | treeType tree; 46 | 47 | // make random 3d points 48 | for ( size_t n = 0; n < 10000; ++n) 49 | { 50 | kdtreeNode node; 51 | node.xyz[0] = double(rand())/RAND_MAX; 52 | node.xyz[1] = double(rand())/RAND_MAX; 53 | node.xyz[2] = double(rand())/RAND_MAX; 54 | node.index = n; 55 | 56 | tree.insert( node); 57 | pts.push_back( node); 58 | } 59 | 60 | for (size_t r = 0; r < 1000; ++r) 61 | { 62 | kdtreeNode refNode; 63 | refNode.xyz[0] = double(rand())/RAND_MAX; 64 | refNode.xyz[1] = double(rand())/RAND_MAX; 65 | refNode.xyz[2] = double(rand())/RAND_MAX; 66 | 67 | double limit = double(rand())/RAND_MAX; 68 | 69 | // find the correct return list by checking every single point 70 | set correctCloseList; 71 | 72 | for ( size_t i= 0; i < pts.size(); ++i) 73 | { 74 | double dist = refNode.distance( pts[i]); 75 | if ( dist < limit) 76 | correctCloseList.insert( i ); 77 | } 78 | 79 | // now do the same with the kdtree. 80 | vector howClose; 81 | tree.find_within_range(refNode,limit,back_insert_iterator >(howClose)); 82 | 83 | // make sure no extra points are returned, and the return has no missing points. 84 | for ( size_t i = 0; i < howClose.size(); ++i) 85 | { 86 | set::iterator hit = correctCloseList.find( howClose[i].index); 87 | 88 | if ( hit != correctCloseList.end()) 89 | { 90 | correctCloseList.erase(hit); 91 | } 92 | else 93 | { 94 | // point that is too far away - fail! 95 | assert(false); 96 | printf("fail, extra points.\n"); 97 | } 98 | } 99 | 100 | // fail, not all of the close enough points returned. 101 | assert( correctCloseList.size() == 0); 102 | if ( correctCloseList.size() > 0) 103 | { 104 | printf("fail, missing points.\n"); 105 | } 106 | } 107 | } 108 | 109 | -------------------------------------------------------------------------------- /examples/test_hayne.cpp: -------------------------------------------------------------------------------- 1 | #define KDTREE_SIZE_T unsigned int 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | struct duplet 12 | { 13 | typedef int value_type; 14 | 15 | inline value_type operator[](int const N) const { return d[N]; } 16 | 17 | inline bool operator==(duplet const& other) const 18 | { 19 | return this->d[0] == other.d[0] && this->d[1] == other.d[1]; 20 | } 21 | 22 | inline bool operator!=(duplet const& other) const 23 | { 24 | return this->d[0] != other.d[0] || this->d[1] != other.d[1]; 25 | } 26 | 27 | friend ostream & operator<<(ostream & o, duplet const& d) 28 | { 29 | return o << "(" << d[0] << "," << d[1] << ")"; 30 | } 31 | 32 | value_type d[2]; 33 | }; 34 | 35 | #if __cplusplus < 201103L || (defined(_MSC_VER) && _MSC_VER <= 1900) 36 | typedef KDTree::KDTree<2, duplet, std::pointer_to_binary_function > duplet_tree_type; 37 | #else 38 | typedef KDTree::KDTree<2, duplet, std::function > duplet_tree_type; 39 | #endif 40 | 41 | inline double return_dup( duplet d, int k ) { return d[k]; } 42 | 43 | int main() 44 | { 45 | #if __cplusplus < 201103L || (defined(_MSC_VER) && _MSC_VER <= 1900) 46 | duplet_tree_type dupl_tree_test(std::ptr_fun(return_dup)); 47 | #else 48 | duplet_tree_type dupl_tree_test(std::ref(return_dup)); 49 | //duplet_tree_type std::function dupl_tree_test = return_dup; 50 | #endif 51 | std::vector vDuplets; 52 | 53 | //srand(time(0)); 54 | int randy1 = 0; 55 | int randy2 = 0; 56 | for (int i=0; i<700; i++) 57 | { 58 | //create coordinate for new duplet 59 | randy1+=2; 60 | randy1=randy1%255; 61 | randy2+=3; 62 | randy2=randy2%255; 63 | //randy1 = rand() % 255; 64 | //randy2 = rand() % 255; 65 | 66 | //new duplet 67 | duplet super_dupre = { {randy1, randy2} }; 68 | 69 | //check if duplet with same coordinate already in vector/tree. If not: insert in vector and tree 70 | duplet_tree_type::iterator pItr = dupl_tree_test.find_nearest(super_dupre,std::numeric_limits::max()).first; 71 | if (*pItr!=super_dupre) 72 | { 73 | dupl_tree_test.insert(super_dupre); 74 | vDuplets.push_back(super_dupre); 75 | } 76 | } 77 | 78 | dupl_tree_test.optimise(); 79 | 80 | while (vDuplets.size() > 0) //delete all duplets from tree which are in the vector 81 | { 82 | duplet element_to_erase = vDuplets.back(); 83 | vDuplets.pop_back(); 84 | 85 | if (vDuplets.size() == 147) 86 | cout << "THIS IS THE BUG TRIGGER" << endl; 87 | 88 | cout << vDuplets.size() << " : Deleting " << element_to_erase << endl; 89 | 90 | assert( find(dupl_tree_test.begin(),dupl_tree_test.end(), element_to_erase) != dupl_tree_test.end() ); 91 | assert(dupl_tree_test.find(element_to_erase) != dupl_tree_test.end()); 92 | 93 | duplet_tree_type::iterator will = dupl_tree_test.find(element_to_erase); 94 | duplet_tree_type::iterator should = dupl_tree_test.find_exact(element_to_erase); 95 | 96 | cout << " tree will delete: " << *will << endl; 97 | cout << " tree should delete: " << *should << endl; 98 | 99 | assert(*will == *should); 100 | 101 | dupl_tree_test.erase(element_to_erase); //erase() : will probably erase wrong element sooner or later 102 | //dupl_tree_test.erase_exact(element_to_erase); --> this works 103 | 104 | // now check that it cannot find the element UNLESS there is another one with the identical location in the list... 105 | if (find(vDuplets.begin(),vDuplets.end(),element_to_erase) == vDuplets.end()) 106 | { 107 | duplet_tree_type::iterator not_there = dupl_tree_test.find(element_to_erase); 108 | if (not_there != dupl_tree_test.end()) 109 | { 110 | cout << "SHOULD NOT HAVE FOUND THIS: " << *not_there << endl; 111 | assert(0); 112 | } 113 | else 114 | { 115 | cout << " find() double-check passed." << endl; 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /examples/test_kdtree.cpp: -------------------------------------------------------------------------------- 1 | #define KDTREE_DEFINE_OSTREAM_OPERATORS 2 | 3 | // Make SURE all our asserts() are checked 4 | #undef NDEBUG 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // used to ensure all triplets that are accessed via the operator<< are initialised. 16 | std::set registered; 17 | 18 | struct triplet 19 | { 20 | typedef double value_type; 21 | 22 | triplet(value_type a, value_type b, value_type c) 23 | { 24 | d[0] = a; 25 | d[1] = b; 26 | d[2] = c; 27 | bool reg_ok = (registered.find(this) == registered.end()); 28 | assert(reg_ok); 29 | bool reg_inserted_ok = registered.insert(this).second; 30 | assert(reg_inserted_ok); 31 | } 32 | 33 | triplet(const triplet & x) 34 | { 35 | d[0] = x.d[0]; 36 | d[1] = x.d[1]; 37 | d[2] = x.d[2]; 38 | bool reg_ok = (registered.find(this) == registered.end()); 39 | assert(reg_ok); 40 | bool reg_inserted_ok = registered.insert(this).second; 41 | assert(reg_inserted_ok); 42 | } 43 | 44 | ~triplet() 45 | { 46 | bool unreg_ok = (registered.find(this) != registered.end()); 47 | assert(unreg_ok); 48 | registered.erase(this); 49 | } 50 | 51 | double distance_to(triplet const& x) const 52 | { 53 | double dist = 0; 54 | for (int i = 0; i != 3; ++i) 55 | dist += (d[i]-x.d[i])*(d[i]-x.d[i]); 56 | return std::sqrt(dist); 57 | } 58 | 59 | inline value_type operator[](size_t const N) const { return d[N]; } 60 | 61 | value_type d[3]; 62 | }; 63 | 64 | 65 | 66 | // same as triplet, except with the values reversed. 67 | struct alternate_triplet 68 | { 69 | typedef double value_type; 70 | 71 | alternate_triplet(const triplet & x) 72 | { 73 | d[0] = x.d[2]; 74 | d[1] = x.d[1]; 75 | d[2] = x.d[0]; 76 | } 77 | 78 | inline value_type operator[](size_t const N) const { return d[2-N]; } 79 | 80 | value_type d[3]; 81 | }; 82 | 83 | inline bool operator==(triplet const& A, triplet const& B) { 84 | return A.d[0] == B.d[0] && A.d[1] == B.d[1] && A.d[2] == B.d[2]; 85 | } 86 | 87 | std::ostream& operator<<(std::ostream& out, triplet const& T) 88 | { 89 | assert(registered.find(&T) != registered.end()); 90 | return out << '(' << T.d[0] << ',' << T.d[1] << ',' << T.d[2] << ')'; 91 | } 92 | 93 | inline double tac( triplet t, size_t k ) { return t[k]; } 94 | 95 | // use tac as a class instead of a function, 96 | // can access more than one type with just 1 definition. 97 | struct alternate_tac 98 | { 99 | typedef double result_type; 100 | double operator()( triplet const& t, size_t k ) const { return t[k]; } 101 | double operator()( alternate_triplet const& t, size_t k ) const { return t[k]; } 102 | }; 103 | 104 | #if __cplusplus < 201103L || (defined(_MSC_VER) && _MSC_VER <= 1900) 105 | typedef KDTree::KDTree<3, triplet, std::pointer_to_binary_function > tree_type; 106 | #else 107 | typedef KDTree::KDTree<3, triplet, std::function > tree_type; 108 | #endif 109 | 110 | struct Predicate 111 | { 112 | bool operator()( triplet const& t ) const 113 | { 114 | return t[0] > 3; // anything, we are currently testing that it compiles. 115 | } 116 | }; 117 | 118 | // never finds anything 119 | struct FalsePredicate 120 | { 121 | bool operator()( triplet const& t ) const { return false; } 122 | }; 123 | 124 | int main() 125 | { 126 | // check that it'll find nodes exactly MAX away 127 | { 128 | tree_type exact_dist(std::ref(tac)); 129 | triplet c0(5, 4, 0); 130 | exact_dist.insert(c0); 131 | triplet target(7,4,0); 132 | 133 | std::pair found = exact_dist.find_nearest(target,2); 134 | assert(found.first != exact_dist.end()); 135 | assert(found.second == 2); 136 | std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << std::endl; 137 | } 138 | 139 | // do the same test, except use alternate_triplet as the search key 140 | { 141 | // NOTE: stores triplet, but we search with alternate_triplet 142 | typedef KDTree::KDTree<3, triplet, alternate_tac> alt_tree; 143 | 144 | triplet actual_target(7,0,0); 145 | 146 | alt_tree tree; 147 | tree.insert( triplet(0, 0, 7) ); 148 | tree.insert( triplet(0, 0, 7) ); 149 | tree.insert( triplet(0, 0, 7) ); 150 | tree.insert( triplet(3, 0, 0) ); 151 | tree.insert( actual_target ); 152 | tree.optimise(); 153 | 154 | alternate_triplet target( actual_target ); 155 | 156 | std::pair found = tree.find_nearest(target); 157 | assert(found.first != tree.end()); 158 | std::cout << "Test with alternate search type, found: " << *found.first << ", wanted " << actual_target << std::endl; 159 | assert(found.second == 0); 160 | assert(*found.first == actual_target); 161 | } 162 | 163 | 164 | { 165 | tree_type exact_dist(std::ref(tac)); 166 | triplet c0(5, 2, 0); 167 | exact_dist.insert(c0); 168 | triplet target(7,4,0); 169 | 170 | // call find_nearest without a range value - it found a compile error earlier. 171 | std::pair found = exact_dist.find_nearest(target); 172 | assert(found.first != exact_dist.end()); 173 | std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << " @ " << found.second << " should be " << std::sqrt(8) << std::endl; 174 | assert(found.second == std::sqrt(8)); 175 | } 176 | 177 | { 178 | tree_type exact_dist(std::ref(tac)); 179 | triplet c0(5, 2, 0); 180 | exact_dist.insert(c0); 181 | triplet target(7,4,0); 182 | 183 | std::pair found = exact_dist.find_nearest(target,std::sqrt(8)); 184 | assert(found.first != exact_dist.end()); 185 | std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << " @ " << found.second << " should be " << std::sqrt(8) << std::endl; 186 | assert(found.second == std::sqrt(8)); 187 | } 188 | 189 | tree_type src(std::ref(tac)); 190 | 191 | triplet c0(5, 4, 0); src.insert(c0); 192 | triplet c1(4, 2, 1); src.insert(c1); 193 | triplet c2(7, 6, 9); src.insert(c2); 194 | triplet c3(2, 2, 1); src.insert(c3); 195 | triplet c4(8, 0, 5); src.insert(c4); 196 | triplet c5(5, 7, 0); src.insert(c5); 197 | triplet c6(3, 3, 8); src.insert(c6); 198 | triplet c7(9, 7, 3); src.insert(c7); 199 | triplet c8(2, 2, 6); src.insert(c8); 200 | triplet c9(2, 0, 6); src.insert(c9); 201 | 202 | std::cout << src << std::endl; 203 | 204 | src.erase(c0); 205 | src.erase(c1); 206 | src.erase(c3); 207 | src.erase(c5); 208 | 209 | src.optimise(); 210 | 211 | 212 | // test the efficient_replace_and_optimise() 213 | tree_type eff_repl = src; 214 | { 215 | std::vector vec; 216 | // erased above as part of test vec.push_back(triplet(5, 4, 0)); 217 | // erased above as part of test vec.push_back(triplet(4, 2, 1)); 218 | vec.push_back(triplet(7, 6, 9)); 219 | // erased above as part of test vec.push_back(triplet(2, 2, 1)); 220 | vec.push_back(triplet(8, 0, 5)); 221 | // erased above as part of test vec.push_back(triplet(5, 7, 0)); 222 | vec.push_back(triplet(3, 3, 8)); 223 | vec.push_back(triplet(9, 7, 3)); 224 | vec.push_back(triplet(2, 2, 6)); 225 | vec.push_back(triplet(2, 0, 6)); 226 | 227 | eff_repl.clear(); 228 | eff_repl.efficient_replace_and_optimise(vec); 229 | } 230 | 231 | 232 | std::cout << std::endl << src << std::endl; 233 | 234 | tree_type copied(src); 235 | std::cout << copied << std::endl; 236 | tree_type assigned = src; 237 | std::cout << assigned << std::endl; 238 | 239 | for (int loop = 0; loop != 4; ++loop) 240 | { 241 | tree_type * target; 242 | switch (loop) 243 | { 244 | case 0: std::cout << "Testing plain construction" << std::endl; 245 | target = &src; 246 | break; 247 | 248 | case 1: std::cout << "Testing copy-construction" << std::endl; 249 | target = &copied; 250 | break; 251 | 252 | case 2: std::cout << "Testing assign-construction" << std::endl; 253 | target = &assigned; 254 | break; 255 | 256 | default: 257 | case 4: std::cout << "Testing efficient-replace-and-optimise" << std::endl; 258 | target = &eff_repl; 259 | break; 260 | } 261 | tree_type & t = *target; 262 | 263 | int i=0; 264 | for (tree_type::const_iterator iter=t.begin(); iter!=t.end(); ++iter, ++i); 265 | std::cout << "iterator walked through " << i << " nodes in total" << std::endl; 266 | if (i!=6) 267 | { 268 | std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl; 269 | return 1; 270 | } 271 | i=0; 272 | for (tree_type::const_reverse_iterator iter=t.rbegin(); iter!=t.rend(); ++iter, ++i); 273 | std::cout << "reverse_iterator walked through " << i << " nodes in total" << std::endl; 274 | if (i!=6) 275 | { 276 | std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl; 277 | return 1; 278 | } 279 | 280 | triplet s(5, 4, 3); 281 | std::vector v; 282 | unsigned int const RANGE = 3; 283 | 284 | size_t count = t.count_within_range(s, RANGE); 285 | std::cout << "counted " << count 286 | << " nodes within range " << RANGE << " of " << s << ".\n"; 287 | t.find_within_range(s, RANGE, std::back_inserter(v)); 288 | 289 | std::cout << "found " << v.size() << " nodes within range " << RANGE 290 | << " of " << s << ":\n"; 291 | std::vector::const_iterator ci = v.begin(); 292 | for (; ci != v.end(); ++ci) 293 | std::cout << *ci << " "; 294 | std::cout << "\n" << std::endl; 295 | 296 | std::cout << std::endl << t << std::endl; 297 | 298 | // search for all the nodes at exactly 0 dist away 299 | for (tree_type::const_iterator target = t.begin(); target != t.end(); ++target) 300 | { 301 | std::pair found = t.find_nearest(*target,0); 302 | assert(found.first != t.end()); 303 | assert(*found.first == *target); 304 | std::cout << "Test find_nearest(), found at exact distance away from " << *target << ", found " << *found.first << std::endl; 305 | } 306 | 307 | { 308 | const double small_dist = 0.0001; 309 | std::pair notfound = t.find_nearest(s,small_dist); 310 | std::cout << "Test find_nearest(), nearest to " << s << " within " << small_dist << " should not be found" << std::endl; 311 | 312 | if (notfound.first != t.end()) 313 | { 314 | std::cout << "ERROR found a node at dist " << notfound.second << " : " << *notfound.first << std::endl; 315 | std::cout << "Actual distance = " << s.distance_to(*notfound.first) << std::endl; 316 | } 317 | 318 | assert(notfound.first == t.end()); 319 | } 320 | 321 | { 322 | std::pair nif = t.find_nearest_if(s,std::numeric_limits::max(),Predicate()); 323 | std::cout << "Test find_nearest_if(), nearest to " << s << " @ " << nif.second << ": " << *nif.first << std::endl; 324 | 325 | std::pair cantfind = t.find_nearest_if(s,std::numeric_limits::max(),FalsePredicate()); 326 | std::cout << "Test find_nearest_if(), nearest to " << s << " should never be found (predicate too strong)" << std::endl; 327 | assert(cantfind.first == t.end()); 328 | } 329 | 330 | 331 | 332 | 333 | { 334 | std::pair found = t.find_nearest(s,std::numeric_limits::max()); 335 | std::cout << "Nearest to " << s << " @ " << found.second << " " << *found.first << std::endl; 336 | std::cout << "Should be " << found.first->distance_to(s) << std::endl; 337 | // NOTE: the assert does not check for an exact match, as it is not exact when -O2 or -O3 is 338 | // switched on. Some sort of optimisation makes the math inexact. 339 | assert( fabs(found.second - found.first->distance_to(s)) < std::numeric_limits::epsilon() ); 340 | } 341 | 342 | { 343 | triplet s2(10, 10, 2); 344 | std::pair found = t.find_nearest(s2,std::numeric_limits::max()); 345 | std::cout << "Nearest to " << s2 << " @ " << found.second << " " << *found.first << std::endl; 346 | std::cout << "Should be " << found.first->distance_to(s2) << std::endl; 347 | // NOTE: the assert does not check for an exact match, as it is not exact when -O2 or -O3 is 348 | // switched on. Some sort of optimisation makes the math inexact. 349 | assert( fabs(found.second - found.first->distance_to(s2)) < std::numeric_limits::epsilon() ); 350 | } 351 | 352 | std::cout << std::endl; 353 | 354 | std::cout << t << std::endl; 355 | 356 | // Testing iterators 357 | { 358 | std::cout << "Testing iterators" << std::endl; 359 | 360 | t.erase(c2); 361 | t.erase(c4); 362 | t.erase(c6); 363 | t.erase(c7); 364 | t.erase(c8); 365 | // t.erase(c9); 366 | 367 | std::cout << std::endl << t << std::endl; 368 | 369 | std::cout << "Forward iterator test..." << std::endl; 370 | std::vector forwards; 371 | for (tree_type::iterator i = t.begin(); i != t.end(); ++i) 372 | { std::cout << *i << " " << std::flush; forwards.push_back(*i); } 373 | std::cout << std::endl; 374 | std::cout << "Reverse iterator test..." << std::endl; 375 | std::vector backwards; 376 | for (tree_type::reverse_iterator i = t.rbegin(); i != t.rend(); ++i) 377 | { std::cout << *i << " " << std::flush; backwards.push_back(*i); } 378 | std::cout << std::endl; 379 | std::reverse(backwards.begin(),backwards.end()); 380 | assert(backwards == forwards); 381 | } 382 | } 383 | 384 | 385 | // Walter reported that the find_within_range() wasn't giving results that were within 386 | // the specified range... this is the test. 387 | { 388 | tree_type tree(std::ref(tac)); 389 | tree.insert( triplet(28.771200,16.921600,-2.665970) ); 390 | tree.insert( triplet(28.553101,18.649700,-2.155560) ); 391 | tree.insert( triplet(28.107500,20.341400,-1.188940) ); 392 | tree.optimise(); 393 | 394 | std::deque< triplet > vectors; 395 | triplet sv(18.892500,20.341400,-1.188940); 396 | tree.find_within_range(sv, 10.0f, std::back_inserter(vectors)); 397 | 398 | std::cout << std::endl << "Test find_with_range( " << sv << ", 10.0f) found " << vectors.size() << " candidates." << std::endl; 399 | 400 | // double-check the ranges 401 | for (std::deque::iterator v = vectors.begin(); v != vectors.end(); ++v) 402 | { 403 | double dist = sv.distance_to(*v); 404 | std::cout << " " << *v << " dist=" << dist << std::endl; 405 | if (dist > 10.0f) 406 | std::cout << " This point is too far! But that is by design, its within a 'box' with a 'radius' of 10, not a sphere with a radius of 10" << std::endl; 407 | // Not a valid test, it can be greater than 10 if the point is in the corners of the box. 408 | // assert(dist <= 10.0f); 409 | } 410 | } 411 | 412 | 413 | return 0; 414 | } 415 | 416 | /* COPYRIGHT -- 417 | * 418 | * This file is part of libkdtree++, a C++ template KD-Tree sorting container. 419 | * libkdtree++ is (c) 2004-2007 Martin F. Krafft 420 | * and Sylvain Bougerel distributed under the 421 | * terms of the Artistic License 2.0. See the ./COPYING file in the source tree 422 | * root for more information. 423 | * 424 | * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 425 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 426 | * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 427 | */ 428 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-compat": { 4 | "locked": { 5 | "lastModified": 1733328505, 6 | "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", 7 | "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", 8 | "revCount": 69, 9 | "type": "tarball", 10 | "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz" 11 | }, 12 | "original": { 13 | "type": "tarball", 14 | "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz" 15 | } 16 | }, 17 | "nixpkgs": { 18 | "locked": { 19 | "lastModified": 1740367490, 20 | "narHash": "sha256-WGaHVAjcrv+Cun7zPlI41SerRtfknGQap281+AakSAw=", 21 | "owner": "nixos", 22 | "repo": "nixpkgs", 23 | "rev": "0196c0175e9191c474c26ab5548db27ef5d34b05", 24 | "type": "github" 25 | }, 26 | "original": { 27 | "owner": "nixos", 28 | "ref": "nixos-unstable", 29 | "repo": "nixpkgs", 30 | "type": "github" 31 | } 32 | }, 33 | "root": { 34 | "inputs": { 35 | "flake-compat": "flake-compat", 36 | "nixpkgs": "nixpkgs" 37 | } 38 | } 39 | }, 40 | "root": "root", 41 | "version": 7 42 | } 43 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Nix flake for libkdtree+ library"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; 6 | flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"; 7 | }; 8 | 9 | outputs = { self, nixpkgs, ... }@inputs: let 10 | lib = nixpkgs.lib; 11 | shellSystems = nixpkgs.lib.systems.flakeExposed; 12 | buildSystems = nixpkgs.lib.systems.flakeExposed; 13 | forSystems = systems: f: nixpkgs.lib.genAttrs systems (system: f system); 14 | in { 15 | 16 | devShells = forSystems shellSystems (system: let 17 | pkgs = nixpkgs.legacyPackages.${system}; 18 | in { 19 | default = pkgs.mkShell { 20 | nativeBuildInputs = with pkgs; [ 21 | nil # lsp language server for nix 22 | cmake 23 | doxygen 24 | ] ++ lib.optionals pkgs.hostPlatform.isLinux [ gdb ]; 25 | }; 26 | }); 27 | 28 | packages = forSystems buildSystems (system: let 29 | pkgs = nixpkgs.legacyPackages.${system}.pkgs; 30 | in { 31 | default = self.packages.${system}.libkdtree; 32 | libkdtree = pkgs.callPackage ./libkdtree.nix {}; 33 | }); 34 | 35 | }; 36 | } -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2006-12-25.00 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -t DIRECTORY install into DIRECTORY. 124 | -T report an error if DSTFILE is a directory. 125 | 126 | Environment variables override the default commands: 127 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 128 | RMPROG STRIPPROG 129 | " 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *' '* | *' 147 | '* | *'*'* | *'?'* | *'['*) 148 | echo "$0: invalid mode: $mode" >&2 149 | exit 1;; 150 | esac 151 | shift;; 152 | 153 | -o) chowncmd="$chownprog $2" 154 | shift;; 155 | 156 | -s) stripcmd=$stripprog;; 157 | 158 | -t) dst_arg=$2 159 | shift;; 160 | 161 | -T) no_target_directory=true;; 162 | 163 | --version) echo "$0 $scriptversion"; exit $?;; 164 | 165 | --) shift 166 | break;; 167 | 168 | -*) echo "$0: invalid option: $1" >&2 169 | exit 1;; 170 | 171 | *) break;; 172 | esac 173 | shift 174 | done 175 | 176 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 177 | # When -d is used, all remaining arguments are directories to create. 178 | # When -t is used, the destination is already specified. 179 | # Otherwise, the last argument is the destination. Remove it from $@. 180 | for arg 181 | do 182 | if test -n "$dst_arg"; then 183 | # $@ is not empty: it contains at least $arg. 184 | set fnord "$@" "$dst_arg" 185 | shift # fnord 186 | fi 187 | shift # arg 188 | dst_arg=$arg 189 | done 190 | fi 191 | 192 | if test $# -eq 0; then 193 | if test -z "$dir_arg"; then 194 | echo "$0: no input file specified." >&2 195 | exit 1 196 | fi 197 | # It's OK to call `install-sh -d' without argument. 198 | # This can happen when creating conditional directories. 199 | exit 0 200 | fi 201 | 202 | if test -z "$dir_arg"; then 203 | trap '(exit $?); exit' 1 2 13 15 204 | 205 | # Set umask so as not to create temps with too-generous modes. 206 | # However, 'strip' requires both read and write access to temps. 207 | case $mode in 208 | # Optimize common cases. 209 | *644) cp_umask=133;; 210 | *755) cp_umask=22;; 211 | 212 | *[0-7]) 213 | if test -z "$stripcmd"; then 214 | u_plus_rw= 215 | else 216 | u_plus_rw='% 200' 217 | fi 218 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 219 | *) 220 | if test -z "$stripcmd"; then 221 | u_plus_rw= 222 | else 223 | u_plus_rw=,u+rw 224 | fi 225 | cp_umask=$mode$u_plus_rw;; 226 | esac 227 | fi 228 | 229 | for src 230 | do 231 | # Protect names starting with `-'. 232 | case $src in 233 | -*) src=./$src;; 234 | esac 235 | 236 | if test -n "$dir_arg"; then 237 | dst=$src 238 | dstdir=$dst 239 | test -d "$dstdir" 240 | dstdir_status=$? 241 | else 242 | 243 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 244 | # might cause directories to be created, which would be especially bad 245 | # if $src (and thus $dsttmp) contains '*'. 246 | if test ! -f "$src" && test ! -d "$src"; then 247 | echo "$0: $src does not exist." >&2 248 | exit 1 249 | fi 250 | 251 | if test -z "$dst_arg"; then 252 | echo "$0: no destination specified." >&2 253 | exit 1 254 | fi 255 | 256 | dst=$dst_arg 257 | # Protect names starting with `-'. 258 | case $dst in 259 | -*) dst=./$dst;; 260 | esac 261 | 262 | # If destination is a directory, append the input filename; won't work 263 | # if double slashes aren't ignored. 264 | if test -d "$dst"; then 265 | if test -n "$no_target_directory"; then 266 | echo "$0: $dst_arg: Is a directory" >&2 267 | exit 1 268 | fi 269 | dstdir=$dst 270 | dst=$dstdir/`basename "$src"` 271 | dstdir_status=0 272 | else 273 | # Prefer dirname, but fall back on a substitute if dirname fails. 274 | dstdir=` 275 | (dirname "$dst") 2>/dev/null || 276 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 277 | X"$dst" : 'X\(//\)[^/]' \| \ 278 | X"$dst" : 'X\(//\)$' \| \ 279 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 280 | echo X"$dst" | 281 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 282 | s//\1/ 283 | q 284 | } 285 | /^X\(\/\/\)[^/].*/{ 286 | s//\1/ 287 | q 288 | } 289 | /^X\(\/\/\)$/{ 290 | s//\1/ 291 | q 292 | } 293 | /^X\(\/\).*/{ 294 | s//\1/ 295 | q 296 | } 297 | s/.*/./; q' 298 | ` 299 | 300 | test -d "$dstdir" 301 | dstdir_status=$? 302 | fi 303 | fi 304 | 305 | obsolete_mkdir_used=false 306 | 307 | if test $dstdir_status != 0; then 308 | case $posix_mkdir in 309 | '') 310 | # Create intermediate dirs using mode 755 as modified by the umask. 311 | # This is like FreeBSD 'install' as of 1997-10-28. 312 | umask=`umask` 313 | case $stripcmd.$umask in 314 | # Optimize common cases. 315 | *[2367][2367]) mkdir_umask=$umask;; 316 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 317 | 318 | *[0-7]) 319 | mkdir_umask=`expr $umask + 22 \ 320 | - $umask % 100 % 40 + $umask % 20 \ 321 | - $umask % 10 % 4 + $umask % 2 322 | `;; 323 | *) mkdir_umask=$umask,go-w;; 324 | esac 325 | 326 | # With -d, create the new directory with the user-specified mode. 327 | # Otherwise, rely on $mkdir_umask. 328 | if test -n "$dir_arg"; then 329 | mkdir_mode=-m$mode 330 | else 331 | mkdir_mode= 332 | fi 333 | 334 | posix_mkdir=false 335 | case $umask in 336 | *[123567][0-7][0-7]) 337 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 338 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 339 | ;; 340 | *) 341 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 342 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 343 | 344 | if (umask $mkdir_umask && 345 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 346 | then 347 | if test -z "$dir_arg" || { 348 | # Check for POSIX incompatibilities with -m. 349 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 350 | # other-writeable bit of parent directory when it shouldn't. 351 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 352 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 353 | case $ls_ld_tmpdir in 354 | d????-?r-*) different_mode=700;; 355 | d????-?--*) different_mode=755;; 356 | *) false;; 357 | esac && 358 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 359 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 360 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 361 | } 362 | } 363 | then posix_mkdir=: 364 | fi 365 | rmdir "$tmpdir/d" "$tmpdir" 366 | else 367 | # Remove any dirs left behind by ancient mkdir implementations. 368 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 369 | fi 370 | trap '' 0;; 371 | esac;; 372 | esac 373 | 374 | if 375 | $posix_mkdir && ( 376 | umask $mkdir_umask && 377 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 378 | ) 379 | then : 380 | else 381 | 382 | # The umask is ridiculous, or mkdir does not conform to POSIX, 383 | # or it failed possibly due to a race condition. Create the 384 | # directory the slow way, step by step, checking for races as we go. 385 | 386 | case $dstdir in 387 | /*) prefix='/';; 388 | -*) prefix='./';; 389 | *) prefix='';; 390 | esac 391 | 392 | eval "$initialize_posix_glob" 393 | 394 | oIFS=$IFS 395 | IFS=/ 396 | $posix_glob set -f 397 | set fnord $dstdir 398 | shift 399 | $posix_glob set +f 400 | IFS=$oIFS 401 | 402 | prefixes= 403 | 404 | for d 405 | do 406 | test -z "$d" && continue 407 | 408 | prefix=$prefix$d 409 | if test -d "$prefix"; then 410 | prefixes= 411 | else 412 | if $posix_mkdir; then 413 | (umask=$mkdir_umask && 414 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 415 | # Don't fail if two instances are running concurrently. 416 | test -d "$prefix" || exit 1 417 | else 418 | case $prefix in 419 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 420 | *) qprefix=$prefix;; 421 | esac 422 | prefixes="$prefixes '$qprefix'" 423 | fi 424 | fi 425 | prefix=$prefix/ 426 | done 427 | 428 | if test -n "$prefixes"; then 429 | # Don't fail if two instances are running concurrently. 430 | (umask $mkdir_umask && 431 | eval "\$doit_exec \$mkdirprog $prefixes") || 432 | test -d "$dstdir" || exit 1 433 | obsolete_mkdir_used=true 434 | fi 435 | fi 436 | fi 437 | 438 | if test -n "$dir_arg"; then 439 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 440 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 441 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 442 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 443 | else 444 | 445 | # Make a couple of temp file names in the proper directory. 446 | dsttmp=$dstdir/_inst.$$_ 447 | rmtmp=$dstdir/_rm.$$_ 448 | 449 | # Trap to clean up those temp files at exit. 450 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 451 | 452 | # Copy the file name to the temp name. 453 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 454 | 455 | # and set any options; do chmod last to preserve setuid bits. 456 | # 457 | # If any of these fail, we abort the whole thing. If we want to 458 | # ignore errors from any of these, just make sure not to ignore 459 | # errors from the above "$doit $cpprog $src $dsttmp" command. 460 | # 461 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 462 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 463 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 464 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 465 | 466 | # If -C, don't bother to copy if it wouldn't change the file. 467 | if $copy_on_change && 468 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 469 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 470 | 471 | eval "$initialize_posix_glob" && 472 | $posix_glob set -f && 473 | set X $old && old=:$2:$4:$5:$6 && 474 | set X $new && new=:$2:$4:$5:$6 && 475 | $posix_glob set +f && 476 | 477 | test "$old" = "$new" && 478 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 479 | then 480 | rm -f "$dsttmp" 481 | else 482 | # Rename the file to the real destination. 483 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 484 | 485 | # The rename failed, perhaps because mv can't rename something else 486 | # to itself, or perhaps because mv is so ancient that it does not 487 | # support -f. 488 | { 489 | # Now remove or move aside any old file at destination location. 490 | # We try this two ways since rm can't unlink itself on some 491 | # systems and the destination file might be busy for other 492 | # reasons. In this case, the final cleanup might fail but the new 493 | # file should still install successfully. 494 | { 495 | test ! -f "$dst" || 496 | $doit $rmcmd -f "$dst" 2>/dev/null || 497 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 498 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 499 | } || 500 | { echo "$0: cannot unlink or rename $dst" >&2 501 | (exit 1); exit 1 502 | } 503 | } && 504 | 505 | # Now rename the file to the real destination. 506 | $doit $mvcmd "$dsttmp" "$dst" 507 | } 508 | fi || exit 1 509 | 510 | trap '' 0 511 | fi 512 | done 513 | 514 | # Local variables: 515 | # eval: (add-hook 'write-file-hooks 'time-stamp) 516 | # time-stamp-start: "scriptversion=" 517 | # time-stamp-format: "%:y-%02m-%02d.%02H" 518 | # time-stamp-end: "$" 519 | # End: 520 | -------------------------------------------------------------------------------- /kdtree++/allocator.hpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Defines the allocator interface as used by the KDTree class. 3 | * 4 | * \author Martin F. Krafft 5 | */ 6 | 7 | #ifndef INCLUDE_KDTREE_ALLOCATOR_HPP 8 | #define INCLUDE_KDTREE_ALLOCATOR_HPP 9 | 10 | #include 11 | 12 | #include "node.hpp" 13 | 14 | namespace KDTree 15 | { 16 | 17 | template 18 | class _Alloc_base 19 | { 20 | public: 21 | typedef _Node<_Tp> _Node_; 22 | typedef typename _Node_::_Base_ptr _Base_ptr; 23 | typedef _Alloc allocator_type; 24 | 25 | _Alloc_base(allocator_type const& __A) 26 | : _M_node_allocator(__A) {} 27 | 28 | allocator_type 29 | get_allocator() const 30 | { 31 | return _M_node_allocator; 32 | } 33 | 34 | 35 | class NoLeakAlloc 36 | { 37 | _Alloc_base * base; 38 | _Node_ * new_node; 39 | 40 | public: 41 | NoLeakAlloc(_Alloc_base * b) : base(b), new_node(base->_M_allocate_node()) {} 42 | 43 | _Node_ * get() { return new_node; } 44 | void disconnect() { new_node = NULL; } 45 | 46 | ~NoLeakAlloc() { if (new_node) base->_M_deallocate_node(new_node); } 47 | }; 48 | 49 | 50 | protected: 51 | allocator_type _M_node_allocator; 52 | 53 | _Node_* 54 | _M_allocate_node() 55 | { 56 | return _M_node_allocator.allocate(1); 57 | } 58 | 59 | void 60 | _M_deallocate_node(_Node_* const __P) 61 | { 62 | return _M_node_allocator.deallocate(__P, 1); 63 | } 64 | 65 | void 66 | _M_construct_node(_Node_* __p, _Tp const __V = _Tp(), 67 | _Base_ptr const __PARENT = NULL, 68 | _Base_ptr const __LEFT = NULL, 69 | _Base_ptr const __RIGHT = NULL) 70 | { 71 | new (__p) _Node_(__V, __PARENT, __LEFT, __RIGHT); 72 | } 73 | 74 | void 75 | _M_destroy_node(_Node_* __p) 76 | { 77 | #if __cplusplus >= 201703L 78 | std::allocator_traits::destroy(_M_node_allocator,__p); 79 | #else 80 | _M_node_allocator.destroy(__p); 81 | #endif 82 | } 83 | }; 84 | 85 | } // namespace KDTree 86 | 87 | #endif // include guard 88 | 89 | /* COPYRIGHT -- 90 | * 91 | * This file is part of libkdtree++, a C++ template KD-Tree sorting container. 92 | * libkdtree++ is (c) 2004-2007 Martin F. Krafft 93 | * and Sylvain Bougerel distributed under the 94 | * terms of the Artistic License 2.0. See the ./COPYING file in the source tree 95 | * root for more information. 96 | * 97 | * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 98 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 99 | * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 100 | */ 101 | -------------------------------------------------------------------------------- /kdtree++/function.hpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Defines the various functors and interfaces used for KDTree. 3 | * 4 | * \author Martin F. Krafft 5 | * \author Sylvain Bougerel 6 | */ 7 | 8 | #ifndef INCLUDE_KDTREE_ACCESSOR_HPP 9 | #define INCLUDE_KDTREE_ACCESSOR_HPP 10 | 11 | #include 12 | 13 | namespace KDTree 14 | { 15 | template 16 | struct _Bracket_accessor 17 | { 18 | typedef typename _Val::value_type result_type; 19 | 20 | result_type 21 | operator()(_Val const& V, size_t const N) const 22 | { 23 | return V[N]; 24 | } 25 | }; 26 | 27 | template 28 | struct always_true 29 | { 30 | bool operator() (const _Tp& ) const { return true; } 31 | }; 32 | 33 | template 34 | struct squared_difference 35 | { 36 | typedef _Dist distance_type; 37 | 38 | distance_type 39 | operator() (const _Tp& __a, const _Tp& __b) const 40 | { 41 | distance_type d=__a - __b; 42 | return d*d; 43 | } 44 | }; 45 | 46 | template 47 | struct squared_difference_counted 48 | { 49 | typedef _Dist distance_type; 50 | 51 | squared_difference_counted() 52 | : _M_count(0) 53 | { } 54 | 55 | void reset () 56 | { _M_count = 0; } 57 | 58 | long& 59 | count () const 60 | { return _M_count; } 61 | 62 | distance_type 63 | operator() (const _Tp& __a, const _Tp& __b) const 64 | { 65 | distance_type d=__a - __b; 66 | ++_M_count; 67 | return d*d; 68 | } 69 | 70 | private: 71 | mutable long _M_count; 72 | }; 73 | 74 | } // namespace KDTree 75 | 76 | #endif // include guard 77 | 78 | /* COPYRIGHT -- 79 | * 80 | * This file is part of libkdtree++, a C++ template KD-Tree sorting container. 81 | * libkdtree++ is (c) 2004-2007 Martin F. Krafft 82 | * and Sylvain Bougerel distributed under the 83 | * terms of the Artistic License 2.0. See the ./COPYING file in the source tree 84 | * root for more information. 85 | * 86 | * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 87 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 88 | * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 89 | */ 90 | -------------------------------------------------------------------------------- /kdtree++/iterator.hpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Defines interfaces for iterators as used by the KDTree class. 3 | * 4 | * \author Martin F. Krafft 5 | */ 6 | 7 | #ifndef INCLUDE_KDTREE_ITERATOR_HPP 8 | #define INCLUDE_KDTREE_ITERATOR_HPP 9 | 10 | #include 11 | 12 | #include "node.hpp" 13 | 14 | namespace KDTree 15 | { 16 | template 17 | class _Iterator; 18 | 19 | template 20 | inline bool 21 | operator==(_Iterator<_Val, _Ref, _Ptr> const&, 22 | _Iterator<_Val, _Ref, _Ptr> const&); 23 | 24 | template 25 | inline bool 26 | operator==(_Iterator<_Val, const _Val&, const _Val*> const&, 27 | _Iterator<_Val, _Val&, _Val*> const&); 28 | 29 | template 30 | inline bool 31 | operator==(_Iterator<_Val, _Val&, _Val*> const&, 32 | _Iterator<_Val, const _Val&, const _Val*> const&); 33 | 34 | template 35 | inline bool 36 | operator!=(_Iterator<_Val, _Ref, _Ptr> const&, 37 | _Iterator<_Val, _Ref, _Ptr> const&); 38 | 39 | template 40 | inline bool 41 | operator!=(_Iterator<_Val, const _Val&, const _Val*> const&, 42 | _Iterator<_Val, _Val&, _Val*> const&); 43 | 44 | template 45 | inline bool 46 | operator!=(_Iterator<_Val, _Val&, _Val*> const&, 47 | _Iterator<_Val, const _Val&, const _Val*> const&); 48 | 49 | class _Base_iterator 50 | { 51 | protected: 52 | typedef _Node_base::_Base_const_ptr _Base_const_ptr; 53 | _Base_const_ptr _M_node; 54 | 55 | inline _Base_iterator(_Base_const_ptr const __N = NULL) 56 | : _M_node(__N) {} 57 | inline _Base_iterator(_Base_iterator const& __THAT) 58 | : _M_node(__THAT._M_node) {} 59 | 60 | inline void 61 | _M_increment() 62 | { 63 | if (_M_node->_M_right) 64 | { 65 | _M_node = _M_node->_M_right; 66 | while (_M_node->_M_left) _M_node = _M_node->_M_left; 67 | } 68 | else 69 | { 70 | _Base_const_ptr __p = _M_node->_M_parent; 71 | while (__p && _M_node == __p->_M_right) 72 | { 73 | _M_node = __p; 74 | __p = _M_node->_M_parent; 75 | } 76 | if (__p) // (__p) provide undetermined behavior on end()++ rather 77 | // than a seg fault, similar to standard iterator. 78 | _M_node = __p; 79 | } 80 | } 81 | 82 | inline void 83 | _M_decrement() 84 | { 85 | if (!_M_node->_M_parent) // clearly identify the header node 86 | { 87 | _M_node = _M_node->_M_right; 88 | } 89 | else if (_M_node->_M_left) 90 | { 91 | _Base_const_ptr x = _M_node->_M_left; 92 | while (x->_M_right) x = x->_M_right; 93 | _M_node = x; 94 | } 95 | else 96 | { 97 | _Base_const_ptr __p = _M_node->_M_parent; 98 | while (__p && _M_node == __p->_M_left) // see below 99 | { 100 | _M_node = __p; 101 | __p = _M_node->_M_parent; 102 | } 103 | if (__p) // (__p) provide undetermined behavior on rend()++ rather 104 | // than a seg fault, similar to standard iterator. 105 | _M_node = __p; 106 | } 107 | } 108 | 109 | template 111 | friend class KDTree; 112 | }; 113 | 114 | template 115 | class _Iterator : protected _Base_iterator 116 | { 117 | public: 118 | typedef _Val value_type; 119 | typedef _Ref reference; 120 | typedef _Ptr pointer; 121 | typedef _Iterator<_Val, _Val&, _Val*> iterator; 122 | typedef _Iterator<_Val, _Val const&, _Val const*> const_iterator; 123 | typedef _Iterator<_Val, _Ref, _Ptr> _Self; 124 | typedef _Node<_Val> const* _Link_const_type; 125 | typedef std::bidirectional_iterator_tag iterator_category; 126 | typedef ptrdiff_t difference_type; 127 | 128 | inline _Iterator() 129 | : _Base_iterator() {} 130 | inline _Iterator(_Link_const_type const __N) 131 | : _Base_iterator(__N) {} 132 | inline _Iterator(iterator const& __THAT) 133 | : _Base_iterator(__THAT) {} 134 | 135 | _Link_const_type get_raw_node() const 136 | { 137 | return _Link_const_type(_M_node); 138 | } 139 | 140 | reference 141 | operator*() const 142 | { 143 | return _Link_const_type(_M_node)->_M_value; 144 | } 145 | 146 | pointer 147 | operator->() const 148 | { 149 | return &(operator*()); 150 | } 151 | 152 | _Self 153 | operator++() 154 | { 155 | _M_increment(); 156 | return *this; 157 | } 158 | 159 | _Self 160 | operator++(int) 161 | { 162 | _Self ret = *this; 163 | _M_increment(); 164 | return ret; 165 | } 166 | 167 | _Self& 168 | operator--() 169 | { 170 | _M_decrement(); 171 | return *this; 172 | } 173 | 174 | _Self 175 | operator--(int) 176 | { 177 | _Self ret = *this; 178 | _M_decrement(); 179 | return ret; 180 | } 181 | 182 | friend bool 183 | operator== <>(_Iterator<_Val, _Ref, _Ptr> const&, 184 | _Iterator<_Val, _Ref, _Ptr> const&); 185 | 186 | friend bool 187 | operator== <>(_Iterator<_Val, const _Val&, const _Val*> const&, 188 | _Iterator<_Val, _Val&, _Val*> const&); 189 | 190 | friend bool 191 | operator== <>(_Iterator<_Val, _Val&, _Val*> const&, 192 | _Iterator<_Val, const _Val&, const _Val*> const&); 193 | 194 | friend bool 195 | operator!= <>(_Iterator<_Val, _Ref, _Ptr> const&, 196 | _Iterator<_Val, _Ref, _Ptr> const&); 197 | 198 | friend bool 199 | operator!= <>(_Iterator<_Val, const _Val&, const _Val*> const&, 200 | _Iterator<_Val, _Val&, _Val*> const&); 201 | 202 | friend bool 203 | operator!= <>(_Iterator<_Val, _Val&, _Val*> const&, 204 | _Iterator<_Val, const _Val&, const _Val*> const&); 205 | }; 206 | 207 | template 208 | bool 209 | operator==(_Iterator<_Val, _Ref, _Ptr> const& __X, 210 | _Iterator<_Val, _Ref, _Ptr> const& __Y) 211 | { return __X._M_node == __Y._M_node; } 212 | 213 | template 214 | bool 215 | operator==(_Iterator<_Val, const _Val&, const _Val*> const& __X, 216 | _Iterator<_Val, _Val&, _Val*> const& __Y) 217 | { return __X._M_node == __Y._M_node; } 218 | 219 | template 220 | bool 221 | operator==(_Iterator<_Val, _Val&, _Val*> const& __X, 222 | _Iterator<_Val, const _Val&, const _Val*> const& __Y) 223 | { return __X._M_node == __Y._M_node; } 224 | 225 | template 226 | bool 227 | operator!=(_Iterator<_Val, _Ref, _Ptr> const& __X, 228 | _Iterator<_Val, _Ref, _Ptr> const& __Y) 229 | { return __X._M_node != __Y._M_node; } 230 | 231 | template 232 | bool 233 | operator!=(_Iterator<_Val, const _Val&, const _Val*> const& __X, 234 | _Iterator<_Val, _Val&, _Val*> const& __Y) 235 | { return __X._M_node != __Y._M_node; } 236 | 237 | template 238 | bool 239 | operator!=(_Iterator<_Val, _Val&, _Val*> const& __X, 240 | _Iterator<_Val, const _Val&, const _Val*> const& __Y) 241 | { return __X._M_node != __Y._M_node; } 242 | 243 | } // namespace KDTree 244 | 245 | #endif // include guard 246 | 247 | /* COPYRIGHT -- 248 | * 249 | * This file is part of libkdtree++, a C++ template KD-Tree sorting container. 250 | * libkdtree++ is (c) 2004-2007 Martin F. Krafft 251 | * and Sylvain Bougerel distributed under the 252 | * terms of the Artistic License 2.0. See the ./COPYING file in the source tree 253 | * root for more information. 254 | * 255 | * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 256 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 257 | * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 258 | */ 259 | -------------------------------------------------------------------------------- /kdtree++/kdtree.hpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Defines the interface for the KDTree class. 3 | * 4 | * \author Martin F. Krafft 5 | * 6 | * Paul Harris figured this stuff out (below) 7 | * Notes: 8 | * This is similar to a binary tree, but its not the same. 9 | * There are a few important differences: 10 | * 11 | * * Each level is sorted by a different criteria (this is fundamental to the design). 12 | * 13 | * * It is possible to have children IDENTICAL to its parent in BOTH branches 14 | * This is different to a binary tree, where identical children are always to the right 15 | * So, KDTree has the relationships: 16 | * * The left branch is <= its parent (in binary tree, this relationship is a plain < ) 17 | * * The right branch is <= its parent (same as binary tree) 18 | * 19 | * This is done for mostly for performance. 20 | * Its a LOT easier to maintain a consistent tree if we use the <= relationship. 21 | * Note that this relationship only makes a difference when searching for an exact 22 | * item with find() or find_exact, other search, erase and insert functions don't notice 23 | * the difference. 24 | * 25 | * In the case of binary trees, you can safely assume that the next identical item 26 | * will be the child leaf, 27 | * but in the case of KDTree, the next identical item might 28 | * be a long way down a subtree, because of the various different sort criteria. 29 | * 30 | * So erase()ing a node from a KDTree could require serious and complicated 31 | * tree rebalancing to maintain consistency... IF we required binary-tree-like relationships. 32 | * 33 | * This has no effect on insert()s, a < test is good enough to keep consistency. 34 | * 35 | * It has an effect on find() searches: 36 | * * Instead of using compare(child,node) for a < relationship and following 1 branch, 37 | * we must use !compare(node,child) for a <= relationship, and test BOTH branches, as 38 | * we could potentially go down both branches. 39 | * 40 | * It has no real effect on bounds-based searches (like find_nearest, find_within_range) 41 | * as it compares vs a boundary and would follow both branches if required. 42 | * 43 | * This has no real effect on erase()s, a < test is good enough to keep consistency. 44 | */ 45 | 46 | #ifndef INCLUDE_KDTREE_KDTREE_HPP 47 | #define INCLUDE_KDTREE_KDTREE_HPP 48 | 49 | 50 | // 51 | // This number is guarenteed to change with every release. 52 | // 53 | // KDTREE_VERSION % 100 is the patch level 54 | // KDTREE_VERSION / 100 % 1000 is the minor version 55 | // KDTREE_VERSION / 100000 is the major version 56 | #define KDTREE_VERSION 704 57 | // 58 | // KDTREE_LIB_VERSION must be defined to be the same as KDTREE_VERSION 59 | // but as a *string* in the form "x_y[_z]" where x is the major version 60 | // number, y is the minor version number, and z is the patch level if not 0. 61 | #define KDTREE_LIB_VERSION "0_7_4" 62 | 63 | 64 | #include 65 | 66 | #ifdef KDTREE_CHECK_PERFORMANCE_COUNTERS 67 | # include 68 | #endif 69 | #include 70 | #include 71 | 72 | #ifdef KDTREE_DEFINE_OSTREAM_OPERATORS 73 | # include 74 | # include 75 | #endif 76 | 77 | #include 78 | #include 79 | #include 80 | 81 | #include "function.hpp" 82 | #include "allocator.hpp" 83 | #include "iterator.hpp" 84 | #include "node.hpp" 85 | #include "region.hpp" 86 | 87 | namespace KDTree 88 | { 89 | 90 | #ifdef KDTREE_CHECK_PERFORMANCE 91 | unsigned long long num_dist_calcs = 0; 92 | #endif 93 | 94 | template , 96 | typename _Dist = squared_difference, 98 | typename _Cmp = std::less, 99 | typename _Alloc = std::allocator<_Node<_Val> > > 100 | class KDTree : protected _Alloc_base<_Val, _Alloc> 101 | { 102 | protected: 103 | typedef _Alloc_base<_Val, _Alloc> _Base; 104 | typedef typename _Base::allocator_type allocator_type; 105 | 106 | typedef _Node_base* _Base_ptr; 107 | typedef _Node_base const* _Base_const_ptr; 108 | typedef _Node<_Val>* _Link_type; 109 | typedef _Node<_Val> const* _Link_const_type; 110 | 111 | typedef _Node_compare<_Val, _Acc, _Cmp> _Node_compare_; 112 | 113 | public: 114 | typedef _Region<__K, _Val, typename _Acc::result_type, _Acc, _Cmp> 115 | _Region_; 116 | typedef _Val value_type; 117 | typedef value_type* pointer; 118 | typedef value_type const* const_pointer; 119 | typedef value_type& reference; 120 | typedef value_type const& const_reference; 121 | typedef typename _Acc::result_type subvalue_type; 122 | typedef typename _Dist::distance_type distance_type; 123 | typedef size_t size_type; 124 | typedef ptrdiff_t difference_type; 125 | 126 | KDTree(_Acc const& __acc = _Acc(), _Dist const& __dist = _Dist(), 127 | _Cmp const& __cmp = _Cmp(), const allocator_type& __a = allocator_type()) 128 | : _Base(__a), _M_header(), 129 | _M_count(0), _M_acc(__acc), _M_cmp(__cmp), _M_dist(__dist) 130 | { 131 | _M_empty_initialise(); 132 | } 133 | 134 | KDTree(const KDTree& __x) 135 | : _Base(__x.get_allocator()), _M_header(), _M_count(0), 136 | _M_acc(__x._M_acc), _M_cmp(__x._M_cmp), _M_dist(__x._M_dist) 137 | { 138 | _M_empty_initialise(); 139 | // this is slow: 140 | // this->insert(begin(), __x.begin(), __x.end()); 141 | // this->optimise(); 142 | 143 | // this is much faster, as it skips a lot of useless work 144 | // do the optimisation before inserting 145 | // Needs to be stored in a vector first as _M_optimise() 146 | // sorts the data in the passed iterators directly. 147 | std::vector temp; 148 | temp.reserve(__x.size()); 149 | std::copy(__x.begin(),__x.end(),std::back_inserter(temp)); 150 | _M_optimise(temp.begin(), temp.end(), 0); 151 | } 152 | 153 | template 154 | KDTree(_InputIterator __first, _InputIterator __last, 155 | _Acc const& acc = _Acc(), _Dist const& __dist = _Dist(), 156 | _Cmp const& __cmp = _Cmp(), const allocator_type& __a = allocator_type()) 157 | : _Base(__a), _M_header(), _M_count(0), 158 | _M_acc(acc), _M_cmp(__cmp), _M_dist(__dist) 159 | { 160 | _M_empty_initialise(); 161 | // this is slow: 162 | // this->insert(begin(), __first, __last); 163 | // this->optimise(); 164 | 165 | // this is much faster, as it skips a lot of useless work 166 | // do the optimisation before inserting 167 | // Needs to be stored in a vector first as _M_optimise() 168 | // sorts the data in the passed iterators directly. 169 | std::vector temp; 170 | temp.reserve(std::distance(__first,__last)); 171 | std::copy(__first,__last,std::back_inserter(temp)); 172 | _M_optimise(temp.begin(), temp.end(), 0); 173 | 174 | // NOTE: this will BREAK users that are passing in 175 | // read-once data via the iterator... 176 | // We increment __first all the way to __last once within 177 | // the distance() call, and again within the copy() call. 178 | // 179 | // This should end up using some funky C++ concepts or 180 | // type traits to check that the iterators can be used in this way... 181 | } 182 | 183 | 184 | // this will CLEAR the tree and fill it with the contents 185 | // of 'writable_vector'. it will use the passed vector directly, 186 | // and will basically resort the vector many times over while 187 | // optimising the tree. 188 | // 189 | // Paul: I use this when I have already built up a vector of data 190 | // that I want to add, and I don't mind if its contents get shuffled 191 | // by the kdtree optimise routine. 192 | void efficient_replace_and_optimise( std::vector & writable_vector ) 193 | { 194 | this->clear(); 195 | _M_optimise(writable_vector.begin(), writable_vector.end(), 0); 196 | } 197 | 198 | 199 | 200 | KDTree& 201 | operator=(const KDTree& __x) 202 | { 203 | if (this != &__x) 204 | { 205 | _M_acc = __x._M_acc; 206 | _M_dist = __x._M_dist; 207 | _M_cmp = __x._M_cmp; 208 | // this is slow: 209 | // this->insert(begin(), __x.begin(), __x.end()); 210 | // this->optimise(); 211 | 212 | // this is much faster, as it skips a lot of useless work 213 | // do the optimisation before inserting 214 | // Needs to be stored in a vector first as _M_optimise() 215 | // sorts the data in the passed iterators directly. 216 | std::vector temp; 217 | temp.reserve(__x.size()); 218 | std::copy(__x.begin(),__x.end(),std::back_inserter(temp)); 219 | efficient_replace_and_optimise(temp); 220 | } 221 | return *this; 222 | } 223 | 224 | ~KDTree() 225 | { 226 | this->clear(); 227 | } 228 | 229 | allocator_type 230 | get_allocator() const 231 | { 232 | return _Base::get_allocator(); 233 | } 234 | 235 | size_type 236 | size() const 237 | { 238 | return _M_count; 239 | } 240 | 241 | size_type 242 | max_size() const 243 | { 244 | return size_type(-1); 245 | } 246 | 247 | bool 248 | empty() const 249 | { 250 | return this->size() == 0; 251 | } 252 | 253 | void 254 | clear() 255 | { 256 | _M_erase_subtree(_M_get_root()); 257 | _M_set_leftmost(&_M_header); 258 | _M_set_rightmost(&_M_header); 259 | _M_set_root(NULL); 260 | _M_count = 0; 261 | } 262 | 263 | /*! \brief Comparator for the values in the KDTree. 264 | 265 | The comparator shall not be modified, it could invalidate the tree. 266 | \return a copy of the comparator used by the KDTree. 267 | */ 268 | _Cmp 269 | value_comp() const 270 | { return _M_cmp; } 271 | 272 | /*! \brief Accessor to the value's elements. 273 | 274 | This accessor shall not be modified, it could invalidate the tree. 275 | \return a copy of the accessor used by the KDTree. 276 | */ 277 | _Acc 278 | value_acc() const 279 | { return _M_acc; } 280 | 281 | /*! \brief Distance calculator between 2 value's element. 282 | 283 | This functor can be modified. It's modification will only affect the 284 | behavior of the find and find_nearest functions. 285 | \return a reference to the distance calculator used by the KDTree. 286 | */ 287 | const _Dist& 288 | value_distance() const 289 | { return _M_dist; } 290 | 291 | _Dist& 292 | value_distance() 293 | { return _M_dist; } 294 | 295 | // typedef _Iterator<_Val, reference, pointer> iterator; 296 | typedef _Iterator<_Val, const_reference, const_pointer> const_iterator; 297 | // No mutable iterator at this stage 298 | typedef const_iterator iterator; 299 | typedef std::reverse_iterator const_reverse_iterator; 300 | typedef std::reverse_iterator reverse_iterator; 301 | 302 | // Note: the static_cast in end() is invalid (_M_header is not convertable to a _Link_type), but 303 | // thats ok as it just means undefined behaviour if the user dereferences the end() iterator. 304 | 305 | const_iterator begin() const { return const_iterator(_M_get_leftmost()); } 306 | const_iterator end() const { return const_iterator(static_cast<_Link_const_type>(&_M_header)); } 307 | const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } 308 | const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } 309 | 310 | iterator 311 | insert(iterator /* ignored */, const_reference __V) 312 | { 313 | return this->insert(__V); 314 | } 315 | 316 | iterator 317 | insert(const_reference __V) 318 | { 319 | if (!_M_get_root()) 320 | { 321 | _Link_type __n = _M_new_node(__V, &_M_header); 322 | ++_M_count; 323 | _M_set_root(__n); 324 | _M_set_leftmost(__n); 325 | _M_set_rightmost(__n); 326 | return iterator(__n); 327 | } 328 | return _M_insert(_M_get_root(), __V, 0); 329 | } 330 | 331 | template 332 | void insert(_InputIterator __first, _InputIterator __last) { 333 | for (; __first != __last; ++__first) 334 | this->insert(*__first); 335 | } 336 | 337 | void 338 | insert(iterator __pos, size_type __n, const value_type& __x) 339 | { 340 | for (; __n > 0; --__n) 341 | this->insert(__pos, __x); 342 | } 343 | 344 | template 345 | void 346 | insert(iterator __pos, _InputIterator __first, _InputIterator __last) { 347 | for (; __first != __last; ++__first) 348 | this->insert(__pos, *__first); 349 | } 350 | 351 | // Note: this uses the find() to location the item you want to erase. 352 | // find() compares by equivalence of location ONLY. See the comments 353 | // above find_exact() for why you may not want this. 354 | // 355 | // If you want to erase ANY item that has the same location as __V, 356 | // then use this function. 357 | // 358 | // If you want to erase a PARTICULAR item, and not any other item 359 | // that might happen to have the same location, then you should use 360 | // erase_exact(). 361 | void 362 | erase(const_reference __V) { 363 | const_iterator b = this->find(__V); 364 | this->erase(b); 365 | } 366 | 367 | void 368 | erase_exact(const_reference __V) { 369 | this->erase(this->find_exact(__V)); 370 | } 371 | 372 | // note: kept as const because its easier to const-cast it away 373 | void 374 | erase(const_iterator const& __IT) 375 | { 376 | assert(__IT != this->end()); 377 | _Link_const_type target = __IT.get_raw_node(); 378 | _Link_const_type n = target; 379 | size_type level = 0; 380 | while ((n = _S_parent(n)) != &_M_header) 381 | ++level; 382 | _M_erase( const_cast<_Link_type>(target), level ); 383 | _M_delete_node( const_cast<_Link_type>(target) ); 384 | --_M_count; 385 | } 386 | 387 | /* this does not work since erasure changes sort order 388 | void 389 | erase(const_iterator __A, const_iterator const& __B) 390 | { 391 | if (0 && __A == this->begin() && __B == this->end()) 392 | { 393 | this->clear(); 394 | } 395 | else 396 | { 397 | while (__A != __B) 398 | this->erase(__A++); 399 | } 400 | } 401 | */ 402 | 403 | // compares via equivalence 404 | // so if you are looking for any item with the same location, 405 | // according to the standard accessor comparisions, 406 | // then this is the function for you. 407 | template 408 | const_iterator 409 | find(SearchVal const& __V) const 410 | { 411 | if (!_M_get_root()) return this->end(); 412 | return _M_find(_M_get_root(), __V, 0); 413 | } 414 | 415 | // compares via equality 416 | // if you are looking for a particular item in the tree, 417 | // and (for example) it has an ID that is checked via an == comparison 418 | // eg 419 | // struct Item 420 | // { 421 | // size_type unique_id; 422 | // bool operator==(Item const& a, Item const& b) { return a.unique_id == b.unique_id; } 423 | // Location location; 424 | // }; 425 | // Two items may be equivalent in location. find() would return 426 | // either one of them. But no two items have the same ID, so 427 | // find_exact() would always return the item with the same location AND id. 428 | // 429 | template 430 | const_iterator 431 | find_exact(SearchVal const& __V) const 432 | { 433 | if (!_M_get_root()) return this->end(); 434 | return _M_find_exact(_M_get_root(), __V, 0); 435 | } 436 | 437 | // NOTE: see notes on find_within_range(). 438 | size_type 439 | count_within_range(const_reference __V, subvalue_type const __R) const 440 | { 441 | if (!_M_get_root()) return 0; 442 | _Region_ __region(__V, __R, _M_acc, _M_cmp); 443 | return this->count_within_range(__region); 444 | } 445 | 446 | size_type 447 | count_within_range(_Region_ const& __REGION) const 448 | { 449 | if (!_M_get_root()) return 0; 450 | 451 | _Region_ __bounds(__REGION); 452 | return _M_count_within_range(_M_get_root(), 453 | __REGION, __bounds, 0); 454 | } 455 | 456 | // NOTE: see notes on find_within_range(). 457 | template 458 | Visitor 459 | visit_within_range(SearchVal const& V, subvalue_type const R, Visitor visitor) const 460 | { 461 | if (!_M_get_root()) return visitor; 462 | _Region_ region(V, R, _M_acc, _M_cmp); 463 | return this->visit_within_range(region, visitor); 464 | } 465 | 466 | template 467 | Visitor 468 | visit_within_range(_Region_ const& REGION, Visitor visitor) const 469 | { 470 | if (_M_get_root()) 471 | { 472 | _Region_ bounds(REGION); 473 | return _M_visit_within_range(visitor, _M_get_root(), REGION, bounds, 0); 474 | } 475 | return visitor; 476 | } 477 | 478 | // NOTE: this will visit points based on 'Manhattan distance' aka city-block distance 479 | // aka taxicab metric. Meaning it will find all points within: 480 | // max(x_dist,max(y_dist,z_dist)); 481 | // AND NOT than what you would expect: sqrt(x_dist*x_dist + y_dist*y_dist + z_dist*z_dist) 482 | // 483 | // This is because it converts the distance into a bounding-box 'region' and compares 484 | // against that. 485 | // 486 | // If you want the sqrt() behaviour, ask on the mailing list for different options. 487 | // 488 | template 489 | _OutputIterator 490 | find_within_range(SearchVal const& val, subvalue_type const range, 491 | _OutputIterator out) const 492 | { 493 | if (!_M_get_root()) return out; 494 | _Region_ region(val, range, _M_acc, _M_cmp); 495 | return this->find_within_range(region, out); 496 | } 497 | 498 | template 499 | _OutputIterator 500 | find_within_range(_Region_ const& region, 501 | _OutputIterator out) const 502 | { 503 | if (_M_get_root()) 504 | { 505 | _Region_ bounds(region); 506 | out = _M_find_within_range(out, _M_get_root(), 507 | region, bounds, 0); 508 | } 509 | return out; 510 | } 511 | 512 | template 513 | std::pair 514 | find_nearest (SearchVal const& __val) const 515 | { 516 | if (_M_get_root()) 517 | { 518 | std::pair*, 519 | std::pair > 520 | best = _S_node_nearest (__K, 0, __val, 521 | _M_get_root(), &_M_header, _M_get_root(), 522 | std::sqrt(_S_accumulate_node_distance 523 | (__K, _M_dist, _M_acc, _M_get_root()->_M_value, __val)), 524 | _M_cmp, _M_acc, _M_dist, 525 | always_true()); 526 | return std::pair 527 | (best.first, best.second.second); 528 | } 529 | return std::pair(end(), 0); 530 | } 531 | 532 | template 533 | std::pair 534 | find_nearest (SearchVal const& __val, distance_type __max) const 535 | { 536 | if (_M_get_root()) 537 | { 538 | bool root_is_candidate = false; 539 | const _Node<_Val>* node = _M_get_root(); 540 | { // scope to ensure we don't use 'root_dist' anywhere else 541 | distance_type root_dist = std::sqrt(_S_accumulate_node_distance 542 | (__K, _M_dist, _M_acc, _M_get_root()->_M_value, __val)); 543 | if (root_dist <= __max) 544 | { 545 | root_is_candidate = true; 546 | __max = root_dist; 547 | } 548 | } 549 | std::pair*, 550 | std::pair > 551 | best = _S_node_nearest (__K, 0, __val, _M_get_root(), &_M_header, 552 | node, __max, _M_cmp, _M_acc, _M_dist, 553 | always_true()); 554 | // make sure we didn't just get stuck with the root node... 555 | if (root_is_candidate || best.first != _M_get_root()) 556 | return std::pair 557 | (best.first, best.second.second); 558 | } 559 | return std::pair(end(), __max); 560 | } 561 | 562 | template 563 | std::pair 564 | find_nearest_if (SearchVal const& __val, distance_type __max, 565 | _Predicate __p) const 566 | { 567 | if (_M_get_root()) 568 | { 569 | bool root_is_candidate = false; 570 | const _Node<_Val>* node = _M_get_root(); 571 | if (__p(_M_get_root()->_M_value)) 572 | { 573 | { // scope to ensure we don't use root_dist anywhere else 574 | distance_type root_dist = std::sqrt(_S_accumulate_node_distance 575 | (__K, _M_dist, _M_acc, _M_get_root()->_M_value, __val)); 576 | if (root_dist <= __max) 577 | { 578 | root_is_candidate = true; 579 | root_dist = __max; 580 | } 581 | } 582 | } 583 | std::pair*, 584 | std::pair > 585 | best = _S_node_nearest (__K, 0, __val, _M_get_root(), &_M_header, 586 | node, __max, _M_cmp, _M_acc, _M_dist, __p); 587 | // make sure we didn't just get stuck with the root node... 588 | if (root_is_candidate || best.first != _M_get_root()) 589 | return std::pair 590 | (best.first, best.second.second); 591 | } 592 | return std::pair(end(), __max); 593 | } 594 | 595 | void 596 | optimise() 597 | { 598 | std::vector __v(this->begin(),this->end()); 599 | this->clear(); 600 | _M_optimise(__v.begin(), __v.end(), 0); 601 | } 602 | 603 | void 604 | optimize() 605 | { // cater for people who cannot spell :) 606 | this->optimise(); 607 | } 608 | 609 | void check_tree() 610 | { 611 | _M_check_node(_M_get_root(),0); 612 | } 613 | 614 | protected: 615 | 616 | void _M_check_children( _Link_const_type child, _Link_const_type parent, size_type const level, bool to_the_left ) 617 | { 618 | assert(parent); 619 | if (child) 620 | { 621 | _Node_compare_ compare(level % __K, _M_acc, _M_cmp); 622 | // REMEMBER! its a <= relationship for BOTH branches 623 | // for left-case (true), child<=node --> !(node !(child_M_value,child->_M_value)); // check the left 626 | assert(to_the_left || !compare(child->_M_value,parent->_M_value)); // check the right 627 | // and recurse down the tree, checking everything 628 | _M_check_children(_S_left(child),parent,level,to_the_left); 629 | _M_check_children(_S_right(child),parent,level,to_the_left); 630 | } 631 | } 632 | 633 | void _M_check_node( _Link_const_type node, size_type const level ) 634 | { 635 | if (node) 636 | { 637 | // (comparing on this level) 638 | // everything to the left of this node must be smaller than this 639 | _M_check_children( _S_left(node), node, level, true ); 640 | // everything to the right of this node must be larger than this 641 | _M_check_children( _S_right(node), node, level, false ); 642 | 643 | _M_check_node( _S_left(node), level+1 ); 644 | _M_check_node( _S_right(node), level+1 ); 645 | } 646 | } 647 | 648 | void _M_empty_initialise() 649 | { 650 | _M_set_leftmost(&_M_header); 651 | _M_set_rightmost(&_M_header); 652 | _M_header._M_parent = NULL; 653 | _M_set_root(NULL); 654 | } 655 | 656 | iterator 657 | _M_insert_left(_Link_type __N, const_reference __V) 658 | { 659 | _S_set_left(__N, _M_new_node(__V)); ++_M_count; 660 | _S_set_parent( _S_left(__N), __N ); 661 | if (__N == _M_get_leftmost()) 662 | _M_set_leftmost( _S_left(__N) ); 663 | return iterator(_S_left(__N)); 664 | } 665 | 666 | iterator 667 | _M_insert_right(_Link_type __N, const_reference __V) 668 | { 669 | _S_set_right(__N, _M_new_node(__V)); ++_M_count; 670 | _S_set_parent( _S_right(__N), __N ); 671 | if (__N == _M_get_rightmost()) 672 | _M_set_rightmost( _S_right(__N) ); 673 | return iterator(_S_right(__N)); 674 | } 675 | 676 | iterator 677 | _M_insert(_Link_type __N, const_reference __V, 678 | size_type const __L) 679 | { 680 | if (_Node_compare_(__L % __K, _M_acc, _M_cmp)(__V, __N->_M_value)) 681 | { 682 | if (!_S_left(__N)) 683 | return _M_insert_left(__N, __V); 684 | return _M_insert(_S_left(__N), __V, __L+1); 685 | } 686 | else 687 | { 688 | if (!_S_right(__N) || __N == _M_get_rightmost()) 689 | return _M_insert_right(__N, __V); 690 | return _M_insert(_S_right(__N), __V, __L+1); 691 | } 692 | } 693 | 694 | _Link_type 695 | _M_erase(_Link_type dead_dad, size_type const level) 696 | { 697 | // find a new step_dad, he will become a drop-in replacement. 698 | _Link_type step_dad = _M_get_erase_replacement(dead_dad, level); 699 | 700 | // tell dead_dad's parent that his new child is step_dad 701 | if (dead_dad == _M_get_root()) 702 | _M_set_root(step_dad); 703 | else if (_S_left(_S_parent(dead_dad)) == dead_dad) 704 | _S_set_left(_S_parent(dead_dad), step_dad); 705 | else 706 | _S_set_right(_S_parent(dead_dad), step_dad); 707 | 708 | // deal with the left and right edges of the tree... 709 | // if the dead_dad was at the edge, then substitude... 710 | // but if there IS no new dead, then left_most is the dead_dad's parent 711 | if (dead_dad == _M_get_leftmost()) 712 | _M_set_leftmost( (step_dad ? step_dad : _S_parent(dead_dad)) ); 713 | if (dead_dad == _M_get_rightmost()) 714 | _M_set_rightmost( (step_dad ? step_dad : _S_parent(dead_dad)) ); 715 | 716 | if (step_dad) 717 | { 718 | // step_dad gets dead_dad's parent 719 | _S_set_parent(step_dad, _S_parent(dead_dad)); 720 | 721 | // first tell the children that step_dad is their new dad 722 | if (_S_left(dead_dad)) 723 | _S_set_parent(_S_left(dead_dad), step_dad); 724 | if (_S_right(dead_dad)) 725 | _S_set_parent(_S_right(dead_dad), step_dad); 726 | 727 | // step_dad gets dead_dad's children 728 | _S_set_left(step_dad, _S_left(dead_dad)); 729 | _S_set_right(step_dad, _S_right(dead_dad)); 730 | } 731 | 732 | return step_dad; 733 | } 734 | 735 | 736 | 737 | _Link_type 738 | _M_get_erase_replacement(_Link_type node, size_type const level) 739 | { 740 | // if 'node' is null, then we can't do any better 741 | if (_S_is_leaf(node)) 742 | return NULL; 743 | 744 | std::pair<_Link_type,size_type> candidate; 745 | // if there is nothing to the left, find a candidate on the right tree 746 | if (!_S_left(node)) 747 | candidate = _M_get_j_min( std::pair<_Link_type,size_type>(_S_right(node),level), level+1); 748 | // ditto for the right 749 | else if ((!_S_right(node))) 750 | candidate = _M_get_j_max( std::pair<_Link_type,size_type>(_S_left(node),level), level+1); 751 | // we have both children ... 752 | else 753 | { 754 | // we need to do a little more work in order to find a good candidate 755 | // this is actually a technique used to choose a node from either the 756 | // left or right branch RANDOMLY, so that the tree has a greater change of 757 | // staying balanced. 758 | // If this were a true binary tree, we would always hunt down the right branch. 759 | // See top for notes. 760 | _Node_compare_ compare(level % __K, _M_acc, _M_cmp); 761 | // compare the children based on this level's criteria... 762 | // (this gives virtually random results) 763 | if (compare(_S_right(node)->_M_value, _S_left(node)->_M_value)) 764 | // the right is smaller, get our replacement from the SMALLEST on the right 765 | candidate = _M_get_j_min(std::pair<_Link_type,size_type>(_S_right(node),level), level+1); 766 | else 767 | candidate = _M_get_j_max( std::pair<_Link_type,size_type>(_S_left(node),level), level+1); 768 | } 769 | 770 | // we have a candidate replacement by now. 771 | // remove it from the tree, but don't delete it. 772 | // it must be disconnected before it can be reconnected. 773 | _Link_type parent = _S_parent(candidate.first); 774 | if (_S_left(parent) == candidate.first) 775 | _S_set_left(parent, _M_erase(candidate.first, candidate.second)); 776 | else 777 | _S_set_right(parent, _M_erase(candidate.first, candidate.second)); 778 | 779 | return candidate.first; 780 | } 781 | 782 | 783 | 784 | std::pair<_Link_type,size_type> 785 | _M_get_j_min( std::pair<_Link_type,size_type> const node, size_type const level) 786 | { 787 | typedef std::pair<_Link_type,size_type> Result; 788 | if (_S_is_leaf(node.first)) 789 | return Result(node.first,level); 790 | 791 | _Node_compare_ compare(node.second % __K, _M_acc, _M_cmp); 792 | Result candidate = node; 793 | if (_S_left(node.first)) 794 | { 795 | Result left = _M_get_j_min(Result(_S_left(node.first), node.second), level+1); 796 | if (compare(left.first->_M_value, candidate.first->_M_value)) 797 | candidate = left; 798 | } 799 | if (_S_right(node.first)) 800 | { 801 | Result right = _M_get_j_min( Result(_S_right(node.first),node.second), level+1); 802 | if (compare(right.first->_M_value, candidate.first->_M_value)) 803 | candidate = right; 804 | } 805 | if (candidate.first == node.first) 806 | return Result(candidate.first,level); 807 | 808 | return candidate; 809 | } 810 | 811 | 812 | 813 | std::pair<_Link_type,size_type> 814 | _M_get_j_max( std::pair<_Link_type,size_type> const node, size_type const level) 815 | { 816 | typedef std::pair<_Link_type,size_type> Result; 817 | 818 | if (_S_is_leaf(node.first)) 819 | return Result(node.first,level); 820 | 821 | _Node_compare_ compare(node.second % __K, _M_acc, _M_cmp); 822 | Result candidate = node; 823 | if (_S_left(node.first)) 824 | { 825 | Result left = _M_get_j_max( Result(_S_left(node.first),node.second), level+1); 826 | if (compare(candidate.first->_M_value, left.first->_M_value)) 827 | candidate = left; 828 | } 829 | if (_S_right(node.first)) 830 | { 831 | Result right = _M_get_j_max(Result(_S_right(node.first),node.second), level+1); 832 | if (compare(candidate.first->_M_value, right.first->_M_value)) 833 | candidate = right; 834 | } 835 | 836 | if (candidate.first == node.first) 837 | return Result(candidate.first,level); 838 | 839 | return candidate; 840 | } 841 | 842 | 843 | void 844 | _M_erase_subtree(_Link_type __n) 845 | { 846 | while (__n) 847 | { 848 | _M_erase_subtree(_S_right(__n)); 849 | _Link_type __t = _S_left(__n); 850 | _M_delete_node(__n); 851 | __n = __t; 852 | } 853 | } 854 | 855 | const_iterator 856 | _M_find(_Link_const_type node, const_reference value, size_type const level) const 857 | { 858 | // be aware! This is very different to normal binary searches, because of the <= 859 | // relationship used. See top for notes. 860 | // Basically we have to check ALL branches, as we may have an identical node 861 | // in different branches. 862 | const_iterator found = this->end(); 863 | 864 | _Node_compare_ compare(level % __K, _M_acc, _M_cmp); 865 | if (!compare(node->_M_value,value)) // note, this is a <= test 866 | { 867 | // this line is the only difference between _M_find_exact() and _M_find() 868 | if (_M_matches_node(node, value, level)) 869 | return const_iterator(node); // return right away 870 | if (_S_left(node)) 871 | found = _M_find(_S_left(node), value, level+1); 872 | } 873 | if ( _S_right(node) && found == this->end() && !compare(value,node->_M_value)) // note, this is a <= test 874 | found = _M_find(_S_right(node), value, level+1); 875 | return found; 876 | } 877 | 878 | const_iterator 879 | _M_find_exact(_Link_const_type node, const_reference value, size_type const level) const 880 | { 881 | // be aware! This is very different to normal binary searches, because of the <= 882 | // relationship used. See top for notes. 883 | // Basically we have to check ALL branches, as we may have an identical node 884 | // in different branches. 885 | const_iterator found = this->end(); 886 | 887 | _Node_compare_ compare(level % __K, _M_acc, _M_cmp); 888 | if (!compare(node->_M_value,value)) // note, this is a <= test 889 | { 890 | // this line is the only difference between _M_find_exact() and _M_find() 891 | if (value == *const_iterator(node)) 892 | return const_iterator(node); // return right away 893 | if (_S_left(node)) 894 | found = _M_find_exact(_S_left(node), value, level+1); 895 | } 896 | 897 | // note: no else! items that are identical can be down both branches 898 | if ( _S_right(node) && found == this->end() && !compare(value,node->_M_value)) // note, this is a <= test 899 | found = _M_find_exact(_S_right(node), value, level+1); 900 | return found; 901 | } 902 | 903 | bool 904 | _M_matches_node_in_d(_Link_const_type __N, const_reference __V, 905 | size_type const __L) const 906 | { 907 | _Node_compare_ compare(__L % __K, _M_acc, _M_cmp); 908 | return !(compare(__N->_M_value, __V) || compare(__V, __N->_M_value)); 909 | } 910 | 911 | bool 912 | _M_matches_node_in_other_ds(_Link_const_type __N, const_reference __V, 913 | size_type const __L = 0) const 914 | { 915 | size_type __i = __L; 916 | while ((__i = (__i + 1) % __K) != __L % __K) 917 | if (!_M_matches_node_in_d(__N, __V, __i)) return false; 918 | return true; 919 | } 920 | 921 | bool 922 | _M_matches_node(_Link_const_type __N, const_reference __V, 923 | size_type __L = 0) const 924 | { 925 | return _M_matches_node_in_d(__N, __V, __L) 926 | && _M_matches_node_in_other_ds(__N, __V, __L); 927 | } 928 | 929 | size_type 930 | _M_count_within_range(_Link_const_type __N, _Region_ const& __REGION, 931 | _Region_ const& __BOUNDS, 932 | size_type const __L) const 933 | { 934 | size_type count = 0; 935 | if (__REGION.encloses(_S_value(__N))) 936 | { 937 | ++count; 938 | } 939 | if (_S_left(__N)) 940 | { 941 | _Region_ __bounds(__BOUNDS); 942 | __bounds.set_high_bound(_S_value(__N), __L); 943 | if (__REGION.intersects_with(__bounds)) 944 | count += _M_count_within_range(_S_left(__N), 945 | __REGION, __bounds, __L+1); 946 | } 947 | if (_S_right(__N)) 948 | { 949 | _Region_ __bounds(__BOUNDS); 950 | __bounds.set_low_bound(_S_value(__N), __L); 951 | if (__REGION.intersects_with(__bounds)) 952 | count += _M_count_within_range(_S_right(__N), 953 | __REGION, __bounds, __L+1); 954 | } 955 | 956 | return count; 957 | } 958 | 959 | 960 | template 961 | Visitor 962 | _M_visit_within_range(Visitor visitor, 963 | _Link_const_type N, _Region_ const& REGION, 964 | _Region_ const& BOUNDS, 965 | size_type const L) const 966 | { 967 | if (REGION.encloses(_S_value(N))) 968 | { 969 | visitor(_S_value(N)); 970 | } 971 | if (_S_left(N)) 972 | { 973 | _Region_ bounds(BOUNDS); 974 | bounds.set_high_bound(_S_value(N), L); 975 | if (REGION.intersects_with(bounds)) 976 | visitor = _M_visit_within_range(visitor, _S_left(N), 977 | REGION, bounds, L+1); 978 | } 979 | if (_S_right(N)) 980 | { 981 | _Region_ bounds(BOUNDS); 982 | bounds.set_low_bound(_S_value(N), L); 983 | if (REGION.intersects_with(bounds)) 984 | visitor = _M_visit_within_range(visitor, _S_right(N), 985 | REGION, bounds, L+1); 986 | } 987 | 988 | return visitor; 989 | } 990 | 991 | 992 | 993 | template 994 | _OutputIterator 995 | _M_find_within_range(_OutputIterator out, 996 | _Link_const_type __N, _Region_ const& __REGION, 997 | _Region_ const& __BOUNDS, 998 | size_type const __L) const 999 | { 1000 | if (__REGION.encloses(_S_value(__N))) 1001 | { 1002 | *out++ = _S_value(__N); 1003 | } 1004 | if (_S_left(__N)) 1005 | { 1006 | _Region_ __bounds(__BOUNDS); 1007 | __bounds.set_high_bound(_S_value(__N), __L); 1008 | if (__REGION.intersects_with(__bounds)) 1009 | out = _M_find_within_range(out, _S_left(__N), 1010 | __REGION, __bounds, __L+1); 1011 | } 1012 | if (_S_right(__N)) 1013 | { 1014 | _Region_ __bounds(__BOUNDS); 1015 | __bounds.set_low_bound(_S_value(__N), __L); 1016 | if (__REGION.intersects_with(__bounds)) 1017 | out = _M_find_within_range(out, _S_right(__N), 1018 | __REGION, __bounds, __L+1); 1019 | } 1020 | 1021 | return out; 1022 | } 1023 | 1024 | 1025 | template 1026 | void 1027 | _M_optimise(_Iter const& __A, _Iter const& __B, 1028 | size_type const __L) 1029 | { 1030 | if (__A == __B) return; 1031 | _Node_compare_ compare(__L % __K, _M_acc, _M_cmp); 1032 | _Iter __m = __A + (__B - __A) / 2; 1033 | std::nth_element(__A, __m, __B, compare); 1034 | this->insert(*__m); 1035 | if (__m != __A) _M_optimise(__A, __m, __L+1); 1036 | if (++__m != __B) _M_optimise(__m, __B, __L+1); 1037 | } 1038 | 1039 | _Link_const_type 1040 | _M_get_root() const 1041 | { 1042 | return const_cast<_Link_const_type>(_M_root); 1043 | } 1044 | 1045 | _Link_type 1046 | _M_get_root() 1047 | { 1048 | return _M_root; 1049 | } 1050 | 1051 | void _M_set_root(_Link_type n) 1052 | { 1053 | _M_root = n; 1054 | } 1055 | 1056 | _Link_const_type 1057 | _M_get_leftmost() const 1058 | { 1059 | return static_cast<_Link_type>(_M_header._M_left); 1060 | } 1061 | 1062 | void 1063 | _M_set_leftmost( _Node_base * a ) 1064 | { 1065 | _M_header._M_left = a; 1066 | } 1067 | 1068 | _Link_const_type 1069 | _M_get_rightmost() const 1070 | { 1071 | return static_cast<_Link_type>( _M_header._M_right ); 1072 | } 1073 | 1074 | void 1075 | _M_set_rightmost( _Node_base * a ) 1076 | { 1077 | _M_header._M_right = a; 1078 | } 1079 | 1080 | static _Link_type 1081 | _S_parent(_Base_ptr N) 1082 | { 1083 | return static_cast<_Link_type>( N->_M_parent ); 1084 | } 1085 | 1086 | static _Link_const_type 1087 | _S_parent(_Base_const_ptr N) 1088 | { 1089 | return static_cast<_Link_const_type>( N->_M_parent ); 1090 | } 1091 | 1092 | static void 1093 | _S_set_parent(_Base_ptr N, _Base_ptr p) 1094 | { 1095 | N->_M_parent = p; 1096 | } 1097 | 1098 | static void 1099 | _S_set_left(_Base_ptr N, _Base_ptr l) 1100 | { 1101 | N->_M_left = l; 1102 | } 1103 | 1104 | static _Link_type 1105 | _S_left(_Base_ptr N) 1106 | { 1107 | return static_cast<_Link_type>( N->_M_left ); 1108 | } 1109 | 1110 | static _Link_const_type 1111 | _S_left(_Base_const_ptr N) 1112 | { 1113 | return static_cast<_Link_const_type>( N->_M_left ); 1114 | } 1115 | 1116 | static void 1117 | _S_set_right(_Base_ptr N, _Base_ptr r) 1118 | { 1119 | N->_M_right = r; 1120 | } 1121 | 1122 | static _Link_type 1123 | _S_right(_Base_ptr N) 1124 | { 1125 | return static_cast<_Link_type>( N->_M_right ); 1126 | } 1127 | 1128 | static _Link_const_type 1129 | _S_right(_Base_const_ptr N) 1130 | { 1131 | return static_cast<_Link_const_type>( N->_M_right ); 1132 | } 1133 | 1134 | static bool 1135 | _S_is_leaf(_Base_const_ptr N) 1136 | { 1137 | return !_S_left(N) && !_S_right(N); 1138 | } 1139 | 1140 | static const_reference 1141 | _S_value(_Link_const_type N) 1142 | { 1143 | return N->_M_value; 1144 | } 1145 | 1146 | static const_reference 1147 | _S_value(_Base_const_ptr N) 1148 | { 1149 | return static_cast<_Link_const_type>(N)->_M_value; 1150 | } 1151 | 1152 | static _Link_const_type 1153 | _S_minimum(_Link_const_type __X) 1154 | { 1155 | return static_cast<_Link_const_type> ( _Node_base::_S_minimum(__X) ); 1156 | } 1157 | 1158 | static _Link_const_type 1159 | _S_maximum(_Link_const_type __X) 1160 | { 1161 | return static_cast<_Link_const_type>( _Node_base::_S_maximum(__X) ); 1162 | } 1163 | 1164 | 1165 | _Link_type 1166 | _M_new_node(const_reference __V, // = value_type(), 1167 | _Base_ptr const __PARENT = NULL, 1168 | _Base_ptr const __LEFT = NULL, 1169 | _Base_ptr const __RIGHT = NULL) 1170 | { 1171 | typename _Base::NoLeakAlloc noleak(this); 1172 | _Link_type new_node = noleak.get(); 1173 | _Base::_M_construct_node(new_node, __V, __PARENT, __LEFT, __RIGHT); 1174 | noleak.disconnect(); 1175 | return new_node; 1176 | } 1177 | 1178 | /* WHAT was this for? 1179 | _Link_type 1180 | _M_clone_node(_Link_const_type __X) 1181 | { 1182 | _Link_type __ret = _M_allocate_node(__X->_M_value); 1183 | // TODO 1184 | return __ret; 1185 | } 1186 | */ 1187 | 1188 | void 1189 | _M_delete_node(_Link_type __p) 1190 | { 1191 | _Base::_M_destroy_node(__p); 1192 | _Base::_M_deallocate_node(__p); 1193 | } 1194 | 1195 | _Link_type _M_root; 1196 | _Node_base _M_header; 1197 | size_type _M_count; 1198 | _Acc _M_acc; 1199 | _Cmp _M_cmp; 1200 | _Dist _M_dist; 1201 | 1202 | #ifdef KDTREE_DEFINE_OSTREAM_OPERATORS 1203 | friend std::ostream& 1204 | operator<<(std::ostream& o, 1205 | KDTree<__K, _Val, _Acc, _Dist, _Cmp, _Alloc> const& tree) 1206 | { 1207 | o << "meta node: " << tree._M_header << std::endl; 1208 | o << "root node: " << tree._M_root << std::endl; 1209 | 1210 | if (tree.empty()) 1211 | return o << "[empty " << __K << "d-tree " << &tree << "]"; 1212 | 1213 | o << "nodes total: " << tree.size() << std::endl; 1214 | o << "dimensions: " << __K << std::endl; 1215 | 1216 | typedef KDTree<__K, _Val, _Acc, _Dist, _Cmp, _Alloc> _Tree; 1217 | 1218 | std::stack<_Link_const_type> s; 1219 | s.push(tree._M_get_root()); 1220 | 1221 | while (!s.empty()) 1222 | { 1223 | _Link_const_type n = s.top(); 1224 | s.pop(); 1225 | o << *n << std::endl; 1226 | if (_Tree::_S_left(n)) s.push(_Tree::_S_left(n)); 1227 | if (_Tree::_S_right(n)) s.push(_Tree::_S_right(n)); 1228 | } 1229 | 1230 | return o; 1231 | } 1232 | #endif 1233 | 1234 | }; // class KDTree 1235 | 1236 | 1237 | } // namespace KDTree 1238 | 1239 | #endif // include guard 1240 | 1241 | /* COPYRIGHT -- 1242 | * 1243 | * This file is part of libkdtree++, a C++ template KD-Tree sorting container. 1244 | * libkdtree++ is (c) 2004-2007 Martin F. Krafft 1245 | * and Sylvain Bougerel distributed under the 1246 | * terms of the Artistic License 2.0. See the ./COPYING file in the source tree 1247 | * root for more information. 1248 | * Parts of this file are (c) 2004-2007 Paul Harris . 1249 | * 1250 | * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 1251 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 1252 | * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1253 | */ 1254 | -------------------------------------------------------------------------------- /kdtree++/node.hpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Defines interfaces for nodes as used by the KDTree class. 3 | * 4 | * \author Martin F. Krafft 5 | */ 6 | 7 | #ifndef INCLUDE_KDTREE_NODE_HPP 8 | #define INCLUDE_KDTREE_NODE_HPP 9 | 10 | #ifdef KDTREE_DEFINE_OSTREAM_OPERATORS 11 | # include 12 | #endif 13 | 14 | #include 15 | #include 16 | 17 | namespace KDTree 18 | { 19 | struct _Node_base 20 | { 21 | typedef _Node_base* _Base_ptr; 22 | typedef _Node_base const* _Base_const_ptr; 23 | 24 | _Base_ptr _M_parent; 25 | _Base_ptr _M_left; 26 | _Base_ptr _M_right; 27 | 28 | _Node_base(_Base_ptr const __PARENT = NULL, 29 | _Base_ptr const __LEFT = NULL, 30 | _Base_ptr const __RIGHT = NULL) 31 | : _M_parent(__PARENT), _M_left(__LEFT), _M_right(__RIGHT) {} 32 | 33 | static _Base_ptr 34 | _S_minimum(_Base_ptr __x) 35 | { 36 | while (__x->_M_left) __x = __x->_M_left; 37 | return __x; 38 | } 39 | 40 | static _Base_ptr 41 | _S_maximum(_Base_ptr __x) 42 | { 43 | while (__x->_M_right) __x = __x->_M_right; 44 | return __x; 45 | } 46 | 47 | #ifdef KDTREE_DEFINE_OSTREAM_OPERATORS 48 | template 49 | friend 50 | std::basic_ostream& 51 | operator<<(typename std::basic_ostream& out, 52 | _Node_base const& node) 53 | { 54 | out << &node; 55 | out << " parent: " << node._M_parent; 56 | out << "; left: " << node._M_left; 57 | out << "; right: " << node._M_right; 58 | return out; 59 | } 60 | #endif 61 | }; 62 | 63 | template 64 | struct _Node : public _Node_base 65 | { 66 | using _Node_base::_Base_ptr; 67 | typedef _Node* _Link_type; 68 | 69 | _Val _M_value; 70 | 71 | _Node(_Val const& __VALUE = _Val(), 72 | _Base_ptr const __PARENT = NULL, 73 | _Base_ptr const __LEFT = NULL, 74 | _Base_ptr const __RIGHT = NULL) 75 | : _Node_base(__PARENT, __LEFT, __RIGHT), _M_value(__VALUE) {} 76 | 77 | #ifdef KDTREE_DEFINE_OSTREAM_OPERATORS 78 | template 79 | friend 80 | std::basic_ostream& 81 | operator<<(typename std::basic_ostream& out, 82 | _Node<_Val> const& node) 83 | { 84 | out << &node; 85 | out << ' ' << node._M_value; 86 | out << "; parent: " << node._M_parent; 87 | out << "; left: " << node._M_left; 88 | out << "; right: " << node._M_right; 89 | return out; 90 | } 91 | #endif 92 | }; 93 | 94 | template 95 | class _Node_compare 96 | { 97 | public: 98 | _Node_compare(size_t const __DIM, _Acc const& acc, _Cmp const& cmp) 99 | : _M_DIM(__DIM), _M_acc(acc), _M_cmp(cmp) {} 100 | 101 | bool 102 | operator()(_Val const& __A, _Val const& __B) const 103 | { 104 | return _M_cmp(_M_acc(__A, _M_DIM), _M_acc(__B, _M_DIM)); 105 | } 106 | 107 | private: 108 | size_t _M_DIM; // don't make this const so that an assignment operator can be auto-generated 109 | _Acc _M_acc; 110 | _Cmp _M_cmp; 111 | }; 112 | 113 | /*! Compare two values on the same dimension using a comparison functor _Cmp 114 | and an accessor _Acc. 115 | 116 | The comparison functor and the accessor are references to the template 117 | parameters of the KDTree. 118 | */ 119 | template 121 | inline 122 | bool 123 | _S_node_compare (const size_t __dim, 124 | const _Cmp& __cmp, const _Acc& __acc, 125 | const _ValA& __a, const _ValB& __b) 126 | { 127 | return __cmp(__acc(__a, __dim), __acc(__b, __dim)); 128 | } 129 | 130 | /*! Compute the distance between two values for one dimension only. 131 | 132 | The distance functor and the accessor are references to the template 133 | parameters of the KDTree. 134 | */ 135 | template 137 | inline 138 | typename _Dist::distance_type 139 | _S_node_distance (const size_t __dim, 140 | const _Dist& __dist, const _Acc& __acc, 141 | const _ValA& __a, const _ValB& __b) 142 | { 143 | return __dist(__acc(__a, __dim), __acc(__b, __dim)); 144 | } 145 | 146 | /*! Compute the distance between two values and accumulate the result for all 147 | dimensions. 148 | 149 | The distance functor and the accessor are references to the template 150 | parameters of the KDTree. 151 | */ 152 | template 154 | inline 155 | typename _Dist::distance_type 156 | _S_accumulate_node_distance (const size_t __dim, 157 | const _Dist& __dist, const _Acc& __acc, 158 | const _ValA& __a, const _ValB& __b) 159 | { 160 | typename _Dist::distance_type d = 0; 161 | for (size_t i=0; i<__dim; ++i) 162 | d += __dist(__acc(__a, i), __acc(__b, i)); 163 | return d; 164 | } 165 | 166 | /*! Descend on the left or the right of the node according to the comparison 167 | between the node's value and the value. 168 | 169 | \note it's the caller responsibility to check if node is NULL. 170 | */ 171 | template 172 | inline 173 | const NodeType* 174 | _S_node_descend (const size_t __dim, 175 | const _Cmp& __cmp, const _Acc& __acc, 176 | const _Val& __val, const NodeType* __node) 177 | { 178 | if (_S_node_compare(__dim, __cmp, __acc, __val, __node->_M_value)) 179 | return static_cast(__node->_M_left); 180 | return static_cast(__node->_M_right); 181 | } 182 | 183 | /*! Find the nearest node to __val from __node 184 | 185 | If many nodes are equidistant to __val, the node with the lowest memory 186 | address is returned. 187 | 188 | \return the nearest node of __end node if no nearest node was found for the 189 | given arguments. 190 | */ 191 | template 195 | inline 196 | std::pair > 198 | _S_node_nearest (const size_t __k, size_t __dim, SearchVal const& __val, 199 | const NodeType* __node, const _Node_base* __end, 200 | const NodeType* __best, typename _Dist::distance_type __max, 201 | const _Cmp& __cmp, const _Acc& __acc, const _Dist& __dist, 202 | _Predicate __p) 203 | { 204 | typedef const NodeType* NodePtr; 205 | NodePtr pcur = __node; 206 | NodePtr cur = _S_node_descend(__dim % __k, __cmp, __acc, __val, __node); 207 | size_t cur_dim = __dim+1; 208 | // find the smallest __max distance in direct descent 209 | while (cur) 210 | { 211 | if (__p(cur->_M_value)) 212 | { 213 | typename _Dist::distance_type d = 0; 214 | for (size_t i=0; i != __k; ++i) 215 | d += _S_node_distance(i, __dist, __acc, __val, cur->_M_value); 216 | d = std::sqrt(d); 217 | if (d <= __max) 218 | // ("bad candidate notes") 219 | // Changed: removed this test: || ( d == __max && cur < __best )) 220 | // Can't do this optimisation without checking that the current 'best' is not the root AND is not a valid candidate... 221 | // This is because find_nearest() etc will call this function with the best set to _M_root EVEN IF _M_root is not a valid answer (eg too far away or doesn't pass the predicate test) 222 | { 223 | __best = cur; 224 | __max = d; 225 | __dim = cur_dim; 226 | } 227 | } 228 | pcur = cur; 229 | cur = _S_node_descend(cur_dim % __k, __cmp, __acc, __val, cur); 230 | ++cur_dim; 231 | } 232 | // Swap cur to prev, only prev is a valid node. 233 | cur = pcur; 234 | --cur_dim; 235 | pcur = NULL; 236 | // Probe all node's children not visited yet (siblings of the visited nodes). 237 | NodePtr probe = cur; 238 | NodePtr pprobe = probe; 239 | NodePtr near_node; 240 | NodePtr far_node; 241 | size_t probe_dim = cur_dim; 242 | if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, probe->_M_value)) 243 | near_node = static_cast(probe->_M_right); 244 | else 245 | near_node = static_cast(probe->_M_left); 246 | if (near_node 247 | // only visit node's children if node's plane intersect hypersphere 248 | && (std::sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, probe->_M_value)) <= __max)) 249 | { 250 | probe = near_node; 251 | ++probe_dim; 252 | } 253 | while (cur != __end) 254 | { 255 | while (probe != cur) 256 | { 257 | if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, probe->_M_value)) 258 | { 259 | near_node = static_cast(probe->_M_left); 260 | far_node = static_cast(probe->_M_right); 261 | } 262 | else 263 | { 264 | near_node = static_cast(probe->_M_right); 265 | far_node = static_cast(probe->_M_left); 266 | } 267 | if (pprobe == probe->_M_parent) // going downward ... 268 | { 269 | if (__p(probe->_M_value)) 270 | { 271 | typename _Dist::distance_type d = 0; 272 | for (size_t i=0; i < __k; ++i) 273 | d += _S_node_distance(i, __dist, __acc, __val, probe->_M_value); 274 | d = std::sqrt(d); 275 | if (d <= __max) // CHANGED, see the above notes ("bad candidate notes") 276 | { 277 | __best = probe; 278 | __max = d; 279 | __dim = probe_dim; 280 | } 281 | } 282 | pprobe = probe; 283 | if (near_node) 284 | { 285 | probe = near_node; 286 | ++probe_dim; 287 | } 288 | else if (far_node && 289 | // only visit node's children if node's plane intersect hypersphere 290 | std::sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, probe->_M_value)) <= __max) 291 | { 292 | probe = far_node; 293 | ++probe_dim; 294 | } 295 | else 296 | { 297 | probe = static_cast(probe->_M_parent); 298 | --probe_dim; 299 | } 300 | } 301 | else // ... and going upward. 302 | { 303 | if (pprobe == near_node && far_node 304 | // only visit node's children if node's plane intersect hypersphere 305 | && std::sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, probe->_M_value)) <= __max) 306 | { 307 | pprobe = probe; 308 | probe = far_node; 309 | ++probe_dim; 310 | } 311 | else 312 | { 313 | pprobe = probe; 314 | probe = static_cast(probe->_M_parent); 315 | --probe_dim; 316 | } 317 | } 318 | } 319 | pcur = cur; 320 | cur = static_cast(cur->_M_parent); 321 | --cur_dim; 322 | pprobe = cur; 323 | probe = cur; 324 | probe_dim = cur_dim; 325 | if (cur != __end) 326 | { 327 | if (pcur == cur->_M_left) 328 | near_node = static_cast(cur->_M_right); 329 | else 330 | near_node = static_cast(cur->_M_left); 331 | if (near_node 332 | // only visit node's children if node's plane intersect hypersphere 333 | && (std::sqrt(_S_node_distance(cur_dim % __k, __dist, __acc, __val, cur->_M_value)) <= __max)) 334 | { 335 | probe = near_node; 336 | ++probe_dim; 337 | } 338 | } 339 | } 340 | return std::pair > 342 | (__best, std::pair 343 | (__dim, __max)); 344 | } 345 | 346 | 347 | } // namespace KDTree 348 | 349 | #endif // include guard 350 | 351 | /* COPYRIGHT -- 352 | * 353 | * This file is part of libkdtree++, a C++ template KD-Tree sorting container. 354 | * libkdtree++ is (c) 2004-2007 Martin F. Krafft 355 | * and Sylvain Bougerel distributed under the 356 | * terms of the Artistic License 2.0. See the ./COPYING file in the source tree 357 | * root for more information. 358 | * 359 | * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 360 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 361 | * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 362 | */ 363 | -------------------------------------------------------------------------------- /kdtree++/region.hpp: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Defines the interface of the _Region class. 3 | * 4 | * \author Martin F. Krafft 5 | */ 6 | 7 | #ifndef INCLUDE_KDTREE_REGION_HPP 8 | #define INCLUDE_KDTREE_REGION_HPP 9 | 10 | #include 11 | 12 | #include "node.hpp" 13 | 14 | namespace KDTree 15 | { 16 | 17 | template 19 | struct _Region 20 | { 21 | typedef _Val value_type; 22 | typedef _SubVal subvalue_type; 23 | 24 | // special typedef for checking against a fuzzy point (for find_nearest) 25 | // Note the region (first) component is not supposed to have an area, its 26 | // bounds should all be set to a specific point. 27 | typedef std::pair<_Region,_SubVal> _CenterPt; 28 | 29 | _Region(_Acc const& __acc=_Acc(), const _Cmp& __cmp=_Cmp()) 30 | : _M_acc(__acc), _M_cmp(__cmp) {} 31 | 32 | template 33 | _Region(Val const& __V, 34 | _Acc const& __acc=_Acc(), const _Cmp& __cmp=_Cmp()) 35 | : _M_acc(__acc), _M_cmp(__cmp) 36 | { 37 | for (size_t __i = 0; __i != __K; ++__i) 38 | { 39 | _M_low_bounds[__i] = _M_high_bounds[__i] = _M_acc(__V,__i); 40 | } 41 | } 42 | 43 | template 44 | _Region(Val const& __V, subvalue_type const& __R, 45 | _Acc const& __acc=_Acc(), const _Cmp& __cmp=_Cmp()) 46 | : _M_acc(__acc), _M_cmp(__cmp) 47 | { 48 | for (size_t __i = 0; __i != __K; ++__i) 49 | { 50 | _M_low_bounds[__i] = _M_acc(__V,__i) - __R; 51 | _M_high_bounds[__i] = _M_acc(__V,__i) + __R; 52 | } 53 | } 54 | 55 | bool 56 | intersects_with(_CenterPt const& __THAT) const 57 | { 58 | for (size_t __i = 0; __i != __K; ++__i) 59 | { 60 | // does it fall outside the bounds? 61 | // ! low-tolerance <= x <= high+tolerance 62 | // ! (low-tol <= x and x <= high+tol) 63 | // !low-tol<=x or !x<=high+tol 64 | // low-tol>x or x>high+tol 65 | // x 124 | * and Sylvain Bougerel distributed under the 125 | * terms of the Artistic License 2.0. See the ./COPYING file in the source tree 126 | * root for more information. 127 | * 128 | * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 129 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 130 | * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 131 | */ 132 | -------------------------------------------------------------------------------- /libkdtree.nix: -------------------------------------------------------------------------------- 1 | { lib 2 | , stdenv 3 | , cmake 4 | , doxygen 5 | }: 6 | 7 | stdenv.mkDerivation (finalAttrs: { 8 | name = "libkdtree++"; 9 | version = "0.7.3"; 10 | 11 | src = builtins.path { name = "libkdtree++"; path = ./.; }; 12 | 13 | nativeBuildInputs = [ 14 | cmake 15 | doxygen 16 | ]; 17 | 18 | buildPhase = '' 19 | make 20 | doxygen ../doc/Doxyfile 21 | ''; 22 | 23 | doCheck = true; 24 | checkPhase = '' 25 | echo Test test_kdtree 26 | ./examples/test_kdtree 27 | echo Test test_hayne 28 | ./examples/test_hayne 29 | echo Test test_find_within_range 30 | ./examples/test_find_within_range 31 | ''; 32 | 33 | installPhase = '' 34 | mkdir -p $out/include/kdtree++ 35 | cp -r $src/kdtree++/*.hpp $out/include/kdtree++/ 36 | 37 | mkdir -p $out/share/doc/libkdtree++ 38 | cp $src/doc/index.txt $out/share/doc/libkdtree++ 39 | cp -r documentation $out/share/doc/libkdtree++/ 40 | 41 | mkdir -p $out/share/doc/libkdtree++/examples 42 | cp -r $src/examples/*.cpp $out/share/doc/libkdtree++/examples 43 | 44 | ''; 45 | 46 | meta = with lib; { 47 | description = "STL-like C++ template container implementatin of a kd-tree."; 48 | longDescription = '' 49 | STL-like C++ template container implementation of k-dimensional space 50 | sorting, using a kd-tree. 51 | It sports a theoretically unlimited number of dimensions, and can store 52 | any data structure. 53 | Fork of the project once available from http://libkdtree.alioth.debian.org/ 54 | ''; 55 | homepage = "https://github.com/nvmd/libkdtree/"; 56 | license = licenses.artistic2; 57 | platforms = platforms.all; 58 | }; 59 | }) 60 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common stub for a few missing GNU programs while installing. 3 | 4 | scriptversion=2006-05-10.23 5 | 6 | # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 7 | # Free Software Foundation, Inc. 8 | # Originally by Fran,cois Pinard , 1996. 9 | 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 23 | # 02110-1301, USA. 24 | 25 | # As a special exception to the GNU General Public License, if you 26 | # distribute this file as part of a program that contains a 27 | # configuration script generated by Autoconf, you may include it under 28 | # the same distribution terms that you use for the rest of that program. 29 | 30 | if test $# -eq 0; then 31 | echo 1>&2 "Try \`$0 --help' for more information" 32 | exit 1 33 | fi 34 | 35 | run=: 36 | sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' 37 | sed_minuso='s/.* -o \([^ ]*\).*/\1/p' 38 | 39 | # In the cases where this matters, `missing' is being run in the 40 | # srcdir already. 41 | if test -f configure.ac; then 42 | configure_ac=configure.ac 43 | else 44 | configure_ac=configure.in 45 | fi 46 | 47 | msg="missing on your system" 48 | 49 | case $1 in 50 | --run) 51 | # Try to run requested program, and just exit if it succeeds. 52 | run= 53 | shift 54 | "$@" && exit 0 55 | # Exit code 63 means version mismatch. This often happens 56 | # when the user try to use an ancient version of a tool on 57 | # a file that requires a minimum version. In this case we 58 | # we should proceed has if the program had been absent, or 59 | # if --run hadn't been passed. 60 | if test $? = 63; then 61 | run=: 62 | msg="probably too old" 63 | fi 64 | ;; 65 | 66 | -h|--h|--he|--hel|--help) 67 | echo "\ 68 | $0 [OPTION]... PROGRAM [ARGUMENT]... 69 | 70 | Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an 71 | error status if there is no known handling for PROGRAM. 72 | 73 | Options: 74 | -h, --help display this help and exit 75 | -v, --version output version information and exit 76 | --run try to run the given command, and emulate it if it fails 77 | 78 | Supported PROGRAM values: 79 | aclocal touch file \`aclocal.m4' 80 | autoconf touch file \`configure' 81 | autoheader touch file \`config.h.in' 82 | autom4te touch the output file, or create a stub one 83 | automake touch all \`Makefile.in' files 84 | bison create \`y.tab.[ch]', if possible, from existing .[ch] 85 | flex create \`lex.yy.c', if possible, from existing .c 86 | help2man touch the output file 87 | lex create \`lex.yy.c', if possible, from existing .c 88 | makeinfo touch the output file 89 | tar try tar, gnutar, gtar, then tar without non-portable flags 90 | yacc create \`y.tab.[ch]', if possible, from existing .[ch] 91 | 92 | Send bug reports to ." 93 | exit $? 94 | ;; 95 | 96 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 97 | echo "missing $scriptversion (GNU Automake)" 98 | exit $? 99 | ;; 100 | 101 | -*) 102 | echo 1>&2 "$0: Unknown \`$1' option" 103 | echo 1>&2 "Try \`$0 --help' for more information" 104 | exit 1 105 | ;; 106 | 107 | esac 108 | 109 | # Now exit if we have it, but it failed. Also exit now if we 110 | # don't have it and --version was passed (most likely to detect 111 | # the program). 112 | case $1 in 113 | lex|yacc) 114 | # Not GNU programs, they don't have --version. 115 | ;; 116 | 117 | tar) 118 | if test -n "$run"; then 119 | echo 1>&2 "ERROR: \`tar' requires --run" 120 | exit 1 121 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 122 | exit 1 123 | fi 124 | ;; 125 | 126 | *) 127 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 128 | # We have it, but it failed. 129 | exit 1 130 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 131 | # Could not run --version or --help. This is probably someone 132 | # running `$TOOL --version' or `$TOOL --help' to check whether 133 | # $TOOL exists and not knowing $TOOL uses missing. 134 | exit 1 135 | fi 136 | ;; 137 | esac 138 | 139 | # If it does not exist, or fails to run (possibly an outdated version), 140 | # try to emulate it. 141 | case $1 in 142 | aclocal*) 143 | echo 1>&2 "\ 144 | WARNING: \`$1' is $msg. You should only need it if 145 | you modified \`acinclude.m4' or \`${configure_ac}'. You might want 146 | to install the \`Automake' and \`Perl' packages. Grab them from 147 | any GNU archive site." 148 | touch aclocal.m4 149 | ;; 150 | 151 | autoconf) 152 | echo 1>&2 "\ 153 | WARNING: \`$1' is $msg. You should only need it if 154 | you modified \`${configure_ac}'. You might want to install the 155 | \`Autoconf' and \`GNU m4' packages. Grab them from any GNU 156 | archive site." 157 | touch configure 158 | ;; 159 | 160 | autoheader) 161 | echo 1>&2 "\ 162 | WARNING: \`$1' is $msg. You should only need it if 163 | you modified \`acconfig.h' or \`${configure_ac}'. You might want 164 | to install the \`Autoconf' and \`GNU m4' packages. Grab them 165 | from any GNU archive site." 166 | files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` 167 | test -z "$files" && files="config.h" 168 | touch_files= 169 | for f in $files; do 170 | case $f in 171 | *:*) touch_files="$touch_files "`echo "$f" | 172 | sed -e 's/^[^:]*://' -e 's/:.*//'`;; 173 | *) touch_files="$touch_files $f.in";; 174 | esac 175 | done 176 | touch $touch_files 177 | ;; 178 | 179 | automake*) 180 | echo 1>&2 "\ 181 | WARNING: \`$1' is $msg. You should only need it if 182 | you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. 183 | You might want to install the \`Automake' and \`Perl' packages. 184 | Grab them from any GNU archive site." 185 | find . -type f -name Makefile.am -print | 186 | sed 's/\.am$/.in/' | 187 | while read f; do touch "$f"; done 188 | ;; 189 | 190 | autom4te) 191 | echo 1>&2 "\ 192 | WARNING: \`$1' is needed, but is $msg. 193 | You might have modified some files without having the 194 | proper tools for further handling them. 195 | You can get \`$1' as part of \`Autoconf' from any GNU 196 | archive site." 197 | 198 | file=`echo "$*" | sed -n "$sed_output"` 199 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 200 | if test -f "$file"; then 201 | touch $file 202 | else 203 | test -z "$file" || exec >$file 204 | echo "#! /bin/sh" 205 | echo "# Created by GNU Automake missing as a replacement of" 206 | echo "# $ $@" 207 | echo "exit 0" 208 | chmod +x $file 209 | exit 1 210 | fi 211 | ;; 212 | 213 | bison|yacc) 214 | echo 1>&2 "\ 215 | WARNING: \`$1' $msg. You should only need it if 216 | you modified a \`.y' file. You may need the \`Bison' package 217 | in order for those modifications to take effect. You can get 218 | \`Bison' from any GNU archive site." 219 | rm -f y.tab.c y.tab.h 220 | if test $# -ne 1; then 221 | eval LASTARG="\${$#}" 222 | case $LASTARG in 223 | *.y) 224 | SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 225 | if test -f "$SRCFILE"; then 226 | cp "$SRCFILE" y.tab.c 227 | fi 228 | SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` 229 | if test -f "$SRCFILE"; then 230 | cp "$SRCFILE" y.tab.h 231 | fi 232 | ;; 233 | esac 234 | fi 235 | if test ! -f y.tab.h; then 236 | echo >y.tab.h 237 | fi 238 | if test ! -f y.tab.c; then 239 | echo 'main() { return 0; }' >y.tab.c 240 | fi 241 | ;; 242 | 243 | lex|flex) 244 | echo 1>&2 "\ 245 | WARNING: \`$1' is $msg. You should only need it if 246 | you modified a \`.l' file. You may need the \`Flex' package 247 | in order for those modifications to take effect. You can get 248 | \`Flex' from any GNU archive site." 249 | rm -f lex.yy.c 250 | if test $# -ne 1; then 251 | eval LASTARG="\${$#}" 252 | case $LASTARG in 253 | *.l) 254 | SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` 255 | if test -f "$SRCFILE"; then 256 | cp "$SRCFILE" lex.yy.c 257 | fi 258 | ;; 259 | esac 260 | fi 261 | if test ! -f lex.yy.c; then 262 | echo 'main() { return 0; }' >lex.yy.c 263 | fi 264 | ;; 265 | 266 | help2man) 267 | echo 1>&2 "\ 268 | WARNING: \`$1' is $msg. You should only need it if 269 | you modified a dependency of a manual page. You may need the 270 | \`Help2man' package in order for those modifications to take 271 | effect. You can get \`Help2man' from any GNU archive site." 272 | 273 | file=`echo "$*" | sed -n "$sed_output"` 274 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 275 | if test -f "$file"; then 276 | touch $file 277 | else 278 | test -z "$file" || exec >$file 279 | echo ".ab help2man is required to generate this page" 280 | exit 1 281 | fi 282 | ;; 283 | 284 | makeinfo) 285 | echo 1>&2 "\ 286 | WARNING: \`$1' is $msg. You should only need it if 287 | you modified a \`.texi' or \`.texinfo' file, or any other file 288 | indirectly affecting the aspect of the manual. The spurious 289 | call might also be the consequence of using a buggy \`make' (AIX, 290 | DU, IRIX). You might want to install the \`Texinfo' package or 291 | the \`GNU make' package. Grab either from any GNU archive site." 292 | # The file to touch is that specified with -o ... 293 | file=`echo "$*" | sed -n "$sed_output"` 294 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 295 | if test -z "$file"; then 296 | # ... or it is the one specified with @setfilename ... 297 | infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` 298 | file=`sed -n ' 299 | /^@setfilename/{ 300 | s/.* \([^ ]*\) *$/\1/ 301 | p 302 | q 303 | }' $infile` 304 | # ... or it is derived from the source name (dir/f.texi becomes f.info) 305 | test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info 306 | fi 307 | # If the file does not exist, the user really needs makeinfo; 308 | # let's fail without touching anything. 309 | test -f $file || exit 1 310 | touch $file 311 | ;; 312 | 313 | tar) 314 | shift 315 | 316 | # We have already tried tar in the generic part. 317 | # Look for gnutar/gtar before invocation to avoid ugly error 318 | # messages. 319 | if (gnutar --version > /dev/null 2>&1); then 320 | gnutar "$@" && exit 0 321 | fi 322 | if (gtar --version > /dev/null 2>&1); then 323 | gtar "$@" && exit 0 324 | fi 325 | firstarg="$1" 326 | if shift; then 327 | case $firstarg in 328 | *o*) 329 | firstarg=`echo "$firstarg" | sed s/o//` 330 | tar "$firstarg" "$@" && exit 0 331 | ;; 332 | esac 333 | case $firstarg in 334 | *h*) 335 | firstarg=`echo "$firstarg" | sed s/h//` 336 | tar "$firstarg" "$@" && exit 0 337 | ;; 338 | esac 339 | fi 340 | 341 | echo 1>&2 "\ 342 | WARNING: I can't seem to be able to run \`tar' with the given arguments. 343 | You may want to install GNU tar or Free paxutils, or check the 344 | command line arguments." 345 | exit 1 346 | ;; 347 | 348 | *) 349 | echo 1>&2 "\ 350 | WARNING: \`$1' is needed, and is $msg. 351 | You might have modified some files without having the 352 | proper tools for further handling them. Check the \`README' file, 353 | it often tells you about the needed prerequisites for installing 354 | this package. You may also peek at any GNU archive site, in case 355 | some other package would contain this missing \`$1' program." 356 | exit 1 357 | ;; 358 | esac 359 | 360 | exit 0 361 | 362 | # Local variables: 363 | # eval: (add-hook 'write-file-hooks 'time-stamp) 364 | # time-stamp-start: "scriptversion=" 365 | # time-stamp-format: "%:y-%02m-%02d.%02H" 366 | # time-stamp-end: "$" 367 | # End: 368 | -------------------------------------------------------------------------------- /pkgconfig/libkdtree++.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: libkdtree++ 7 | Description: C++ template container implementation of kd-tree sorting. 8 | Version: @VERSION@ 9 | Libs: -L${libdir} 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /python-bindings/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package (SWIG REQUIRED) 2 | include (${SWIG_USE_FILE}) 3 | 4 | find_package (PythonLibs) 5 | include_directories (${PYTHON_INCLUDE_PATH}) 6 | 7 | include_directories (${CMAKE_CURRENT_SOURCE_DIR}) 8 | include_directories (${CMAKE_CURRENT_SOURCE_DIR}/..) 9 | 10 | # Build the _kdtree python module 11 | set_source_files_properties (py-kdtree.i PROPERTIES CPLUSPLUS ON) 12 | swig_add_module (kdtree python py-kdtree.i) 13 | swig_link_libraries (kdtree ${PYTHON_LIBRARIES}) 14 | 15 | # Copy the test file into the build dir 16 | install (FILES py-kdtree_test.py DESTINATION ${CMAKE_INSTALL_PREFIX}/python) 17 | install (FILES ${CMAKE_BINARY_DIR}/python-bindings/kdtree.py DESTINATION ${CMAKE_INSTALL_PREFIX}/python) 18 | install (FILES ${CMAKE_BINARY_DIR}/python-bindings/_kdtree.so DESTINATION ${CMAKE_INSTALL_PREFIX}/python) 19 | 20 | -------------------------------------------------------------------------------- /python-bindings/Makefile: -------------------------------------------------------------------------------- 1 | 2 | INCLUDE_DIR=.. 3 | CXX=g++ 4 | 5 | PY_INCLUDE_DIR=$(shell python-config --includes) 6 | 7 | # CPPFLAGS is used by the default rules. Using "override" and "+=" 8 | # allows the user to prepend things to CPPFLAGS on the command line. 9 | override CPPFLAGS += -I$(INCLUDE_DIR) -pedantic -Wno-long-long -Wall -ansi -pedantic 10 | # These options are set by the configure script. 11 | override CPPFLAGS += -DHAVE_CONFIG_H 12 | 13 | ifeq ($(MINUSG),1) 14 | override CPPFLAGS += -g -fPIC 15 | else 16 | override CPPFLAGS += -O3 -fPIC 17 | endif 18 | 19 | ifeq ($(MINUSPG),1) 20 | override CPPFLAGS += -pg 21 | endif 22 | 23 | 24 | # swig bindings 25 | py-kdtree: _kdtree.so 26 | cp _kdtree.so kdtree.py ../../ 27 | 28 | py-kdtree_test: py-kdtree.hpp py-kdtree_test.cpp 29 | $(CXX) $(CPPFLAGS) -I$(PY_INCLUDE_DIR) -c -o py-kdtree_test.o py-kdtree_test.cpp 30 | $(CXX) $(CPPFLAGS) $(LDLIBS) py-kdtree_test.o -o py-kdtree_test 31 | 32 | py-kdtree.i: py-kdtree.i.tmpl py-kdtree.hpp.tmpl gen-swig-hpp.py 33 | python gen-swig-hpp.py 34 | 35 | py-kdtree_wrap.cxx: py-kdtree.i py-kdtree.hpp py-kdtree.i.tmpl py-kdtree.hpp.tmpl 36 | swig -python -modern -c++ py-kdtree.i 37 | 38 | _kdtree.so: py-kdtree_wrap.cxx 39 | $(CXX) $(CPPFLAGS) -c py-kdtree_wrap.cxx -I$(PY_INCLUDE_DIR) -I$(INCLUDE_DIR) 40 | $(CXX) $(CPPFLAGS) -shared py-kdtree_wrap.o $(LDLIBS) -o _kdtree.so 41 | 42 | clean: 43 | rm -f test_kdtree *.so py-kdtree_wrap.cxx *.o dkdtree.py py-kdtree_test kdtree.py *.pyc py-kdtree.i py-kdtree.hpp 44 | 45 | .PHONY: clean 46 | 47 | -------------------------------------------------------------------------------- /python-bindings/gen-swig-hpp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | TREE_TYPES = [(dim, "int", "unsigned long long", "i", "L") for dim in range(2,7)] + \ 5 | [(dim, "float", "unsigned long long", "f", "L") for dim in range(2,7)] 6 | 7 | 8 | def write_swig_file(tmpl_fn_name, swig_fn_name): 9 | TMPL_SEPARATOR_DEF="""\ 10 | //////////////////////////////////////////////////////////////////////////////// 11 | // TYPE (%s) -> %s 12 | //////////////////////////////////////////////////////////////////////////////// 13 | """ 14 | TMPL_SEPARATOR=[] 15 | 16 | TMPL_RECORD_DEF="""\ 17 | #define RECORD_%i%s%s record_t<%i, %s, %s> // cf. py-kdtree.hpp 18 | """ 19 | TMPL_RECORD=[] 20 | 21 | TMPL_IN_CONV_RECORD_DEF="""\ 22 | %%typemap(in) RECORD_%i%s%s (RECORD_%i%s%s temp) { 23 | if (PyTuple_Check($input)) { 24 | if (PyArg_ParseTuple($input,"(%s)%s", %s, &temp.data)!=0) 25 | { 26 | $1 = temp; 27 | } else { 28 | PyErr_SetString(PyExc_TypeError,"tuple must have %i elements: (%i dim %s vector, %s value)"); 29 | return NULL; 30 | } 31 | 32 | } else { 33 | PyErr_SetString(PyExc_TypeError,"expected a tuple."); 34 | return NULL; 35 | } 36 | } 37 | """ 38 | TMPL_IN_CONV_RECORD=[] 39 | 40 | TMPL_IN_CONV_POINT_DEF="""\ 41 | %%typemap(in) RECORD_%i%s%s::point_t (RECORD_%i%s%s::point_t point) { 42 | if (PyTuple_Check($input)) { 43 | if (PyArg_ParseTuple($input,"%s", %s)!=0) 44 | { 45 | $1 = point; 46 | } else { 47 | PyErr_SetString(PyExc_TypeError,"tuple must contain %i ints"); 48 | return NULL; 49 | } 50 | 51 | } else { 52 | PyErr_SetString(PyExc_TypeError,"expected a tuple."); 53 | return NULL; 54 | } 55 | } 56 | """ 57 | TMPL_IN_CONV_POINT=[] 58 | 59 | 60 | TMPL_OUT_CONV_POINT_DEF="""\ 61 | %%typemap(out) RECORD_%i%s%s * { 62 | RECORD_%i%s%s * r = $1; 63 | PyObject* py_result; 64 | 65 | if (r != NULL) { 66 | 67 | py_result = PyTuple_New(2); 68 | if (py_result==NULL) { 69 | PyErr_SetString(PyErr_Occurred(),"unable to create a tuple."); 70 | return NULL; 71 | } 72 | 73 | if (PyTuple_SetItem(py_result, 0, Py_BuildValue("(%s)", %s))==-1) { 74 | PyErr_SetString(PyErr_Occurred(),"(a) when setting element"); 75 | 76 | Py_DECREF(py_result); 77 | return NULL; 78 | } 79 | 80 | if (PyTuple_SetItem(py_result, 1, Py_BuildValue("%s", r->data))==-1) { 81 | PyErr_SetString(PyErr_Occurred(),"(b) when setting element"); 82 | 83 | Py_DECREF(py_result); 84 | return NULL; 85 | } 86 | } else { 87 | py_result = Py_BuildValue(""); 88 | } 89 | 90 | $result = py_result; 91 | } 92 | """ 93 | TMPL_OUT_CONV_POINT=[] 94 | 95 | TMPL_OUT_CONV_RECORD_DEF="""\ 96 | %%typemap(out) std::vector* { 97 | std::vector* v = $1; 98 | 99 | PyObject* py_result = PyList_New(v->size()); 100 | if (py_result==NULL) { 101 | PyErr_SetString(PyErr_Occurred(),"unable to create a list."); 102 | return NULL; 103 | } 104 | std::vector::const_iterator iter = v->begin(); 105 | 106 | for (size_t i=0; isize(); i++, iter++) { 107 | if (PyList_SetItem(py_result, i, Py_BuildValue("(%s)%s", %s, (*iter).data))==-1) { 108 | PyErr_SetString(PyErr_Occurred(),"(c) when setting element"); 109 | 110 | Py_DECREF(py_result); 111 | return NULL; 112 | } else { 113 | //std::cout << "successfully set element " << *iter << std::endl; 114 | } 115 | } 116 | 117 | $result = py_result; 118 | } 119 | """ 120 | TMPL_OUT_CONV_RECORD=[] 121 | 122 | TMPL_PY_CLASS_DEF="""\ 123 | %%template () RECORD_%i%s%s; 124 | %%template (KDTree_%i%s) PyKDTree<%i, %s, %s>; 125 | """ 126 | TMPL_PY_CLASS=[] 127 | 128 | 129 | TYPE_DEFS = [] 130 | 131 | for t in TREE_TYPES: 132 | dim, coord_t, data_t, py_coord_t, py_data_t = t 133 | coord_t_short = "".join([_[0] for _ in coord_t.split(" ")]) 134 | data_t_short = "".join([_[0] for _ in data_t.split(" ")]) 135 | 136 | TMPL_SEPARATOR.append(TMPL_SEPARATOR_DEF%(",".join([coord_t for _ in range(dim)]), data_t)) 137 | 138 | TMPL_RECORD.append(TMPL_RECORD_DEF%(dim, coord_t_short, data_t_short, dim, coord_t, data_t)) 139 | 140 | TMPL_IN_CONV_RECORD.append(TMPL_IN_CONV_RECORD_DEF%\ 141 | (dim, coord_t_short, data_t_short, 142 | dim, coord_t_short, data_t_short, 143 | py_coord_t*dim, py_data_t, ",".join(["&temp.point[%i]"%i for i in range(dim)]), 144 | dim, dim, coord_t, data_t) 145 | ) 146 | 147 | TMPL_IN_CONV_POINT.append(TMPL_IN_CONV_POINT_DEF%\ 148 | (dim, coord_t_short, data_t_short, 149 | dim, coord_t_short, data_t_short, 150 | py_coord_t*dim, ",".join(["&point[%i]"%i for i in range(dim)]), 151 | dim) 152 | ) 153 | 154 | TMPL_OUT_CONV_RECORD.append(TMPL_OUT_CONV_RECORD_DEF%\ 155 | (dim, coord_t_short, data_t_short, 156 | dim, coord_t_short, data_t_short, 157 | dim, coord_t_short, data_t_short, 158 | py_coord_t*dim, py_data_t, ",".join(["(*iter).point[%i]"%i for i in range(dim)]), 159 | ) 160 | ) 161 | TMPL_OUT_CONV_POINT.append(TMPL_OUT_CONV_POINT_DEF%\ 162 | (dim, coord_t_short, data_t_short, 163 | dim, coord_t_short, data_t_short, 164 | py_coord_t*dim, ",".join(["r->point[%i]"%i for i in range(dim)]), 165 | py_data_t) 166 | ) 167 | 168 | TMPL_PY_CLASS.append(TMPL_PY_CLASS_DEF%\ 169 | (dim, coord_t_short, data_t_short, 170 | dim, coord_t.capitalize(), dim, coord_t, data_t) 171 | ) 172 | 173 | 174 | TMPL_BODY_LIST = [] 175 | for i in range(len(TREE_TYPES)): 176 | TMPL_BODY_LIST.append(TMPL_SEPARATOR[i] + "\n" + \ 177 | TMPL_RECORD[i] + "\n" + \ 178 | TMPL_IN_CONV_POINT[i] + "\n" + \ 179 | TMPL_IN_CONV_RECORD[i] + "\n" + \ 180 | TMPL_OUT_CONV_POINT[i] + "\n" + \ 181 | TMPL_OUT_CONV_RECORD[i]) 182 | 183 | TMPL_BODY = "\n\n".join(TMPL_BODY_LIST) 184 | 185 | # write swig file 186 | i_content = open(tmpl_fn_name, "r").read() 187 | i_content = i_content.replace("%%TMPL_BODY%%", TMPL_BODY).replace("%%TMPL_PY_CLASS_DEF%%", "\n".join(TMPL_PY_CLASS)) 188 | f=open(swig_fn_name, "w") 189 | f.write(i_content) 190 | f.close() 191 | 192 | 193 | def write_hpp_file(tmpl_fn_name, hpp_fn_name): 194 | TMPL_SEPARATOR_DEF="""\ 195 | //////////////////////////////////////////////////////////////////////////////// 196 | // Definition of (%s) with data type %s 197 | //////////////////////////////////////////////////////////////////////////////// 198 | """ 199 | TMPL_SEPARATOR=[] 200 | 201 | TMPL_RECORD_DEF = """\ 202 | #define RECORD_%i%s%s record_t<%i, %s, %s> 203 | #define KDTREE_TYPE_%i%s%s KDTree::KDTree<%i, RECORD_%i%s%s, std::pointer_to_binary_function > 204 | """ 205 | TMPL_RECORD=[] 206 | 207 | TMPL_OP_EQ_DEF = """\ 208 | inline bool operator==(RECORD_%i%s%s const& A, RECORD_%i%s%s const& B) { 209 | return %s && A.data == B.data; 210 | } 211 | """ 212 | TMPL_OP_EQ = [] 213 | 214 | TMPL_OP_OUT_DEF="""\ 215 | std::ostream& operator<<(std::ostream& out, RECORD_%i%s%s const& T) 216 | { 217 | return out << '(' << %s << '|' << T.data << ')'; 218 | } 219 | """ 220 | TMPL_OP_OUT = [] 221 | 222 | TYPE_DEFS = [] 223 | 224 | for t in TREE_TYPES: 225 | dim, coord_t, data_t, py_coord_t, py_data_t = t 226 | coord_t_short = "".join([_[0] for _ in coord_t.split(" ")]) 227 | data_t_short = "".join([_[0] for _ in data_t.split(" ")]) 228 | 229 | TMPL_SEPARATOR.append(TMPL_SEPARATOR_DEF%(",".join([coord_t for _ in range(dim)]), data_t)) 230 | 231 | TMPL_RECORD.append(TMPL_RECORD_DEF%(dim, coord_t_short, data_t_short, 232 | dim, coord_t, data_t, 233 | dim, coord_t_short, data_t_short, 234 | dim, 235 | dim, coord_t_short, data_t_short, 236 | dim, coord_t_short, data_t_short) 237 | ) 238 | 239 | TMPL_OP_EQ.append(TMPL_OP_EQ_DEF%(dim, coord_t_short, data_t_short, 240 | dim, coord_t_short, data_t_short, 241 | " && ".join(["A.point[%i] == B.point[%i]"%(i,i) for i in range(dim)]))) 242 | 243 | TMPL_OP_OUT.append(TMPL_OP_OUT_DEF%(dim, coord_t_short, data_t_short, 244 | " << ',' << ".join(["T.point[%i]"%i for i in range(dim)]))) 245 | 246 | 247 | TMPL_BODY_LIST = [] 248 | for i in range(len(TREE_TYPES)): 249 | TMPL_BODY_LIST.append(TMPL_SEPARATOR[i] + "\n" + TMPL_RECORD[i] + "\n" + TMPL_OP_EQ[i] + "\n" + TMPL_OP_OUT[i]) 250 | 251 | TMPL_BODY = "\n\n".join(TMPL_BODY_LIST) 252 | 253 | # write hpp file 254 | hpp_content = open(tmpl_fn_name, "r").read() 255 | hpp_content = hpp_content.replace("%%TMPL_HPP_DEFS%%", TMPL_BODY) 256 | f=open(hpp_fn_name, "w") 257 | f.write(hpp_content) 258 | f.close() 259 | 260 | 261 | if __name__=="__main__": 262 | write_swig_file("py-kdtree.i.tmpl", "py-kdtree.i") 263 | write_hpp_file("py-kdtree.hpp.tmpl", "py-kdtree.hpp") 264 | 265 | -------------------------------------------------------------------------------- /python-bindings/py-kdtree.hpp.tmpl: -------------------------------------------------------------------------------- 1 | /** \file 2 | * Provides a Python interface for the libkdtree++. 3 | * 4 | * \author Willi Richert 5 | * 6 | * 7 | * This defines a proxy to a (int, int) -> long long KD-Tree. The long 8 | * long is needed to save a reference to Python's object id(). Thereby, 9 | * you can associate Python objects with 2D integer points. 10 | * 11 | * If you want to customize it you can adapt the following: 12 | * 13 | * * Dimension of the KD-Tree point vector. 14 | * * DIM: number of dimensions. 15 | * * operator==() and operator<<(): adapt to the number of comparisons 16 | * * py-kdtree.i: Add or adapt all usages of PyArg_ParseTuple() to reflect the 17 | * number of dimensions. 18 | * * adapt query_records in find_nearest() and count_within_range() 19 | * * Type of points. 20 | * * coord_t: If you want to have e.g. floats you have 21 | * to adapt all usages of PyArg_ParseTuple(): Change "i" to "f" e.g. 22 | * * Type of associated data. 23 | * * data_t: currently unsigned long long, which is "L" in py-kdtree.i 24 | * * PyArg_ParseTuple() has to be changed to reflect changes in data_t 25 | * 26 | */ 27 | 28 | 29 | #ifndef _PY_KDTREE_H_ 30 | #define _PY_KDTREE_H_ 31 | 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | template 39 | struct record_t { 40 | static const size_t dim = DIM; 41 | typedef COORD_T coord_t; 42 | typedef DATA_T data_t; 43 | 44 | typedef coord_t point_t[dim]; 45 | 46 | inline coord_t operator[](size_t const N) const { return point[N]; } 47 | 48 | point_t point; 49 | data_t data; 50 | }; 51 | 52 | typedef double RANGE_T; 53 | 54 | %%TMPL_HPP_DEFS%% 55 | 56 | //////////////////////////////////////////////////////////////////////////////// 57 | // END OF TYPE SPECIFIC DEFINITIONS 58 | //////////////////////////////////////////////////////////////////////////////// 59 | 60 | 61 | template 62 | inline double tac(RECORD_T r, int k) { return r[k]; } 63 | 64 | template 65 | class PyKDTree { 66 | public: 67 | 68 | typedef record_t RECORD_T; 69 | typedef KDTree::KDTree > TREE_T; 70 | TREE_T tree; 71 | 72 | PyKDTree() : tree(std::ptr_fun(tac)) { }; 73 | 74 | void add(RECORD_T T) { tree.insert(T); }; 75 | 76 | /** 77 | Exact erase. 78 | */ 79 | bool remove(RECORD_T T) { 80 | bool removed = false; 81 | 82 | typename TREE_T::const_iterator it = tree.find_exact(T); 83 | if (it!=tree.end()) { 84 | tree.erase_exact(T); 85 | removed = true; 86 | } 87 | return removed; 88 | }; 89 | 90 | int size(void) { return tree.size(); } 91 | 92 | void optimize(void) { tree.optimise(); } 93 | 94 | RECORD_T* find_exact(RECORD_T T) { 95 | RECORD_T* found = NULL; 96 | typename TREE_T::const_iterator it = tree.find_exact(T); 97 | if (it!=tree.end()) 98 | found = new RECORD_T(*it); 99 | 100 | return found; 101 | } 102 | 103 | size_t count_within_range(typename RECORD_T::point_t T, RANGE_T range) { 104 | RECORD_T query_record; 105 | memcpy(query_record.point, T, sizeof(COORD_T)*DIM); 106 | 107 | return tree.count_within_range(query_record, range); 108 | } 109 | 110 | std::vector* find_within_range(typename RECORD_T::point_t T, RANGE_T range) { 111 | RECORD_T query_record; 112 | memcpy(query_record.point, T, sizeof(COORD_T)*DIM); 113 | 114 | std::vector *v = new std::vector; 115 | tree.find_within_range(query_record, range, std::back_inserter(*v)); 116 | return v; 117 | } 118 | 119 | RECORD_T* find_nearest (typename RECORD_T::point_t T) { 120 | RECORD_T* found = NULL; 121 | RECORD_T query_record; 122 | memcpy(query_record.point, T, sizeof(COORD_T)*DIM); 123 | 124 | std::pair best = 125 | tree.find_nearest(query_record, std::numeric_limits::max()); 126 | 127 | if (best.first!=tree.end()) { 128 | found = new RECORD_T(*best.first); 129 | } 130 | return found; 131 | } 132 | 133 | std::vector* get_all() { 134 | std::vector* v = new std::vector; 135 | 136 | for (typename TREE_T::const_iterator iter=tree.begin(); iter!=tree.end(); ++iter) { 137 | v->push_back(*iter); 138 | } 139 | 140 | return v; 141 | } 142 | 143 | size_t __len__() { return tree.size(); } 144 | }; 145 | #endif //_PY_KDTREE_H_ 146 | -------------------------------------------------------------------------------- /python-bindings/py-kdtree.i.tmpl: -------------------------------------------------------------------------------- 1 | /** \file 2 | * 3 | * Provides a Python interface for the libkdtree++. 4 | * 5 | * \author Willi Richert 6 | * 7 | */ 8 | 9 | %module kdtree 10 | 11 | %{ 12 | #define SWIG_FILE_WITH_INIT 13 | #include "py-kdtree.hpp" 14 | %} 15 | 16 | 17 | %ignore record_t::operator[]; 18 | %ignore operator==; 19 | %ignore operator<<; 20 | %ignore KDTree::KDTree::operator=; 21 | %ignore tac; 22 | 23 | %%TMPL_BODY%% 24 | 25 | %include "py-kdtree.hpp" 26 | 27 | %%TMPL_PY_CLASS_DEF%% 28 | -------------------------------------------------------------------------------- /python-bindings/py-kdtree_test.cpp: -------------------------------------------------------------------------------- 1 | #define KDTREE_DEFINE_OSTREAM_OPERATORS 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include "py-kdtree.hpp" 9 | 10 | int main() 11 | { 12 | 13 | 14 | KDTree_2Int t; 15 | 16 | RECORD_2il c0 = { {5, 4} }; t.add(c0); 17 | RECORD_2il c1 = { {4, 2} }; t.add(c1); 18 | RECORD_2il c2 = { {7, 6} }; t.add(c2); 19 | RECORD_2il c3 = { {2, 2} }; t.add(c3); 20 | RECORD_2il c4 = { {8, 0} }; t.add(c4); 21 | RECORD_2il c5 = { {5, 7} }; t.add(c5); 22 | RECORD_2il c6 = { {3, 3} }; t.add(c6); 23 | RECORD_2il c7 = { {9, 7} }; t.add(c7); 24 | RECORD_2il c8 = { {2, 2} }; t.add(c8); 25 | RECORD_2il c9 = { {2, 0} }; t.add(c9); 26 | 27 | std::cout << t.tree << std::endl; 28 | 29 | t.remove(c0); 30 | t.remove(c1); 31 | t.remove(c3); 32 | t.remove(c5); 33 | 34 | t.optimize(); 35 | 36 | std::cout << std::endl << t.tree << std::endl; 37 | 38 | int i=0; 39 | for (KDTREE_TYPE_2il::const_iterator iter=t.tree.begin(); iter!=t.tree.end(); ++iter, ++i); 40 | std::cout << "iterator walked through " << i << " nodes in total" << std::endl; 41 | if (i!=6) 42 | { 43 | std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl; 44 | return 1; 45 | } 46 | i=0; 47 | for (KDTREE_TYPE_2il::const_reverse_iterator iter=t.tree.rbegin(); iter!=t.tree.rend(); ++iter, ++i); 48 | std::cout << "reverse_iterator walked through " << i << " nodes in total" << std::endl; 49 | if (i!=6) 50 | { 51 | std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl; 52 | return 1; 53 | } 54 | 55 | RECORD_2il::point_t s = {5, 4}; 56 | std::vector v; 57 | unsigned int const RANGE = 3; 58 | 59 | size_t count = t.count_within_range(s, RANGE); 60 | std::cout << "counted " << count 61 | << " nodes within range " << RANGE << " of " << s << ".\n"; 62 | v = t.find_within_range(s, RANGE); 63 | 64 | std::cout << "found " << v.size() << " nodes within range " << RANGE 65 | << " of " << s << ":\n"; 66 | std::vector::const_iterator ci = v.begin(); 67 | for (; ci != v.end(); ++ci) 68 | std::cout << *ci << " "; 69 | std::cout << "\n" << std::endl; 70 | 71 | std::cout << "Nearest to " << s << ": " << 72 | t.find_nearest(s) << std::endl; 73 | 74 | RECORD_2il::point_t s2 = { 10, 10}; 75 | std::cout << "Nearest to " << s2 << ": " << 76 | t.find_nearest(s2) << std::endl; 77 | 78 | std::cout << std::endl; 79 | 80 | std::cout << t.tree << std::endl; 81 | 82 | return 0; 83 | } 84 | 85 | /* COPYRIGHT -- 86 | * 87 | * This file is part of libkdtree++, a C++ template KD-Tree sorting container. 88 | * libkdtree++ is (c) 2004-2007 Martin F. Krafft 89 | * and Sylvain Bougerel distributed under the 90 | * terms of the Artistic License 2.0. See the ./COPYING file in the source tree 91 | * root for more information. 92 | * 93 | * THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED 94 | * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES 95 | * OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 96 | */ 97 | -------------------------------------------------------------------------------- /python-bindings/py-kdtree_test.py: -------------------------------------------------------------------------------- 1 | # 2 | # $Id: py-kdtree_test.py 2268 2008-08-20 10:08:58Z richert $ 3 | # 4 | 5 | import unittest 6 | 7 | from kdtree import KDTree_2Int, KDTree_4Int, KDTree_3Float, KDTree_4Float, KDTree_6Float 8 | 9 | 10 | class KDTree_2IntTestCase(unittest.TestCase): 11 | def test_empty(self): 12 | nn = KDTree_2Int() 13 | self.assertEqual(0, nn.size()) 14 | 15 | actual = nn.find_nearest((2,3)) 16 | self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual))) 17 | 18 | def test_get_all(self): 19 | nn = KDTree_2Int() 20 | o1 = object() 21 | nn.add(((1,1), id(o1))) 22 | o2 = object() 23 | nn.add(((10,10), id(o2))) 24 | o3 = object() 25 | nn.add(((11,11), id(o3))) 26 | 27 | self.assertEqual([((1,1), id(o1)), ((10,10), id(o2)), ((11,11), id(o3))], nn.get_all()) 28 | self.assertEqual(3, len(nn)) 29 | 30 | nn.remove(((10,10), id(o2))) 31 | self.assertEqual(2, len(nn)) 32 | self.assertEqual([((1,1), id(o1)), ((11,11), id(o3))], nn.get_all()) 33 | 34 | def test_nearest(self): 35 | nn = KDTree_2Int() 36 | 37 | nn_id = {} 38 | 39 | o1 = object() 40 | nn.add(((1,1), id(o1))) 41 | nn_id[id(o1)] = o1 42 | o2 = object() 43 | nn.add(((10,10), id(o2))) 44 | nn_id[id(o2)] = o2 45 | 46 | expected = o1 47 | actual = nn.find_nearest((2,2))[1] 48 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 49 | 50 | expected = o2 51 | actual = nn.find_nearest((6, 6))[1] 52 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 53 | 54 | def test_find_within_range(self): 55 | nn = KDTree_6Float() 56 | 57 | nn_id = {} 58 | 59 | o1 = object() 60 | nn.add(((1,1,0,0,0,0), id(o1))) 61 | nn_id[id(o1)] = o1 62 | o2 = object() 63 | nn.add(((10,10,0,0,0,0), id(o2))) 64 | nn_id[id(o2)] = o2 65 | o3 = object() 66 | nn.add(((4.1, 4.1,0,0,0,0), id(o3))) 67 | nn_id[id(o3)] = o3 68 | 69 | expected = set([long(id(o1)), long(id(o3))]) 70 | actual = set([ident 71 | for _coord, ident 72 | in nn.find_within_range((2.1,2.1,0,0,0,0), 3.9)]) 73 | self.assertTrue(expected==actual, "%s != %s"%(str(expected), str(actual))) 74 | 75 | 76 | def test_remove(self): 77 | class C: 78 | def __init__(self, i): 79 | self.i = i 80 | self.next = None 81 | 82 | nn = KDTree_2Int() 83 | 84 | k1, o1 = (1,1), C(7) 85 | self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!") 86 | nn.add((k1, id(o1))) 87 | 88 | k2, o2 = (1,1), C(7) 89 | nn.add((k2, id(o2))) 90 | 91 | self.assertEqual(2, nn.size()) 92 | self.assertTrue(nn.remove((k2, id(o2)))) 93 | self.assertEqual(1, nn.size()) 94 | self.assertFalse(nn.remove((k2, id(o2)))) 95 | self.assertEqual(1, nn.size()) 96 | 97 | nearest = nn.find_nearest(k1) 98 | self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1)) 99 | #self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1))))) 100 | 101 | def test_count_within_range(self): 102 | nn = KDTree_2Int() 103 | 104 | for p in [(0,0), (1,0), (0,1), (1,1)]: 105 | nn.add((p, id(p))) 106 | 107 | res = nn.count_within_range((0,0), 1.0) 108 | self.assertEqual(3, res, "Counted %i points instead of %i"%(res, 3)) 109 | 110 | res = nn.count_within_range((0,0), 1.9) 111 | self.assertEqual(4, res, "Counted %i points instead of %i"%(res, 4)) 112 | 113 | class KDTree_4IntTestCase(unittest.TestCase): 114 | def test_empty(self): 115 | nn = KDTree_4Int() 116 | self.assertEqual(0, nn.size()) 117 | 118 | actual = nn.find_nearest((0,0,2,3)) 119 | self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual))) 120 | 121 | def test_get_all(self): 122 | nn = KDTree_4Int() 123 | o1 = object() 124 | nn.add(((0,0,1,1), id(o1))) 125 | o2 = object() 126 | nn.add(((0,0,10,10), id(o2))) 127 | o3 = object() 128 | nn.add(((0,0,11,11), id(o3))) 129 | 130 | self.assertEqual([((0,0,1,1), id(o1)), ((0,0,10,10), id(o2)), ((0,0,11,11), id(o3))], nn.get_all()) 131 | self.assertEqual(3, len(nn)) 132 | 133 | nn.remove(((0,0,10,10), id(o2))) 134 | self.assertEqual(2, len(nn)) 135 | self.assertEqual([((0,0,1,1), id(o1)), ((0,0,11,11), id(o3))], nn.get_all()) 136 | 137 | def test_nearest(self): 138 | nn = KDTree_4Int() 139 | 140 | nn_id = {} 141 | 142 | o1 = object() 143 | nn.add(((0,0,1,1), id(o1))) 144 | nn_id[id(o1)] = o1 145 | o2 = object() 146 | nn.add(((0,0,10,10), id(o2))) 147 | nn_id[id(o2)] = o2 148 | 149 | expected = o1 150 | actual = nn.find_nearest((0,0,2,2))[1] 151 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 152 | 153 | expected = o2 154 | actual = nn.find_nearest((0,0,6,6))[1] 155 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 156 | 157 | def test_remove(self): 158 | class C: 159 | def __init__(self, i): 160 | self.i = i 161 | self.next = None 162 | 163 | nn = KDTree_4Int() 164 | 165 | k1, o1 = (0,0,1,1), C(7) 166 | self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!") 167 | nn.add((k1, id(o1))) 168 | 169 | k2, o2 = (0,0,1,1), C(7) 170 | nn.add((k2, id(o2))) 171 | 172 | self.assertEqual(2, nn.size()) 173 | self.assertTrue(nn.remove((k2, id(o2)))) 174 | self.assertEqual(1, nn.size()) 175 | self.assertFalse(nn.remove((k2, id(o2)))) 176 | self.assertEqual(1, nn.size()) 177 | 178 | nearest = nn.find_nearest(k1) 179 | self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1)) 180 | #self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1))))) 181 | 182 | class KDTree_4FloatTestCase(unittest.TestCase): 183 | def test_empty(self): 184 | nn = KDTree_4Float() 185 | self.assertEqual(0, nn.size()) 186 | 187 | actual = nn.find_nearest((0,0,2,3)) 188 | self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual))) 189 | 190 | def test_get_all(self): 191 | nn = KDTree_4Int() 192 | o1 = object() 193 | nn.add(((0,0,1,1), id(o1))) 194 | o2 = object() 195 | nn.add(((0,0,10,10), id(o2))) 196 | o3 = object() 197 | nn.add(((0,0,11,11), id(o3))) 198 | 199 | self.assertEqual([((0,0,1,1), id(o1)), ((0,0,10,10), id(o2)), ((0,0,11,11), id(o3))], nn.get_all()) 200 | self.assertEqual(3, len(nn)) 201 | 202 | nn.remove(((0,0,10,10), id(o2))) 203 | self.assertEqual(2, len(nn)) 204 | self.assertEqual([((0,0,1,1), id(o1)), ((0,0,11,11), id(o3))], nn.get_all()) 205 | 206 | def test_nearest(self): 207 | nn = KDTree_4Int() 208 | 209 | nn_id = {} 210 | 211 | o1 = object() 212 | nn.add(((0,0,1,1), id(o1))) 213 | nn_id[id(o1)] = o1 214 | o2 = object() 215 | nn.add(((0,0,10,10), id(o2))) 216 | nn_id[id(o2)] = o2 217 | 218 | expected = o1 219 | actual = nn.find_nearest((0,0,2,2))[1] 220 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 221 | 222 | expected = o2 223 | actual = nn.find_nearest((0,0,6,6))[1] 224 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 225 | 226 | def test_remove(self): 227 | class C: 228 | def __init__(self, i): 229 | self.i = i 230 | self.next = None 231 | 232 | nn = KDTree_4Int() 233 | 234 | k1, o1 = (0,0,1,1), C(7) 235 | self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!") 236 | nn.add((k1, id(o1))) 237 | 238 | k2, o2 = (0,0,1,1), C(7) 239 | nn.add((k2, id(o2))) 240 | 241 | self.assertEqual(2, nn.size()) 242 | self.assertTrue(nn.remove((k2, id(o2)))) 243 | self.assertEqual(1, nn.size()) 244 | self.assertFalse(nn.remove((k2, id(o2)))) 245 | self.assertEqual(1, nn.size()) 246 | 247 | nearest = nn.find_nearest(k1) 248 | self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1)) 249 | #self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1))))) 250 | 251 | class KDTree_3FloatTestCase(unittest.TestCase): 252 | def test_empty(self): 253 | nn = KDTree_3Float() 254 | self.assertEqual(0, nn.size()) 255 | 256 | actual = nn.find_nearest((2,3,0)) 257 | self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual))) 258 | 259 | def test_get_all(self): 260 | nn = KDTree_3Float() 261 | o1 = object() 262 | nn.add(((1,1,0), id(o1))) 263 | o2 = object() 264 | nn.add(((10,10,0), id(o2))) 265 | o3 = object() 266 | nn.add(((11,11,0), id(o3))) 267 | 268 | self.assertEqual([((1,1,0), id(o1)), ((10,10,0), id(o2)), ((11,11,0), id(o3))], nn.get_all()) 269 | self.assertEqual(3, len(nn)) 270 | 271 | nn.remove(((10,10,0), id(o2))) 272 | self.assertEqual(2, len(nn)) 273 | self.assertEqual([((1,1,0), id(o1)), ((11,11,0), id(o3))], nn.get_all()) 274 | 275 | def test_nearest(self): 276 | nn = KDTree_3Float() 277 | 278 | nn_id = {} 279 | 280 | o1 = object() 281 | nn.add(((1,1,0), id(o1))) 282 | nn_id[id(o1)] = o1 283 | o2 = object() 284 | nn.add(((10,10,0), id(o2))) 285 | nn_id[id(o2)] = o2 286 | o3 = object() 287 | nn.add(((4.1, 4.1,0), id(o3))) 288 | nn_id[id(o3)] = o3 289 | 290 | expected = o3 291 | actual = nn.find_nearest((2.9,2.9,0))[1] 292 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 293 | 294 | expected = o3 295 | actual = nn.find_nearest((6, 6,0))[1] 296 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 297 | 298 | def test_remove(self): 299 | class C: 300 | def __init__(self, i): 301 | self.i = i 302 | self.next = None 303 | 304 | nn = KDTree_3Float() 305 | 306 | k1, o1 = (1.1,1.1,0), C(7) 307 | self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!") 308 | nn.add((k1, id(o1))) 309 | 310 | k2, o2 = (1.1,1.1,0), C(7) 311 | nn.add((k2, id(o2))) 312 | 313 | self.assertEqual(2, nn.size()) 314 | self.assertTrue(nn.remove((k2, id(o2)))) 315 | self.assertEqual(1, nn.size()) 316 | self.assertFalse(nn.remove((k2, id(o2)))) 317 | self.assertEqual(1, nn.size()) 318 | 319 | nearest = nn.find_nearest(k1) 320 | self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1)) 321 | #self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1))))) 322 | 323 | class KDTree_6FloatTestCase(unittest.TestCase): 324 | def test_empty(self): 325 | nn = KDTree_6Float() 326 | self.assertEqual(0, nn.size()) 327 | 328 | actual = nn.find_nearest((2,3,0,0,0,0)) 329 | self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual))) 330 | 331 | def test_get_all(self): 332 | nn = KDTree_6Float() 333 | o1 = object() 334 | nn.add(((1,1,0,0,0,0), id(o1))) 335 | o2 = object() 336 | nn.add(((10,10,0,0,0,0), id(o2))) 337 | o3 = object() 338 | nn.add(((11,11,0,0,0,0), id(o3))) 339 | 340 | self.assertEqual([((1,1,0,0,0,0), id(o1)), ((10,10,0,0,0,0), id(o2)), ((11,11,0,0,0,0 ), id(o3))], nn.get_all()) 341 | self.assertEqual(3, len(nn)) 342 | 343 | nn.remove(((10,10,0,0,0,0), id(o2))) 344 | self.assertEqual(2, len(nn)) 345 | self.assertEqual([((1,1,0,0,0,0), id(o1)), ((11,11,0,0,0,0), id(o3))], nn.get_all()) 346 | 347 | def test_nearest(self): 348 | nn = KDTree_6Float() 349 | 350 | nn_id = {} 351 | 352 | o1 = object() 353 | nn.add(((1,1,0,0,0,0), id(o1))) 354 | nn_id[id(o1)] = o1 355 | o2 = object() 356 | nn.add(((10,10,0,0,0,0), id(o2))) 357 | nn_id[id(o2)] = o2 358 | o3 = object() 359 | nn.add(((4.1, 4.1,0,0,0,0), id(o3))) 360 | nn_id[id(o3)] = o3 361 | 362 | expected = o3 363 | actual = nn.find_nearest((2.9,2.9,0,0,0,0))[1] 364 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 365 | 366 | expected = o3 367 | actual = nn.find_nearest((6, 6,0,0,0,0))[1] 368 | self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual]))) 369 | 370 | def test_remove(self): 371 | class C: 372 | def __init__(self, i): 373 | self.i = i 374 | self.next = None 375 | 376 | nn = KDTree_6Float() 377 | 378 | k1, o1 = (1.1,1.1,0,0,0,0), C(7) 379 | self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!") 380 | nn.add((k1, id(o1))) 381 | 382 | k2, o2 = (1.1,1.1,0,0,0,0), C(7) 383 | nn.add((k2, id(o2))) 384 | 385 | self.assertEqual(2, nn.size()) 386 | self.assertTrue(nn.remove((k2, id(o2)))) 387 | self.assertEqual(1, nn.size()) 388 | self.assertFalse(nn.remove((k2, id(o2)))) 389 | self.assertEqual(1, nn.size()) 390 | 391 | nearest = nn.find_nearest(k1) 392 | self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1)) 393 | #self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1))))) 394 | 395 | 396 | def suite(): 397 | return unittest.defaultTestLoader.loadTestsFromModule(sys.modules.get(__name__)) 398 | 399 | if __name__ == '__main__': 400 | unittest.main() 401 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | (import 2 | ( 3 | let lock = builtins.fromJSON (builtins.readFile ./flake.lock); in 4 | fetchTarball { 5 | url = lock.nodes.flake-compat.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.flake-compat.locked.rev}.tar.gz"; 6 | sha256 = lock.nodes.flake-compat.locked.narHash; 7 | } 8 | ) 9 | { src = ./.; } 10 | ).shellNix --------------------------------------------------------------------------------