Skip to content

Commit 04ee8ef

Browse files
committed
Refactor Pipeline
- Rename PyPipeline to Pipeline and drop pure Python Pipeline - Rename Pipeline to PyPipelineExecutor - Replace composition with inheritance between PyPipelineExecutor and PipelineExecutor - Refactor libpdalpython.pyx
1 parent a692f06 commit 04ee8ef

File tree

5 files changed

+83
-218
lines changed

5 files changed

+83
-218
lines changed

pdal/PyPipeline.cpp

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ namespace python
5353
{
5454

5555
// Create a pipeline for writing data to PDAL
56-
Pipeline::Pipeline(std::string const& json, std::vector<Array*> arrays) :
57-
m_executor(new PipelineExecutor(json))
56+
PyPipelineExecutor::PyPipelineExecutor(std::string const& json,
57+
std::vector<Array*> arrays) : PipelineExecutor(json)
5858
{
5959
#ifndef _WIN32
6060
// See comment in alternate constructor below.
@@ -64,8 +64,7 @@ Pipeline::Pipeline(std::string const& json, std::vector<Array*> arrays) :
6464
if (_import_array() < 0)
6565
throw pdal_error("Could not impory numpy.core.multiarray.");
6666

67-
PipelineManager& manager = m_executor->getManager();
68-
67+
PipelineManager& manager = getManager();
6968
std::stringstream strm(json);
7069
manager.readPipeline(strm);
7170
std::vector<Stage *> roots = manager.roots();
@@ -107,8 +106,7 @@ Pipeline::Pipeline(std::string const& json, std::vector<Array*> arrays) :
107106
}
108107

109108
// Create a pipeline for reading data from PDAL
110-
Pipeline::Pipeline(std::string const& json) :
111-
m_executor(new PipelineExecutor(json))
109+
PyPipelineExecutor::PyPipelineExecutor(std::string const& json) : PipelineExecutor(json)
112110
{
113111
// Make the symbols in pdal_base global so that they're accessible
114112
// to PDAL plugins. Python dlopen's this extension with RTLD_LOCAL,
@@ -124,65 +122,32 @@ Pipeline::Pipeline(std::string const& json) :
124122
throw pdal_error("Could not impory numpy.core.multiarray.");
125123
}
126124

127-
Pipeline::~Pipeline()
128-
{}
129-
130-
131-
void Pipeline::setLogLevel(int level)
132-
{
133-
m_executor->setLogLevel(level);
134-
}
135-
136-
137-
int Pipeline::getLogLevel() const
125+
std::vector<Array*> PyPipelineExecutor::getArrays() const
138126
{
139-
return static_cast<int>(m_executor->getLogLevel());
140-
}
141-
142-
143-
int64_t Pipeline::execute()
144-
{
145-
return m_executor->execute();
146-
}
147-
148-
bool Pipeline::validate()
149-
{
150-
auto res = m_executor->validate();
151-
return res;
152-
}
153-
154-
std::vector<Array *> Pipeline::getArrays() const
155-
{
156-
std::vector<Array *> output;
157-
158-
if (!m_executor->executed())
127+
if (!executed())
159128
throw python_error("call execute() before fetching arrays");
160129

161-
const PointViewSet& pvset = m_executor->getManagerConst().views();
162-
163-
for (auto i: pvset)
130+
std::vector<Array *> output;
131+
for (auto view: getManagerConst().views())
164132
{
165133
//ABELL - Leak?
166134
Array *array = new python::Array;
167-
array->update(i);
135+
array->update(view);
168136
output.push_back(array);
169137
}
170138
return output;
171139
}
172140

173-
std::vector<Mesh *> Pipeline::getMeshes() const
141+
std::vector<Mesh*> PyPipelineExecutor::getMeshes() const
174142
{
175-
std::vector<Mesh *> output;
176-
177-
if (!m_executor->executed())
143+
if (!executed())
178144
throw python_error("call execute() before fetching the mesh");
179145

180-
const PointViewSet& pvset = m_executor->getManagerConst().views();
181-
182-
for (auto i: pvset)
146+
std::vector<Mesh *> output;
147+
for (auto view: getManagerConst().views())
183148
{
184149
Mesh *mesh = new python::Mesh;
185-
mesh->update(i);
150+
mesh->update(view);
186151
output.push_back(mesh);
187152
}
188153
return output;

pdal/PyPipeline.hpp

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -58,39 +58,15 @@ class python_error : public std::runtime_error
5858
{}
5959
};
6060

61-
class Pipeline
61+
class PyPipelineExecutor : public PipelineExecutor
6262
{
6363
public:
64-
Pipeline(std::string const& json);
65-
Pipeline(std::string const& json,
64+
PyPipelineExecutor(std::string const& json);
65+
PyPipelineExecutor(std::string const& json,
6666
std::vector<pdal::python::Array*> arrays);
67-
~Pipeline();
6867

69-
int64_t execute();
70-
bool validate();
71-
inline std::string getPipeline() const
72-
{
73-
return m_executor->getPipeline();
74-
}
75-
inline std::string getMetadata() const
76-
{
77-
return m_executor->getMetadata();
78-
}
79-
inline std::string getSchema() const
80-
{
81-
return m_executor->getSchema();
82-
}
83-
inline std::string getLog() const
84-
{
85-
return m_executor->getLog();
86-
}
8768
std::vector<pdal::python::Array *> getArrays() const;
8869
std::vector<pdal::python::Mesh *> getMeshes() const;
89-
void setLogLevel(int level);
90-
int getLogLevel() const;
91-
92-
private:
93-
std::shared_ptr<pdal::PipelineExecutor> m_executor;
9470
};
9571

9672
} // namespace python

pdal/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
from .libpdalpython import Pipeline
12
from .libpdalpython import getDimensions, getInfo
2-
from .pipeline import Pipeline
33

44
__version__ = "2.4.2"
55

pdal/libpdalpython.pyx

Lines changed: 65 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
# distutils: language = c++
22
# cython: c_string_type=unicode, c_string_encoding=utf8
33

4+
import json
45
from libcpp.vector cimport vector
56
from libcpp.string cimport string
67
from libc.stdint cimport int64_t
78
from libcpp cimport bool
89
from types import SimpleNamespace
10+
11+
import numpy as np
912
cimport numpy as np
1013
np.import_array()
1114

1215
from cython.operator cimport dereference as deref, preincrement as inc
1316

17+
1418
cdef extern from "pdal/pdal_config.hpp" namespace "pdal::Config":
1519
cdef int versionMajor() except +
1620
cdef int versionMinor() except +
@@ -20,7 +24,6 @@ cdef extern from "pdal/pdal_config.hpp" namespace "pdal::Config":
2024
cdef string pluginInstallPath() except+
2125
cdef string versionString() except+
2226

23-
2427
def getInfo():
2528
return SimpleNamespace(
2629
version=versionString(),
@@ -33,20 +36,39 @@ def getInfo():
3336
)
3437

3538

39+
cdef extern from "PyDimension.hpp":
40+
ctypedef struct Dimension:
41+
string name;
42+
string description;
43+
int size;
44+
string type;
45+
## string units; // Not defined by PDAL yet
46+
cdef vector[Dimension] getValidDimensions() except +
47+
48+
def getDimensions():
49+
output = []
50+
for dim in getValidDimensions():
51+
output.append({
52+
'name': dim.name,
53+
'description': dim.description,
54+
'dtype': np.dtype(dim.type + str(dim.size))
55+
})
56+
return output
57+
58+
3659
cdef extern from "PyArray.hpp" namespace "pdal::python":
3760
cdef cppclass Array:
3861
Array(np.ndarray) except +
3962
void *getPythonArray() except+
4063

4164
cdef extern from "PyMesh.hpp" namespace "pdal::python":
4265
cdef cppclass Mesh:
43-
Mesh(np.ndarray) except +
4466
void *getPythonArray() except +
4567

4668
cdef extern from "PyPipeline.hpp" namespace "pdal::python":
47-
cdef cppclass Pipeline:
48-
Pipeline(const char* ) except +
49-
Pipeline(const char*, vector[Array*]& ) except +
69+
cdef cppclass PyPipelineExecutor:
70+
PyPipelineExecutor(const char*) except +
71+
PyPipelineExecutor(const char*, vector[Array*]&) except +
5072
int64_t execute() except +
5173
bool validate() except +
5274
string getPipeline() except +
@@ -58,118 +80,90 @@ cdef extern from "PyPipeline.hpp" namespace "pdal::python":
5880
int getLogLevel()
5981
void setLogLevel(int)
6082

61-
cdef extern from "PyDimension.hpp":
62-
ctypedef struct Dimension:
63-
string name;
64-
string description;
65-
int size;
66-
string type;
67-
## string units; // Not defined by PDAL yet
68-
69-
cdef vector[Dimension] getValidDimensions() except +
7083

71-
72-
def getDimensions():
73-
cdef vector[Dimension] c_dims;
74-
c_dims = getValidDimensions()
75-
output = []
76-
cdef vector[Dimension].iterator it = c_dims.begin()
77-
while it != c_dims.end():
78-
ptr = deref(it)
79-
d = {}
80-
d['name'] = ptr.name
81-
d['description'] = ptr.description
82-
kind = ptr.type + str(ptr.size)
83-
d['dtype'] = np.dtype(kind)
84-
ptr = deref(it)
85-
output.append(d)
86-
inc(it)
87-
return output
88-
89-
90-
cdef class PyPipeline:
91-
cdef Pipeline *thisptr # hold a c++ instance which we're wrapping
92-
cdef vector[Array *] c_arrays;
84+
cdef class Pipeline:
85+
cdef PyPipelineExecutor* _executor
86+
cdef vector[Array *] _arrays;
9387

9488
def __cinit__(self, unicode json, list arrays=None):
95-
cdef char* x = NULL
96-
9789
if arrays is not None:
9890
for array in arrays:
99-
self.c_arrays.push_back(new Array(array))
100-
self.thisptr = new Pipeline(json.encode('UTF-8'), self.c_arrays)
91+
self._arrays.push_back(new Array(array))
92+
self._executor = new PyPipelineExecutor(json.encode('UTF-8'), self._arrays)
10193
else:
102-
self.thisptr = new Pipeline(json.encode('UTF-8'))
94+
self._executor = new PyPipelineExecutor(json.encode('UTF-8'))
10395

10496
def __dealloc__(self):
105-
for array in self.c_arrays:
97+
for array in self._arrays:
10698
del array
107-
del self.thisptr
99+
del self._executor
108100

109101
property pipeline:
110102
def __get__(self):
111-
return self.thisptr.getPipeline()
103+
return self._executor.getPipeline()
112104

113105
property metadata:
114106
def __get__(self):
115-
return self.thisptr.getMetadata()
107+
return self._executor.getMetadata()
116108

117109
property loglevel:
118110
def __get__(self):
119-
return self.thisptr.getLogLevel()
111+
return self._executor.getLogLevel()
120112
def __set__(self, v):
121-
self.thisptr.setLogLevel(v)
113+
self._executor.setLogLevel(v)
122114

123115
property log:
124116
def __get__(self):
125-
126-
return self.thisptr.getLog()
117+
return self._executor.getLog()
127118

128119
property schema:
129120
def __get__(self):
130-
import json
131-
132-
j = self.thisptr.getSchema()
133-
return json.loads(j)
121+
return json.loads(self._executor.getSchema())
134122

135123
property arrays:
136-
137124
def __get__(self):
138-
v = self.thisptr.getArrays()
139125
output = []
126+
v = self._executor.getArrays()
140127
cdef vector[Array*].iterator it = v.begin()
141-
cdef Array* a
128+
cdef Array* ptr
142129
while it != v.end():
143130
ptr = deref(it)
144-
a = ptr#.get()
145-
o = a.getPythonArray()
146-
output.append(<object>o)
131+
output.append(<object>ptr.getPythonArray())
147132
del ptr
148133
inc(it)
149134
return output
150135

151136
property meshes:
152-
153137
def __get__(self):
154-
v = self.thisptr.getMeshes()
155138
output = []
139+
v = self._executor.getMeshes()
156140
cdef vector[Mesh *].iterator it = v.begin()
157-
cdef Mesh* m
141+
cdef Mesh* ptr
158142
while it != v.end():
159143
ptr = deref(it)
160-
m = ptr#.get()
161-
o = m.getPythonArray()
162-
output.append(<object>o)
144+
output.append(<object>ptr.getPythonArray())
163145
del ptr
164146
inc(it)
165147
return output
166148

167149
def execute(self):
168-
if not self.thisptr:
169-
raise Exception("C++ Pipeline object not constructed!")
170-
return self.thisptr.execute()
150+
return self._executor.execute()
171151

172152
def validate(self):
173-
if not self.thisptr:
174-
raise Exception("C++ Pipeline object not constructed!")
175-
return self.thisptr.validate()
153+
return self._executor.validate()
154+
155+
def get_meshio(self, idx):
156+
try:
157+
from meshio import Mesh
158+
except ModuleNotFoundError:
159+
raise RuntimeError(
160+
"The get_meshio function can only be used if you have installed meshio. Try pip install meshio"
161+
)
162+
array = self.arrays[idx]
163+
mesh = self.meshes[idx]
164+
if len(mesh) == 0:
165+
return None
166+
return Mesh(
167+
np.stack((array["X"], array["Y"], array["Z"]), 1),
168+
[("triangle", np.stack((mesh["A"], mesh["B"], mesh["C"]), 1))],
169+
)

0 commit comments

Comments
 (0)