Skip to content

Commit 807ed64

Browse files
committed
Refactor Array/Mesh classes
1 parent 04ee8ef commit 807ed64

File tree

7 files changed

+143
-420
lines changed

7 files changed

+143
-420
lines changed

pdal/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
set(EXTENSION_SRC
22
PyArray.cpp
33
PyArray.hpp
4-
PyMesh.cpp
5-
PyMesh.hpp
64
PyDimension.hpp
75
PyPipeline.cpp
86
PyPipeline.hpp)

pdal/PyArray.cpp

Lines changed: 105 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434

3535
#include "PyArray.hpp"
3636
#include <pdal/io/MemoryViewReader.hpp>
37-
3837
#include <numpy/arrayobject.h>
3938

4039
namespace pdal
@@ -90,12 +89,36 @@ std::string toString(PyObject *pname)
9089

9190
} // unnamed namespace
9291

93-
Array::Array() : m_array(nullptr)
92+
Array::Array(PointViewPtr view)
9493
{
9594
if (_import_array() < 0)
9695
throw pdal_error("Could not import numpy.core.multiarray.");
96+
97+
PyObject *dtype_dict = (PyObject*)buildNumpyDescription(view);
98+
if (!dtype_dict)
99+
throw pdal_error("Unable to build numpy dtype "
100+
"description dictionary");
101+
102+
PyArray_Descr *dtype = nullptr;
103+
if (PyArray_DescrConverter(dtype_dict, &dtype) == NPY_FAIL)
104+
throw pdal_error("Unable to build numpy dtype");
105+
Py_XDECREF(dtype_dict);
106+
107+
// This is a 1 x size array.
108+
npy_intp size = view->size();
109+
m_array = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype,
110+
1, &size, 0, nullptr, NPY_ARRAY_CARRAY, nullptr);
111+
112+
// copy the data
113+
DimTypeList types = view->dimTypes();
114+
for (PointId idx = 0; idx < view->size(); idx++)
115+
{
116+
char *p = (char *)PyArray_GETPTR1(m_array, idx);
117+
view->getPackedPoint(types, idx, p);
118+
}
97119
}
98120

121+
99122
Array::Array(PyArrayObject* array) : m_array(array), m_rowMajor(true)
100123
{
101124
if (_import_array() < 0)
@@ -163,50 +186,10 @@ Array::Array(PyArrayObject* array) : m_array(array), m_rowMajor(true)
163186

164187
Array::~Array()
165188
{
166-
if (m_array)
167-
Py_XDECREF((PyObject *)m_array);
189+
Py_XDECREF(m_array);
168190
}
169191

170192

171-
void Array::update(PointViewPtr view)
172-
{
173-
if (m_array)
174-
Py_XDECREF((PyObject *)m_array);
175-
m_array = nullptr; // Just in case of an exception.
176-
177-
Dimension::IdList dims = view->dims();
178-
npy_intp size = view->size();
179-
180-
PyObject *dtype_dict = (PyObject*)buildNumpyDescription(view);
181-
if (!dtype_dict)
182-
throw pdal_error("Unable to build numpy dtype "
183-
"description dictionary");
184-
185-
PyArray_Descr *dtype = nullptr;
186-
if (PyArray_DescrConverter(dtype_dict, &dtype) == NPY_FAIL)
187-
throw pdal_error("Unable to build numpy dtype");
188-
Py_XDECREF(dtype_dict);
189-
190-
// This is a 1 x size array.
191-
m_array = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype,
192-
1, &size, 0, nullptr, NPY_ARRAY_CARRAY, nullptr);
193-
194-
// copy the data
195-
DimTypeList types = view->dimTypes();
196-
for (PointId idx = 0; idx < view->size(); idx++)
197-
{
198-
char *p = (char *)PyArray_GETPTR1(m_array, idx);
199-
view->getPackedPoint(types, idx, p);
200-
}
201-
}
202-
203-
204-
//ABELL - Who's responsible for incrementing the ref count?
205-
PyArrayObject *Array::getPythonArray() const
206-
{
207-
return m_array;
208-
}
209-
210193
PyObject* Array::buildNumpyDescription(PointViewPtr view) const
211194
{
212195
// Build up a numpy dtype dictionary
@@ -263,31 +246,100 @@ PyObject* Array::buildNumpyDescription(PointViewPtr view) const
263246
return dict;
264247
}
265248

