libkdtree experiences and questions
Sam Hayne
Sam.Hayne at gmx.de
Mon Nov 10 18:19:28 UTC 2008
Hello! :)
First: Thx for libkdtree!
(and sorry for posting in the wrong maillist at first... :-/ )
Started to use libkdtree last week and it speeds up things a LOT compared to
a naive simple search in my case.
Version used:
Copied the current files out of here manually:
http://git.debian.org/?p=libkdtree/libkdtree.git;a=tree
Here the experiences I made. :)
As the posting is a bit longer, a short summary:
1) compiler errors in VC2005 + solution
I don't claim that they are the best way of solving the errors - but maybe
you want to make some changes in your project to ease lives of VC users. :)
2) "My" 2D Nearest Neighbor search solution (basically some changes to the
previously mentioned approach)
...as the previously mentioned ones didn't compile for me at all and
ultimately resulted in a heap corruption (shared_ptr behaved like a beast
here).
3) some questions
=====================================
1) compiler errors in VC2005 + solution
=====================================
allocator.hpp:
typedef confusion
error: kdtree++/kdtree.hpp(95) : error C2059: syntax error : '<'
solved by:
rename all _Node to e.g. _Node_Ab in this file starting from line 21:
old: typedef typename _Node<_Tp> _Node;
new: typedef typename _Node<_Tp> _Node_Ab;
node.hpp:
confusion:
reserved #defines (in windef.h) "near" and "far" used as variable names:
=> rename near and far to something like near_N and far_N, starting from
line 337
iterator.hpp:
error: error C2248: 'KDTree::_Iterator<_Val,_Ref,_Ptr>::operator *' : cannot
access private member declared in class 'KDTree::_Iterator<_Val,_Ref,_Ptr>'
solved by:
add "public:" in line 110:
template <typename _Val, typename _Ref, typename _Ptr>
class _Iterator : protected _Base_iterator
{
public: //added
typedef _Val value_type;
...
error C2247: 'KDTree::_Base_iterator::_M_node' not accessible because
'KDTree::_Iterator<_Val,_Ref,_Ptr>' uses 'protected' to inherit from
'KDTree::_Base_iterator'
solved by:
line 108: change "protected" to public
old: class _Iterator : protected _Base_iterator
new: class _Iterator : public _Base_iterator
(may be really bad though..)
kdtree.hpp:
comment away "__throw_exception_again;" in line 1175 => unknown identifier
error in test_kdtree.cpp:
warning C4003: not enough actual parameters for macro 'max'
error C2589: '(' : illegal token on right side of '::'
error C2059: syntax error : '::'
caused by: *t.find_nearest(s,std::numeric_limits<double>::max()).first;
Solved by: Undefine min/max previously defined in windows.h:
#undef max;
#undef min;
triplet result =
*t.find_nearest(s,std::numeric_limits<double>::max()).first;
change in triplet definition:
struct triplet {
typedef int value_type;
inline value_type operator[](size_t const N) const { return d[N]; }
inline bool operator==(triplet const& other) {
return this->d[0] == other.d[0] && this->d[1] == other.d[1]
&& this->d[2] == other.d[2];
}
value_type d[3];
};
===========================
2) Nearest neighbor search
===========================
One thing: As I was really unable to do a pointer comparison of the "duplet"
struct I chose to compare coordinates.
The tradeoff (of course): If two points have the same coordinate a 3rd one
will be found as nearest neighbor.
So I wouldn't claim this being the smartest code out there... but it works
in my case and maybe it will help someone out there:
//struct for a 2D point
struct duplet {
typedef int value_type;
inline value_type operator[](size_t 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];
}
value_type d[2];
};
inline double return_dup( duplet d, int k ) { return d[k]; }
typedef KDTree::KDTree<2, duplet,
std::pointer_to_binary_function<duplet,int,double> > duplet_tree_type;
struct not_me //struct to sort out a coordinate
{
duplet* me;
not_me(duplet* m) : me(m) {}
bool operator()( KDTree::_Node< duplet > const* n ) const
{
return n->_M_value != *me;
}
bool operator()( const duplet & n ) const
{
return n != *me;
}
};
struct not_us //struct to sort out a vector of coordinates
{
std::vector<duplet> us;
not_us(std::vector<duplet> m) : us(m) {}
bool operator()( KDTree::_Node< duplet > const* n ) const
{
//return n->_M_value != *me;
bool bNotContained = TRUE;
for (int i=0; i<us.size(); i++)
if (n->_M_value == us[i]) bNotContained = FALSE;
return bNotContained;
}
bool operator()( const duplet & n ) const
{
/* return n != *me; */
bool bNotContained = TRUE;
for (int i=0; i<us.size(); i++)
if (n == us[i]) bNotContained = FALSE;
return bNotContained;
}
};
//just to feed function with iterators... though making no usage of their
advantages duplet_tree_type::iterator findNearestNeighbor( duplet_tree_type&
tree, duplet_tree_type::iterator it ) {
/////!!!! Will not find NN if search point and NN have same
coordinates as coordinates are compared!!!
duplet tmpTT = *it;
return findNearestNeighbor(tree, &tmpTT); }
duplet_tree_type::iterator findNearestNeighbor( duplet_tree_type& tree,
duplet* dup_point ) {
/////!!!! Will not find NN if search point and NN have same
coordinates as coordinates are compared!!!
#undef max; //undef windows.h max and min
#undef min;
float mmax = std::numeric_limits<float>::max();
duplet_tree_type::const_iterator found = tree.find_nearest_if(
*dup_point, mmax, not_me( dup_point ) ).first;
return found;
}
// to sort out a vector of points...
duplet_tree_type::iterator findNearestNeighbor_except( duplet_tree_type&
tree, duplet* dup_point, const std::vector<duplet>& exceptionlist ) {
/////!!!! Will not find NN if search point and NN have same
coordinates as coordinates are compared!!!
#undef max; //undef windows.h max and min
#undef min;
float mmax = std::numeric_limits<float>::max();
duplet_tree_type::const_iterator found = tree.find_nearest_if(
*dup_point, mmax, not_us( exceptionlist ) ).first;
return found;
}
usage:
duplet_tree_type dupl_tree_test(std::ptr_fun(return_dup));
duplet d0 = { {1,4} }; dupl_tree_test.insert(d0); duplet d1 = { {4,2} };
dupl_tree_test.insert(d1); duplet d2 = { {3,2} }; dupl_tree_test.insert(d2);
duplet d3 = { {5,6} }; dupl_tree_test.insert(d3); duplet d4 = { {2,2} };
dupl_tree_test.insert(d4);
dupl_tree_test.optimise();
duplet searchPoint = {{3,2}};
//duplet_tree_type::iterator pItr =
dupl_tree_test.find_nearest(searchPoint,std::numeric_limits<double>::max()).
first;
//duplet d_result = *findNearestNeighbor(dupl_tree_test, pItr);
duplet d_result = *findNearestNeighbor(dupl_tree_test, &searchPoint); //will
return point (2,2)
std::vector<duplet> exceptionlist;
exceptionlist.push_back(d0);
exceptionlist.push_back(d4);
d_result = *findNearestNeighbor_except(dupl_tree_test, &searchPoint,
exceptionlist); //will return point (3,2)
==================
3) Some questions
==================
3.1)
I always ended up with runtime errors using erase(). :(
I even did a optimise() after every erase() but sooner or later erase()
obviously tried to delete a value which had already been deleted.
Debugging showed that instead of a point (187,74) the point (176,74) was
deleted.
Soon later when trying to delete (176,74) the program crashed with a runtime
error.
erase_exact() solved this though. Is this intended to happen with erase()??
3.2) When should optimise() be called? Just at the beginning? After one
third of a ... let's say 700 Nodes containing tree have been erased?
3.3) Could you pleaaaaaaaaase :) provide libkdtree starters with some sort
of minimanual?
It's really time consuming (and frustrating) to
* find out what all those parameters do
* how a struct for "find_nearest_if()" works
* and what definition necessities there are, so a user defined object can be
put in a libkdtree.
..just by looking deeper in the code and fishing out some infos from the
mailing list.
3.4) Someone mentioned doing a "Find_N_NearestNeighbors" search could be
done by feeding find_nearest_if() with a fitting struct.
How would this look like? I can't see how/where to store the points...
Best wishes and I hope this lib finds its way into boost one day, :)
Sam Hayne
More information about the libkdtree-devel
mailing list