[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