Update libkdtree from 0.7.0 to 0.7.1.1

This commit is contained in:
andrea
2023-08-21 10:50:03 +02:00
committed by Chris Hennes
parent d3af7e1e8d
commit 6dc39dd5d9
9 changed files with 1234 additions and 1222 deletions

View File

@@ -1,14 +1,5 @@
libkdtree++ README
==================
libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
and distributed under the terms of the Artistic License 2.0.
See the file LICENSE in the source distribution for more information.
Please send bugreports to <libkdtree-devel@lists.alioth.debian.org>.
Introduction
------------
libkdtree++
===========
libkdtree++ is a C++ template container implementation of k-dimensional space
sorting, using a kd-tree. It:
@@ -16,34 +7,108 @@ sorting, using a kd-tree. It:
- sports an unlimited number of dimensions (in theory)
- can store any data structure, access and comparison between the
individual dimensional components defaults to the bracket operator, in
the range [0, k-1] and the std::less functor by default, but other
the range `[0, k-1]` and the `std::less` functor by default, but other
accessors and comparator can be defined.
- has support for custom allocators
- implements iterators
- provides standard find as well as range queries
- has amortised O(lg n) time (O(n lg n) worst case) on most
operations (insert/erase/find optimised) and worst-case O(n) space.
- has amortised `O(lg n)` time (`O(n lg n)` worst case) on most
operations (insert/erase/find optimised) and worst-case `O(n)` space.
- provides a means to rebalance and thus optimise the tree.
- exists in its own namespace
- uses STL coding style, basing a lot of the code on stl_tree.h
- uses STL coding style, basing a lot of the code on `stl_tree.h`
Notes
Please leave bugreports on Github Issues page <https://github.com/nvmd/libkdtree/issues>.
Historical background
---------------------
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 a preserved below.
Installation
------------
As there is no need to compile any files, you can just:
```sh
$ ./configure
$ sudo make install
```
It now also supports cmake, which can be used to build the examples
and tests.
To build with cmake:
```sh
$ mkdir build
$ cd build
$ cmake ..
$ make
```
You can use cmake to build the tests and examples on Windows with
Visual C++. Use the windows cmake to create a Visual C++ solution and
build that.
Note that `cmake` and `./configure` is not needed at all in order to use
kdtree in your application. As libkdtree++ is a header-only library, you
just need to #include the `kdtree.hpp`.
Read the following to make use of the library.
Usage
-----
A simple example program is provided in the `./examples` directory
(`/usr/share/doc/libkdtree++-dev/examples` on Debian).
For those using the ./configure system, the library supports pkg-config.
Thus, to compile with the library,
```c++
#include <kdtree++/kdtree.hpp>
```
and append the output of `pkg-config libkdtree++ --cflags` to your `$CPPFLAGS`.
Each call to `erase()` and `insert()` unbalances the tree. It is possible that
nodes will not be found while the tree is unbalanced. You rebalance the
tree by calling `optimize()`, and you should call it before you need to search
the tree (this includes `erase(value)` calls, which search the tree).
It is ok to call `insert(value)` many times and `optimize()` at the end, but
every `erase()` call should be followed with `optimize()`.
Notes (Martin F. Kraft)
-----------------------
Note that the library is not (yet) complete and it's not thoroughly tested.
However, given the effort and grief I went through in writing it, I would
like to make it available to folks, get people to test it, and hopefully have
some peeps submit improvements. If you have any suggestions, please write to
libkdtree-devel@lists.alioth.debian.org .
some peeps submit improvements. If you have any suggestions, please create an
issue on Github Issue page <https://github.com/nvmd/libkdtree/issues>.
It's not yet documented, although the usage should be fairly straight
forward. I am hoping to find someone else to document it as I suck at
documentation and as the author, it's exceptionally difficult to stay
didactically correct.
Credits (Martin F. Kraft)
-------------------------
libkdtree++ is (c) 2004-2007 Martin F. Krafft <libkdtree@pobox.madduck.net>
and distributed under the terms of the Artistic License 2.0.
See the file LICENSE in the source distribution for more information.
While the library was written all by myself, it would not have been possible
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)
@@ -54,68 +119,8 @@ Gabriel G
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++
implementation of red-black trees (stl_tree.h).
implementation of red-black trees (`stl_tree.h`).
I also have to thank the Debian project for providing an amazingly reliable
and flexible developer station with their operating system. I am sorry for
everyone who has to use something else.
Installation
------------
As there is no need to compile any files, you can just:
$ ./configure
$ sudo make install
It now also supports cmake, which can be used to build the examples
and tests.
To build with cmake, do an out-of-source build like so:
# ASSUMING you have decompressed it into a directory called libkdtree,
# and you are currently in that directory...
$ cd .. # go up, out of the kdtree source directory
$ mkdir build
$ cd build
$ cmake ../libkdtree
$ make
You can use cmake to build the tests and examples on Windows with
Visual C++. Use the windows cmake to create a Visual C++ solution and
build that.
Note that cmake and ./configure is not needed at all in order to use
kdtree in your application. As kdtree is a header-only library, you
just need to #include the kdtree.hpp
Read the following to make use of the library.
Usage
-----
A simple example program is provided in the ./examples directory
(/usr/share/doc/libkdtree++-dev/examples on Debian).
For those using the ./configure system, the library supports pkg-config.
Thus, to compile with the library,
#include <kdtree++/kdtree.hpp>
and append the output of `pkg-config libkdtree++ --cflags` to your $CPPFLAGS.
Each call to erase() and insert() unbalances the tree. It is possible that
nodes will not be found while the tree is unbalanced. You rebalance the
tree by calling optimize(), and you should call it before you need to search
the tree (this includes erase(value) calls, which search the tree).
It is ok to call insert(value) many times and optimize() at the end, but
every erase() call should be followed with optimize().
These notes are a bit out of date, please check the webpage and mailing list
for more info. Documentation is on the TODO list.
Have fun.

