update libkdtree

switch to version 0.7.4
fix for a compiler warning inkdtree++/region.hpp
fixes of warnings, latest c++ standard compatibility.

.
This commit is contained in:
Andrea
2025-03-13 11:54:23 +01:00
committed by Chris Hennes
parent 85179089b1
commit c197032384
12 changed files with 13 additions and 901 deletions

View File

@@ -1,5 +1,5 @@
cmake_minimum_required (VERSION 2.8.12)
project (libkdtree CXX)
cmake_minimum_required (VERSION 2.6.0)
option (BUILD_PYTHON_BINDINGS "Build Python bindings (requires SWIG)")

View File

@@ -1,6 +1,6 @@
"The Artistic Licence 2.0"
Copyright (c) 2000-2006, The Perl Foundation.
https://www.perlfoundation.org/artistic-license-20.html
http://www.perlfoundation.org/legal/licenses/artistic-2_0.html
Everyone is permitted to copy and distribute verbatim copies of this license
document, but changing it is not allowed.

View File

@@ -1,236 +0,0 @@
libkdtree++ ChangeLog
=====================
2008-11-17 Sylvain Bougerel <sylvain.bougerel@asia.thalesgroup.com>
- Added #include<cstdio> in order to compile 'printf' statements in the
file 'examples/test_find_within_range.cpp'.
- Added patch from Max Fellermann in order to compile libkdtree++ with
clang++.
2009-02-10 Paul Harris <paulharris@computer.org>
- Bug fix: was incorrectly casting a pointer when the search key type
was different to the stored type.
2008-12-30 Paul Harris <paulharris@computer.org>
- New function: efficient_replace_and_optimise().
Yes, its a long name. Sylvain doesn't like it.
The reason for the long name is that it is a dangerous function,
and it will resort whatever vector<> of data that you pass it.
So I wanted the user to really know what they were doing before
they called this function.
- Now calls sqrt() when required in order to search for items
in 'real' distance units... And so it will accept and return distance
in 'real' units (as opposed to squared units).
This is not an ideal solution, we have all sorts of ideas to improve
kdtree which will include less calls to sqrt() for more speed, and
the ability to change the standard euclidean distance measurements
for distance-on-a-sphere or whatever the user wants.
- Changed from using std::sort() to std::nth_element() when optimising
the tree. Performance boost.
- Added lots of tests to check that the find functions are working
correctly when fed edge-cases, including:
- Items that are exactly 'max' distance away from the target.
- When there are no value items to find.
- Templated the find functions so that the target/center point can be
anything that can be accessed via the Accessor.
- Fixes to make it compile.
- And, a Python wrapper ! See README.Python
- CMake support now can build the python wrapper and install the headers
and the python wrapper to a destination folder. Its simple, but neat.
Does not install python module into the python site packages or anything
like that.
2008-11-17 Sylvain Bougerel <sylvain.bougerel@asia.thalesgroup.com>
- The version number of the library is now part of the headers.
- Fixed a bug with assignment operator.
- Fixed uninitialized memory problem with valgrind, when printing the
content of the tree. Due to the fact the _M_header was a _Link_type
instead of a _Node_base type and _M_root was a _Base_ptr type instead of
a _Link_type.
- Paul Harris fixed find() by ensuring that the correct node is being
matched during a find(). Thus, fixed a similar problem in erase. Paul
also added a new test courtesy of Hayne.
- Paul Harris augmented test_kdtree with various test on copy
construction, assignment, and formatting operator.
- Paul Harris added support for CMake, which should suit not only
MSVC users but others too.
- Paul Harris fixed bug with compiling with MSVC2005 with the 64bit
warnings turned on.
2008-11-12 Sylvain Bougerel <sylvain.bougerel@asia.thalesgroup.com>
- Fix segfault on the regular iterator when _M_header->_M_right ==
_M_root. Fix segfault on the reverse iterator when _M_header->_M_left ==
_M_root.
Besides, it also change the behavior when iterating past the end() or
rend(). Previously this would result in segfaults, now it makes the
iterator points to an undetermined location in the tree, similarly to
the current implementation of GNU libstdc++.
2008-11-10 Sylvain Bougerel <sylvain.bougerel@asia.thalesgroup.com>
- kdtree++/iterator.hpp (KDTree): the decrement iterator was
ill-written. Its buggy behavior, and the use of non-standard
reverse_iterator initialiser needed to be fixed. These error were do to
a previous failed attempt by me at fixing the reverse_iterator.
This time, I believe I got it right, however it needed the kdtree
structure to be modified. The reason is that without modification it is
not possible to distinguish the "header" from the "root" within the
iterator. This is required for the reverse_iterator to work properly.
Now the kdtree has an additional pointer that points directly to the
root. The parent pointer of the header is permanently null. And
therefore the header can be distinguished from the root within the
iterator by checking the parent of the current node: if it is null, we
are at the header.
2008-11-10 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
- patch from Martin Shreiber to make libkdtree to compile with newer
version of g++-4.2 and g++4.3.
- patch from Paul Harris to make libkdtree more exception transparent.
2007-12-08 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
- fix bug where find_nearest() could return the wrong value if a
maximum distance greater than the root distance to the target value
was given in argument to the function.
- find_nearest() still returns SQUARED value of the distance. You still
have to use sqrt() on the second member of the iterator.
- find_nearest() behavior was slightly changed: if many nodes are at
the same distance from the target value, the node with the lowest
memory address will be returned. This is to catter for the
reimplementation of find_exact() coming soon.
2007-12-02 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
- find_nearest() now returned the SQUARED value of the distance for
euclidean space calculation (the default). You have to use sqrt() on
the returned distance (i.e. iterator->second) if you want to read the
absolute distance returned by find_nearest. My apologies for not
making highlighting this beforehand.
- Increased the performance of find and find_nearest/find_nearest_if by
about 50x to 100x depending on your compilation flags.
- KDTree are not defined as:
KDTree<__K, _Val, _Acc, _Cmp, _Alloc>
but as:
KDTree<__K, _Val, _Acc, _Dist, _Cmp, _Alloc>
So pay attention to the _Dist functor. The distance functor calculate
the squared difference between 2 elements returned by the accessor. You
might have to change your code to reflect the new definition, or it wont
compile if you have set custom accessor and comparison functors.
- The following functors are now accessible in the tree:
- the comparison functor, accessible by copy only
- the accessor functor, accessible by copy only
- the distance functor, accessible read-write, this means that
you can modify the behavior of find, find_nearest,
find_nearest_if within the same KDTree object.
- find_exact has not be modified and retained the code of the former,
slower algorithm. I have to write some more code to do this. Pls wait a
little more.
- The file accessor.hpp was renamed as function.hpp for it now boast
more than just the KDTree accessor
2007-11-25 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
- fixed the reverse_iterator. Now it can be used.
2007-10-24 Sylvain Bougerel (sylvain.bougerel.devel@gmail.com)
- Removal of all the warnings that are yield by the compiler when
using the following flags:
-Wall -pedantic -ansi
Do not hesitate to suggest any flags for additional code checking.
This release also feature numerous of enhancements by Paul Harris
(paulharris@computer.org):
- const kdtrees can be searched
- find_nearest_if() enforce validation of a predicate
- visit_within_range() walk the tree and calls
Visitor::operator() on template argument <Visitor> for
each node within the range
- find_exact() matches an kdtree::value_type by location and by
calling kdtree::value_type::operator==() (in case two different
items have the same location find_exact() will not return the
wrong item)
- erase_exact() is to erase() what find_exact() is to find()
- check_tree() and num_dist_calcs for debugging purpose plus
additional improvements on erase and region intersection
2004-11-26 Paul Harris (paulharris@computer.org)
- New feature: find_nearest()
- Accessors can now be initialised with the tree, so ptr_fun()
or functors can be used to access datapoints.
- Accessors now much more generic, so you can use the same
accessor to access multiple types.
- Range-constructors now optimise() automatically, simplifying
the construction of a filled tree.
- _Range is now more easy to construct.
2004-11-15 Martin F. Krafft (libkdtree@pobox.madduck.net)
- fixed numerous little bugs that led to compilation problems
- changed code to compile cleanly with GCC 3.4 and GCC 4.0
2004-11-06 Martin F. Krafft (libkdtree@pobox.madduck.net)
- reverted to optimise() to prevent API change, and added an optimize()
passthrough method with an appropriate comment.
2004-11-05 Paul Harris (paulharris@computer.org)
- Renamed optimise() to optimize().
- Added a full set of range constructors and insert(range) methods.
it now works with inserter(tree,tree.begin())
- Target type no longer needs a default constructor. This also fixes
problems with empty trees (would crash if optimized).
- Some code cleanup (removed inlines, switched from const_iterator to
iterator, added this-> to ensure the methods are called).
- Added a new method: count_within_range().
- Fixed bug in rend().
2004-11-04 Martin F. Krafft (libkdtree@pobox.madduck.net)
- Integrated patch by Paul Harris to fix a logic error pertaining to
OutputIterators in find_within_range. find_within_range() now
returns the output iterator instead of a count. Thanks, Paul!
- Added another fix by Paul Harris to _M_get_j_max, which would cause
a dimensional overflow for trees with depths >= K. Thanks (again) Paul!
- Made some improvements to the autotools files.
2004-05-11 Martin F. Krafft (libkdtree@pobox.madduck.net)
- Fixed CFlags and Libs entries in pkgconfig file.
2004-05-11 Martin F. Krafft (libkdtree@pobox.madduck.net)
- Initial release.
COPYRIGHT --
libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net> and
Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> and distributed under the
terms of the Artistic License 2.0. See the ./COPYING file in the source tree
root for more information.
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND
FITNESS FOR A PARTICULAR PURPOSE.

