diff options
author | Lars Buitinck <l.buitinck@esciencecenter.nl> | 2015-01-20 14:26:33 +0100 |
---|---|---|
committer | Lars Buitinck <l.buitinck@esciencecenter.nl> | 2015-01-20 14:26:33 +0100 |
commit | 102ee66d227bc408166e9393519d364c8f488e6b (patch) | |
tree | 4176d6291c55d7e471a36956974fed953268e4c7 /pcl | |
parent | 8507941c4dc3bc0524b425bba1239dbe26ceb052 (diff) |
add buffer protocol support to PointCloud
Diffstat (limited to 'pcl')
-rw-r--r-- | pcl/_pcl.pxd | 4 | ||||
-rw-r--r-- | pcl/_pcl.pyx | 48 |
2 files changed, 52 insertions, 0 deletions
diff --git a/pcl/_pcl.pxd b/pcl/_pcl.pxd index 6bae71d..6f37d56 100644 --- a/pcl/_pcl.pxd +++ b/pcl/_pcl.pxd @@ -7,6 +7,10 @@ cimport pcl_defs as cpp cdef class PointCloud: cdef cpp.PointCloudPtr_t thisptr_shared + # Buffer protocol support. + cdef Py_ssize_t _shape[2] + cdef Py_ssize_t _view_count + cdef inline cpp.PointCloud[cpp.PointXYZ] *thisptr(self) nogil: # Shortcut to get raw pointer to underlying PointCloud<PointXYZ>. return self.thisptr_shared.get() diff --git a/pcl/_pcl.pyx b/pcl/_pcl.pyx index 22316e8..8eaf54b 100644 --- a/pcl/_pcl.pyx +++ b/pcl/_pcl.pyx @@ -10,6 +10,9 @@ cimport pcl_defs as cpp cimport cython from cython.operator import dereference as deref + +from cpython cimport Py_buffer + from libcpp.string cimport string from libcpp cimport bool from libcpp.vector cimport vector @@ -125,6 +128,20 @@ cdef class SegmentationNormal: def set_axis(self, double ax, double ay, double az): mpcl_sacnormal_set_axis(deref(self.me),ax,ay,az) + +# Empirically determine strides, for buffer support. +# XXX Is there a more elegant way to get these? +cdef Py_ssize_t _strides[2] +cdef PointCloud _pc_tmp = PointCloud(np.array([[1, 2, 3], + [4, 5, 6]], dtype=np.float32)) +cdef cpp.PointCloud[cpp.PointXYZ] *p = _pc_tmp.thisptr() +_strides[0] = ( <Py_ssize_t><void *>cpp.getptr(p, 1) + - <Py_ssize_t><void *>cpp.getptr(p, 0)) +_strides[1] = ( <Py_ssize_t><void *>&(cpp.getptr(p, 0).y) + - <Py_ssize_t><void *>&(cpp.getptr(p, 0).x)) +_pc_tmp = None + + cdef class PointCloud: """Represents a cloud of points in 3-d space. @@ -137,6 +154,8 @@ cdef class PointCloud: def __cinit__(self, init=None): cdef PointCloud other + self._view_count = 0 + sp_assign(self.thisptr_shared, new cpp.PointCloud[cpp.PointXYZ]()) if init is None: @@ -170,6 +189,32 @@ cdef class PointCloud: def __repr__(self): return "<PointCloud of %d points>" % self.size + # Buffer protocol support. Taking a view locks the pointcloud for + # resizing, because that can move it around in memory. + def __getbuffer__(self, Py_buffer *buffer, int flags): + # TODO parse flags + cdef Py_ssize_t npoints = self.thisptr().size() + + if self._view_count == 0: + self._view_count += 1 + self._shape[0] = npoints + self._shape[1] = 3 + + buffer.buf = <char *>&(cpp.getptr_at(self.thisptr(), 0).x) + buffer.format = 'f' + buffer.internal = NULL + buffer.itemsize = sizeof(float) + buffer.len = npoints * 3 * sizeof(float) + buffer.ndim = 2 + buffer.obj = self + buffer.readonly = 0 + buffer.shape = self._shape + buffer.strides = _strides + buffer.suboffsets = NULL + + def __releasebuffer__(self, Py_buffer *buffer): + self._view_count -= 1 + # Pickle support. XXX this copies the entire pointcloud; it would be nice # to have an asarray member that returns a view, or even better, implement # the buffer protocol (https://docs.python.org/c-api/buffer.html). @@ -246,6 +291,9 @@ cdef class PointCloud: return self.to_array().tolist() def resize(self, cnp.npy_intp x): + if self._view_count > 0: + raise ValueError("can't resize PointCloud while there are" + " arrays/memoryviews referencing it") self.thisptr().resize(x) def get_point(self, cnp.npy_intp row, cnp.npy_intp col): |