Skip to content

Commit

Permalink
Merge pull request #743 from PDAL/add-passthrough-filter
Browse files Browse the repository at this point in the history
Add passthrough filter
  • Loading branch information
hobu committed Feb 5, 2015
2 parents a8240e4 + 6f8d6b2 commit 2fade5c
Show file tree
Hide file tree
Showing 14 changed files with 661 additions and 0 deletions.
58 changes: 58 additions & 0 deletions doc/stages/filters.range.rst
@@ -0,0 +1,58 @@
.. _filters.range:

filters.range
======================

The range filter applies rudimentary filtering to the input point cloud
based on a set of criteria on the given dimensions.

Example
-------

This example passes through all points whose Z value is in the range [0,100]
and whose classification equals 2 (corresponding to ground in LAS).

.. code-block:: xml
<?xml version="1.0" encoding="utf-8"?>
<Pipeline version="1.0">
<Writer type="writers.las">
<Option name="filename">
filtered.las
</Option>
<Filter type="filters.range">
<Option name="dimension">
Z
<Options>
<Option name="min">0</Option>
<Option name="max">100</Option>
</Options>
</Option>
<Option name="dimension">
Classification
<Options>
<Option name="equals">2</Option>
</Options>
</Option>
<Reader type="readers.las">
<Option name="filename">
input.las
</Option>
</Reader>
</Filter>
</Writer>
</Pipeline>
Options
-------

dimension
A dimension Option with an Options block containing the range criteria.

* min: The minimum allowable value (inclusive) to pass through to the filtered point cloud.

* max: The maximum allowable value (inclusive) to pass through to the filtered point cloud.

* equals: The exact value to pass through to the filtered point cloud (i.e., min = max).

1 change: 1 addition & 0 deletions doc/stages/index.rst
Expand Up @@ -53,6 +53,7 @@ Filters
filters.pclblock
filters.predicate
filters.programmable
filters.range
filters.reprojection
filters.sort
filters.transformation
Expand Down
1 change: 1 addition & 0 deletions filters/CMakeLists.txt
Expand Up @@ -5,6 +5,7 @@ add_subdirectory(decimation)
add_subdirectory(ferry)
add_subdirectory(merge)
add_subdirectory(mortonorder)
add_subdirectory(range)
add_subdirectory(reprojection)
add_subdirectory(sort)
add_subdirectory(splitter)
Expand Down
5 changes: 5 additions & 0 deletions filters/range/CMakeLists.txt
@@ -0,0 +1,5 @@
set(srcs RangeFilter.cpp)
set(incs RangeFilter.hpp)

PDAL_ADD_DRIVER(filter range "${srcs}" "${incs}" objects)
set(PDAL_TARGET_OBJECTS ${PDAL_TARGET_OBJECTS} ${objects} PARENT_SCOPE)
112 changes: 112 additions & 0 deletions filters/range/RangeFilter.cpp
@@ -0,0 +1,112 @@
/******************************************************************************
* Copyright (c) 2015, Bradley J Chambers (brad.chambers@gmail.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#include "RangeFilter.hpp"

#include <cmath>
#include <limits>
#include <map>
#include <string>
#include <utility>
#include <vector>

namespace pdal
{


void RangeFilter::processOptions(const Options& options)
{
std::vector<Option> dimensions = options.getOptions("dimension");
if (dimensions.size() == 0)
throw pdal_error("No dimensions given");

for (auto const& d : dimensions)
{
std::string name = d.getValue<std::string>();
boost::optional<Options const&> dimensionOptions = d.getOptions();
if (!dimensionOptions)
throw pdal_error("No dimension options");

double val = dimensionOptions->getValueOrDefault<double>("equals", NAN);
double min = dimensionOptions->getValueOrDefault<double>("min", -std::numeric_limits<double>::max());
double max = dimensionOptions->getValueOrDefault<double>("max", std::numeric_limits<double>::max());

if (!std::isnan(val))
min = max = val;

Range range;
range.min = min;
range.max = max;

m_name_map.insert(std::make_pair(name, range));
}
}

void RangeFilter::ready(PointContext ctx)
{
for (auto const& d : m_name_map)
m_dimensions_map.insert(std::make_pair(ctx.findDim(d.first), d.second));
}

PointBufferSet RangeFilter::run(PointBufferPtr buf)
{
PointBufferSet pbSet;
if (!buf->size())
return pbSet;

PointBufferPtr outbuf = buf->makeNew();

for (PointId i = 0; i < buf->size(); ++i)
{
bool keep_point = true;
for (auto const& d : m_dimensions_map)
{
double v = buf->getFieldAs<double>(d.first, i);
if (v < d.second.min || v > d.second.max)
{
keep_point = false;
break;
}
}
if (keep_point)
outbuf->appendPoint(*buf, i);
}

pbSet.insert(outbuf);

return pbSet;
}

} // pdal

81 changes: 81 additions & 0 deletions filters/range/RangeFilter.hpp
@@ -0,0 +1,81 @@
/******************************************************************************
* Copyright (c) 2015, Bradley J Chambers (brad.chambers@gmail.com)
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following
* conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided
* with the distribution.
* * Neither the name of Hobu, Inc. or Flaxen Geo Consulting nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
****************************************************************************/