View File

@@ -24,12 +24,12 @@ Please leave bugreports on Github Issues page <https://github.com/nvmd/libkdtree
Historical background
---------------------
In the past, this library was available from [http://libkdtree.alioth.debian.org/](https://web.archive.org/web/20180422154001/http://libkdtree.alioth.debian.org/).
This page seems to be gone now, available only via [WebArchive](https://web.archive.org/web/20180422154001/http://libkdtree.alioth.debian.org/).
In the past, this library was available from <http://libkdtree.alioth.debian.org/>.
This page seems to be gone now, available only via WebArchive.
This is a mirror and a fork of that original repository, created in
2011 and maintained ever since.
Notes of the original author are preserved below.
Notes of the original author a preserved below.
Installation
------------
@@ -114,8 +114,8 @@ without the help of a number of people. Foremost, I would like to thank the
folks from the #c++ channel on Freenode, specifically (in no particular order)
orbitz, quix, Erwin, pwned, wcstok, dasOp, Chaku, Adrinael, The_Vulture, and
LIM2 (if I left anyone out, let me know). Finally, I thank the Artificial
Intelligence Laboratory of the University of Zurich, Dr. Peter Eggenberger, and
Gabriel Gómez for giving me the opportunity to write this stuff.
Intelligence Laboratory of the University of Zurich, Dr. Peter Eggenberger and
Gabriel Gómez for giving me the opportunity to write this stuff.
Since libkdtree++ makes an effort to stay as close as possible to the feel of
a STL container, concepts and inspiration was gained from the SGI C++

View File

@@ -1,3 +0,0 @@
add_executable (test_hayne test_hayne.cpp)
add_executable (test_kdtree test_kdtree.cpp)
add_executable (test_find_within_range test_find_within_range.cpp)

View File

@@ -1,108 +0,0 @@
// Thanks to James Remillard
//
#include <cstdio>
#include <kdtree++/kdtree.hpp>
#include <vector>
#include <map>
#include <set>
using namespace std;
struct kdtreeNode
{
typedef double value_type;
double xyz[3];
size_t index;
value_type operator[](size_t n) const
{
return xyz[n];
}
double distance( const kdtreeNode &node)
{
double x = xyz[0] - node.xyz[0];
double y = xyz[1] - node.xyz[1];
double z = xyz[2] - node.xyz[2];
// this is not correct return sqrt( x*x+y*y+z*z);
// this is what kdtree checks with find_within_range()
// the "manhattan distance" from the search point.
// effectively, distance is the maximum distance in any one dimension.
return max(fabs(x),max(fabs(y),fabs(z)));
}
};
int main(int argc,char *argv[])
{
vector<kdtreeNode> pts;
typedef KDTree::KDTree<3,kdtreeNode> treeType;
treeType tree;
// make random 3d points
for ( size_t n = 0; n < 10000; ++n)
{
kdtreeNode node;
node.xyz[0] = double(rand())/RAND_MAX;
node.xyz[1] = double(rand())/RAND_MAX;
node.xyz[2] = double(rand())/RAND_MAX;
node.index = n;
tree.insert( node);
pts.push_back( node);
}
for (size_t r = 0; r < 1000; ++r)
{
kdtreeNode refNode;
refNode.xyz[0] = double(rand())/RAND_MAX;
refNode.xyz[1] = double(rand())/RAND_MAX;
refNode.xyz[2] = double(rand())/RAND_MAX;
double limit = double(rand())/RAND_MAX;
// find the correct return list by checking every single point
set<size_t> correctCloseList;
for ( size_t i= 0; i < pts.size(); ++i)
{
double dist = refNode.distance( pts[i]);
if ( dist < limit)
correctCloseList.insert( i );
}
// now do the same with the kdtree.
vector<kdtreeNode> howClose;
tree.find_within_range(refNode,limit,back_insert_iterator<vector<kdtreeNode> >(howClose));
// make sure no extra points are returned, and the return has no missing points.
for ( size_t i = 0; i < howClose.size(); ++i)
{
set<size_t>::iterator hit = correctCloseList.find( howClose[i].index);
if ( hit != correctCloseList.end())
{
correctCloseList.erase(hit);
}
else
{
// point that is too far away - fail!
assert(false);
printf("fail, extra points.\n");
}
}
// fail, not all of the close enough points returned.
assert( correctCloseList.size() == 0);
if ( correctCloseList.size() > 0)
{
printf("fail, missing points.\n");
}
}
}

View File

@@ -1,116 +0,0 @@
#define KDTREE_SIZE_T unsigned int
#include <kdtree++/kdtree.hpp>
#include <vector>
#include <limits>
#include <iostream>
#include <functional>
using namespace std;
struct duplet
{
typedef int value_type;
inline value_type operator[](int const N) const { return d[N]; }
inline bool operator==(duplet const& other) const
{
return this->d[0] == other.d[0] && this->d[1] == other.d[1];
}
inline bool operator!=(duplet const& other) const
{
return this->d[0] != other.d[0] || this->d[1] != other.d[1];
}
friend ostream & operator<<(ostream & o, duplet const& d)
{
return o << "(" << d[0] << "," << d[1] << ")";
}
value_type d[2];
};
typedef KDTree::KDTree<2, duplet, std::pointer_to_binary_function<duplet,int,double> > duplet_tree_type;
inline double return_dup( duplet d, int k ) { return d[k]; }
int main()
{
duplet_tree_type dupl_tree_test(std::ptr_fun(return_dup));
std::vector<duplet> vDuplets;
//srand(time(0));
int randy1 = 0;
int randy2 = 0;
for (int i=0; i<700; i++)
{
//create coordinate for new duplet
randy1+=2;
randy1=randy1%255;
randy2+=3;
randy2=randy2%255;
//randy1 = rand() % 255;
//randy2 = rand() % 255;
//new duplet
duplet super_dupre = { {randy1, randy2} };
//check if duplet with same coordinate already in vector/tree. If not: insert in vector and tree
duplet_tree_type::iterator pItr = dupl_tree_test.find_nearest(super_dupre,std::numeric_limits<double>::max()).first;
if (*pItr!=super_dupre)
{
dupl_tree_test.insert(super_dupre);
vDuplets.push_back(super_dupre);
}
}
dupl_tree_test.optimise();
size_t elements;
while (vDuplets.size() > 0) //delete all duplets from tree which are in the vector
{
elements = vDuplets.size();
duplet element_to_erase = vDuplets.back();
vDuplets.pop_back();
if (vDuplets.size() == 147)
cout << "THIS IS THE BUG TRIGGER" << endl;
cout << vDuplets.size() << " : Deleting " << element_to_erase << endl;
assert( find(dupl_tree_test.begin(),dupl_tree_test.end(), element_to_erase) != dupl_tree_test.end() );
assert(dupl_tree_test.find(element_to_erase) != dupl_tree_test.end());
duplet_tree_type::iterator will = dupl_tree_test.find(element_to_erase);
duplet_tree_type::iterator should = dupl_tree_test.find_exact(element_to_erase);
cout << " tree will delete: " << *will << endl;
cout << " tree should delete: " << *should << endl;
assert(*will == *should);
dupl_tree_test.erase(element_to_erase); //erase() : will probably erase wrong element sooner or later
//dupl_tree_test.erase_exact(element_to_erase); --> this works
// now check that it cannot find the element UNLESS there is another one with the identical location in the list...
if (find(vDuplets.begin(),vDuplets.end(),element_to_erase) == vDuplets.end())
{
duplet_tree_type::iterator not_there = dupl_tree_test.find(element_to_erase);
if (not_there != dupl_tree_test.end())
{
cout << "SHOULD NOT HAVE FOUND THIS: " << *not_there << endl;
assert(0);
}
else
{
cout << " find() double-check passed." << endl;
}
}
}
}

View File

@@ -1,424 +0,0 @@
#define KDTREE_DEFINE_OSTREAM_OPERATORS
// Make SURE all our asserts() are checked
#undef NDEBUG
#include <kdtree++/kdtree.hpp>
#include <deque>
#include <iostream>
#include <vector>
#include <limits>
#include <functional>
#include <set>
// used to ensure all triplets that are accessed via the operator<< are initialised.
std::set<const void*> registered;
struct triplet
{
typedef double value_type;
triplet(value_type a, value_type b, value_type c)
{
d[0] = a;
d[1] = b;
d[2] = c;
bool reg_ok = (registered.find(this) == registered.end());
assert(reg_ok);
bool reg_inserted_ok = registered.insert(this).second;
assert(reg_inserted_ok);
}
triplet(const triplet & x)
{
d[0] = x.d[0];
d[1] = x.d[1];
d[2] = x.d[2];
bool reg_ok = (registered.find(this) == registered.end());
assert(reg_ok);
bool reg_inserted_ok = registered.insert(this).second;
assert(reg_inserted_ok);
}
~triplet()
{
bool unreg_ok = (registered.find(this) != registered.end());
assert(unreg_ok);
registered.erase(this);
}
double distance_to(triplet const& x) const
{
double dist = 0;
for (int i = 0; i != 3; ++i)
dist += (d[i]-x.d[i])*(d[i]-x.d[i]);
return std::sqrt(dist);
}
inline value_type operator[](size_t const N) const { return d[N]; }
value_type d[3];
};
// same as triplet, except with the values reversed.
struct alternate_triplet
{
typedef double value_type;
alternate_triplet(const triplet & x)
{
d[0] = x.d[2];
d[1] = x.d[1];
d[2] = x.d[0];
}
inline value_type operator[](size_t const N) const { return d[2-N]; }
value_type d[3];
};
inline bool operator==(triplet const& A, triplet const& B) {
return A.d[0] == B.d[0] && A.d[1] == B.d[1] && A.d[2] == B.d[2];
}
std::ostream& operator<<(std::ostream& out, triplet const& T)
{
assert(registered.find(&T) != registered.end());
return out << '(' << T.d[0] << ',' << T.d[1] << ',' << T.d[2] << ')';
}
inline double tac( triplet t, size_t k ) { return t[k]; }
// use tac as a class instead of a function,
// can access more than one type with just 1 definition.
struct alternate_tac
{
typedef double result_type;
double operator()( triplet const& t, size_t k ) const { return t[k]; }
double operator()( alternate_triplet const& t, size_t k ) const { return t[k]; }
};
typedef KDTree::KDTree<3, triplet, std::pointer_to_binary_function<triplet,size_t,double> > tree_type;
struct Predicate
{
bool operator()( triplet const& t ) const
{
return t[0] > 3; // anything, we are currently testing that it compiles.
}
};
// never finds anything
struct FalsePredicate
{
bool operator()( triplet const& t ) const { return false; }
};
int main()
{
// check that it'll find nodes exactly MAX away
{
tree_type exact_dist(std::ptr_fun(tac));
triplet c0(5, 4, 0);
exact_dist.insert(c0);
triplet target(7,4,0);
std::pair<tree_type::const_iterator,double> found = exact_dist.find_nearest(target,2);
assert(found.first != exact_dist.end());
assert(found.second == 2);
std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << std::endl;
}
// do the same test, except use alternate_triplet as the search key
{
// NOTE: stores triplet, but we search with alternate_triplet
typedef KDTree::KDTree<3, triplet, alternate_tac> alt_tree;
triplet actual_target(7,0,0);
alt_tree tree;
tree.insert( triplet(0, 0, 7) );
tree.insert( triplet(0, 0, 7) );
tree.insert( triplet(0, 0, 7) );
tree.insert( triplet(3, 0, 0) );
tree.insert( actual_target );
tree.optimise();
alternate_triplet target( actual_target );
std::pair<alt_tree::const_iterator,double> found = tree.find_nearest(target);
assert(found.first != tree.end());
std::cout << "Test with alternate search type, found: " << *found.first << ", wanted " << actual_target << std::endl;
assert(found.second == 0);
assert(*found.first == actual_target);
}
{
tree_type exact_dist(std::ptr_fun(tac));
triplet c0(5, 2, 0);
exact_dist.insert(c0);
triplet target(7,4,0);
// call find_nearest without a range value - it found a compile error earlier.
std::pair<tree_type::const_iterator,double> found = exact_dist.find_nearest(target);
assert(found.first != exact_dist.end());
std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << " @ " << found.second << " should be " << std::sqrt(8) << std::endl;
assert(found.second == std::sqrt(8));
}
{
tree_type exact_dist(std::ptr_fun(tac));
triplet c0(5, 2, 0);
exact_dist.insert(c0);
triplet target(7,4,0);
std::pair<tree_type::const_iterator,double> found = exact_dist.find_nearest(target,std::sqrt(8));
assert(found.first != exact_dist.end());
std::cout << "Test find_nearest(), found at exact distance away from " << target << ", found " << *found.first << " @ " << found.second << " should be " << std::sqrt(8) << std::endl;
assert(found.second == std::sqrt(8));
}
tree_type src(std::ptr_fun(tac));
triplet c0(5, 4, 0); src.insert(c0);
triplet c1(4, 2, 1); src.insert(c1);
triplet c2(7, 6, 9); src.insert(c2);
triplet c3(2, 2, 1); src.insert(c3);
triplet c4(8, 0, 5); src.insert(c4);
triplet c5(5, 7, 0); src.insert(c5);
triplet c6(3, 3, 8); src.insert(c6);
triplet c7(9, 7, 3); src.insert(c7);
triplet c8(2, 2, 6); src.insert(c8);
triplet c9(2, 0, 6); src.insert(c9);
std::cout << src << std::endl;
src.erase(c0);
src.erase(c1);
src.erase(c3);
src.erase(c5);
src.optimise();
// test the efficient_replace_and_optimise()
tree_type eff_repl = src;
{
std::vector<triplet> vec;
// erased above as part of test vec.push_back(triplet(5, 4, 0));
// erased above as part of test vec.push_back(triplet(4, 2, 1));
vec.push_back(triplet(7, 6, 9));
// erased above as part of test vec.push_back(triplet(2, 2, 1));
vec.push_back(triplet(8, 0, 5));
// erased above as part of test vec.push_back(triplet(5, 7, 0));
vec.push_back(triplet(3, 3, 8));
vec.push_back(triplet(9, 7, 3));
vec.push_back(triplet(2, 2, 6));
vec.push_back(triplet(2, 0, 6));
eff_repl.clear();
eff_repl.efficient_replace_and_optimise(vec);
}
std::cout << std::endl << src << std::endl;
tree_type copied(src);
std::cout << copied << std::endl;
tree_type assigned = src;
std::cout << assigned << std::endl;
for (int loop = 0; loop != 4; ++loop)
{
tree_type * target;
switch (loop)
{
case 0: std::cout << "Testing plain construction" << std::endl;
target = &src;
break;
case 1: std::cout << "Testing copy-construction" << std::endl;
target = &copied;
break;
case 2: std::cout << "Testing assign-construction" << std::endl;
target = &assigned;
break;
default:
case 4: std::cout << "Testing efficient-replace-and-optimise" << std::endl;
target = &eff_repl;
break;
}
tree_type & t = *target;
int i=0;
for (tree_type::const_iterator iter=t.begin(); iter!=t.end(); ++iter, ++i);
std::cout << "iterator walked through " << i << " nodes in total" << std::endl;
if (i!=6)
{
std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl;
return 1;
}
i=0;
for (tree_type::const_reverse_iterator iter=t.rbegin(); iter!=t.rend(); ++iter, ++i);
std::cout << "reverse_iterator walked through " << i << " nodes in total" << std::endl;
if (i!=6)
{
std::cerr << "Error: does not tally with the expected number of nodes (6)" << std::endl;
return 1;
}
triplet s(5, 4, 3);
std::vector<triplet> v;
unsigned int const RANGE = 3;
size_t count = t.count_within_range(s, RANGE);
std::cout << "counted " << count
<< " nodes within range " << RANGE << " of " << s << ".\n";
t.find_within_range(s, RANGE, std::back_inserter(v));
std::cout << "found " << v.size() << " nodes within range " << RANGE
<< " of " << s << ":\n";
std::vector<triplet>::const_iterator ci = v.begin();
for (; ci != v.end(); ++ci)
std::cout << *ci << " ";
std::cout << "\n" << std::endl;
std::cout << std::endl << t << std::endl;
// search for all the nodes at exactly 0 dist away
for (tree_type::const_iterator target = t.begin(); target != t.end(); ++target)
{
std::pair<tree_type::const_iterator,double> found = t.find_nearest(*target,0);
assert(found.first != t.end());
assert(*found.first == *target);
std::cout << "Test find_nearest(), found at exact distance away from " << *target << ", found " << *found.first << std::endl;
}
{
const double small_dist = 0.0001;
std::pair<tree_type::const_iterator,double> notfound = t.find_nearest(s,small_dist);
std::cout << "Test find_nearest(), nearest to " << s << " within " << small_dist << " should not be found" << std::endl;
if (notfound.first != t.end())
{
std::cout << "ERROR found a node at dist " << notfound.second << " : " << *notfound.first << std::endl;
std::cout << "Actual distance = " << s.distance_to(*notfound.first) << std::endl;
}
assert(notfound.first == t.end());
}
{
std::pair<tree_type::const_iterator,double> nif = t.find_nearest_if(s,std::numeric_limits<double>::max(),Predicate());
std::cout << "Test find_nearest_if(), nearest to " << s << " @ " << nif.second << ": " << *nif.first << std::endl;
std::pair<tree_type::const_iterator,double> cantfind = t.find_nearest_if(s,std::numeric_limits<double>::max(),FalsePredicate());
std::cout << "Test find_nearest_if(), nearest to " << s << " should never be found (predicate too strong)" << std::endl;
assert(cantfind.first == t.end());
}
{
std::pair<tree_type::const_iterator,double> found = t.find_nearest(s,std::numeric_limits<double>::max());
std::cout << "Nearest to " << s << " @ " << found.second << " " << *found.first << std::endl;
std::cout << "Should be " << found.first->distance_to(s) << std::endl;
// NOTE: the assert does not check for an exact match, as it is not exact when -O2 or -O3 is
// switched on. Some sort of optimisation makes the math inexact.
assert( fabs(found.second - found.first->distance_to(s)) < std::numeric_limits<double>::epsilon() );
}
{
triplet s2(10, 10, 2);
std::pair<tree_type::const_iterator,double> found = t.find_nearest(s2,std::numeric_limits<double>::max());
std::cout << "Nearest to " << s2 << " @ " << found.second << " " << *found.first << std::endl;
std::cout << "Should be " << found.first->distance_to(s2) << std::endl;
// NOTE: the assert does not check for an exact match, as it is not exact when -O2 or -O3 is
// switched on. Some sort of optimisation makes the math inexact.
assert( fabs(found.second - found.first->distance_to(s2)) < std::numeric_limits<double>::epsilon() );
}
std::cout << std::endl;
std::cout << t << std::endl;
// Testing iterators
{
std::cout << "Testing iterators" << std::endl;
t.erase(c2);
t.erase(c4);
t.erase(c6);
t.erase(c7);
t.erase(c8);
// t.erase(c9);
std::cout << std::endl << t << std::endl;
std::cout << "Forward iterator test..." << std::endl;
std::vector<triplet> forwards;
for (tree_type::iterator i = t.begin(); i != t.end(); ++i)
{ std::cout << *i << " " << std::flush; forwards.push_back(*i); }
std::cout << std::endl;
std::cout << "Reverse iterator test..." << std::endl;
std::vector<triplet> backwards;
for (tree_type::reverse_iterator i = t.rbegin(); i != t.rend(); ++i)
{ std::cout << *i << " " << std::flush; backwards.push_back(*i); }
std::cout << std::endl;
std::reverse(backwards.begin(),backwards.end());
assert(backwards == forwards);
}
}
// Walter reported that the find_within_range() wasn't giving results that were within
// the specified range... this is the test.
{
tree_type tree(std::ptr_fun(tac));
tree.insert( triplet(28.771200,16.921600,-2.665970) );
tree.insert( triplet(28.553101,18.649700,-2.155560) );
tree.insert( triplet(28.107500,20.341400,-1.188940) );
tree.optimise();
std::deque< triplet > vectors;
triplet sv(18.892500,20.341400,-1.188940);
tree.find_within_range(sv, 10.0f, std::back_inserter(vectors));
std::cout << std::endl << "Test find_with_range( " << sv << ", 10.0f) found " << vectors.size() << " candidates." << std::endl;
// double-check the ranges
for (std::deque<triplet>::iterator v = vectors.begin(); v != vectors.end(); ++v)
{
double dist = sv.distance_to(*v);
std::cout << " " << *v << " dist=" << dist << std::endl;
if (dist > 10.0f)
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;
// Not a valid test, it can be greater than 10 if the point is in the corners of the box.
// assert(dist <= 10.0f);
}
}
return 0;
}
/* COPYRIGHT --
*
* This file is part of libkdtree++, a C++ template KD-Tree sorting container.
* libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
* and Sylvain Bougerel <sylvain.bougerel.devel@gmail.com> distributed under the
* terms of the Artistic License 2.0. See the ./COPYING file in the source tree
* root for more information.
*
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
* OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/

View File

@@ -54,8 +54,8 @@ namespace KDTree
inline _Base_iterator(_Base_const_ptr const __N = NULL)
: _M_node(__N) {}
//inline _Base_iterator(_Base_iterator const& __THAT)
// : _M_node(__THAT._M_node) {}
inline _Base_iterator(_Base_iterator const& __THAT)
: _M_node(__THAT._M_node) {}
inline void
_M_increment()

View File

@@ -53,12 +53,12 @@
// KDTREE_VERSION % 100 is the patch level
// KDTREE_VERSION / 100 % 1000 is the minor version
// KDTREE_VERSION / 100000 is the major version
#define KDTREE_VERSION 702
#define KDTREE_VERSION 704
//
// KDTREE_LIB_VERSION must be defined to be the same as KDTREE_VERSION
// but as a *string* in the form "x_y[_z]" where x is the major version
// number, y is the minor version number, and z is the patch level if not 0.
#define KDTREE_LIB_VERSION "0_7_2"
#define KDTREE_LIB_VERSION "0_7_4"
#include <vector>
@@ -1214,7 +1214,6 @@ protected:
o << "dimensions: " << __K << std::endl;
typedef KDTree<__K, _Val, _Acc, _Dist, _Cmp, _Alloc> _Tree;
typedef typename _Tree::_Link_type _Link_type;
std::stack<_Link_const_type> s;
s.push(tree._M_get_root());

View File

@@ -27,7 +27,7 @@ namespace KDTree
typedef std::pair<_Region,_SubVal> _CenterPt;
_Region(_Acc const& __acc=_Acc(), const _Cmp& __cmp=_Cmp())
: _M_cmp(__cmp), _M_acc(__acc) {}
: _M_acc(__acc), _M_cmp(__cmp) {}
template <typename Val>
_Region(Val const& __V,

View File

@@ -10,7 +10,7 @@ include_directories (${CMAKE_CURRENT_SOURCE_DIR}/..)
# Build the _kdtree python module
set_source_files_properties (py-kdtree.i PROPERTIES CPLUSPLUS ON)
swig_add_module (kdtree python py-kdtree.i)
swig_link_libraries (kdtree ${Python3_LIBRARIES})
swig_link_libraries (kdtree ${PYTHON_LIBRARIES})
# Copy the test file into the build dir
install (FILES py-kdtree_test.py DESTINATION ${CMAKE_INSTALL_PREFIX}/python)