diff --git a/doc/stages/filters.groupby.rst b/doc/stages/filters.groupby.rst new file mode 100644 index 0000000000..c13b1f810e --- /dev/null +++ b/doc/stages/filters.groupby.rst @@ -0,0 +1,29 @@ +.. _filters.groupby: + +filters.groupby +=============================================================================== + +The groupby filter takes a single PointView as its input and creates a PointView +for each category in the named ``dimension`` as its output. + +Example +------- + +.. code-block:: json + + { + "pipeline":[ + "input.las", + { + "type":"filters.groupby", + "dimension":"Classification" + }, + "output_#.las" + ] + } + +Options +------- + +dimension + The dimension containing data to be grouped. diff --git a/filters/GroupByFilter.cpp b/filters/GroupByFilter.cpp new file mode 100644 index 0000000000..463b05363a --- /dev/null +++ b/filters/GroupByFilter.cpp @@ -0,0 +1,98 @@ +/****************************************************************************** + * Copyright (c) 2016, 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 "GroupByFilter.hpp" + +#include +#include + +namespace pdal +{ + +static PluginInfo const s_info = + PluginInfo("filters.groupby", "Split data categorically by dimension.", + "http://pdal.io/stages/filters.groupby.html"); + +CREATE_STATIC_PLUGIN(1, 0, GroupByFilter, Filter, s_info) + +GroupByFilter::GroupByFilter() : m_viewMap() +{} + +std::string GroupByFilter::getName() const +{ + return s_info.name; +} + +void GroupByFilter::addArgs(ProgramArgs& args) +{ + args.add("dimension", "Dimension containing data to be grouped", m_dimName); +} + +void GroupByFilter::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.groupby 'dimension' " + "option: '" << m_dimName << "'."; + throw pdal_error(oss.str()); + } + // also need to check that we have a dimension with discrete values +} + +PointViewSet GroupByFilter::run(PointViewPtr inView) +{ + PointViewSet viewSet; + if (!inView->size()) + return viewSet; + + for (PointId idx = 0; idx < inView->size(); idx++) + { + uint64_t val = inView->getFieldAs(m_dimId, idx); + PointViewPtr& outView = m_viewMap[val]; + if (!outView) + outView = inView->makeNew(); + outView->appendPoint(*inView.get(), idx); + } + + // Pull the buffers out of the map and stick them in the standard + // output set. + for (auto bi = m_viewMap.begin(); bi != m_viewMap.end(); ++bi) + viewSet.insert(bi->second); + return viewSet; +} + +} // pdal diff --git a/filters/GroupByFilter.hpp b/filters/GroupByFilter.hpp new file mode 100644 index 0000000000..d381b8422d --- /dev/null +++ b/filters/GroupByFilter.hpp @@ -0,0 +1,74 @@ +/****************************************************************************** + * Copyright (c) 2016, 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 +#include + +#include +#include + +extern "C" int32_t GroupByFilter_ExitFunc(); +extern "C" PF_ExitFunc GroupByFilter_InitPlugin(); + +namespace pdal +{ + +class PointView; +class ProgramArgs; + +class PDAL_DLL GroupByFilter : public Filter +{ +public: + GroupByFilter(); + + static void * create(); + static int32_t destroy(void *); + std::string getName() const; + +private: + std::map m_viewMap; + std::string m_dimName; + Dimension::Id m_dimId; + + virtual void addArgs(ProgramArgs& args); + virtual void prepared(PointTableRef table); + virtual PointViewSet run(PointViewPtr view); + + GroupByFilter& operator=(const GroupByFilter&); // not implemented + GroupByFilter(const GroupByFilter&); // not implemented +}; + +} // namespace pdal diff --git a/pdal/StageFactory.cpp b/pdal/StageFactory.cpp index debf2f1387..c696266c65 100644 --- a/pdal/StageFactory.cpp +++ b/pdal/StageFactory.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -244,6 +245,7 @@ StageFactory::StageFactory(bool no_plugins) PluginManager::initializePlugin(EigenvaluesFilter_InitPlugin); PluginManager::initializePlugin(EstimateRankFilter_InitPlugin); PluginManager::initializePlugin(FerryFilter_InitPlugin); + PluginManager::initializePlugin(GroupByFilter_InitPlugin); PluginManager::initializePlugin(HAGFilter_InitPlugin); PluginManager::initializePlugin(IQRFilter_InitPlugin); PluginManager::initializePlugin(KDistanceFilter_InitPlugin); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index ef38297dc1..0f86dee684 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -86,6 +86,7 @@ PDAL_ADD_TEST(pdal_filters_decimation_test FILES filters/DecimationFilterTest.cpp) 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_merge_test FILES filters/MergeTest.cpp) PDAL_ADD_TEST(pdal_filters_additional_merge_test FILES filters/AdditionalMergeTest.cpp) diff --git a/test/unit/filters/GroupByFilterTest.cpp b/test/unit/filters/GroupByFilterTest.cpp new file mode 100644 index 0000000000..ed57fdccdc --- /dev/null +++ b/test/unit/filters/GroupByFilterTest.cpp @@ -0,0 +1,70 @@ +/****************************************************************************** +* Copyright (c) 2016, 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 + +#include +#include +#include "Support.hpp" + +using namespace pdal; + +TEST(GroupByTest, basic_test) +{ + Options ro; + ro.add("filename", Support::datapath("las/1.2-with-color.las")); + LasReader r; + r.setOptions(ro); + + Options fo; + fo.add("dimension", "Classification"); + + GroupByFilter s; + s.setOptions(fo); + s.setInput(r); + + PointTable table; + PointViewPtr view(new PointView(table)); + s.prepare(table); + PointViewSet viewSet = s.execute(table); + + EXPECT_EQ(2u, viewSet.size()); + + std::vector views; + for (auto it = viewSet.begin(); it != viewSet.end(); ++it) + views.push_back(*it); + + EXPECT_EQ(789u, views[0]->size()); + EXPECT_EQ(276u, views[1]->size()); +}