Skip to content

Commit

Permalink
Merge pull request #447 from gadomski/programmable-add-dimension
Browse files Browse the repository at this point in the history
Programmable filter can add dimensions to context
  • Loading branch information
hobu committed Sep 12, 2014
2 parents cd36bf8 + c9cb95e commit 943cbbc
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 0 deletions.
4 changes: 4 additions & 0 deletions doc/stages/filters.programmable.rst
Expand Up @@ -21,6 +21,8 @@ This example scales the Z value by a factor of ten (of course, you could also us
Note that the function always returns `True`. If the function returned `False`, an error would be thrown and the translation shut down.

If you want to write a dimension that might not be available, use can use one or more `add_dimension` options.

To filter points based on a `Python`_ function, use the :ref:`filters.predicate` filter.

Example
Expand Down Expand Up @@ -75,6 +77,8 @@ function
source
The literal `Python`_ code to execute, when the script option is not being used.

add_dimension
The name of a dimension to add to the pipeline that does not already exist.

.. _Python: http://python.org/
.. _NumPy: http://www.numpy.org/
2 changes: 2 additions & 0 deletions include/pdal/filters/Programmable.hpp
Expand Up @@ -69,8 +69,10 @@ class PDAL_DLL Programmable : public Filter
std::string m_source;
std::string m_module;
std::string m_function;
Dimension::IdList m_addDimensions;

virtual void processOptions(const Options& options);
virtual void addDimensions(PointContext ctx);
virtual void ready(PointContext ctx);
virtual void filter(PointBuffer& buf);
virtual void done(PointContext ctx);
Expand Down
15 changes: 15 additions & 0 deletions src/filters/Programmable.cpp
Expand Up @@ -63,6 +63,21 @@ void Programmable::processOptions(const Options& options)
options.getValueOrThrow<std::string>("filename"));
m_module = options.getValueOrThrow<std::string>("module");
m_function = options.getValueOrThrow<std::string>("function");

auto addDims = options.getOptions("add_dimension");
for (auto it = addDims.cbegin(); it != addDims.cend(); ++it)
{
m_addDimensions.push_back(Dimension::id(it->getValue<std::string>()));
}
}


void Programmable::addDimensions(PointContext ctx)
{
for (auto it = m_addDimensions.cbegin(); it != m_addDimensions.cend(); ++it)
{
ctx.registerDim(*it);
}
}


Expand Down
46 changes: 46 additions & 0 deletions test/unit/plang/ProgrammableFilterTest.cpp
Expand Up @@ -130,6 +130,52 @@ BOOST_AUTO_TEST_CASE(pipeline)
}
}


BOOST_AUTO_TEST_CASE(add_dimension)
{
Bounds<double> bounds(0.0, 0.0, 0.0, 1.0, 1.0, 1.0);

Options ops;
ops.add("bounds", bounds);
ops.add("num_points", 10);
ops.add("mode", "ramp");

drivers::faux::Reader reader(ops);

Option source("source", "import numpy\n"
"def myfunc(ins,outs):\n"
" outs['Intensity'] = np.zeros(ins['X'].size, dtype=numpy.uint16) + 1\n"
" outs['PointSourceId'] = np.zeros(ins['X'].size, dtype=numpy.uint16) + 2\n"
" return True\n"
);
Option module("module", "MyModule");
Option function("function", "myfunc");
Option intensity("add_dimension", "Intensity");
Option scanDirection("add_dimension", "PointSourceId");
Options opts;
opts.add(source);
opts.add(module);
opts.add(function);
opts.add(intensity);
opts.add(scanDirection);

filters::Programmable filter(opts);
filter.setInput(&reader);

PointContext ctx;
filter.prepare(ctx);
PointBufferSet pbSet = filter.execute(ctx);
BOOST_CHECK_EQUAL(pbSet.size(), 1);
PointBufferPtr buf = *pbSet.begin();

for (unsigned int i = 0; i < buf->size(); ++i)
{
BOOST_CHECK_EQUAL(buf->getFieldAs<uint16_t>(Dimension::Id::Intensity, i), 1);
BOOST_CHECK_EQUAL(buf->getFieldAs<uint16_t>(Dimension::Id::PointSourceId, i), 2);
}
}


BOOST_AUTO_TEST_SUITE_END()

#endif // PDAL_HAVE_PYTHON

0 comments on commit 943cbbc

Please sign in to comment.