[PATCH] commit 6fd75d34617f1023c709d26655f8bfe931186ad0
Willi Richert
w.richert at gmx.net
Sat Mar 21 10:19:23 UTC 2009
Clean switch to template based python binding support
Signed-off-by: Willi Richert <w.richert at gmx.net>
---
python-bindings/Makefile | 18 +-
python-bindings/gen-swig-hpp.py | 264 +++++++++++++++++
python-bindings/py-kdtree.hpp | 210 --------------
python-bindings/py-kdtree.hpp.tmpl | 145 ++++++++++
python-bindings/py-kdtree.i | 545 ------------------------------------
python-bindings/py-kdtree.i.tmpl | 27 ++
python-bindings/py-kdtree_test.py | 84 ++++--
7 files changed, 504 insertions(+), 789 deletions(-)
create mode 100755 python-bindings/gen-swig-hpp.py
delete mode 100644 python-bindings/py-kdtree.hpp
create mode 100644 python-bindings/py-kdtree.hpp.tmpl
delete mode 100644 python-bindings/py-kdtree.i
create mode 100644 python-bindings/py-kdtree.i.tmpl
diff --git a/python-bindings/Makefile b/python-bindings/Makefile
index 6aeb33c..cf12901 100644
--- a/python-bindings/Makefile
+++ b/python-bindings/Makefile
@@ -2,6 +2,8 @@
INCLUDE_DIR=..
CXX=g++
+PY_INCLUDE_DIR=$(shell python-config --includes)
+
# CPPFLAGS is used by the default rules. Using "override" and "+="
# allows the user to prepend things to CPPFLAGS on the command line.
override CPPFLAGS += -I$(INCLUDE_DIR) -pedantic -Wno-long-long -Wall -ansi -pedantic
@@ -9,9 +11,9 @@ override CPPFLAGS += -I$(INCLUDE_DIR) -pedantic -Wno-long-long -Wall -ansi -peda
override CPPFLAGS += -DHAVE_CONFIG_H
ifeq ($(MINUSG),1)
-override CPPFLAGS += -g
+override CPPFLAGS += -g -fPIC
else
-override CPPFLAGS += -O3
+override CPPFLAGS += -O3 -fPIC
endif
ifeq ($(MINUSPG),1)
@@ -24,19 +26,21 @@ py-kdtree: _kdtree.so
cp _kdtree.so kdtree.py ../../
py-kdtree_test: py-kdtree.hpp py-kdtree_test.cpp
- $(CXX) $(CPPFLAGS) -I/usr/include/python2.5 -c -o py-kdtree_test.o py-kdtree_test.cpp
+ $(CXX) $(CPPFLAGS) -I$(PY_INCLUDE_DIR) -c -o py-kdtree_test.o py-kdtree_test.cpp
$(CXX) $(CPPFLAGS) $(LDLIBS) py-kdtree_test.o -o py-kdtree_test
-py-kdtree_wrap.cxx: py-kdtree.i py-kdtree.hpp
- swig -python -modern -c++ py-kdtree.i
+py-kdtree.i: py-kdtree.i.tmpl py-kdtree.hpp.tmpl gen-swig-hpp.py
+ python gen-swig-hpp.py
+py-kdtree_wrap.cxx: py-kdtree.i py-kdtree.hpp py-kdtree.i.tmpl py-kdtree.hpp.tmpl
+ swig -python -modern -c++ py-kdtree.i
_kdtree.so: py-kdtree_wrap.cxx
- $(CXX) $(CPPFLAGS) -c py-kdtree_wrap.cxx -I/usr/include/python2.5 -I$(INCLUDE_DIR)
+ $(CXX) $(CPPFLAGS) -c py-kdtree_wrap.cxx -I$(PY_INCLUDE_DIR) -I$(INCLUDE_DIR)
$(CXX) $(CPPFLAGS) -shared py-kdtree_wrap.o $(LDLIBS) -o _kdtree.so
clean:
- rm -f test_kdtree *.so py-kdtree_wrap.cxx *.o py-kdtree_test kdtree.py *.pyc
+ rm -f test_kdtree *.so py-kdtree_wrap.cxx *.o dkdtree.py py-kdtree_test kdtree.py *.pyc py-kdtree.i py-kdtree.hpp
.PHONY: clean
diff --git a/python-bindings/gen-swig-hpp.py b/python-bindings/gen-swig-hpp.py
new file mode 100755
index 0000000..c675648
--- /dev/null
+++ b/python-bindings/gen-swig-hpp.py
@@ -0,0 +1,264 @@
+#!/usr/bin/python
+
+
+TREE_TYPES = [(dim, "int", "unsigned long long", "i", "L") for dim in range(2,7)] + \
+ [(dim, "float", "unsigned long long", "f", "L") for dim in range(2,7)]
+
+
+def write_swig_file(tmpl_fn_name, swig_fn_name):
+ TMPL_SEPARATOR_DEF="""\
+////////////////////////////////////////////////////////////////////////////////
+// TYPE (%s) -> %s
+////////////////////////////////////////////////////////////////////////////////
+"""
+ TMPL_SEPARATOR=[]
+
+ TMPL_RECORD_DEF="""\
+#define RECORD_%i%s%s record_t<%i, %s, %s> // cf. py-kdtree.hpp
+"""
+ TMPL_RECORD=[]
+
+ TMPL_IN_CONV_RECORD_DEF="""\
+%%typemap(in) RECORD_%i%s%s (RECORD_%i%s%s temp) {
+ if (PyTuple_Check($input)) {
+ if (PyArg_ParseTuple($input,"(%s)%s", %s, &temp.data)!=0)
+ {
+ $1 = temp;
+ } else {
+ PyErr_SetString(PyExc_TypeError,"tuple must have %i elements: (%i dim %s vector, %s value)");
+ return NULL;
+ }
+
+ } else {
+ PyErr_SetString(PyExc_TypeError,"expected a tuple.");
+ return NULL;
+ }
+ }
+"""
+ TMPL_IN_CONV_RECORD=[]
+
+ TMPL_IN_CONV_POINT_DEF="""\
+%%typemap(in) RECORD_%i%s%s::point_t (RECORD_%i%s%s::point_t point) {
+ if (PyTuple_Check($input)) {
+ if (PyArg_ParseTuple($input,"%s", %s)!=0)
+ {
+ $1 = point;
+ } else {
+ PyErr_SetString(PyExc_TypeError,"tuple must contain %i ints");
+ return NULL;
+ }
+
+ } else {
+ PyErr_SetString(PyExc_TypeError,"expected a tuple.");
+ return NULL;
+ }
+ }
+ """
+ TMPL_IN_CONV_POINT=[]
+
+
+ TMPL_OUT_CONV_POINT_DEF="""\
+ %%typemap(out) RECORD_%i%s%s * {
+ RECORD_%i%s%s * r = $1;
+ PyObject* py_result;
+
+ if (r != NULL) {
+
+ py_result = PyTuple_New(2);
+ if (py_result==NULL) {
+ PyErr_SetString(PyErr_Occurred(),"unable to create a tuple.");
+ return NULL;
+ }
+
+ if (PyTuple_SetItem(py_result, 0, Py_BuildValue("(%s)", %s))==-1) {
+ PyErr_SetString(PyErr_Occurred(),"(a) when setting element");
+
+ Py_DECREF(py_result);
+ return NULL;
+ }
+
+ if (PyTuple_SetItem(py_result, 1, Py_BuildValue("%s", r->data))==-1) {
+ PyErr_SetString(PyErr_Occurred(),"(b) when setting element");
+
+ Py_DECREF(py_result);
+ return NULL;
+ }
+ } else {
+ py_result = Py_BuildValue("");
+ }
+
+ $result = py_result;
+ }
+ """
+ TMPL_OUT_CONV_POINT=[]
+
+ TMPL_OUT_CONV_RECORD_DEF="""\
+%%typemap(out) std::vector<RECORD_%i%s%s >* {
+ std::vector<RECORD_%i%s%s >* v = $1;
+
+ PyObject* py_result = PyList_New(v->size());
+ if (py_result==NULL) {
+ PyErr_SetString(PyErr_Occurred(),"unable to create a list.");
+ return NULL;
+ }
+ std::vector<RECORD_%i%s%s >::const_iterator iter = v->begin();
+
+ for (size_t i=0; i<v->size(); i++, iter++) {
+ if (PyList_SetItem(py_result, i, Py_BuildValue("(%s)%s", %s, (*iter).data))==-1) {
+ PyErr_SetString(PyErr_Occurred(),"(c) when setting element");
+
+ Py_DECREF(py_result);
+ return NULL;
+ } else {
+ //std::cout << "successfully set element " << *iter << std::endl;
+ }
+ }
+
+ $result = py_result;
+ }
+"""
+ TMPL_OUT_CONV_RECORD=[]
+
+ TMPL_PY_CLASS_DEF="""\
+%%template () RECORD_%i%s%s;
+%%template (KDTree_%i%s) PyKDTree<%i, %s, %s>;
+"""
+ TMPL_PY_CLASS=[]
+
+
+ TYPE_DEFS = []
+
+ for t in TREE_TYPES:
+ dim, coord_t, data_t, py_coord_t, py_data_t = t
+ coord_t_short = "".join([_[0] for _ in coord_t.split(" ")])
+ data_t_short = "".join([_[0] for _ in data_t.split(" ")])
+
+ TMPL_SEPARATOR.append(TMPL_SEPARATOR_DEF%(",".join([coord_t for _ in range(dim)]), data_t))
+
+ TMPL_RECORD.append(TMPL_RECORD_DEF%(dim, coord_t_short, data_t_short, dim, coord_t, data_t))
+
+ TMPL_IN_CONV_RECORD.append(TMPL_IN_CONV_RECORD_DEF%\
+ (dim, coord_t_short, data_t_short,
+ dim, coord_t_short, data_t_short,
+ py_coord_t*dim, py_data_t, ",".join(["&temp.point[%i]"%i for i in range(dim)]),
+ dim, dim, coord_t, data_t)
+ )
+
+ TMPL_IN_CONV_POINT.append(TMPL_IN_CONV_POINT_DEF%\
+ (dim, coord_t_short, data_t_short,
+ dim, coord_t_short, data_t_short,
+ py_coord_t*dim, ",".join(["&point[%i]"%i for i in range(dim)]),
+ dim)
+ )
+
+ TMPL_OUT_CONV_RECORD.append(TMPL_OUT_CONV_RECORD_DEF%\
+ (dim, coord_t_short, data_t_short,
+ dim, coord_t_short, data_t_short,
+ dim, coord_t_short, data_t_short,
+ py_coord_t*dim, py_data_t, ",".join(["(*iter).point[%i]"%i for i in range(dim)]),
+ )
+ )
+ TMPL_OUT_CONV_POINT.append(TMPL_OUT_CONV_POINT_DEF%\
+ (dim, coord_t_short, data_t_short,
+ dim, coord_t_short, data_t_short,
+ py_coord_t*dim, ",".join(["r->point[%i]"%i for i in range(dim)]),
+ py_data_t)
+ )
+
+ TMPL_PY_CLASS.append(TMPL_PY_CLASS_DEF%\
+ (dim, coord_t_short, data_t_short,
+ dim, coord_t.capitalize(), dim, coord_t, data_t)
+ )
+
+
+ TMPL_BODY_LIST = []
+ for i in range(len(TREE_TYPES)):
+ TMPL_BODY_LIST.append(TMPL_SEPARATOR[i] + "\n" + \
+ TMPL_RECORD[i] + "\n" + \
+ TMPL_IN_CONV_POINT[i] + "\n" + \
+ TMPL_IN_CONV_RECORD[i] + "\n" + \
+ TMPL_OUT_CONV_POINT[i] + "\n" + \
+ TMPL_OUT_CONV_RECORD[i])
+
+ TMPL_BODY = "\n\n".join(TMPL_BODY_LIST)
+
+ # write swig file
+ i_content = open(tmpl_fn_name, "r").read()
+ i_content = i_content.replace("%%TMPL_BODY%%", TMPL_BODY).replace("%%TMPL_PY_CLASS_DEF%%", "\n".join(TMPL_PY_CLASS))
+ f=open(swig_fn_name, "w")
+ f.write(i_content)
+ f.close()
+
+
+def write_hpp_file(tmpl_fn_name, hpp_fn_name):
+ TMPL_SEPARATOR_DEF="""\
+////////////////////////////////////////////////////////////////////////////////
+// Definition of (%s) with data type %s
+////////////////////////////////////////////////////////////////////////////////
+"""
+ TMPL_SEPARATOR=[]
+
+ TMPL_RECORD_DEF = """\
+#define RECORD_%i%s%s record_t<%i, %s, %s>
+#define KDTREE_TYPE_%i%s%s KDTree::KDTree<%i, RECORD_%i%s%s, std::pointer_to_binary_function<RECORD_%i%s%s,int,double> >
+"""
+ TMPL_RECORD=[]
+
+ TMPL_OP_EQ_DEF = """\
+inline bool operator==(RECORD_%i%s%s const& A, RECORD_%i%s%s const& B) {
+ return %s && A.data == B.data;
+}
+"""
+ TMPL_OP_EQ = []
+
+ TMPL_OP_OUT_DEF="""\
+std::ostream& operator<<(std::ostream& out, RECORD_%i%s%s const& T)
+{
+ return out << '(' << %s << '|' << T.data << ')';
+}
+"""
+ TMPL_OP_OUT = []
+
+ TYPE_DEFS = []
+
+ for t in TREE_TYPES:
+ dim, coord_t, data_t, py_coord_t, py_data_t = t
+ coord_t_short = "".join([_[0] for _ in coord_t.split(" ")])
+ data_t_short = "".join([_[0] for _ in data_t.split(" ")])
+
+ TMPL_SEPARATOR.append(TMPL_SEPARATOR_DEF%(",".join([coord_t for _ in range(dim)]), data_t))
+
+ TMPL_RECORD.append(TMPL_RECORD_DEF%(dim, coord_t_short, data_t_short,
+ dim, coord_t, data_t,
+ dim, coord_t_short, data_t_short,
+ dim,
+ dim, coord_t_short, data_t_short,
+ dim, coord_t_short, data_t_short)
+ )
+
+ TMPL_OP_EQ.append(TMPL_OP_EQ_DEF%(dim, coord_t_short, data_t_short,
+ dim, coord_t_short, data_t_short,
+ " && ".join(["A.point[%i] == B.point[%i]"%(i,i) for i in range(dim)])))
+
+ TMPL_OP_OUT.append(TMPL_OP_OUT_DEF%(dim, coord_t_short, data_t_short,
+ " << ',' << ".join(["T.point[%i]"%i for i in range(dim)])))
+
+
+ TMPL_BODY_LIST = []
+ for i in range(len(TREE_TYPES)):
+ TMPL_BODY_LIST.append(TMPL_SEPARATOR[i] + "\n" + TMPL_RECORD[i] + "\n" + TMPL_OP_EQ[i] + "\n" + TMPL_OP_OUT[i])
+
+ TMPL_BODY = "\n\n".join(TMPL_BODY_LIST)
+
+ # write hpp file
+ hpp_content = open(tmpl_fn_name, "r").read()
+ hpp_content = hpp_content.replace("%%TMPL_HPP_DEFS%%", TMPL_BODY)
+ f=open(hpp_fn_name, "w")
+ f.write(hpp_content)
+ f.close()
+
+
+if __name__=="__main__":
+ write_swig_file("py-kdtree.i.tmpl", "py-kdtree.i")
+ write_hpp_file("py-kdtree.hpp.tmpl", "py-kdtree.hpp")
+
diff --git a/python-bindings/py-kdtree.hpp b/python-bindings/py-kdtree.hpp
deleted file mode 100644
index ec78d33..0000000
--- a/python-bindings/py-kdtree.hpp
+++ /dev/null
@@ -1,210 +0,0 @@
-/** \file
- * Provides a Python interface for the libkdtree++.
- *
- * \author Willi Richert <w.richert at gmx.net>
- *
- *
- * This defines a proxy to a (int, int) -> long long KD-Tree. The long
- * long is needed to save a reference to Python's object id(). Thereby,
- * you can associate Python objects with 2D integer points.
- *
- * If you want to customize it you can adapt the following:
- *
- * * Dimension of the KD-Tree point vector.
- * * DIM: number of dimensions.
- * * operator==() and operator<<(): adapt to the number of comparisons
- * * py-kdtree.i: Add or adapt all usages of PyArg_ParseTuple() to reflect the
- * number of dimensions.
- * * adapt query_records in find_nearest() and count_within_range()
- * * Type of points.
- * * coord_t: If you want to have e.g. floats you have
- * to adapt all usages of PyArg_ParseTuple(): Change "i" to "f" e.g.
- * * Type of associated data.
- * * data_t: currently unsigned long long, which is "L" in py-kdtree.i
- * * PyArg_ParseTuple() has to be changed to reflect changes in data_t
- *
- */
-
-
-#ifndef _PY_KDTREE_H_
-#define _PY_KDTREE_H_
-
-#include <kdtree++/kdtree.hpp>
-
-#include <iostream>
-#include <vector>
-#include <limits>
-
-template <size_t DIM, typename COORD_T, typename DATA_T >
-struct record_t {
- static const size_t dim = DIM;
- typedef COORD_T coord_t;
- typedef DATA_T data_t;
-
- typedef coord_t point_t[dim];
-
- inline coord_t operator[](size_t const N) const { return point[N]; }
-
- point_t point;
- data_t data;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// Definition of (int, int) points that has an unsigned long long as payload
-////////////////////////////////////////////////////////////////////////////////
-#define RECORD_2il record_t<2, int, unsigned long long>
-#define KDTREE_TYPE_2il KDTree::KDTree<2, RECORD_2il, std::pointer_to_binary_function<RECORD_2il,int,double> >
-
-inline bool operator==(RECORD_2il const& A, RECORD_2il const& B) {
- return A.point[0] == B.point[0] && A.point[1] == B.point[1] && A.data == B.data;
-}
-
-std::ostream& operator<<(std::ostream& out, RECORD_2il const& T)
-{
- return out << '(' << T.point[0] << ',' << T.point[1] << '|' << T.data << ')';
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Definition of (int, int, int, int) points that has an unsigned long long as payload
-////////////////////////////////////////////////////////////////////////////////
-#define RECORD_4il record_t<4, int, unsigned long long>
-#define KDTREE_TYPE_4il KDTree::KDTree<4, RECORD_4il, std::pointer_to_binary_function<RECORD_4il,int,double> >
-
-inline bool operator==(RECORD_4il const& A, RECORD_4il const& B) {
- return A.point[0] == B.point[0] && A.point[1] == B.point[1] &&
- A.point[2] == B.point[2] && A.point[3] == B.point[3] &&
- A.data == B.data;
-}
-
-std::ostream& operator<<(std::ostream& out, RECORD_4il const& T)
-{
- return out << '(' << T.point[0] << ',' << T.point[1] << ',' << T.point[2] << ',' << T.point[3] << '|' << T.data << ')';
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Definition of (float) points that has an unsigned long long as payload
-////////////////////////////////////////////////////////////////////////////////
-#define RECORD_1fl record_t<1, float, unsigned long long>
-#define KDTREE_TYPE_1fl KDTree::KDTree<1, RECORD_1fl, std::pointer_to_binary_function<RECORD_1fl,int,double> >
-
-inline bool operator==(RECORD_1fl const& A, RECORD_1fl const& B) {
- return A.point[0] == B.point[0] &&
- A.data == B.data;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Definition of (float, float, float) points that has an unsigned long long as payload
-////////////////////////////////////////////////////////////////////////////////
-#define RECORD_3fl record_t<3, float, unsigned long long>
-#define KDTREE_TYPE_3fl KDTree::KDTree<3, RECORD_3fl, std::pointer_to_binary_function<RECORD_3fl,int,double> >
-
-inline bool operator==(RECORD_3fl const& A, RECORD_3fl const& B) {
- return A.point[0] == B.point[0] && A.point[1] == B.point[1] &&
- A.point[2] == B.point[2] &&
- A.data == B.data;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Definition of (float, float, float, float, float, float) points that has an unsigned long long as payload
-////////////////////////////////////////////////////////////////////////////////
-#define RECORD_6fl record_t<6, float, unsigned long long>
-#define KDTREE_TYPE_6fl KDTree::KDTree<6, RECORD_6fl, std::pointer_to_binary_function<RECORD_6fl,int,double> >
-
-inline bool operator==(RECORD_6fl const& A, RECORD_6fl const& B) {
- return A.point[0] == B.point[0] && A.point[1] == B.point[1] &&
- A.point[2] == B.point[2] && A.point[3] == B.point[3] &&
- A.point[4] == B.point[4] && A.point[5] == B.point[5] &&
- A.data == B.data;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// END OF TYPE SPECIFIC DEFINITIONS
-////////////////////////////////////////////////////////////////////////////////
-
-
-template <class RECORD_T>
-inline double tac(RECORD_T r, int k) { return r[k]; }
-
-template <size_t DIM, typename COORD_T, typename DATA_T >
-class PyKDTree {
-public:
-
- typedef record_t<DIM, COORD_T, DATA_T> RECORD_T;
- typedef KDTree::KDTree<DIM, RECORD_T, std::pointer_to_binary_function<RECORD_T,int,double> > TREE_T;
- TREE_T tree;
-
- PyKDTree() : tree(std::ptr_fun(tac<RECORD_T>)) { };
-
- void add(RECORD_T T) { tree.insert(T); };
-
- /**
- Exact erase.
- */
- bool remove(RECORD_T T) {
- bool removed = false;
-
- typename TREE_T::const_iterator it = tree.find_exact(T);
- if (it!=tree.end()) {
- tree.erase_exact(T);
- removed = true;
- }
- return removed;
- };
-
- int size(void) { return tree.size(); }
-
- void optimize(void) { tree.optimise(); }
-
- RECORD_T* find_exact(RECORD_T T) {
- RECORD_T* found = NULL;
- typename TREE_T::const_iterator it = tree.find_exact(T);
- if (it!=tree.end())
- found = new RECORD_T(*it);
-
- return found;
- }
-
- size_t count_within_range(typename RECORD_T::point_t T, typename TREE_T::distance_type range) {
- RECORD_T query_record;
- memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
-
- return tree.count_within_range(query_record, range);
- }
-
- std::vector<RECORD_T > find_within_range(typename RECORD_T::point_t T, typename TREE_T::distance_type range) {
- RECORD_T query_record;
- memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
-
- std::vector<RECORD_T> v;
- tree.find_within_range(query_record, range, std::back_inserter(v));
- return v;
- }
-
- RECORD_T* find_nearest (typename RECORD_T::point_t T) {
- RECORD_T* found = NULL;
- RECORD_T query_record;
- memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
-
- std::pair<typename TREE_T::const_iterator, typename TREE_T::distance_type> best =
- tree.find_nearest(query_record, std::numeric_limits<typename TREE_T::distance_type>::max());
-
- if (best.first!=tree.end()) {
- found = new RECORD_T(*best.first);
- }
- return found;
- }
-
- std::vector<RECORD_T >* get_all() {
- std::vector<RECORD_T>* v = new std::vector<RECORD_T>;
-
- for (typename TREE_T::const_iterator iter=tree.begin(); iter!=tree.end(); ++iter) {
- v->push_back(*iter);
- }
-
- return v;
- }
-
- size_t __len__() { return tree.size(); }
-};
-#endif //_PY_KDTREE_H_
diff --git a/python-bindings/py-kdtree.hpp.tmpl b/python-bindings/py-kdtree.hpp.tmpl
new file mode 100644
index 0000000..786eee4
--- /dev/null
+++ b/python-bindings/py-kdtree.hpp.tmpl
@@ -0,0 +1,145 @@
+/** \file
+ * Provides a Python interface for the libkdtree++.
+ *
+ * \author Willi Richert <w.richert at gmx.net>
+ *
+ *
+ * This defines a proxy to a (int, int) -> long long KD-Tree. The long
+ * long is needed to save a reference to Python's object id(). Thereby,
+ * you can associate Python objects with 2D integer points.
+ *
+ * If you want to customize it you can adapt the following:
+ *
+ * * Dimension of the KD-Tree point vector.
+ * * DIM: number of dimensions.
+ * * operator==() and operator<<(): adapt to the number of comparisons
+ * * py-kdtree.i: Add or adapt all usages of PyArg_ParseTuple() to reflect the
+ * number of dimensions.
+ * * adapt query_records in find_nearest() and count_within_range()
+ * * Type of points.
+ * * coord_t: If you want to have e.g. floats you have
+ * to adapt all usages of PyArg_ParseTuple(): Change "i" to "f" e.g.
+ * * Type of associated data.
+ * * data_t: currently unsigned long long, which is "L" in py-kdtree.i
+ * * PyArg_ParseTuple() has to be changed to reflect changes in data_t
+ *
+ */
+
+
+#ifndef _PY_KDTREE_H_
+#define _PY_KDTREE_H_
+
+#include <kdtree++/kdtree.hpp>
+
+#include <iostream>
+#include <vector>
+#include <limits>
+
+template <size_t DIM, typename COORD_T, typename DATA_T >
+struct record_t {
+ static const size_t dim = DIM;
+ typedef COORD_T coord_t;
+ typedef DATA_T data_t;
+
+ typedef coord_t point_t[dim];
+
+ inline coord_t operator[](size_t const N) const { return point[N]; }
+
+ point_t point;
+ data_t data;
+};
+
+typedef double RANGE_T;
+
+%%TMPL_HPP_DEFS%%
+
+////////////////////////////////////////////////////////////////////////////////
+// END OF TYPE SPECIFIC DEFINITIONS
+////////////////////////////////////////////////////////////////////////////////
+
+
+template <class RECORD_T>
+inline double tac(RECORD_T r, int k) { return r[k]; }
+
+template <size_t DIM, typename COORD_T, typename DATA_T >
+class PyKDTree {
+public:
+
+ typedef record_t<DIM, COORD_T, DATA_T> RECORD_T;
+ typedef KDTree::KDTree<DIM, RECORD_T, std::pointer_to_binary_function<RECORD_T,int,double> > TREE_T;
+ TREE_T tree;
+
+ PyKDTree() : tree(std::ptr_fun(tac<RECORD_T>)) { };
+
+ void add(RECORD_T T) { tree.insert(T); };
+
+ /**
+ Exact erase.
+ */
+ bool remove(RECORD_T T) {
+ bool removed = false;
+
+ typename TREE_T::const_iterator it = tree.find_exact(T);
+ if (it!=tree.end()) {
+ tree.erase_exact(T);
+ removed = true;
+ }
+ return removed;
+ };
+
+ int size(void) { return tree.size(); }
+
+ void optimize(void) { tree.optimise(); }
+
+ RECORD_T* find_exact(RECORD_T T) {
+ RECORD_T* found = NULL;
+ typename TREE_T::const_iterator it = tree.find_exact(T);
+ if (it!=tree.end())
+ found = new RECORD_T(*it);
+
+ return found;
+ }
+
+ size_t count_within_range(typename RECORD_T::point_t T, RANGE_T range) {
+ RECORD_T query_record;
+ memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
+
+ return tree.count_within_range(query_record, range);
+ }
+
+ std::vector<RECORD_T >* find_within_range(typename RECORD_T::point_t T, RANGE_T range) {
+ RECORD_T query_record;
+ memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
+
+ std::vector<RECORD_T> *v = new std::vector<RECORD_T>;
+ tree.find_within_range(query_record, range, std::back_inserter(*v));
+ return v;
+ }
+
+ RECORD_T* find_nearest (typename RECORD_T::point_t T) {
+ RECORD_T* found = NULL;
+ RECORD_T query_record;
+ memcpy(query_record.point, T, sizeof(COORD_T)*DIM);
+
+ std::pair<typename TREE_T::const_iterator, typename TREE_T::distance_type> best =
+ tree.find_nearest(query_record, std::numeric_limits<typename TREE_T::distance_type>::max());
+
+ if (best.first!=tree.end()) {
+ found = new RECORD_T(*best.first);
+ }
+ return found;
+ }
+
+ std::vector<RECORD_T >* get_all() {
+ std::vector<RECORD_T>* v = new std::vector<RECORD_T>;
+
+ for (typename TREE_T::const_iterator iter=tree.begin(); iter!=tree.end(); ++iter) {
+ v->push_back(*iter);
+ }
+
+ return v;
+ }
+
+ size_t __len__() { return tree.size(); }
+};
+#endif //_PY_KDTREE_H_
diff --git a/python-bindings/py-kdtree.i b/python-bindings/py-kdtree.i
deleted file mode 100644
index cd45828..0000000
--- a/python-bindings/py-kdtree.i
+++ /dev/null
@@ -1,545 +0,0 @@
-/** \file
- * $Id$
- *
- * Provides a Python interface for the libkdtree++.
- *
- * \author Willi Richert <w.richert at gmx.net>
- *
- */
-
-%module kdtree
- //%include exception.i
-
-%{
-#define SWIG_FILE_WITH_INIT
-#include "py-kdtree.hpp"
-%}
-
-
-%ignore record_t::operator[];
-%ignore operator==;
-%ignore operator<<;
-%ignore KDTree::KDTree::operator=;
-%ignore tac;
-
-#define RECORD_2il record_t<2, int, unsigned long long> // cf. py-kdtree.hpp
-#define RECORD_4il record_t<4, int, unsigned long long> // cf. py-kdtree.hpp
-
-#define RECORD_1fl record_t<1, float, unsigned long long>
-#define RECORD_3fl record_t<3, float, unsigned long long>
-#define RECORD_6fl record_t<6, float, unsigned long long>
-
-////////////////////////////////////////////////////////////////////////////////
-// TYPE (int, int)
-////////////////////////////////////////////////////////////////////////////////
-%typemap(in) RECORD_2il (RECORD_2il temp) {
- if (PyTuple_Check($input)) {
-
- if (PyArg_ParseTuple($input,"(ii)L", &temp.point[0], &temp.point[1], &temp.data)!=0)
- {
- $1 = temp;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must have 2 elements: (2dim int vector, long value)");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(in) RECORD_2il::point_t (RECORD_2il::point_t point) {
- if (PyTuple_Check($input)) {
- if (PyArg_ParseTuple($input,"ii", &point[0], &point[1])!=0)
- {
- $1 = point;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must contain 2 ints");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(out) RECORD_2il * {
- RECORD_2il * r = $1;
- PyObject* py_result;
-
- if (r != NULL) {
-
- py_result = PyTuple_New(2);
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a tuple.");
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 0, Py_BuildValue("(ii)", r->point[0], r->point[1]))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(a) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 1, Py_BuildValue("L", r->data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(b) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
- } else {
- py_result = Py_BuildValue("");
- }
-
- $result = py_result;
- }
-
-%typemap(out) std::vector<RECORD_2il >* {
- std::vector<RECORD_2il >* v = $1;
-
- PyObject* py_result = PyList_New(v->size());
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a list.");
- return NULL;
- }
- std::vector<RECORD_2il >::const_iterator iter = v->begin();
-
- for (size_t i=0; i<v->size(); i++, iter++) {
- if (PyList_SetItem(py_result, i, Py_BuildValue("(ii)L", (*iter).point[0], (*iter).point[1], (*iter).data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(c) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- } else {
- //std::cout << "successfully set element " << *iter << std::endl;
- }
- }
-
- $result = py_result;
- }
-////////////////////////////////////////////////////////////////////////////////
-// TYPE (int, int, int, int)
-////////////////////////////////////////////////////////////////////////////////
-%typemap(in) RECORD_4il (RECORD_4il temp) {
- if (PyTuple_Check($input)) {
-
- if (PyArg_ParseTuple($input,"(iiii)L", &temp.point[0], &temp.point[1],
- &temp.point[2], &temp.point[3],
- &temp.data)!=0)
- {
- $1 = temp;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must have 4 elements: (4dim int vector, long value)");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(in) RECORD_4il::point_t (RECORD_4il::point_t point) {
- if (PyTuple_Check($input)) {
- if (PyArg_ParseTuple($input,"iiii", &point[0], &point[1], &point[2], &point[3])!=0)
- {
- $1 = point;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must contain 4 ints");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(out) RECORD_4il * {
- RECORD_4il * r = $1;
- PyObject* py_result;
-
- if (r != NULL) {
-
- py_result = PyTuple_New(2);
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a tuple.");
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 0, Py_BuildValue("(iiii)",
- r->point[0], r->point[1], r->point[2], r->point[3]))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(a) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 1, Py_BuildValue("L", r->data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(b) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
- } else {
- py_result = Py_BuildValue("");
- }
-
- $result = py_result;
- }
-
-%typemap(out) std::vector<RECORD_4il >* {
- std::vector<RECORD_4il >* v = $1;
-
- PyObject* py_result = PyList_New(v->size());
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a list.");
- return NULL;
- }
- std::vector<RECORD_4il >::const_iterator iter = v->begin();
-
- for (size_t i=0; i<v->size(); i++, iter++) {
- if (PyList_SetItem(py_result, i, Py_BuildValue("(iiii)L",
- (*iter).point[0], (*iter).point[1], (*iter).point[2], (*iter).point[3],
- (*iter).data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(c) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- } else {
- //std::cout << "successfully set element " << *iter << std::endl;
- }
- }
-
- $result = py_result;
- }
-
-////////////////////////////////////////////////////////////////////////////////
-// TYPE (float)
-////////////////////////////////////////////////////////////////////////////////
-%typemap(in) RECORD_1fl (RECORD_1fl temp) {
- if (PyTuple_Check($input)) {
-
- if (PyArg_ParseTuple($input,"(f)L",
- &temp.point[0],
- &temp.data)!=0)
- {
- $1 = temp;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must have 2 elements: (1dim float tuple, long value)");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(in) RECORD_1fl::point_t (RECORD_1fl::point_t point) {
- if (PyTuple_Check($input)) {
- if (PyArg_ParseTuple($input,"f",
- &point[0])!=0)
- {
- $1 = point;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must contain 1 float");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(out) RECORD_1fl * {
- RECORD_1fl * r = $1;
- PyObject* py_result;
-
- if (r != NULL) {
-
- py_result = PyTuple_New(2);
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a tuple.");
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 0, Py_BuildValue("(f)",
- r->point[0]))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(a) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 1, Py_BuildValue("L", r->data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(b) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
- } else {
- py_result = Py_BuildValue("");
- }
-
- $result = py_result;
- }
-
-%typemap(out) std::vector<RECORD_1fl >* {
- std::vector<RECORD_1fl >* v = $1;
-
- PyObject* py_result = PyList_New(v->size());
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a list.");
- return NULL;
- }
- std::vector<RECORD_1fl >::const_iterator iter = v->begin();
-
- for (size_t i=0; i<v->size(); i++, iter++) {
- if (PyList_SetItem(py_result, i, Py_BuildValue("(f)L",
- (*iter).point[0],
- (*iter).data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(c) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- } else {
- //std::cout << "successfully set element " << *iter << std::endl;
- }
- }
-
- $result = py_result;
- }
-
-////////////////////////////////////////////////////////////////////////////////
-// TYPE (float, float, float)
-////////////////////////////////////////////////////////////////////////////////
-%typemap(in) RECORD_3fl (RECORD_3fl temp) {
- if (PyTuple_Check($input)) {
-
- if (PyArg_ParseTuple($input,"(fff)L",
- &temp.point[0], &temp.point[1],
- &temp.point[2],
- &temp.data)!=0)
- {
- $1 = temp;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must have 2 elements: (3dim float tuple, long value)");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(in) RECORD_3fl::point_t (RECORD_3fl::point_t point) {
- if (PyTuple_Check($input)) {
- if (PyArg_ParseTuple($input,"fff",
- &point[0], &point[1],
- &point[2])!=0)
- {
- $1 = point;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must contain 3 floats");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(out) RECORD_3fl * {
- RECORD_3fl * r = $1;
- PyObject* py_result;
-
- if (r != NULL) {
-
- py_result = PyTuple_New(2);
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a tuple.");
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 0, Py_BuildValue("(fff)",
- r->point[0], r->point[1], r->point[2]))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(a) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 1, Py_BuildValue("L", r->data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(b) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
- } else {
- py_result = Py_BuildValue("");
- }
-
- $result = py_result;
- }
-
-%typemap(out) std::vector<RECORD_3fl >* {
- std::vector<RECORD_3fl >* v = $1;
-
- PyObject* py_result = PyList_New(v->size());
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a list.");
- return NULL;
- }
- std::vector<RECORD_3fl >::const_iterator iter = v->begin();
-
- for (size_t i=0; i<v->size(); i++, iter++) {
- if (PyList_SetItem(py_result, i, Py_BuildValue("(fff)L",
- (*iter).point[0], (*iter).point[1],
- (*iter).point[2],
- (*iter).data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(c) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- } else {
- //std::cout << "successfully set element " << *iter << std::endl;
- }
- }
-
- $result = py_result;
- }
-
-////////////////////////////////////////////////////////////////////////////////
-// TYPE (float, float, float, float, float, float)
-////////////////////////////////////////////////////////////////////////////////
-%typemap(in) RECORD_6fl (RECORD_6fl temp) {
- if (PyTuple_Check($input)) {
-
- if (PyArg_ParseTuple($input,"(ffffff)L",
- &temp.point[0], &temp.point[1],
- &temp.point[2], &temp.point[3],
- &temp.point[4], &temp.point[5],
- &temp.data)!=0)
- {
- $1 = temp;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must have 2 elements: (6dim float tuple, long value)");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(in) RECORD_6fl::point_t (RECORD_6fl::point_t point) {
- if (PyTuple_Check($input)) {
- if (PyArg_ParseTuple($input,"ffffff",
- &point[0], &point[1],
- &point[2], &point[3],
- &point[4], &point[5])!=0)
- {
- $1 = point;
- } else {
- PyErr_SetString(PyExc_TypeError,"tuple must contain 6 floats");
- return NULL;
- }
-
- } else {
- PyErr_SetString(PyExc_TypeError,"expected a tuple.");
- return NULL;
- }
- }
-
-%typemap(out) RECORD_6fl * {
- RECORD_6fl * r = $1;
- PyObject* py_result;
-
- if (r != NULL) {
-
- py_result = PyTuple_New(2);
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a tuple.");
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 0, Py_BuildValue("(ffffff)",
- r->point[0], r->point[1],
- r->point[2], r->point[3],
- r->point[4], r->point[5]))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(a) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
-
- if (PyTuple_SetItem(py_result, 1, Py_BuildValue("L", r->data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(b) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- }
- } else {
- py_result = Py_BuildValue("");
- }
-
- $result = py_result;
- }
-
-%typemap(out) std::vector<RECORD_6fl >* {
- std::vector<RECORD_6fl >* v = $1;
-
- PyObject* py_result = PyList_New(v->size());
- if (py_result==NULL) {
- PyErr_SetString(PyErr_Occurred(),"unable to create a list.");
- return NULL;
- }
- std::vector<RECORD_6fl >::const_iterator iter = v->begin();
-
- for (size_t i=0; i<v->size(); i++, iter++) {
- if (PyList_SetItem(py_result, i, Py_BuildValue("(ffffff)L",
- (*iter).point[0], (*iter).point[1],
- (*iter).point[2], (*iter).point[3],
- (*iter).point[4], (*iter).point[5],
- (*iter).data))==-1) {
- PyErr_SetString(PyErr_Occurred(),"(c) when setting element");
-
- Py_DECREF(py_result);
- return NULL;
- } else {
- //std::cout << "successfully set element " << *iter << std::endl;
- }
- }
-
- $result = py_result;
- }
-
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-%include "py-kdtree.hpp"
-
-%template () RECORD_2il;
-%template (KDTree_2Int) PyKDTree<2, int, unsigned long long>;
-
-%template () RECORD_4il;
-%template (KDTree_4Int) PyKDTree<4, int, unsigned long long>;
-
-%template () RECORD_1fl;
-%template (KDTree_1Float) PyKDTree<1, float, unsigned long long>;
-
-%template () RECORD_3fl;
-%template (KDTree_3Float) PyKDTree<3, float, unsigned long long>;
-
-%template () RECORD_6fl;
-%template (KDTree_6Float) PyKDTree<6, float, unsigned long long>;
diff --git a/python-bindings/py-kdtree.i.tmpl b/python-bindings/py-kdtree.i.tmpl
new file mode 100644
index 0000000..e150940
--- /dev/null
+++ b/python-bindings/py-kdtree.i.tmpl
@@ -0,0 +1,27 @@
+/** \file
+ *
+ * Provides a Python interface for the libkdtree++.
+ *
+ * \author Willi Richert <w.richert at gmx.net>
+ *
+ */
+
+%module kdtree
+
+%{
+#define SWIG_FILE_WITH_INIT
+#include "py-kdtree.hpp"
+%}
+
+
+%ignore record_t::operator[];
+%ignore operator==;
+%ignore operator<<;
+%ignore KDTree::KDTree::operator=;
+%ignore tac;
+
+%%TMPL_BODY%%
+
+%include "py-kdtree.hpp"
+
+%%TMPL_PY_CLASS_DEF%%
diff --git a/python-bindings/py-kdtree_test.py b/python-bindings/py-kdtree_test.py
index 6b96a9a..4227b71 100644
--- a/python-bindings/py-kdtree_test.py
+++ b/python-bindings/py-kdtree_test.py
@@ -4,7 +4,7 @@
import unittest
-from kdtree import KDTree_2Int, KDTree_4Int, KDTree_1Float, KDTree_3Float, KDTree_6Float
+from kdtree import KDTree_2Int, KDTree_4Int, KDTree_3Float, KDTree_4Float, KDTree_6Float
class KDTree_2IntTestCase(unittest.TestCase):
@@ -51,6 +51,28 @@ class KDTree_2IntTestCase(unittest.TestCase):
actual = nn.find_nearest((6, 6))[1]
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
+ def test_find_within_range(self):
+ nn = KDTree_6Float()
+
+ nn_id = {}
+
+ o1 = object()
+ nn.add(((1,1,0,0,0,0), id(o1)))
+ nn_id[id(o1)] = o1
+ o2 = object()
+ nn.add(((10,10,0,0,0,0), id(o2)))
+ nn_id[id(o2)] = o2
+ o3 = object()
+ nn.add(((4.1, 4.1,0,0,0,0), id(o3)))
+ nn_id[id(o3)] = o3
+
+ expected = set([long(id(o1)), long(id(o3))])
+ actual = set([ident
+ for _coord, ident
+ in nn.find_within_range((2.1,2.1,0,0,0,0), 3.9)])
+ self.assertTrue(expected==actual, "%s != %s"%(str(expected), str(actual)))
+
+
def test_remove(self):
class C:
def __init__(self, i):
@@ -76,6 +98,18 @@ class KDTree_2IntTestCase(unittest.TestCase):
self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1))
#self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1)))))
+ def test_count_within_range(self):
+ nn = KDTree_2Int()
+
+ for p in [(0,0), (1,0), (0,1), (1,1)]:
+ nn.add((p, id(p)))
+
+ res = nn.count_within_range((0,0), 1.0)
+ self.assertEqual(3, res, "Counted %i points instead of %i"%(res, 3))
+
+ res = nn.count_within_range((0,0), 1.9)
+ self.assertEqual(4, res, "Counted %i points instead of %i"%(res, 4))
+
class KDTree_4IntTestCase(unittest.TestCase):
def test_empty(self):
nn = KDTree_4Int()
@@ -145,51 +179,48 @@ class KDTree_4IntTestCase(unittest.TestCase):
self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1))
#self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1)))))
-class KDTree_1FloatTestCase(unittest.TestCase):
+class KDTree_4FloatTestCase(unittest.TestCase):
def test_empty(self):
- nn = KDTree_1Float()
+ nn = KDTree_4Float()
self.assertEqual(0, nn.size())
- actual = nn.find_nearest((2.,))
+ actual = nn.find_nearest((0,0,2,3))
self.assertTrue(None==actual, "%s != %s"%(str(None), str(actual)))
def test_get_all(self):
- nn = KDTree_1Float()
+ nn = KDTree_4Int()
o1 = object()
- nn.add(((1.,), id(o1)))
+ nn.add(((0,0,1,1), id(o1)))
o2 = object()
- nn.add(((10.,), id(o2)))
+ nn.add(((0,0,10,10), id(o2)))
o3 = object()
- nn.add(((11.,), id(o3)))
+ nn.add(((0,0,11,11), id(o3)))
- self.assertEqual([((1.,), id(o1)), ((10.,), id(o2)), ((11.,), id(o3))], nn.get_all())
+ self.assertEqual([((0,0,1,1), id(o1)), ((0,0,10,10), id(o2)), ((0,0,11,11), id(o3))], nn.get_all())
self.assertEqual(3, len(nn))
- nn.remove(((10.,), id(o2)))
+ nn.remove(((0,0,10,10), id(o2)))
self.assertEqual(2, len(nn))
- self.assertEqual([((1.,), id(o1)), ((11.,), id(o3))], nn.get_all())
+ self.assertEqual([((0,0,1,1), id(o1)), ((0,0,11,11), id(o3))], nn.get_all())
def test_nearest(self):
- nn = KDTree_1Float()
+ nn = KDTree_4Int()
nn_id = {}
o1 = object()
- nn.add(((1.,), id(o1)))
+ nn.add(((0,0,1,1), id(o1)))
nn_id[id(o1)] = o1
o2 = object()
- nn.add(((10.,), id(o2)))
+ nn.add(((0,0,10,10), id(o2)))
nn_id[id(o2)] = o2
- o3 = object()
- nn.add(((4.1,), id(o3)))
- nn_id[id(o3)] = o3
- expected = o3
- actual = nn.find_nearest((2.9,))[1]
+ expected = o1
+ actual = nn.find_nearest((0,0,2,2))[1]
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
- expected = o3
- actual = nn.find_nearest((6.,))[1]
+ expected = o2
+ actual = nn.find_nearest((0,0,6,6))[1]
self.assertTrue(expected==nn_id[actual], "%s != %s"%(str(expected), str(nn_id[actual])))
def test_remove(self):
@@ -198,13 +229,13 @@ class KDTree_1FloatTestCase(unittest.TestCase):
self.i = i
self.next = None
- nn = KDTree_1Float()
+ nn = KDTree_4Int()
- k1, o1 = (1.1,), C(7)
+ k1, o1 = (0,0,1,1), C(7)
self.assertFalse(nn.remove((k1, id(o1))), "This cannot be removed!")
nn.add((k1, id(o1)))
- k2, o2 = (1.1,), C(7)
+ k2, o2 = (0,0,1,1), C(7)
nn.add((k2, id(o2)))
self.assertEqual(2, nn.size())
@@ -216,7 +247,7 @@ class KDTree_1FloatTestCase(unittest.TestCase):
nearest = nn.find_nearest(k1)
self.assertTrue(nearest[1] == id(o1), "%s != %s"%(nearest[1], o1))
#self.assertTrue(nearest[1] is o1, "%s,%s is not %s"%(str(nearest[0]), str(nearest[1]), str((k1,id(o1)))))
-
+
class KDTree_3FloatTestCase(unittest.TestCase):
def test_empty(self):
nn = KDTree_3Float()
@@ -364,7 +395,6 @@ class KDTree_6FloatTestCase(unittest.TestCase):
def suite():
return unittest.defaultTestLoader.loadTestsFromModule(sys.modules.get(__name__))
-
+
if __name__ == '__main__':
unittest.main()
-
--
1.5.6.3
More information about the libkdtree-devel
mailing list