View File

@@ -17,7 +17,7 @@ std::set<const void*> registered;
struct triplet
{
typedef int value_type;
typedef double value_type;
triplet(value_type a, value_type b, value_type c)
{
@@ -26,7 +26,8 @@ struct triplet
d[2] = c;
bool reg_ok = (registered.find(this) == registered.end());
assert(reg_ok);
registered.insert(this).second;
bool reg_inserted_ok = registered.insert(this).second;
assert(reg_inserted_ok);
}
triplet(const triplet & x)
@@ -36,7 +37,8 @@ struct triplet
d[2] = x.d[2];
bool reg_ok = (registered.find(this) == registered.end());
assert(reg_ok);
registered.insert(this).second;
bool reg_inserted_ok = registered.insert(this).second;
assert(reg_inserted_ok);
}
~triplet()
@@ -64,7 +66,7 @@ struct triplet
// same as triplet, except with the values reversed.
struct alternate_triplet
{
typedef int value_type;
typedef double value_type;
alternate_triplet(const triplet & x)
{
@@ -228,8 +230,7 @@ int main()
tree_type copied(src);
std::cout << copied << std::endl;
tree_type assigned;
assigned = src;
tree_type assigned = src;
std::cout << assigned << std::endl;
for (int loop = 0; loop != 4; ++loop)

View File

@@ -41,7 +41,7 @@ namespace KDTree
NoLeakAlloc(_Alloc_base * b) : base(b), new_node(base->_M_allocate_node()) {}
_Node_ * get() { return new_node; }
void disconnect() { new_node = nullptr; }
void disconnect() { new_node = NULL; }
~NoLeakAlloc() { if (new_node) base->_M_deallocate_node(new_node); }
};
@@ -74,7 +74,11 @@ namespace KDTree
void
_M_destroy_node(_Node_* __p)
{
#if __cplusplus >= 201703L
std::allocator_traits<allocator_type>::destroy(_M_node_allocator,__p);
#else
_M_node_allocator.destroy(__p);
#endif
}
};

View File

