@@ -10,6 +10,9 @@ cimport pcl_defs as cpp
10
10
11
11
cimport cython
12
12
from cython.operator import dereference as deref
13
+
14
+ from cpython cimport Py_buffer
15
+
13
16
from libcpp.string cimport string
14
17
from libcpp cimport bool
15
18
from libcpp.vector cimport vector
@@ -125,6 +128,20 @@ cdef class SegmentationNormal:
125
128
def set_axis (self , double ax , double ay , double az ):
126
129
mpcl_sacnormal_set_axis(deref(self .me),ax,ay,az)
127
130
131
+
132
+ # Empirically determine strides, for buffer support.
133
+ # XXX Is there a more elegant way to get these?
134
+ cdef Py_ssize_t _strides[2 ]
135
+ cdef PointCloud _pc_tmp = PointCloud(np.array([[1 , 2 , 3 ],
136
+ [4 , 5 , 6 ]], dtype = np.float32))
137
+ cdef cpp.PointCloud[cpp.PointXYZ] * p = _pc_tmp.thisptr()
138
+ _strides[0 ] = ( < Py_ssize_t>< void * > cpp.getptr(p, 1 )
139
+ - < Py_ssize_t>< void * > cpp.getptr(p, 0 ))
140
+ _strides[1 ] = ( < Py_ssize_t>< void * > & (cpp.getptr(p, 0 ).y)
141
+ - < Py_ssize_t>< void * > & (cpp.getptr(p, 0 ).x))
142
+ _pc_tmp = None
143
+
144
+
128
145
cdef class PointCloud:
129
146
""" Represents a cloud of points in 3-d space.
130
147
@@ -137,6 +154,8 @@ cdef class PointCloud:
137
154
def __cinit__ (self , init = None ):
138
155
cdef PointCloud other
139
156
157
+ self ._view_count = 0
158
+
140
159
sp_assign(self .thisptr_shared, new cpp.PointCloud[cpp.PointXYZ]())
141
160
142
161
if init is None :
@@ -170,6 +189,32 @@ cdef class PointCloud:
170
189
def __repr__ (self ):
171
190
return " <PointCloud of %d points>" % self .size
172
191
192
+ # Buffer protocol support. Taking a view locks the pointcloud for
193
+ # resizing, because that can move it around in memory.
194
+ def __getbuffer__ (self , Py_buffer *buffer , int flags ):
195
+ # TODO parse flags
196
+ cdef Py_ssize_t npoints = self .thisptr().size()
197
+
198
+ if self ._view_count == 0 :
199
+ self ._view_count += 1
200
+ self ._shape[0 ] = npoints
201
+ self ._shape[1 ] = 3
202
+
203
+ buffer .buf = < char * > & (cpp.getptr_at(self .thisptr(), 0 ).x)
204
+ buffer .format = ' f'
205
+ buffer .internal = NULL
206
+ buffer .itemsize = sizeof(float )
207
+ buffer .len = npoints * 3 * sizeof(float )
208
+ buffer .ndim = 2
209
+ buffer .obj = self
210
+ buffer .readonly = 0
211
+ buffer .shape = self ._shape
212
+ buffer .strides = _strides
213
+ buffer .suboffsets = NULL
214
+
215
+ def __releasebuffer__ (self , Py_buffer *buffer ):
216
+ self ._view_count -= 1
217
+
173
218
# Pickle support. XXX this copies the entire pointcloud; it would be nice
174
219
# to have an asarray member that returns a view, or even better, implement
175
220
# the buffer protocol (https://docs.python.org/c-api/buffer.html).
@@ -246,6 +291,9 @@ cdef class PointCloud:
246
291
return self .to_array().tolist()
247
292
248
293
def resize (self , cnp.npy_intp x ):
294
+ if self ._view_count > 0 :
295
+ raise ValueError (" can't resize PointCloud while there are"
296
+ " arrays/memoryviews referencing it" )
249
297
self .thisptr().resize(x)
250
298
251
299
def get_point (self , cnp.npy_intp row , cnp.npy_intp col ):
0 commit comments