2 #include <boost/python.hpp>
3 #include <numpy/arrayobject.h>
4 #include "../nabo/nabo.h"
8 using namespace boost::python;
17 static const double infD = std::numeric_limits<double>::infinity();
18 static const Index maxI = std::numeric_limits<Index>::max();
20 #if PY_MAJOR_VERSION >= 3
37 assert(PyArray_CHKFLAGS(cloudObj, NPY_C_CONTIGUOUS) || PyArray_CHKFLAGS(cloudObj, NPY_F_CONTIGUOUS));
38 assert(PyArray_NDIM(cloudObj) == 2);
39 const npy_intp *shape = PyArray_DIMS(cloudObj);
40 if (PyArray_CHKFLAGS(cloudObj, NPY_F_CONTIGUOUS))
54 std::string startMsg(
"Argument \"");
55 startMsg += paramName;
58 if (!PyArray_Check(cloudObj))
59 throw std::runtime_error(startMsg +
"must be a multi-dimensional array");
60 const int nDim = PyArray_NDIM(cloudObj);
62 throw std::runtime_error(startMsg +
"must be a two-dimensional array");
63 if (PyArray_TYPE(cloudObj) != NPY_FLOAT64)
64 throw std::runtime_error(startMsg +
"must hold doubles");
65 if (!PyArray_CHKFLAGS(cloudObj, NPY_C_CONTIGUOUS) && !PyArray_CHKFLAGS(cloudObj, NPY_F_CONTIGUOUS))
66 throw std::runtime_error(startMsg +
"must be a continuous array");
71 int dimCount, pointCount;
72 const PyObject *cloudObj(cloudIn.ptr());
77 double* cloudData(
reinterpret_cast<double*
>(PyArray_DATA(cloudObj)));
84 int dimCount, pointCount;
85 const PyObject *cloudObj(cloudIn.ptr());
90 cloudOut.resize(dimCount, pointCount);
92 memcpy(cloudOut.data(), PyArray_DATA(cloudObj), pointCount*dimCount*
sizeof(
double));
106 #if PY_MAJOR_VERSION >=3
107 object it = params.items();
109 object it = params.iteritems();
112 for(
int i = 0; i < len(params); ++i)
114 const tuple item(it.attr(
"next")());
115 const std::string key = extract<std::string>(item[0]);
116 const object val(item[1]);
117 const std::string valType(val.ptr()->ob_type->tp_name);
118 if (valType ==
"int")
120 const int iVal = extract<int>(val);
122 _params[key] = (unsigned)iVal;
137 tuple
knn(
const object query,
const Index k = 1,
const double epsilon = 0,
const unsigned optionFlags = 0,
const double maxRadius =
infD)
145 nns->knn(*mappedQuery, indexMatrix, dists2Matrix, k, epsilon, optionFlags, maxRadius);
148 npy_intp retDims[2] = { mappedQuery->cols(), k };
149 const int dataCount(k * mappedQuery->cols());
150 PyObject* dists2 = PyArray_EMPTY(2, retDims, PyArray_DOUBLE, PyArray_ISFORTRAN(query.ptr()));
151 memcpy(PyArray_DATA(dists2), dists2Matrix.data(), dataCount*
sizeof(
double));
152 PyObject* indices = PyArray_EMPTY(2, retDims, PyArray_INT, PyArray_ISFORTRAN(query.ptr()));
153 memcpy(PyArray_DATA(indices), indexMatrix.data(), dataCount*
sizeof(
int));
157 return make_tuple(
object(handle<>(indices)),
object(handle<>(dists2)));
165 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(knn_overloads, knn, 1, 5)
171 enum_<SearchType>(
"SearchType",
"Type of algorithm used for search.")
177 enum_<SearchOptionFlags>(
"SearchOptionFlags",
"Flags you can OR when creating search.")
182 class_<NearestNeighbourSearch>(
183 "NearestNeighbourSearch",
184 "Nearest-neighbour search object, containing the data, on which you can do the knn(...) query.\n\n"
185 "The data and query must be continuous numpy arrays.\n"
186 "As numpy proposes both C and Fortran data orders, pynabo\n"
187 "will always consider the contiguous dimension to be coordinates\n"
188 "of points, regardless of order, as this provides the fastest\n"
189 "possible execution. The return values of knn(...) will have\n"
190 "the same order as the query and will have the different results\n"
191 "of each point in the contiguous dimension."
193 init<
const object, optional<const SearchType, const Index, const dict> >(
194 "Create a nearest-neighbour search.\n\n"
196 " data -- data-point cloud in which to search, must be a numpy array\n"
197 " searchType -- type of search, default: KDTREE_LINEAR_HEAP\n"
198 " dim -- number of dimensions to consider, must be lower or equal to cloud.rows(), default: dim of data\n"
199 " creationOptionFlags -- creation options, a bitwise OR of elements of CreationOptionFlags",
200 args(
"self",
"data",
"searchType",
"dim",
"creationOptionFlags, default: 0")
205 args(
"self",
"query",
"k",
"epsilon",
"optionFlags",
"maxRadius"),
206 "Find the k nearest neighbours of query in data.\n\n"
208 " query -- query points, must be a numpy array\n"
209 " k -- number of nearest neighbour requested, default: 1\n"
210 " epsilon -- maximal ratio of error for approximate search, 0 for exact search; has no effect if the number of neighbour found is smaller than the number requested; default: 0.\n"
211 " optionFlags -- search options, a bitwise OR of elements of SearchOptionFlags, default: 0\n"
212 " maxRadius -- maximum radius in which to search, can be used to prune search, is not affected by epsilon, default: inf\n\n"
214 " A tuple of two 2D numpy arrays, the first containing indices to points in data, the other containing squared distances."