@@ -9,7 +9,7 @@
#include <iterator>
#include <kdtree++/node.hpp>
#include "node.hpp"
namespace KDTree
{
@@ -52,10 +52,10 @@ namespace KDTree
typedef _Node_base::_Base_const_ptr _Base_const_ptr;
_Base_const_ptr _M_node;
inline _Base_iterator(_Base_const_ptr const __N = nullptr)
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()
@@ -205,37 +205,37 @@ namespace KDTree
};
template<typename _Val, typename _Ref, typename _Ptr>
inline bool
bool
operator==(_Iterator<_Val, _Ref, _Ptr> const& __X,
_Iterator<_Val, _Ref, _Ptr> const& __Y)
{ return __X._M_node == __Y._M_node; }
template<typename _Val>
inline bool
bool
operator==(_Iterator<_Val, const _Val&, const _Val*> const& __X,
_Iterator<_Val, _Val&, _Val*> const& __Y)
{ return __X._M_node == __Y._M_node; }
template<typename _Val>
inline bool
bool
operator==(_Iterator<_Val, _Val&, _Val*> const& __X,
_Iterator<_Val, const _Val&, const _Val*> const& __Y)
{ return __X._M_node == __Y._M_node; }
template<typename _Val, typename _Ref, typename _Ptr>
inline bool
bool
operator!=(_Iterator<_Val, _Ref, _Ptr> const& __X,
_Iterator<_Val, _Ref, _Ptr> const& __Y)
{ return __X._M_node != __Y._M_node; }
template<typename _Val>
inline bool
bool
operator!=(_Iterator<_Val, const _Val&, const _Val*> const& __X,
_Iterator<_Val, _Val&, _Val*> const& __Y)
{ return __X._M_node != __Y._M_node; }
template<typename _Val>
inline bool
bool
operator!=(_Iterator<_Val, _Val&, _Val*> const& __X,
_Iterator<_Val, const _Val&, const _Val*> const& __Y)
{ return __X._M_node != __Y._M_node; }

File diff suppressed because it is too large Load Diff

View File