266-
bool Array::rowMajor() const
249+
250+
ArrayIter& Array::iterator()
267251
{
268-
return m_rowMajor;
252+
ArrayIter *it = new ArrayIter(m_array);
253+
m_iterators.push_back(std::unique_ptr<ArrayIter>(it));
254+
return *it;
269255
}
270256

271-
Array::Shape Array::shape() const
257+
258+
Mesh::Mesh(PointViewPtr view)
272259
{
273-
return m_shape;
260+
if (_import_array() < 0)
261+
throw pdal_error("Could not import numpy.core.multiarray.");
262+
263+
PyObject *dtype_dict = (PyObject*)buildNumpyDescription(view);
264+
if (!dtype_dict)
265+
throw pdal_error("Unable to build numpy dtype "
266+
"description dictionary");
267+
268+
PyArray_Descr *dtype = nullptr;
269+
if (PyArray_DescrConverter(dtype_dict, &dtype) == NPY_FAIL)
270+
throw pdal_error("Unable to build numpy dtype");
271+
Py_XDECREF(dtype_dict);
272+
273+
// This is a 1 x size array.
274+
TriangularMesh* mesh = view->mesh();
275+
npy_intp size = mesh ? mesh->size() : 0;
276+
m_mesh = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dtype,
277+
1, &size, 0, nullptr, NPY_ARRAY_CARRAY, nullptr);
278+
279+
for (PointId idx = 0; idx < size; idx++)
280+
{
281+
char* p = (char *)PyArray_GETPTR1(m_mesh, idx);
282+
const Triangle& t = (*mesh)[idx];
283+
uint32_t a = (uint32_t)t.m_a;
284+
std::memcpy(p, &a, 4);
285+
uint32_t b = (uint32_t)t.m_b;
286+
std::memcpy(p + 4, &b, 4);
287+
uint32_t c = (uint32_t)t.m_c;
288+
std::memcpy(p + 8, &c, 4);
289+
}
274290
}
275291

276-
const Array::Fields& Array::fields() const
292+
293+
Mesh::~Mesh()
277294
{
278-
return m_fields;
295+
if (m_mesh)
296+
Py_XDECREF((PyObject *)m_mesh);
279297
}
280298

281-
ArrayIter& Array::iterator()
299+
300+
PyObject* Mesh::buildNumpyDescription(PointViewPtr view) const
301+
{
302+
// Build up a numpy dtype dictionary
303+
//
304+
// {'formats': ['f8', 'f8', 'f8', 'u2', 'u1', 'u1', 'u1', 'u1', 'u1',
305+
// 'f4', 'u1', 'u2', 'f8', 'u2', 'u2', 'u2'],
306+
// 'names': ['X', 'Y', 'Z', 'Intensity', 'ReturnNumber',
307+
// 'NumberOfReturns', 'ScanDirectionFlag', 'EdgeOfFlightLine',
308+
// 'Classification', 'ScanAngleRank', 'UserData',
309+
// 'PointSourceId', 'GpsTime', 'Red', 'Green', 'Blue']}
310+
//
311+
312+
Dimension::IdList dims = view->dims();
313+
314+
PyObject* dict = PyDict_New();
315+
PyObject* formats = PyList_New(3);
316+
PyObject* titles = PyList_New(3);
317+
318+
PyList_SetItem(titles, 0, PyUnicode_FromString("A"));
319+
PyList_SetItem(formats, 0, PyUnicode_FromString("u4"));
320+
PyList_SetItem(titles, 1, PyUnicode_FromString("B"));
321+
PyList_SetItem(formats, 1, PyUnicode_FromString("u4"));
322+
PyList_SetItem(titles, 2, PyUnicode_FromString("C"));
323+
PyList_SetItem(formats, 2, PyUnicode_FromString("u4"));
324+
325+
326+
PyDict_SetItemString(dict, "names", titles);
327+
PyDict_SetItemString(dict, "formats", formats);
328+
329+
return dict;
330+
}
331+
332+
ArrayIter& Mesh::iterator()
282333
{
283-
ArrayIter *it = new ArrayIter(*this);
334+
ArrayIter *it = new ArrayIter(m_mesh);
284335
m_iterators.push_back(std::unique_ptr<ArrayIter>(it));
285336
return *it;
286337
}
287338

