3939#include < dlfcn.h>
4040#endif
4141
42- #include < Python.h>
43-
44- #include < pdal/Stage.hpp>
45- #include < pdal/pdal_features.hpp>
46-
4742namespace pdal
4843{
4944namespace python
5045{
5146
5247
53- void readPipeline (PipelineExecutor* executor, std::string json)
48+ void CountPointTable::reset ()
49+ {
50+ for (PointId idx = 0 ; idx < numPoints (); idx++)
51+ if (!skip (idx))
52+ m_count++;
53+ FixedPointTable::reset ();
54+ }
55+
56+
57+ PipelineExecutor::PipelineExecutor (
58+ std::string const & json, std::vector<std::shared_ptr<Array>> arrays, int level)
59+ {
60+ if (level < 0 || level > 8 )
61+ throw pdal_error (" log level must be between 0 and 8!" );
62+
63+ LogPtr log (Log::makeLog (" pypipeline" , &m_logStream));
64+ log->setLevel (static_cast <pdal::LogLevel>(level));
65+ m_manager.setLog (log);
66+
67+ std::stringstream strm;
68+ strm << json;
69+ m_manager.readPipeline (strm);
70+
71+ addArrayReaders (arrays);
72+ }
73+
74+
75+ point_count_t PipelineExecutor::execute ()
76+ {
77+ point_count_t count = m_manager.execute ();
78+ m_executed = true ;
79+ return count;
80+ }
81+
82+
83+ point_count_t PipelineExecutor::executeStream (point_count_t streamLimit)
84+ {
85+ CountPointTable table (streamLimit);
86+ m_manager.executeStream (table);
87+ m_executed = true ;
88+ return table.count ();
89+ }
90+
91+ const PointViewSet& PipelineExecutor::views () const
92+ {
93+ if (!m_executed)
94+ throw pdal_error (" Pipeline has not been executed!" );
95+
96+ return m_manager.views ();
97+ }
98+
99+
100+ std::string PipelineExecutor::getPipeline () const
54101{
55- std::stringstream strm (json);
56- executor->getManager ().readPipeline (strm);
102+ if (!m_executed)
103+ throw pdal_error (" Pipeline has not been executed!" );
104+
105+ std::stringstream strm;
106+ pdal::PipelineWriter::writePipeline (m_manager.getStage (), strm);
107+ return strm.str ();
57108}
58109
59110
60- void addArrayReaders (PipelineExecutor* executor, std::vector<std::shared_ptr<Array>> arrays)
111+ std::string PipelineExecutor::getMetadata () const
112+ {
113+ if (!m_executed)
114+ throw pdal_error (" Pipeline has not been executed!" );
115+
116+ std::stringstream strm;
117+ MetadataNode root = m_manager.getMetadata ().clone (" metadata" );
118+ pdal::Utils::toJSON (root, strm);
119+ return strm.str ();
120+ }
121+
122+
123+ std::string PipelineExecutor::getSchema () const
124+ {
125+ if (!m_executed)
126+ throw pdal_error (" Pipeline has not been executed!" );
127+
128+ std::stringstream strm;
129+ MetadataNode root = pointTable ().layout ()->toMetadata ().clone (" schema" );
130+ pdal::Utils::toJSON (root, strm);
131+ return strm.str ();
132+ }
133+
134+
135+ void PipelineExecutor::addArrayReaders (std::vector<std::shared_ptr<Array>> arrays)
61136{
62137 // Make the symbols in pdal_base global so that they're accessible
63138 // to PDAL plugins. Python dlopen's this extension with RTLD_LOCAL,
@@ -72,8 +147,7 @@ void addArrayReaders(PipelineExecutor* executor, std::vector<std::shared_ptr<Arr
72147 if (arrays.empty ())
73148 return ;
74149
75- PipelineManager& manager = executor->getManager ();
76- std::vector<Stage *> roots = manager.roots ();
150+ std::vector<Stage *> roots = m_manager.roots ();
77151 if (roots.size () != 1 )
78152 throw pdal_error (" Filter pipeline must contain a single root stage." );
79153
@@ -88,7 +162,7 @@ void addArrayReaders(PipelineExecutor* executor, std::vector<std::shared_ptr<Arr
88162 MemoryViewReader::Order::ColumnMajor);
89163 options.add (" shape" , MemoryViewReader::Shape (array->shape ()));
90164
91- Stage& s = manager .makeReader (" " , " readers.memoryview" , options);
165+ Stage& s = m_manager .makeReader (" " , " readers.memoryview" , options);
92166 MemoryViewReader& r = dynamic_cast <MemoryViewReader &>(s);
93167 for (auto f : array->fields ())
94168 r.pushField (f);
@@ -108,11 +182,11 @@ void addArrayReaders(PipelineExecutor* executor, std::vector<std::shared_ptr<Arr
108182 roots[0 ]->setInput (r);
109183 }
110184
111- manager .validateStageOptions ();
185+ m_manager .validateStageOptions ();
112186}
113187
114188
115- inline PyObject* buildNumpyDescription (PointViewPtr view )
189+ PyObject* buildNumpyDescriptor (PointLayoutPtr layout )
116190{
117191 // Build up a numpy dtype dictionary
118192 //
@@ -123,31 +197,42 @@ inline PyObject* buildNumpyDescription(PointViewPtr view)
123197 // 'Classification', 'ScanAngleRank', 'UserData',
124198 // 'PointSourceId', 'GpsTime', 'Red', 'Green', 'Blue']}
125199 //
126- Dimension::IdList dims = view->dims ();
200+
201+ // Ensure that the dimensions are sorted by offset
202+ // Is there a better way? Can they be sorted by offset already?
203+ auto sortByOffset = [layout](Dimension::Id id1, Dimension::Id id2) -> bool
204+ {
205+ return layout->dimOffset (id1) < layout->dimOffset (id2);
206+ };
207+ auto dims = layout->dims ();
208+ std::sort (dims.begin (), dims.end (), sortByOffset);
209+
127210 PyObject* names = PyList_New (dims.size ());
128211 PyObject* formats = PyList_New (dims.size ());
129212 for (size_t i = 0 ; i < dims.size (); ++i)
130213 {
131214 Dimension::Id id = dims[i];
132- std::string name = view->dimName (id);
133- npy_intp stride = view->dimSize (id);
134-
135- std::string kind;
136- Dimension::BaseType b = Dimension::base (view->dimType (id));
137- if (b == Dimension::BaseType::Unsigned)
138- kind = " u" ;
139- else if (b == Dimension::BaseType::Signed)
140- kind = " i" ;
141- else if (b == Dimension::BaseType::Floating)
142- kind = " f" ;
143- else
144- throw pdal_error (" Unable to map kind '" + kind +
145- " ' to PDAL dimension type" );
146-
147- std::stringstream oss;
148- oss << kind << stride;
215+ auto name = layout->dimName (id);
149216 PyList_SetItem (names, i, PyUnicode_FromString (name.c_str ()));
150- PyList_SetItem (formats, i, PyUnicode_FromString (oss.str ().c_str ()));
217+
218+ std::stringstream format;
219+ switch (Dimension::base (layout->dimType (id)))
220+ {
221+ case Dimension::BaseType::Unsigned:
222+ format << ' u' ;
223+ break ;
224+ case Dimension::BaseType::Signed:
225+ format << ' i' ;
226+ break ;
227+ case Dimension::BaseType::Floating:
228+ format << ' f' ;
229+ break ;
230+ default :
231+ throw pdal_error (" Unable to map dimension '" + name + " ' to Numpy" );
232+ }
233+ format << layout->dimSize (id);
234+ PyList_SetItem (formats, i, PyUnicode_FromString (format.str ().c_str ()));
235+
151236 }
152237 PyObject* dtype_dict = PyDict_New ();
153238 PyDict_SetItemString (dtype_dict, " names" , names);
@@ -161,7 +246,7 @@ PyArrayObject* viewToNumpyArray(PointViewPtr view)
161246 if (_import_array () < 0 )
162247 throw pdal_error (" Could not import numpy.core.multiarray." );
163248
164- PyObject* dtype_dict = buildNumpyDescription (view);
249+ PyObject* dtype_dict = buildNumpyDescriptor (view-> layout () );
165250 PyArray_Descr *dtype = nullptr ;
166251 if (PyArray_DescrConverter (dtype_dict, &dtype) == NPY_FAIL)
167252 throw pdal_error (" Unable to build numpy dtype" );
0 commit comments