#pragma once

#include <pdal/Filter.hpp>

#include <memory>
#include <map>
#include <string>

namespace pdal
{

class Options;
class PointBuffer;
class PointContext;

typedef std::shared_ptr<PointBuffer> PointBufferPtr;
typedef PointContext PointContextRef;

struct Range
{
double min;
double max;
};

#define RANGEDOCS "Pass only points given a dimension/range."
class PDAL_DLL RangeFilter : public pdal::Filter
{
public:
SET_STAGE_NAME("filters.range", RANGEDOCS)
SET_STAGE_LINK("http://pdal.io/stages/filters.range.html")

RangeFilter() : Filter()
{}

private:
std::map<std::string, Range> m_name_map;
std::map<Dimension::Id::Enum, Range> m_dimensions_map;

virtual void processOptions(const Options&options);
virtual void ready(PointContextRef ctx);
virtual PointBufferSet run(PointBufferPtr buf);

RangeFilter& operator=(const RangeFilter&); // not implemented
RangeFilter(const RangeFilter&); // not implemented
};

} // namespace pdal
1 change: 1 addition & 0 deletions include/pdal/Filters.hpp
Expand Up @@ -41,6 +41,7 @@
#include <ferry/FerryFilter.hpp>
#include <merge/MergeFilter.hpp>
#include <mortonorder/MortonOrderFilter.hpp>
#include <range/RangeFilter.hpp>
#include <reprojection/ReprojectionFilter.hpp>
#include <sort/SortFilter.hpp>
#include <splitter/SplitterFilter.hpp>
Expand Down
2 changes: 2 additions & 0 deletions src/StageFactory.cpp
Expand Up @@ -79,6 +79,7 @@ MAKE_FILTER_CREATOR(Decimation, pdal::DecimationFilter)
MAKE_FILTER_CREATOR(Ferry, pdal::FerryFilter)
MAKE_FILTER_CREATOR(Merge, pdal::MergeFilter)
MAKE_FILTER_CREATOR(MortonOrder, pdal::MortonOrderFilter)
MAKE_FILTER_CREATOR(Range, pdal::RangeFilter)
MAKE_FILTER_CREATOR(Reprojection, pdal::ReprojectionFilter)
MAKE_FILTER_CREATOR(Sort, pdal::SortFilter)
MAKE_FILTER_CREATOR(Splitter, pdal::SplitterFilter)
Expand Down Expand Up @@ -323,6 +324,7 @@ void StageFactory::registerKnownFilters()
REGISTER_FILTER(Ferry, pdal::FerryFilter);
REGISTER_FILTER(Merge, pdal::MergeFilter);
REGISTER_FILTER(MortonOrder, pdal::MortonOrderFilter);
REGISTER_FILTER(Range, pdal::RangeFilter);
REGISTER_FILTER(Reprojection, pdal::ReprojectionFilter);
REGISTER_FILTER(Sort, pdal::SortFilter);
REGISTER_FILTER(Splitter, pdal::SplitterFilter);
Expand Down
22 changes: 22 additions & 0 deletions test/data/filters/range_classification.xml.in
@@ -0,0 +1,22 @@
<?xml version="2.0" encoding="utf-8"?>
<Pipeline version="1.0">
<Writer type="writers.las">
<Option name="filename">
@CMAKE_SOURCE_DIR@/test/temp/only_class_equals_2.las
</Option>
<Filter type="filters.range">
<Option name="dimension">
Classification
<Options>
<Option name="equals">2</Option>
</Options>
</Option>
<Reader type="readers.las">
<Option name="filename">
@CMAKE_SOURCE_DIR@/test/data/las/1.2-with-color.las
</Option>
</Reader>
</Filter>
</Writer>
</Pipeline>