@@ -25,9 +25,9 @@ namespace KDTree
_Base_ptr _M_left;
_Base_ptr _M_right;
_Node_base(_Base_ptr const __PARENT = nullptr,
_Base_ptr const __LEFT = nullptr,
_Base_ptr const __RIGHT = nullptr)
_Node_base(_Base_ptr const __PARENT = NULL,
_Base_ptr const __LEFT = NULL,
_Base_ptr const __RIGHT = NULL)
: _M_parent(__PARENT), _M_left(__LEFT), _M_right(__RIGHT) {}
static _Base_ptr
@@ -43,24 +43,8 @@ namespace KDTree
while (__x->_M_right) __x = __x->_M_right;
return __x;
}
};
template <typename _Val>
struct _Node : public _Node_base
{
using _Node_base::_Base_ptr;
typedef _Node* _Link_type;
_Val _M_value;
_Node(_Val const& __VALUE = _Val(),
_Base_ptr const __PARENT = nullptr,
_Base_ptr const __LEFT = nullptr,
_Base_ptr const __RIGHT = nullptr)
: _Node_base(__PARENT, __LEFT, __RIGHT), _M_value(__VALUE) {}
#ifdef KDTREE_DEFINE_OSTREAM_OPERATORS
template <typename Char, typename Traits>
friend
std::basic_ostream<Char, Traits>&
@@ -73,7 +57,24 @@ namespace KDTree
out << "; right: " << node._M_right;
return out;
}
#endif
};
template <typename _Val>
struct _Node : public _Node_base
{
using _Node_base::_Base_ptr;
typedef _Node* _Link_type;
_Val _M_value;
_Node(_Val const& __VALUE = _Val(),
_Base_ptr const __PARENT = NULL,
_Base_ptr const __LEFT = NULL,
_Base_ptr const __RIGHT = NULL)
: _Node_base(__PARENT, __LEFT, __RIGHT), _M_value(__VALUE) {}
#ifdef KDTREE_DEFINE_OSTREAM_OPERATORS
template <typename Char, typename Traits>
friend
std::basic_ostream<Char, Traits>&
@@ -87,7 +88,6 @@ namespace KDTree
out << "; right: " << node._M_right;
return out;
}
#endif
};
@@ -168,17 +168,16 @@ namespace KDTree
\note it's the caller responsibility to check if node is NULL.
*/
template <typename _Val, typename _Cmp, typename _Acc>
template <typename _Val, typename _Cmp, typename _Acc, typename NodeType>
inline
_Node_base*
const NodeType*
_S_node_descend (const size_t __dim,
const _Cmp& __cmp, const _Acc& __acc,
const _Val& __val, const _Node_base* __node)
const _Val& __val, const NodeType* __node)
{
if (_S_node_compare(__dim, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(__node)->_M_value))
return __node->_M_left;
else
return __node->_M_right;
if (_S_node_compare(__dim, __cmp, __acc, __val, __node->_M_value))
return static_cast<const NodeType *>(__node->_M_left);
return static_cast<const NodeType *>(__node->_M_right);
}
/*! Find the nearest node to __val from __node
@@ -190,37 +189,38 @@ namespace KDTree
given arguments.
*/
template <class SearchVal,
typename _Val, typename _Cmp,
typename NodeType, typename _Cmp,
typename _Acc, typename _Dist,
typename _Predicate>
inline
std::pair<const _Node<_Val>*,
std::pair<const NodeType*,
std::pair<size_t, typename _Dist::distance_type> >
_S_node_nearest (const size_t __k, size_t __dim, SearchVal const& __val,
const _Node<_Val>* __node, const _Node_base* __end,
const _Node<_Val>* __best, typename _Dist::distance_type __max,
const NodeType* __node, const _Node_base* __end,
const NodeType* __best, typename _Dist::distance_type __max,
const _Cmp& __cmp, const _Acc& __acc, const _Dist& __dist,
_Predicate __p)
{
const _Node_base* pcur = __node;
const _Node_base* cur = _S_node_descend(__dim % __k, __cmp, __acc, __val, __node);
typedef const NodeType* NodePtr;
NodePtr pcur = __node;
NodePtr cur = _S_node_descend(__dim % __k, __cmp, __acc, __val, __node);
size_t cur_dim = __dim+1;
// find the smallest __max distance in direct descent
while (cur)
{
if (__p(static_cast<const _Node<_Val>* >(cur)->_M_value))
if (__p(cur->_M_value))
{
typename _Dist::distance_type d = 0;
for (size_t i=0; i != __k; ++i)
d += _S_node_distance(i, __dist, __acc, __val, static_cast<const _Node<_Val>* >(cur)->_M_value);
d = sqrt(d);
d += _S_node_distance(i, __dist, __acc, __val, cur->_M_value);
d = std::sqrt(d);
if (d <= __max)
// ("bad candidate notes")
// Changed: removed this test: || ( d == __max && cur < __best ))
// Can't do this optimisation without checking that the current 'best' is not the root AND is not a valid candidate...
// 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)
{
__best = static_cast<const _Node<_Val>* >(cur);
__best = cur;
__max = d;
__dim = cur_dim;
}
@@ -232,20 +232,20 @@ namespace KDTree
// Swap cur to prev, only prev is a valid node.
cur = pcur;
--cur_dim;
pcur = nullptr;
pcur = NULL;
// Probe all node's children not visited yet (siblings of the visited nodes).
const _Node_base* probe = cur;
const _Node_base* pprobe = probe;
const _Node_base* near_node;
const _Node_base* far_node;
NodePtr probe = cur;
NodePtr pprobe = probe;
NodePtr near_node;
NodePtr far_node;
size_t probe_dim = cur_dim;
if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value))
near_node = probe->_M_right;
if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, probe->_M_value))
near_node = static_cast<NodePtr>(probe->_M_right);
else
near_node = probe->_M_left;
near_node = static_cast<NodePtr>(probe->_M_left);
if (near_node
// only visit node's children if node's plane intersect hypersphere
&& (sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max))
&& (std::sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, probe->_M_value)) <= __max))
{
probe = near_node;
++probe_dim;
@@ -254,27 +254,27 @@ namespace KDTree
{
while (probe != cur)
{
if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value))
if (_S_node_compare(probe_dim % __k, __cmp, __acc, __val, probe->_M_value))
{
near_node = probe->_M_left;
far_node = probe->_M_right;
near_node = static_cast<NodePtr>(probe->_M_left);
far_node = static_cast<NodePtr>(probe->_M_right);
}
else
{
near_node = probe->_M_right;
far_node = probe->_M_left;
near_node = static_cast<NodePtr>(probe->_M_right);
far_node = static_cast<NodePtr>(probe->_M_left);
}
if (pprobe == probe->_M_parent) // going downward ...
{
if (__p(static_cast<const _Node<_Val>* >(probe)->_M_value))
if (__p(probe->_M_value))
{
typename _Dist::distance_type d = 0;
for (size_t i=0; i < __k; ++i)
d += _S_node_distance(i, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value);
d = sqrt(d);
d += _S_node_distance(i, __dist, __acc, __val, probe->_M_value);
d = std::sqrt(d);
if (d <= __max) // CHANGED, see the above notes ("bad candidate notes")
{
__best = static_cast<const _Node<_Val>* >(probe);
__best = probe;
__max = d;
__dim = probe_dim;
}
@@ -287,14 +287,14 @@ namespace KDTree
}
else if (far_node &&
// only visit node's children if node's plane intersect hypersphere
sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max)
std::sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, probe->_M_value)) <= __max)
{
probe = far_node;
++probe_dim;
}
else
{
probe = probe->_M_parent;
probe = static_cast<NodePtr>(probe->_M_parent);
--probe_dim;
}
}
@@ -302,7 +302,7 @@ namespace KDTree
{
if (pprobe == near_node && far_node
// only visit node's children if node's plane intersect hypersphere
&& sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(probe)->_M_value)) <= __max)
&& std::sqrt(_S_node_distance(probe_dim % __k, __dist, __acc, __val, probe->_M_value)) <= __max)
{
pprobe = probe;
probe = far_node;
@@ -311,13 +311,13 @@ namespace KDTree
else
{
pprobe = probe;
probe = probe->_M_parent;
probe = static_cast<NodePtr>(probe->_M_parent);
--probe_dim;
}
}
}
pcur = cur;
cur = cur->_M_parent;
cur = static_cast<NodePtr>(cur->_M_parent);
--cur_dim;
pprobe = cur;
probe = cur;
@@ -325,19 +325,19 @@ namespace KDTree
if (cur != __end)
{
if (pcur == cur->_M_left)
near_node = cur->_M_right;
near_node = static_cast<NodePtr>(cur->_M_right);
else
near_node = cur->_M_left;
near_node = static_cast<NodePtr>(cur->_M_left);
if (near_node
// only visit node's children if node's plane intersect hypersphere
&& (sqrt(_S_node_distance(cur_dim % __k, __dist, __acc, __val, static_cast<const _Node<_Val>* >(cur)->_M_value)) <= __max))
&& (std::sqrt(_S_node_distance(cur_dim % __k, __dist, __acc, __val, cur->_M_value)) <= __max))
{
probe = near_node;
++probe_dim;
}
}
}
return std::pair<const _Node<_Val>*,
return std::pair<NodePtr,
std::pair<size_t, typename _Dist::distance_type> >
(__best, std::pair<size_t, typename _Dist::distance_type>
(__dim, __max));

View File

@@ -9,7 +9,7 @@
#include <cstddef>
#include <kdtree++/node.hpp>
#include "node.hpp"
namespace KDTree
{
@@ -27,7 +27,7 @@ namespace KDTree
typedef std::pair<_Region,_SubVal> _CenterPt;
_Region(_Acc const& __acc=_Acc(), const _Cmp& __cmp=_Cmp())
: _M_cmp(__acc), _M_acc(__cmp) {}
: _M_cmp(__cmp), _M_acc(__acc) {}
template <typename Val>
_Region(Val const& __V,

0
src/3rdParty/libkdtree/python-bindings/gen-swig-hpp.py vendored Normal file → Executable file
View File

View File

@@ -6,11 +6,6 @@ import unittest
from kdtree import KDTree_2Int, KDTree_4Int, KDTree_3Float, KDTree_4Float, KDTree_6Float
try:
long
except NameError:
long = int
class KDTree_2IntTestCase(unittest.TestCase):
def test_empty(self):