Skip to content

Commit 2d035ab

Browse files
authored
Support limiting dimensions with execute() and executeStreaming() (#184)
1 parent f2fdc7c commit 2d035ab

File tree

8 files changed

+64
-22
lines changed

8 files changed

+64
-22
lines changed

src/pdal/PyArray.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ Dimension::Type pdalType(int t)
7878
return Type::None;
7979
}
8080

81-
std::string toString(PyObject *pname)
81+
std::string pyObjectToString(PyObject *pname)
8282
{
8383
PyObject* r = PyObject_Str(pname);
8484
if (!r)
@@ -92,6 +92,7 @@ std::string toString(PyObject *pname)
9292

9393
#if NPY_ABI_VERSION < 0x02000000
9494
#define PyDataType_FIELDS(descr) ((descr)->fields)
95+
#define PyDataType_NAMES(descr) ((descr)->names)
9596
#endif
9697

9798
Array::Array(PyArrayObject* array) : m_array(array), m_rowMajor(true)
@@ -124,7 +125,7 @@ Array::Array(PyArrayObject* array) : m_array(array), m_rowMajor(true)
124125

125126
for (int i = 0; i < numFields; ++i)
126127
{
127-
std::string name = toString(PyList_GetItem(names, i));
128+
std::string name = python::pyObjectToString(PyList_GetItem(names, i));
128129
if (name == "X")
129130
xyz |= 1;
130131
else if (name == "Y")

src/pdal/PyArray.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ namespace pdal
5555
namespace python
5656
{
5757

58+
5859
class ArrayIter;
5960

6061

@@ -87,7 +88,7 @@ class PDAL_DLL Array
8788
};
8889

8990

90-
class ArrayIter
91+
class PDAL_DLL ArrayIter
9192
{
9293
public:
9394
ArrayIter(const ArrayIter&) = delete;

src/pdal/PyPipeline.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,13 @@ PipelineExecutor::PipelineExecutor(
7373
}
7474

7575

76-
point_count_t PipelineExecutor::execute()
76+
point_count_t PipelineExecutor::execute(pdal::StringList allowedDims)
7777
{
78+
if (allowedDims.size())
79+
{
80+
m_manager.pointTable().layout()->setAllowedDims(allowedDims);
81+
}
82+
7883
point_count_t count = m_manager.execute();
7984
m_executed = true;
8085
return count;
@@ -92,9 +97,14 @@ std::string PipelineExecutor::getSrsWKT2() const
9297
return output;
9398
}
9499

95-
point_count_t PipelineExecutor::executeStream(point_count_t streamLimit)
100+
point_count_t PipelineExecutor::executeStream(point_count_t streamLimit,
101+
pdal::StringList allowedDims)
96102
{
97103
CountPointTable table(streamLimit);
104+
if (allowedDims.size())
105+
{
106+
pointTable().layout()->setAllowedDims(allowedDims);
107+
}
98108
m_manager.executeStream(table);
99109
m_executed = true;
100110
return table.count();
@@ -272,6 +282,7 @@ PyObject* buildNumpyDescriptor(PointLayoutPtr layout)
272282
{
273283
return layout->dimOffset(id1) < layout->dimOffset(id2);
274284
};
285+
275286
auto dims = layout->dims();
276287
std::sort(dims.begin(), dims.end(), sortByOffset);
277288

src/pdal/PyPipeline.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ class PDAL_DLL PipelineExecutor {
6060
PipelineExecutor(std::string const& json, std::vector<std::shared_ptr<Array>> arrays, int level);
6161
virtual ~PipelineExecutor() = default;
6262

63-
point_count_t execute();
64-
point_count_t executeStream(point_count_t streamLimit);
63+
point_count_t execute(pdal::StringList allowedDims);
64+
point_count_t executeStream(point_count_t streamLimit, pdal::StringList allowedDims);
6565

6666
const PointViewSet& views() const;
6767
std::string getPipeline() const;

src/pdal/StreamableExecutor.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,11 +187,17 @@ StreamableExecutor::StreamableExecutor(std::string const& json,
187187
std::vector<std::shared_ptr<Array>> arrays,
188188
int level,
189189
point_count_t chunkSize,
190-
int prefetch)
190+
int prefetch,
191+
pdal::StringList allowedDims)
191192
: PipelineExecutor(json, arrays, level)
192193
, m_table(chunkSize, prefetch)
193194
, m_exc(nullptr)
194195
{
196+
197+
if (allowedDims.size())
198+
{
199+
m_table.layout()->setAllowedDims(allowedDims);
200+
}
195201
m_thread.reset(new std::thread([this]()
196202
{
197203
try {

src/pdal/StreamableExecutor.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ class StreamableExecutor : public PipelineExecutor
8181
std::vector<std::shared_ptr<Array>> arrays,
8282
int level,
8383
point_count_t chunkSize,
84-
int prefetch);
84+
int prefetch,
85+
pdal::StringList allowedDim);
8586
~StreamableExecutor();
8687

8788
MetadataNode getMetadata() { return m_table.metadata(); }

src/pdal/libpdalpython.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -165,28 +165,27 @@ namespace pdal {
165165

166166
class Pipeline {
167167
public:
168-
point_count_t execute() {
168+
point_count_t execute(pdal::StringList allowedDims) {
169169
point_count_t response(0);
170170
{
171171
py::gil_scoped_release release;
172-
response = getExecutor()->execute();
172+
response = getExecutor()->execute(allowedDims);
173173
}
174174
return response;
175-
176175
}
177176

178-
point_count_t executeStream(point_count_t streamLimit) {
177+
point_count_t executeStream(point_count_t streamLimit, pdal::StringList allowedDims) {
179178
point_count_t response(0);
180179
{
181180
py::gil_scoped_release release;
182-
response = getExecutor()->executeStream(streamLimit);
181+
response = getExecutor()->executeStream(streamLimit, allowedDims);
183182
}
184183
return response;
185184
}
186185

187-
std::unique_ptr<PipelineIterator> iterator(int chunk_size, int prefetch) {
186+
std::unique_ptr<PipelineIterator> iterator(int chunk_size, int prefetch, pdal::StringList allowedDims) {
188187
return std::unique_ptr<PipelineIterator>(new PipelineIterator(
189-
getJson(), _inputs, _loglevel, chunk_size, prefetch
188+
getJson(), _inputs, _loglevel, chunk_size, prefetch, allowedDims
190189
));
191190
}
192191

@@ -308,9 +307,9 @@ namespace pdal {
308307

309308
py::class_<Pipeline>(m, "Pipeline")
310309
.def(py::init<>())
311-
.def("execute", &Pipeline::execute)
312-
.def("execute_streaming", &Pipeline::executeStream, "chunk_size"_a=10000)
313-
.def("iterator", &Pipeline::iterator, "chunk_size"_a=10000, "prefetch"_a=0)
310+
.def("execute", &Pipeline::execute, py::arg("allowed_dims") =py::list())
311+
.def("execute_streaming", &Pipeline::executeStream, "chunk_size"_a=10000, py::arg("allowed_dims") =py::list())
312+
.def("iterator", &Pipeline::iterator, "chunk_size"_a=10000, "prefetch"_a=0, py::arg("allowed_dims") =py::list())
314313
.def_property("inputs", nullptr, &Pipeline::setInputs)
315314
.def_property("loglevel", &Pipeline::getLoglevel, &Pipeline::setLogLevel)
316315
.def_property_readonly("log", &Pipeline::getLog)
@@ -333,10 +332,10 @@ namespace pdal {
333332
m.def("infer_writer_driver", &getWriterDriver);
334333

335334
if (pdal::Config::versionMajor() < 2)
336-
throw pybind11::import_error("PDAL version must be >= 2.6");
335+
throw pybind11::import_error("PDAL version must be >= 2.7");
337336

338-
if (pdal::Config::versionMajor() == 2 && pdal::Config::versionMinor() < 6)
339-
throw pybind11::import_error("PDAL version must be >= 2.6");
337+
if (pdal::Config::versionMajor() == 2 && pdal::Config::versionMinor() < 7)
338+
throw pybind11::import_error("PDAL version must be >= 2.7");
340339
};
341340

342341
}; // namespace pdal

test/test_pipeline.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ def test_execute_streaming(self, filename):
8282
count2 = r.execute_streaming(chunk_size=100)
8383
assert count == count2
8484

85+
86+
@pytest.mark.parametrize("filename", ["range.json", "range.py"])
87+
def test_subsetstreaming(self, filename):
88+
"""Can we fetch a subset of PDAL dimensions as a numpy array while streaming"""
89+
r = get_pipeline(filename)
90+
limit = ['X','Y','Z','Intensity']
91+
arrays = list(r.iterator(chunk_size=100,allowed_dims=limit))
92+
assert len(arrays) == 11
93+
assert len(arrays[0].dtype) == 4
94+
95+
8596
@pytest.mark.parametrize("filename", ["sort.json", "sort.py"])
8697
def test_execute_streaming_non_streamable(self, filename):
8798
r = get_pipeline(filename)
@@ -113,6 +124,18 @@ def test_array(self, filename):
113124
assert a[0][0] == 635619.85
114125
assert a[1064][2] == 456.92
115126

127+
@pytest.mark.parametrize("filename", ["sort.json", "sort.py"])
128+
def test_subsetarray(self, filename):
129+
"""Can we fetch a subset of PDAL dimensions as a numpy array"""
130+
r = get_pipeline(filename)
131+
limit = ['X','Y','Z']
132+
r.execute(allowed_dims=limit)
133+
arrays = r.arrays
134+
assert len(arrays) == 1
135+
assert len(arrays[0].dtype) == 3
136+
137+
138+
116139
@pytest.mark.parametrize("filename", ["sort.json", "sort.py"])
117140
def test_metadata(self, filename):
118141
"""Can we fetch PDAL metadata"""

0 commit comments

Comments
 (0)