23 changes: 23 additions & 0 deletions test/data/filters/range_z.xml.in
@@ -0,0 +1,23 @@
<?xml version="2.0" encoding="utf-8"?>
<Pipeline version="1.0">
<Writer type="writers.las">
<Option name="filename">
@CMAKE_SOURCE_DIR@/test/temp/only_z_400-500.las
</Option>
<Filter type="filters.range">
<Option name="dimension">
Z
<Options>
<Option name="min">400</Option>
<Option name="max">500</Option>
</Options>
</Option>
<Reader type="readers.las">
<Option name="filename">
@CMAKE_SOURCE_DIR@/test/data/las/1.2-with-color.las
</Option>
</Reader>
</Filter>
</Writer>
</Pipeline>

29 changes: 29 additions & 0 deletions test/data/filters/range_z_classification.xml.in
@@ -0,0 +1,29 @@
<?xml version="2.0" encoding="utf-8"?>
<Pipeline version="1.0">
<Writer type="writers.las">
<Option name="filename">
@CMAKE_SOURCE_DIR@/test/temp/only_z_400-500_class_equals_2.las
</Option>
<Filter type="filters.range">
<Option name="dimension">
Z
<Options>
<Option name="min">400</Option>
<Option name="max">500</Option>
</Options>
</Option>
<Option name="dimension">
Classification
<Options>
<Option name="equals">2</Option>
</Options>
</Option>
<Reader type="readers.las">
<Option name="filename">
@CMAKE_SOURCE_DIR@/test/data/las/1.2-with-color.las
</Option>
</Reader>
</Filter>
</Writer>
</Pipeline>

2 changes: 2 additions & 0 deletions test/unit/CMakeLists.txt
Expand Up @@ -34,6 +34,7 @@ include_directories(
${PROJECT_SOURCE_DIR}/filters/ferry
${PROJECT_SOURCE_DIR}/filters/mortonorder
${PROJECT_SOURCE_DIR}/filters/reprojection
${PROJECT_SOURCE_DIR}/filters/range
${PROJECT_SOURCE_DIR}/filters/sort
${PROJECT_SOURCE_DIR}/filters/splitter
${PROJECT_SOURCE_DIR}/filters/stats
Expand Down Expand Up @@ -90,6 +91,7 @@ PDAL_ADD_TEST(pdal_filters_decimation_test FILES filters/DecimationFilterTest.cp
PDAL_ADD_TEST(pdal_filters_ferry_test FILES filters/FerryFilterTest.cpp)
PDAL_ADD_TEST(pdal_filters_merge_test FILES filters/MergeTest.cpp)
PDAL_ADD_TEST(pdal_filters_reprojection_test FILES filters/ReprojectionFilterTest.cpp)
PDAL_ADD_TEST(pdal_filters_range_test FILES filters/RangeFilterTest.cpp)
PDAL_ADD_TEST(pdal_filters_sort_test FILES filters/SortFilterTest.cpp)
PDAL_ADD_TEST(pdal_filters_splitter_test FILES filters/SplitterTest.cpp)
PDAL_ADD_TEST(pdal_filters_stats_test FILES filters/StatsFilterTest.cpp)
Expand Down

0 comments on commit 2fade5c

Please sign in to comment.