288-
ArrayIter::ArrayIter(Array& array)
339+
340+
ArrayIter::ArrayIter(PyArrayObject* np_array)
289341
{
290-
m_iter = NpyIter_New(array.getPythonArray(),
342+
m_iter = NpyIter_New(np_array,
291343
NPY_ITER_EXTERNAL_LOOP | NPY_ITER_READONLY | NPY_ITER_REFS_OK,
292344
NPY_KEEPORDER, NPY_NO_CASTING, NULL);
293345
if (!m_iter)
@@ -324,16 +376,6 @@ ArrayIter& ArrayIter::operator++()
324376
return *this;
325377
}
326378

327-
ArrayIter::operator bool () const
328-
{
329-
return !m_done;
330-
}
331-
332-
char * ArrayIter::operator * () const
333-
{
334-
return *m_data;
335-
}
336-
337379
} // namespace python
338380
} // namespace pdal
339381

pdal/PyArray.hpp

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,9 @@
3434

3535
#pragma once
3636

37-
#include <numpy/ndarraytypes.h>
38-
3937
#include <pdal/PointView.hpp>
4038
#include <pdal/io/MemoryViewReader.hpp>
41-
42-
#include <utility>
39+
#include <numpy/ndarraytypes.h>
4340

4441
namespace pdal
4542
{
@@ -48,51 +45,71 @@ namespace python
4845

4946
class ArrayIter;
5047

48+
49+
class PDAL_DLL Mesh
50+
{
51+
public:
52+
using Shape = std::array<size_t, 3>;
53+
54+
Mesh(PointViewPtr view);
55+
~Mesh();
56+
57+
PyArrayObject *getPythonArray() const { return m_mesh; }
58+
bool rowMajor() const { return m_rowMajor; }
59+
Shape shape() const { return m_shape; }
60+
ArrayIter& iterator();
61+
62+
private:
63+
inline PyObject* buildNumpyDescription(PointViewPtr view) const;
64+
65+
PyArrayObject* m_mesh;
66+
bool m_rowMajor;
67+
Shape m_shape {};
68+
std::vector<std::unique_ptr<ArrayIter>> m_iterators;
69+
};
70+
71+
5172
class PDAL_DLL Array
5273
{
5374
public:
5475
using Shape = std::array<size_t, 3>;
5576
using Fields = std::vector<MemoryViewReader::Field>;
5677

5778
// Create an array for reading data from PDAL.
58-
Array();
59-
79+
Array(PointViewPtr view);
6080
// Create an array for writing data to PDAL.
6181
Array(PyArrayObject* array);
62-
6382
~Array();
64-
void update(PointViewPtr view);
65-
PyArrayObject *getPythonArray() const;
66-
bool rowMajor() const;
67-
Shape shape() const;
68-
const Fields& fields() const;
69-
ArrayIter& iterator();
7083

84+
PyArrayObject *getPythonArray() const { return m_array; }
85+
bool rowMajor() const { return m_rowMajor; };
86+
Shape shape() const { return m_shape; }
87+
const Fields& fields() const { return m_fields; };
88+
ArrayIter& iterator();
7189

7290
private:
7391
inline PyObject* buildNumpyDescription(PointViewPtr view) const;
7492

75-
7693
PyArrayObject* m_array;
77-
Array& operator=(Array const& rhs);
7894
Fields m_fields;
7995
bool m_rowMajor;
8096
Shape m_shape {};
8197
std::vector<std::unique_ptr<ArrayIter>> m_iterators;
8298
};
8399

100+
84101
class ArrayIter
85102
{
86103
public:
87104
ArrayIter(const ArrayIter&) = delete;
88105
ArrayIter() = delete;
89106

90-
ArrayIter(Array& array);
107+
ArrayIter(PyArrayObject*);
91108
~ArrayIter();
92109

93110
ArrayIter& operator++();
94-
operator bool () const;
95-
char *operator * () const;
111+
operator bool () const { return !m_done; }
112+
char* operator*() const { return *m_data; }
96113

97114
private:
98115
NpyIter *m_iter;

0 commit comments

Comments
 (0)