diff --git a/doc/stages/filters.locatemax.rst b/doc/stages/filters.locate.rst similarity index 72% rename from doc/stages/filters.locatemax.rst rename to doc/stages/filters.locate.rst index 4e9d77ef4a..46569b5da8 100644 --- a/doc/stages/filters.locatemax.rst +++ b/doc/stages/filters.locate.rst @@ -1,7 +1,7 @@ -.. _filters.locatemax: +.. _filters.locate: =============================================================================== -filters.locatemax +filters.locate =============================================================================== The Locate Max filter searches the specified ``dimension`` for the maximum value @@ -20,8 +20,9 @@ This example returns the point at the highest elevation. "pipeline":[ "input.las", { - "type":"filters.locatemax", - "dimension":"Z" + "type":"filters.locate", + "dimension":"Z", + "minmax":"max" }, "output.las" ] @@ -31,4 +32,7 @@ Options ------- dimension - Name of the dimension in which to search for max value. + Name of the dimension in which to search for min/max value. + +minmax + Whether to return the minimum or maximum value in the dimension. diff --git a/filters/LocateMaxFilter.cpp b/filters/LocateFilter.cpp similarity index 73% rename from filters/LocateMaxFilter.cpp rename to filters/LocateFilter.cpp index da034b2f39..970aefa516 100644 --- a/filters/LocateMaxFilter.cpp +++ b/filters/LocateFilter.cpp @@ -32,51 +32,55 @@ * OF SUCH DAMAGE. ****************************************************************************/ -#include "LocateMaxFilter.hpp" +#include "LocateFilter.hpp" #include #include +#include namespace pdal { static PluginInfo const s_info = - PluginInfo("filters.locatemax", - "Return a single point with max value in the named dimension.", - "http://pdal.io/stages/filters.locatemax.html"); + PluginInfo("filters.locate", + "Return a single point with min/max value in the named dimension.", + "http://pdal.io/stages/filters.locate.html"); -CREATE_STATIC_PLUGIN(1, 0, LocateMaxFilter, Filter, s_info) +CREATE_STATIC_PLUGIN(1, 0, LocateFilter, Filter, s_info) -std::string LocateMaxFilter::getName() const +std::string LocateFilter::getName() const { return s_info.name; } -void LocateMaxFilter::addArgs(ProgramArgs& args) +void LocateFilter::addArgs(ProgramArgs& args) { args.add("dimension", "Dimension in which to locate max", m_dimName); + args.add("minmax", "Whether to search for the minimum or maximum value", + m_minmax, "max"); } -void LocateMaxFilter::prepared(PointTableRef table) +void LocateFilter::prepared(PointTableRef table) { PointLayoutPtr layout(table.layout()); m_dimId = layout->findDim(m_dimName); if (m_dimId == Dimension::Id::Unknown) { std::ostringstream oss; - oss << "Invalid dimension name in filters.locatemax 'dimension' " + oss << "Invalid dimension name in filters.locate 'dimension' " "option: '" << m_dimName << "'."; throw pdal_error(oss.str()); } } -PointViewSet LocateMaxFilter::run(PointViewPtr inView) +PointViewSet LocateFilter::run(PointViewPtr inView) { PointViewSet viewSet; if (!inView->size()) return viewSet; - PointId maxidx; + PointId minidx, maxidx; + double minval = std::numeric_limits::max(); double maxval = std::numeric_limits::lowest(); for (PointId idx = 0; idx < inView->size(); idx++) @@ -87,10 +91,19 @@ PointViewSet LocateMaxFilter::run(PointViewPtr inView) maxval = val; maxidx = idx; } + if (val < minval) + { + minval = val; + minidx = idx; + } } PointViewPtr outView = inView->makeNew(); - outView->appendPoint(*inView.get(), maxidx); + + if (Utils::iequals("min", m_minmax)) + outView->appendPoint(*inView.get(), minidx); + if (Utils::iequals("max", m_minmax)) + outView->appendPoint(*inView.get(), maxidx); viewSet.insert(outView); return viewSet; diff --git a/filters/LocateMaxFilter.hpp b/filters/LocateFilter.hpp similarity index 87% rename from filters/LocateMaxFilter.hpp rename to filters/LocateFilter.hpp index dd32714dd4..265ed48fba 100644 --- a/filters/LocateMaxFilter.hpp +++ b/filters/LocateFilter.hpp @@ -40,8 +40,8 @@ #include #include -extern "C" int32_t LocateMaxFilter_ExitFunc(); -extern "C" PF_ExitFunc LocateMaxFilter_InitPlugin(); +extern "C" int32_t LocateFilter_ExitFunc(); +extern "C" PF_ExitFunc LocateFilter_InitPlugin(); namespace pdal { @@ -49,10 +49,10 @@ namespace pdal class PointView; class ProgramArgs; -class PDAL_DLL LocateMaxFilter : public Filter +class PDAL_DLL LocateFilter : public Filter { public: - LocateMaxFilter() : Filter() + LocateFilter() : Filter() {} static void * create(); @@ -62,13 +62,14 @@ class PDAL_DLL LocateMaxFilter : public Filter private: std::string m_dimName; Dimension::Id m_dimId; + std::string m_minmax; virtual void addArgs(ProgramArgs& args); virtual void prepared(PointTableRef table); virtual PointViewSet run(PointViewPtr view); - LocateMaxFilter& operator=(const LocateMaxFilter&); // not implemented - LocateMaxFilter(const LocateMaxFilter&); // not implemented + LocateFilter& operator=(const LocateFilter&); // not implemented + LocateFilter(const LocateFilter&); // not implemented }; } // namespace pdal diff --git a/pdal/StageFactory.cpp b/pdal/StageFactory.cpp index cecc76beb9..1e96ea1508 100644 --- a/pdal/StageFactory.cpp +++ b/pdal/StageFactory.cpp @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include #include @@ -252,7 +252,7 @@ StageFactory::StageFactory(bool no_plugins) PluginManager::initializePlugin(HAGFilter_InitPlugin); PluginManager::initializePlugin(IQRFilter_InitPlugin); PluginManager::initializePlugin(KDistanceFilter_InitPlugin); - PluginManager::initializePlugin(LocateMaxFilter_InitPlugin); + PluginManager::initializePlugin(LocateFilter_InitPlugin); PluginManager::initializePlugin(LOFFilter_InitPlugin); PluginManager::initializePlugin(MADFilter_InitPlugin); PluginManager::initializePlugin(MergeFilter_InitPlugin); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 26cd16f046..e7ad970df2 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -87,7 +87,7 @@ PDAL_ADD_TEST(pdal_filters_decimation_test FILES PDAL_ADD_TEST(pdal_filters_divider_test FILES filters/DividerFilterTest.cpp) PDAL_ADD_TEST(pdal_filters_ferry_test FILES filters/FerryFilterTest.cpp) PDAL_ADD_TEST(pdal_filters_groupby_test FILES filters/GroupByFilterTest.cpp) -PDAL_ADD_TEST(pdal_filters_locatemax_test FILES filters/LocateMaxFilterTest.cpp) +PDAL_ADD_TEST(pdal_filters_locate_test FILES filters/LocateFilterTest.cpp) PDAL_ADD_TEST(pdal_filters_merge_test FILES filters/MergeTest.cpp) PDAL_ADD_TEST(pdal_filters_additional_merge_test FILES filters/AdditionalMergeTest.cpp) diff --git a/test/unit/filters/LocateMaxFilterTest.cpp b/test/unit/filters/LocateFilterTest.cpp similarity index 77% rename from test/unit/filters/LocateMaxFilterTest.cpp rename to test/unit/filters/LocateFilterTest.cpp index 9bfbf257cd..3f2a541116 100644 --- a/test/unit/filters/LocateMaxFilterTest.cpp +++ b/test/unit/filters/LocateFilterTest.cpp @@ -35,14 +35,14 @@ #include #include -#include +#include #include #include "Support.hpp" using namespace pdal; -TEST(LocateMaxTest, basic) +TEST(LocateTest, locate_max) { PointTable table; @@ -53,8 +53,9 @@ TEST(LocateMaxTest, basic) Options fo; fo.add("dimension", "Z"); + fo.add("minmax", "max"); - LocateMaxFilter f; + LocateFilter f; f.setInput(r); f.setOptions(fo); f.prepare(table); @@ -66,3 +67,29 @@ TEST(LocateMaxTest, basic) EXPECT_NEAR(586.38, view->getFieldAs(Dimension::Id::Z, 0), 0.0001); } + +TEST(LocateTest, locate_min) +{ + PointTable table; + + Options ro; + ro.add("filename", Support::datapath("las/1.2-with-color.las")); + LasReader r; + r.setOptions(ro); + + Options fo; + fo.add("dimension", "Z"); + fo.add("minmax", "min"); + + LocateFilter f; + f.setInput(r); + f.setOptions(fo); + f.prepare(table); + PointViewSet viewSet = f.execute(table); + EXPECT_EQ(1u, viewSet.size()); + + PointViewPtr view = *viewSet.begin(); + EXPECT_EQ(1u, view->size()); + + EXPECT_NEAR(406.59, view->getFieldAs(Dimension::Id::Z, 0), 0.0001); +}