diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cab7b461b..05bada919e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,10 @@ option(BUILD_PLUGIN_SQLITE "Choose if SQLite database support should be built" F add_feature_info("SQLite plugin" BUILD_PLUGIN_SQLITE "read/write SQLite objects") +option(BUILD_PLUGIN_RIALTO "Choose if Rialto (file or database) support should be built" FALSE) +add_feature_info("Rialto plugin" BUILD_PLUGIN_RIALTO + "read/write Rialto files and databases") + option(BUILD_PLUGIN_RIVLIB "Choose if RiVLib support should be built" FALSE) add_feature_info("RiVLib plugin" BUILD_PLUGIN_RIVLIB "read data in the RXP format") @@ -165,11 +169,12 @@ include(CMakeDependentOption) cmake_dependent_option(BUILD_PGPOINTCLOUD_TESTS "Choose if PostgreSQL PointCloud tests should be built" ON "BUILD_PLUGIN_PGPOINTCLOUD; WITH_TESTS" OFF) cmake_dependent_option(BUILD_SQLITE_TESTS "Choose if SQLite tests should be built" ON "BUILD_PLUGIN_SQLITE; WITH_TESTS" OFF) +cmake_dependent_option(BUILD_RIALTO_TESTS "Choose if Rialto tests should be built" ON "BUILD_PLUGIN_RIALTO; WITH_TESTS" OFF) cmake_dependent_option(BUILD_OCI_TESTS "Choose if OCI tests should be built" ON "BUILD_PLUGIN_OCI; WITH_TESTS" OFF) cmake_dependent_option(BUILD_RIVLIB_TESTS "Choose if RiVLib tests should be built" ON "BUILD_PLUGIN_RIVLIB; WITH_TESTS" OFF) cmake_dependent_option(BUILD_PIPELINE_TESTS "Choose if pipeline tests should be built" OFF "WITH_APPS; WITH_TESTS" OFF) -if(BUILD_PLUGIN_PGPOINTCLOUD OR BUILD_PLUGIN_OCI OR BUILD_PLUGIN_SQLITE) +if(BUILD_PLUGIN_PGPOINTCLOUD OR BUILD_PLUGIN_OCI OR BUILD_PLUGIN_SQLITE OR BUILD_PLUGIN_RIALTO) include(${PDAL_CMAKE_DIR}/libxml2.cmake) endif() if(BUILD_PLUGIN_PYTHON) diff --git a/io/CMakeLists.txt b/io/CMakeLists.txt index d325d07168..fb5c1b0050 100644 --- a/io/CMakeLists.txt +++ b/io/CMakeLists.txt @@ -4,7 +4,6 @@ add_subdirectory(las) add_subdirectory(null) add_subdirectory(optech) add_subdirectory(qfit) -add_subdirectory(rialto) add_subdirectory(sbet) add_subdirectory(text) add_subdirectory(terrasolid) diff --git a/io/rialto/CMakeLists.txt b/io/rialto/CMakeLists.txt deleted file mode 100644 index b8ec9f2919..0000000000 --- a/io/rialto/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -set(srcs - RialtoWriter.cpp -) - -set(incs - RialtoWriter.hpp -) - -PDAL_ADD_DRIVER(writer rialto "${srcs}" "${incs}" objects) -set(PDAL_TARGET_OBJECTS ${PDAL_TARGET_OBJECTS} ${objects} PARENT_SCOPE) diff --git a/io/rialto/RialtoWriter.cpp b/io/rialto/RialtoWriter.cpp deleted file mode 100644 index 6cce9702bb..0000000000 --- a/io/rialto/RialtoWriter.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/****************************************************************************** -* Copyright (c) 2014-2015, RadiantBlue Technologies, Inc. -* -* 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 "RialtoWriter.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace pdal -{ - -static PluginInfo const s_info = PluginInfo( - "writers.rialto", - "Rialto Writer", - "http://pdal.io/stages/writers.rialto.html" ); - -CREATE_STATIC_PLUGIN(1, 0, RialtoWriter, Writer, s_info) - -namespace -{ - static uint32_t getMetadataU32(const MetadataNode& parent, const std::string& name) - { - const MetadataNode node = parent.findChild(name); - if (!node.valid()) { - std::ostringstream oss; - oss << "RialtoWriter: required metadata item not found: " << name; - throw pdal_error(oss.str()); - } - uint32_t v = boost::lexical_cast(node.value()); - return v; - } - - - static double getMetadataF64(const MetadataNode& parent, const std::string& name) - { - const MetadataNode node = parent.findChild(name); - if (!node.valid()) { - std::ostringstream oss; - oss << "RialtoWriter: required metadata item not found: " << name; - throw pdal_error(oss.str()); - } - double v = boost::lexical_cast(node.value()); - return v; - } - - void extractStatistics(MetadataNode& tileSetNode, const std::string& dimName, - double& minimum, double& mean, double& maximum) - { - MetadataNode statisticNodes = tileSetNode.findChild("statistics"); - assert(statisticNodes.valid()); - - MetadataNode dimNode = statisticNodes.findChild(dimName); - if (!dimNode.valid()) - { - std::ostringstream oss; - oss << "RialtoWriter: statistics not found for dimension: " << dimName; - throw pdal_error(oss.str()); - } - - minimum = getMetadataF64(dimNode, "minimum"); - mean = getMetadataF64(dimNode, "mean"); - maximum = getMetadataF64(dimNode, "maximum"); - } - - static void writeHeader( - const std::string& directory, - MetadataNode tileSetNode, - PointLayoutPtr layout) - { - MetadataNode headerNode = tileSetNode.findChild("header"); - assert(headerNode.valid()); - const uint32_t maxLevel = getMetadataU32(headerNode, "maxLevel"); - - const uint32_t numCols = getMetadataU32(headerNode, "numCols"); - const uint32_t numRows = getMetadataU32(headerNode, "numRows"); - assert(numCols == 2 && numRows == 1); - - const double minx = getMetadataF64(headerNode, "minX"); - const double miny = getMetadataF64(headerNode, "minY"); - const double maxx = getMetadataF64(headerNode, "maxX"); - const double maxy = getMetadataF64(headerNode, "maxY"); - assert(minx==-180.0 && miny==-90.0 && maxx==180.0 && maxy==90.0); - - const std::string filename(directory + "/header.json"); - FILE* fp = fopen(filename.c_str(), "wt"); - - fprintf(fp, "{\n"); - fprintf(fp, " \"version\": 4,\n"); - - fprintf(fp, " \"bbox\": [%lf, %lf, %lf, %lf],\n", - minx, miny, maxx, maxy); - - fprintf(fp, " \"maxLevel\": %d,\n", maxLevel); - fprintf(fp, " \"numCols\": %d,\n", numCols); - fprintf(fp, " \"numRows\": %d,\n", numRows); - - fprintf(fp, " \"dimensions\": [\n"); - - const size_t numDims = layout->dims().size(); - size_t i = 0; - for (const auto& dim : layout->dims()) - { - const Dimension::Type::Enum dataType = layout->dimType(dim); - const std::string& dataTypeName = Dimension::interpretationName(dataType); - const std::string& name = Dimension::name(dim); - - double minimum, mean, maximum; - extractStatistics(tileSetNode, name, minimum, mean, maximum); - - fprintf(fp, " {\n"); - fprintf(fp, " \"datatype\": \"%s\",\n", dataTypeName.c_str()); - fprintf(fp, " \"name\": \"%s\",\n", name.c_str()); - fprintf(fp, " \"minimum\": %f,\n", minimum); - fprintf(fp, " \"mean\": %f,\n", mean); - fprintf(fp, " \"maximum\": %f\n", maximum); - fprintf(fp, " }%s\n", i++==numDims-1 ? "" : ","); - } - fprintf(fp, " ]\n"); - fprintf(fp, "}\n"); - - fclose(fp); - } - - - static void fillBuffer(const PointView* view, const PointId& idx, char* buf) - { - char* p = buf; - char* q = p; - - for (const auto& dim : view->dims()) - { - view->getRawField(dim, idx, q); - q += view->dimSize(dim); - } - } - - - static void writeDataForOneTile(FILE* fp, PointView* view) - { - const size_t len = view->pointSize(); - char* buf = new char[len]; - - for (size_t i=0; isize(); ++i) - { - const PointId idx = i; - fillBuffer(view, idx, buf); - fwrite(buf, len, 1, fp); - } - - delete[] buf; - } - - - static void writeOneTile(MetadataNode& tileNode, PointView* view, const std::string& directory) - { - const uint32_t level = getMetadataU32(tileNode, "level"); - const uint32_t tileX = getMetadataU32(tileNode, "tileX"); - const uint32_t tileY = getMetadataU32(tileNode, "tileY"); - const uint32_t mask = getMetadataU32(tileNode, "mask"); - - std::ostringstream os; - - os << directory; - FileUtils::createDirectory(os.str()); - - os << "/" << level; - FileUtils::createDirectory(os.str()); - - os << "/" << tileX; - FileUtils::createDirectory(os.str()); - - os << "/" << tileY << ".ria"; - FILE* fp = fopen(os.str().c_str(), "wb"); - - if (view) - { - writeDataForOneTile(fp, view); - } - - uint8_t mask8 = mask; - fwrite(&mask8, 1, 1, fp); - - fclose(fp); - } - -} // anonymous namespace - - -std::string RialtoWriter::getName() const -{ - return s_info.name; -} - - -void RialtoWriter::processOptions(const Options& options) -{ - // we treat the target "filename" as the output directory, - // so we'll use a differently named variable to make it clear - m_directory = m_filename; -} - - -Options RialtoWriter::getDefaultOptions() -{ - Options options; - return options; -} - - -void RialtoWriter::ready(PointTableRef table) -{ - m_table = &table; - - // pdal writers always clobber their output file, so we follow - // the same convention here -- even though we're dealing with - // an output "directory" instead of and output "file" - if (FileUtils::directoryExists(m_filename)) - { - FileUtils::deleteDirectory(m_filename); - } - - if (!FileUtils::createDirectory(m_filename)) { - throw pdal_error("RialtoWriter: Error creating directory"); - } - - MetadataNode tileSetNode = m_table->metadata().findChild("filters.tiler"); - if (!tileSetNode.valid()) { - throw pdal_error("RialtoWriter: \"filters.tiler\" metadata not found"); - } - - writeHeader(m_directory, tileSetNode, m_table->layout()); - - // the metadata nodes are listed by tile id, not by point view id, - // so we need make to make a map from point view id to metadata node - const MetadataNode tilesNode = tileSetNode.findChild("tiles"); - if (!tilesNode.valid()) { - throw pdal_error("RialtoWriter: \"filters.tiler/tiles\" metadata not found"); - } - const MetadataNodeList tileNodes = tilesNode.children(); - for (auto node: tileNodes) - { - MetadataNode n = node.findChild("pointView"); - if (n.valid()) { - const uint32_t viewId = boost::lexical_cast(n.value()); - m_dataMap[viewId] = node; - } - } -} - - -// write out the tile with this pointview -void RialtoWriter::write(const PointViewPtr view) -{ - MetadataNode tileNode = m_dataMap[view->id()]; - assert(tileNode.valid()); - - PointView* viewptr = view.get(); - writeOneTile(tileNode, viewptr, m_directory); -} - - -// write out all the remaining tiles: those without point views -void RialtoWriter::done(PointTableRef table) -{ - const MetadataNode tileSetNode = m_table->metadata().findChild("filters.tiler"); - const MetadataNode tilesNode = tileSetNode.findChild("tiles"); - const MetadataNodeList tileNodes = tilesNode.children(); - - for (auto iter = tileNodes.begin(); iter != tileNodes.end(); ++iter) - { - MetadataNode tileNode = *iter; - const MetadataNode nodeP = tileNode.findChild("pointView"); - if (!nodeP.valid()) { - writeOneTile(tileNode, NULL, m_directory); - } - } - -} - - -} // namespace pdal diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 37efdc7d85..6f345fa073 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -58,3 +58,6 @@ if(BUILD_PLUGIN_SQLITE) add_subdirectory(sqlite) endif() +if(BUILD_PLUGIN_RIALTO) + add_subdirectory(rialto) +endif() diff --git a/plugins/rialto/CMakeLists.txt b/plugins/rialto/CMakeLists.txt new file mode 100644 index 0000000000..6f35005204 --- /dev/null +++ b/plugins/rialto/CMakeLists.txt @@ -0,0 +1,44 @@ +# +# Rialto plugin CMake configuration +# + +include (${PDAL_CMAKE_DIR}/sqlite.cmake) + +set(srcsF + io/RialtoWriter.cpp + io/RialtoFileWriter.cpp) + +set(srcsD + io/RialtoWriter.cpp + io/RialtoDbWriter.cpp) + +set(incsF + io/RialtoWriter.hpp + io/RialtoFileWriter.hpp +) + +set(incsD + io/RialtoWriter.hpp + io/RialtoDbWriter.hpp +) + +PDAL_ADD_PLUGIN(dbwriter_libname writer rialtodb + FILES "${srcsD}" "${incsD}" + LINK_WITH ${SQLITE3_LIBRARY}) + +PDAL_ADD_PLUGIN(filewriter_libname writer rialtofile + FILES "${srcsF}" "${incsF}") + +# +# Rialto tests +# +if(BUILD_RIALTO_TESTS) + PDAL_ADD_TEST(rialtofiletest + FILES test/RialtoFileWriterTest.cpp + LINK_WITH ${filewriter_libname} +) +PDAL_ADD_TEST(rialtodbtest + FILES test/RialtoDbWriterTest.cpp + LINK_WITH ${dbwriter_libname} +) +endif() diff --git a/plugins/rialto/io/RialtoDbWriter.cpp b/plugins/rialto/io/RialtoDbWriter.cpp new file mode 100644 index 0000000000..af0f5b36c7 --- /dev/null +++ b/plugins/rialto/io/RialtoDbWriter.cpp @@ -0,0 +1,198 @@ +/****************************************************************************** +* Copyright (c) 2014-2015, RadiantBlue Technologies, Inc. +* +* 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 "RialtoDbWriter.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace pdal +{ + +static PluginInfo const s_info = PluginInfo( + "writers.rialtodb", + "Rialto DB Writer", + "http://pdal.io/stages/writers.rialtodb.html" ); + +CREATE_SHARED_PLUGIN(1, 0, RialtoDbWriter, Writer, s_info) + +namespace +{ +} // anonymous namespace + + +void RialtoDbWriter::writeHeader(MetadataNode tileSetNode, + PointLayoutPtr layout) +{ + MetadataNode headerNode = tileSetNode.findChild("header"); + assert(headerNode.valid()); + const uint32_t maxLevel = getMetadataU32(headerNode, "maxLevel"); + + const uint32_t numCols = getMetadataU32(headerNode, "numCols"); + const uint32_t numRows = getMetadataU32(headerNode, "numRows"); + assert(numCols == 2 && numRows == 1); + + const double minx = getMetadataF64(headerNode, "minX"); + const double miny = getMetadataF64(headerNode, "minY"); + const double maxx = getMetadataF64(headerNode, "maxX"); + const double maxy = getMetadataF64(headerNode, "maxY"); + assert(minx==-180.0 && miny==-90.0 && maxx==180.0 && maxy==90.0); + + const std::string filename(m_directory + "/header.json-db"); + FILE* fp = fopen(filename.c_str(), "wt"); + + fprintf(fp, "{\n"); + fprintf(fp, " \"version\": 4,\n"); + + fprintf(fp, " \"bbox\": [%lf, %lf, %lf, %lf],\n", + minx, miny, maxx, maxy); + + fprintf(fp, " \"maxLevel\": %d,\n", maxLevel); + fprintf(fp, " \"numCols\": %d,\n", numCols); + fprintf(fp, " \"numRows\": %d,\n", numRows); + + fprintf(fp, " \"dimensions\": [\n"); + + const size_t numDims = layout->dims().size(); + size_t i = 0; + for (const auto& dim : layout->dims()) + { + const Dimension::Type::Enum dataType = layout->dimType(dim); + const std::string& dataTypeName = Dimension::interpretationName(dataType); + const std::string& name = Dimension::name(dim); + + double minimum, mean, maximum; + extractStatistics(tileSetNode, name, minimum, mean, maximum); + + fprintf(fp, " {\n"); + fprintf(fp, " \"datatype\": \"%s\",\n", dataTypeName.c_str()); + fprintf(fp, " \"name\": \"%s\",\n", name.c_str()); + fprintf(fp, " \"minimum\": %f,\n", minimum); + fprintf(fp, " \"mean\": %f,\n", mean); + fprintf(fp, " \"maximum\": %f\n", maximum); + fprintf(fp, " }%s\n", i++==numDims-1 ? "" : ","); + } + fprintf(fp, " ]\n"); + fprintf(fp, "}\n"); + + fclose(fp); +} + +void RialtoDbWriter::writeTile(MetadataNode tileNode, PointView* view) +{ + const uint32_t level = getMetadataU32(tileNode, "level"); + const uint32_t tileX = getMetadataU32(tileNode, "tileX"); + const uint32_t tileY = getMetadataU32(tileNode, "tileY"); + const uint32_t mask = getMetadataU32(tileNode, "mask"); + + std::ostringstream os; + + os << m_directory; + FileUtils::createDirectory(os.str()); + + os << "/" << level; + FileUtils::createDirectory(os.str()); + + os << "/" << tileX; + FileUtils::createDirectory(os.str()); + + os << "/" << tileY << ".ria-db"; + FILE* fp = fopen(os.str().c_str(), "wb"); + + if (view) + { + size_t bufsiz; + char* buf = createBlob(view, bufsiz); + fwrite(buf, bufsiz, 1, fp); + } + + uint8_t mask8 = mask; + fwrite(&mask8, 1, 1, fp); + + fclose(fp); +} + + +std::string RialtoDbWriter::getName() const +{ + return s_info.name; +} + + +void RialtoDbWriter::processOptions(const Options& options) +{ + // we treat the target "filename" as the output directory, + // so we'll use a differently named variable to make it clear + m_directory = m_filename; +} + + +Options RialtoDbWriter::getDefaultOptions() +{ + Options options; + return options; +} + + +void RialtoDbWriter::localStart() +{ + // pdal writers always clobber their output file, so we follow + // the same convention here -- even though we're dealing with + // an output "directory" instead of and output "file" + if (FileUtils::directoryExists(m_filename)) + { + FileUtils::deleteDirectory(m_filename); + } + + if (!FileUtils::createDirectory(m_filename)) { + throw pdal_error("RialtoFileWriter: Error creating directory"); + } +} + + +void RialtoDbWriter::localFinish() +{ +} + + +} // namespace pdal diff --git a/io/rialto/RialtoWriter.hpp b/plugins/rialto/io/RialtoDbWriter.hpp similarity index 79% rename from io/rialto/RialtoWriter.hpp rename to plugins/rialto/io/RialtoDbWriter.hpp index 422aca826a..64e1cb96ec 100644 --- a/io/rialto/RialtoWriter.hpp +++ b/plugins/rialto/io/RialtoDbWriter.hpp @@ -35,25 +35,23 @@ #pragma once #include -#include +#include "RialtoWriter.hpp" #include #include -extern "C" int32_t RialtoWriter_ExitFunc(); -extern "C" PF_ExitFunc RialtoWriter_InitPlugin(); +extern "C" int32_t RialtoDbWriter_ExitFunc(); +extern "C" PF_ExitFunc RialtoDbWriter_InitPlugin(); namespace pdal { class Options; -class Tile; -class PDAL_DLL RialtoWriter : public Writer +class PDAL_DLL RialtoDbWriter : public RialtoWriter { public: - RialtoWriter() : - m_table(NULL) + RialtoDbWriter() {} static void * create(); @@ -62,19 +60,19 @@ class PDAL_DLL RialtoWriter : public Writer Options getDefaultOptions(); + virtual void localStart(); + virtual void writeHeader(MetadataNode tileSetNode, + PointLayoutPtr layout); + virtual void writeTile(MetadataNode, PointView*); + virtual void localFinish(); + private: virtual void processOptions(const Options& options); - virtual void ready(PointTableRef table); - virtual void write(const PointViewPtr view); - virtual void done(PointTableRef table); - BasePointTable *m_table; std::string m_directory; - std::map m_dataMap; - - RialtoWriter& operator=(const RialtoWriter&); // not implemented - RialtoWriter(const RialtoWriter&); // not implemented + RialtoDbWriter& operator=(const RialtoDbWriter&); // not implemented + RialtoDbWriter(const RialtoDbWriter&); // not implemented }; } // namespace pdal diff --git a/plugins/rialto/io/RialtoFileWriter.cpp b/plugins/rialto/io/RialtoFileWriter.cpp new file mode 100644 index 0000000000..bb9b6778dc --- /dev/null +++ b/plugins/rialto/io/RialtoFileWriter.cpp @@ -0,0 +1,198 @@ +/****************************************************************************** +* Copyright (c) 2014-2015, RadiantBlue Technologies, Inc. +* +* 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 "RialtoFileWriter.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace pdal +{ + +static PluginInfo const s_info = PluginInfo( + "writers.rialtofile", + "Rialto File Writer", + "http://pdal.io/stages/writers.rialtofile.html" ); + +CREATE_SHARED_PLUGIN(1, 0, RialtoFileWriter, Writer, s_info) + +namespace +{ +} // anonymous namespace + + +void RialtoFileWriter::writeHeader(MetadataNode tileSetNode, + PointLayoutPtr layout) +{ + MetadataNode headerNode = tileSetNode.findChild("header"); + assert(headerNode.valid()); + const uint32_t maxLevel = getMetadataU32(headerNode, "maxLevel"); + + const uint32_t numCols = getMetadataU32(headerNode, "numCols"); + const uint32_t numRows = getMetadataU32(headerNode, "numRows"); + assert(numCols == 2 && numRows == 1); + + const double minx = getMetadataF64(headerNode, "minX"); + const double miny = getMetadataF64(headerNode, "minY"); + const double maxx = getMetadataF64(headerNode, "maxX"); + const double maxy = getMetadataF64(headerNode, "maxY"); + assert(minx==-180.0 && miny==-90.0 && maxx==180.0 && maxy==90.0); + + const std::string filename(m_directory + "/header.json"); + FILE* fp = fopen(filename.c_str(), "wt"); + + fprintf(fp, "{\n"); + fprintf(fp, " \"version\": 4,\n"); + + fprintf(fp, " \"bbox\": [%lf, %lf, %lf, %lf],\n", + minx, miny, maxx, maxy); + + fprintf(fp, " \"maxLevel\": %d,\n", maxLevel); + fprintf(fp, " \"numCols\": %d,\n", numCols); + fprintf(fp, " \"numRows\": %d,\n", numRows); + + fprintf(fp, " \"dimensions\": [\n"); + + const size_t numDims = layout->dims().size(); + size_t i = 0; + for (const auto& dim : layout->dims()) + { + const Dimension::Type::Enum dataType = layout->dimType(dim); + const std::string& dataTypeName = Dimension::interpretationName(dataType); + const std::string& name = Dimension::name(dim); + + double minimum, mean, maximum; + extractStatistics(tileSetNode, name, minimum, mean, maximum); + + fprintf(fp, " {\n"); + fprintf(fp, " \"datatype\": \"%s\",\n", dataTypeName.c_str()); + fprintf(fp, " \"name\": \"%s\",\n", name.c_str()); + fprintf(fp, " \"minimum\": %f,\n", minimum); + fprintf(fp, " \"mean\": %f,\n", mean); + fprintf(fp, " \"maximum\": %f\n", maximum); + fprintf(fp, " }%s\n", i++==numDims-1 ? "" : ","); + } + fprintf(fp, " ]\n"); + fprintf(fp, "}\n"); + + fclose(fp); +} + +void RialtoFileWriter::writeTile(MetadataNode tileNode, PointView* view) +{ + const uint32_t level = getMetadataU32(tileNode, "level"); + const uint32_t tileX = getMetadataU32(tileNode, "tileX"); + const uint32_t tileY = getMetadataU32(tileNode, "tileY"); + const uint32_t mask = getMetadataU32(tileNode, "mask"); + + std::ostringstream os; + + os << m_directory; + FileUtils::createDirectory(os.str()); + + os << "/" << level; + FileUtils::createDirectory(os.str()); + + os << "/" << tileX; + FileUtils::createDirectory(os.str()); + + os << "/" << tileY << ".ria"; + FILE* fp = fopen(os.str().c_str(), "wb"); + + if (view) + { + size_t bufsiz; + char* buf = createBlob(view, bufsiz); + fwrite(buf, bufsiz, 1, fp); + } + + uint8_t mask8 = mask; + fwrite(&mask8, 1, 1, fp); + + fclose(fp); +} + + +std::string RialtoFileWriter::getName() const +{ + return s_info.name; +} + + +void RialtoFileWriter::processOptions(const Options& options) +{ + // we treat the target "filename" as the output directory, + // so we'll use a differently named variable to make it clear + m_directory = m_filename; +} + + +Options RialtoFileWriter::getDefaultOptions() +{ + Options options; + return options; +} + + +void RialtoFileWriter::localStart() +{ + // pdal writers always clobber their output file, so we follow + // the same convention here -- even though we're dealing with + // an output "directory" instead of and output "file" + if (FileUtils::directoryExists(m_filename)) + { + FileUtils::deleteDirectory(m_filename); + } + + if (!FileUtils::createDirectory(m_filename)) { + throw pdal_error("RialtoFileWriter: Error creating directory"); + } +} + + +void RialtoFileWriter::localFinish() +{ +} + + +} // namespace pdal diff --git a/plugins/rialto/io/RialtoFileWriter.hpp b/plugins/rialto/io/RialtoFileWriter.hpp new file mode 100644 index 0000000000..d4b33097b7 --- /dev/null +++ b/plugins/rialto/io/RialtoFileWriter.hpp @@ -0,0 +1,78 @@ +/****************************************************************************** +* Copyright (c) 2014-2015, RadiantBlue Technologies, Inc. +* +* 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 "RialtoWriter.hpp" + +#include +#include + +extern "C" int32_t RialtoFileWriter_ExitFunc(); +extern "C" PF_ExitFunc RialtoFileWriter_InitPlugin(); + +namespace pdal +{ + +class Options; + +class PDAL_DLL RialtoFileWriter : public RialtoWriter +{ +public: + RialtoFileWriter() + {} + + static void * create(); + static int32_t destroy(void *); + std::string getName() const; + + Options getDefaultOptions(); + + virtual void localStart(); + virtual void writeHeader(MetadataNode tileSetNode, + PointLayoutPtr layout); + virtual void writeTile(MetadataNode, PointView*); + virtual void localFinish(); + +private: + virtual void processOptions(const Options& options); + + std::string m_directory; + + RialtoFileWriter& operator=(const RialtoFileWriter&); // not implemented + RialtoFileWriter(const RialtoFileWriter&); // not implemented +}; + +} // namespace pdal diff --git a/plugins/rialto/io/RialtoWriter.cpp b/plugins/rialto/io/RialtoWriter.cpp new file mode 100644 index 0000000000..3fa9473c59 --- /dev/null +++ b/plugins/rialto/io/RialtoWriter.cpp @@ -0,0 +1,213 @@ +/****************************************************************************** +* Copyright (c) 2014-2015, RadiantBlue Technologies, Inc. +* +* 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 "RialtoWriter.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace pdal +{ + +namespace +{ + static void fillBufferWithPoint(const PointView* view, const PointId& idx, char* buf) + { + char* p = buf; + char* q = p; + + for (const auto& dim : view->dims()) + { + view->getRawField(dim, idx, q); + q += view->dimSize(dim); + } + } + + static void fillBufferWithPointView(const PointView* view, char* buf) + { + for (size_t i=0; isize(); ++i) + { + const PointId idx = i; + fillBufferWithPoint(view, idx, buf); + } + + } + +} // anonymous namespace + + +// caller responisble for deleting the buffer +char* RialtoWriter::createBlob(PointView* view, size_t& buflen) +{ + const uint32_t pointSize = view->pointSize(); + const uint32_t numPoints = view->size(); + buflen = pointSize * numPoints; + char* buf = new char[buflen]; + + fillBufferWithPointView(view, buf); + + return buf; +} + + +void RialtoWriter::extractStatistics(MetadataNode& tileSetNode, const std::string& dimName, + double& minimum, double& mean, double& maximum) +{ + MetadataNode statisticNodes = tileSetNode.findChild("statistics"); + assert(statisticNodes.valid()); + + MetadataNode dimNode = statisticNodes.findChild(dimName); + if (!dimNode.valid()) + { + std::ostringstream oss; + oss << "RialtoWriter: statistics not found for dimension: " << dimName; + throw pdal_error(oss.str()); + } + + minimum = getMetadataF64(dimNode, "minimum"); + mean = getMetadataF64(dimNode, "mean"); + maximum = getMetadataF64(dimNode, "maximum"); +} + + +uint32_t RialtoWriter::getMetadataU32(const MetadataNode& parent, const std::string& name) +{ + const MetadataNode node = parent.findChild(name); + if (!node.valid()) { + std::ostringstream oss; + oss << "RialtoWriter: required metadata item not found: " << name; + throw pdal_error(oss.str()); + } + uint32_t v = boost::lexical_cast(node.value()); + return v; +} + + +double RialtoWriter::getMetadataF64(const MetadataNode& parent, const std::string& name) +{ + const MetadataNode node = parent.findChild(name); + if (!node.valid()) { + std::ostringstream oss; + oss << "RialtoWriter: required metadata item not found: " << name; + throw pdal_error(oss.str()); + } + double v = boost::lexical_cast(node.value()); + return v; +} + + +void RialtoWriter::ready(PointTableRef table) +{ + m_table = &table; + + localStart(); + + MetadataNode tileSetNode = m_table->metadata().findChild("filters.tiler"); + if (!tileSetNode.valid()) { + throw pdal_error("RialtoWriter: \"filters.tiler\" metadata not found"); + } + + writeHeader(tileSetNode, m_table->layout()); + + makePointViewMap(tileSetNode); +} + + +// write out the tile with this pointview +void RialtoWriter::write(const PointViewPtr viewPtr) +{ + MetadataNode tileNode = m_pointViewMap[viewPtr->id()]; + assert(tileNode.valid()); + + PointView* view = viewPtr.get(); + writeTile(tileNode, view); +} + + +// write out all the remaining tiles: those without point views +void RialtoWriter::done(PointTableRef table) +{ + writeEmptyTiles(); + + localFinish(); +} + + +void RialtoWriter::makePointViewMap(MetadataNode tileSetNode) +{ + // the metadata nodes are listed by tile id, not by point view id, + // so we need make to make a map from point view id to metadata node + const MetadataNode tilesNode = tileSetNode.findChild("tiles"); + if (!tilesNode.valid()) { + throw pdal_error("RialtoWriter: \"filters.tiler/tiles\" metadata not found"); + } + const MetadataNodeList tileNodes = tilesNode.children(); + for (auto node: tileNodes) + { + MetadataNode n = node.findChild("pointView"); + if (n.valid()) { + const uint32_t viewId = boost::lexical_cast(n.value()); + m_pointViewMap[viewId] = node; + } + } +} + + +void RialtoWriter::writeEmptyTiles() +{ + const MetadataNode tileSetNode = m_table->metadata().findChild("filters.tiler"); + const MetadataNode tilesNode = tileSetNode.findChild("tiles"); + const MetadataNodeList tileNodes = tilesNode.children(); + + for (auto iter = tileNodes.begin(); iter != tileNodes.end(); ++iter) + { + MetadataNode tileNode = *iter; + const MetadataNode nodeP = tileNode.findChild("pointView"); + if (!nodeP.valid()) { + writeTile(tileNode, NULL); + } + } +} + + +} // namespace pdal diff --git a/plugins/rialto/io/RialtoWriter.hpp b/plugins/rialto/io/RialtoWriter.hpp new file mode 100644 index 0000000000..45c8271418 --- /dev/null +++ b/plugins/rialto/io/RialtoWriter.hpp @@ -0,0 +1,99 @@ +/****************************************************************************** +* Copyright (c) 2014-2015, RadiantBlue Technologies, Inc. +* +* 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 + +namespace pdal +{ + +class Options; + +class PDAL_DLL RialtoWriter : public Writer +{ +public: + RialtoWriter() : + m_table(NULL) + {} + + static void * create(); + static int32_t destroy(void *); + + // implemented in derived classes + virtual std::string getName() const=0; + virtual Options getDefaultOptions()=0; + +protected: + + // implemented in derived classes + virtual void processOptions(const Options& options)=0; + + // implemented in derived classes + virtual void localStart() = 0; + virtual void writeHeader(MetadataNode tileSetNode, + PointLayoutPtr layout) = 0; + virtual void writeTile(MetadataNode, PointView*) = 0; + virtual void localFinish() = 0; + + // helper functions + static uint32_t getMetadataU32(const MetadataNode& parent, const std::string& name); + static double getMetadataF64(const MetadataNode& parent, const std::string& name); + static void extractStatistics(MetadataNode& tileSetNode, const std::string& dimName, + double& minimum, double& mean, double& maximum); + static char* createBlob(PointView* view, size_t& buflen); + +private: + virtual void ready(PointTableRef table); + virtual void write(const PointViewPtr view); + virtual void done(PointTableRef table); + + char* makeBuffer(PointView*); + void makePointViewMap(MetadataNode tileSetNode); + void writeEmptyTiles(); + + BasePointTable *m_table; + std::string m_directory; + + std::map m_pointViewMap; + + RialtoWriter& operator=(const RialtoWriter&); // not implemented + RialtoWriter(const RialtoWriter&); // not implemented +}; + +} // namespace pdal diff --git a/plugins/rialto/test/RialtoDbWriterTest.cpp b/plugins/rialto/test/RialtoDbWriterTest.cpp new file mode 100644 index 0000000000..1f81cc8f4f --- /dev/null +++ b/plugins/rialto/test/RialtoDbWriterTest.cpp @@ -0,0 +1,197 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Support.hpp" + +#include + +using namespace pdal; + +TEST(RialtoDbWriterTest, createWriter) +{ + StageFactory f; + std::unique_ptr writer(f.createStage("writers.rialtodb")); + EXPECT_TRUE(writer.get()); +} + + +const struct Data { + double x; + double y; + double z; +} data[8] = { + /*0*/ { -179.0, 89.0, 0.0}, + /*1*/ { -1.0, 89.0, 11.0}, + /*2*/ { -179.0, -89.0, 22.0}, + /*3*/ { -1.0, -89.0, 33.0}, + /*4*/ { 89.0, 1.0, 44.0}, + /*5*/ { 91.0, 1.0, 55.0}, + /*6*/ { 89.0, -1.0, 66.0}, + /*7*/ { 91.0, -1.0, 77.0} +}; + + +static void readBytes(const std::string& filename, uint8_t* buf, uint32_t len) +{ + const char* name = Support::temppath(filename).c_str(); + FILE* fp = fopen(name, "rb"); + EXPECT_TRUE(fp != NULL); + size_t cnt = fread(buf, 1, len, fp); + EXPECT_EQ(cnt, len); + fclose(fp); +} + + +static void verify(const std::string& filename, + const Data* expectedData, + uint8_t expectedMask) +{ + uint32_t actualSize = FileUtils::fileSize(Support::temppath(filename)); + + if (expectedData) { + EXPECT_EQ(actualSize, 25u); + union { + uint8_t buf[25]; + struct { + double x; + double y; + double z; + uint8_t m; + } actualData; + } u; + readBytes(filename, u.buf, 25); + EXPECT_EQ(u.actualData.x, expectedData->x); + EXPECT_EQ(u.actualData.y, expectedData->y); + EXPECT_EQ(u.actualData.z, expectedData->z); + EXPECT_EQ(u.actualData.m, expectedMask); + } else { + EXPECT_EQ(actualSize, 1u); + uint8_t actualMask; + readBytes(filename, &actualMask, 1); + EXPECT_EQ(actualMask, expectedMask); + } +} + + +static void verifyDirectorySize(const std::string& path, uint32_t expectedSize) +{ + boost::filesystem::directory_iterator iter(Support::temppath(path)); + uint32_t cnt = 0; + while (iter != boost::filesystem::directory_iterator()) { + ++cnt; + ++iter; + } + EXPECT_EQ(cnt, expectedSize); +} + + +TEST(RialtoDbWriterTest, testWriter) +{ + //FileUtils::deleteFile(Support::temppath("RialtoTest/header.json")); + + // set up test data + PointTable table; + PointViewPtr inputView(new PointView(table)); + + table.layout()->registerDim(Dimension::Id::X); + table.layout()->registerDim(Dimension::Id::Y); + table.layout()->registerDim(Dimension::Id::Z); + + for (int i=0; i<8; i++) + { + inputView->setField(Dimension::Id::X, i, data[i].x); + inputView->setField(Dimension::Id::Y, i, data[i].y); + inputView->setField(Dimension::Id::Z, i, data[i].z); + } + + + // options + Options readerOptions; + + Options tilerOptions; + tilerOptions.add("maxLevel", 2); + + Options writerOptions; + writerOptions.add("filename", Support::temppath("rialto1")); + writerOptions.add("overwrite", true); + + Options statsOptions; + + // stages + BufferReader reader; + reader.setOptions(readerOptions); + reader.addView(inputView); + reader.setSpatialReference(SpatialReference("EPSG:4326")); + + StatsFilter stats; + stats.setOptions(statsOptions); + stats.setInput(reader); + + TilerFilter tiler; + tiler.setOptions(tilerOptions); + tiler.setInput(stats); + + //RialtoFileWriter writer; + StageFactory f; + std::unique_ptr writer(f.createStage("writers.rialtodb")); + writer->setOptions(writerOptions); + writer->setInput(tiler); + + + // execution + writer->prepare(table); + PointViewSet outputViews = writer->execute(table); + + bool ok = Support::compare_text_files(Support::temppath("rialto1/header.json-db"), + Support::datapath("io/rialto1-header.json")); + EXPECT_TRUE(ok); + + verify("rialto1/0/0/0.ria-db", &data[0], 15); + verify("rialto1/0/1/0.ria-db", NULL, 15); + + verify("rialto1/1/0/0.ria-db", &data[0], 8); + verify("rialto1/1/0/1.ria-db", NULL, 1); + verify("rialto1/1/1/0.ria-db", NULL, 4); + verify("rialto1/1/1/1.ria-db", NULL, 2); + verify("rialto1/1/2/0.ria-db", &data[4], 2); + verify("rialto1/1/2/1.ria-db", NULL, 4); + verify("rialto1/1/3/0.ria-db", NULL, 1); + verify("rialto1/1/3/1.ria-db", NULL, 8); + + verify("rialto1/2/0/0.ria-db", &data[0], 0); + verify("rialto1/2/0/3.ria-db", &data[2], 0); + verify("rialto1/2/3/0.ria-db", &data[1], 0); + verify("rialto1/2/3/3.ria-db", &data[3], 0); + verify("rialto1/2/5/1.ria-db", &data[4], 0); + verify("rialto1/2/5/2.ria-db", &data[6], 0); + verify("rialto1/2/6/1.ria-db", &data[5], 0); + verify("rialto1/2/6/2.ria-db", &data[7], 0); + + verifyDirectorySize("rialto1", 4); + verifyDirectorySize("rialto1/0", 2); + verifyDirectorySize("rialto1/0/0", 1); + verifyDirectorySize("rialto1/0/1", 1); + verifyDirectorySize("rialto1/1", 4); + verifyDirectorySize("rialto1/1/0", 2); + verifyDirectorySize("rialto1/1/1", 2); + verifyDirectorySize("rialto1/1/2", 2); + verifyDirectorySize("rialto1/1/3", 2); + verifyDirectorySize("rialto1/2", 4); + verifyDirectorySize("rialto1/2/0", 2); + verifyDirectorySize("rialto1/2/3", 2); + verifyDirectorySize("rialto1/2/5", 2); + verifyDirectorySize("rialto1/2/6", 2); + + if (ok) { + //FileUtils::deleteDirectory(Support::temppath("rialto1")); + } +} diff --git a/plugins/rialto/test/RialtoFileWriterTest.cpp b/plugins/rialto/test/RialtoFileWriterTest.cpp new file mode 100644 index 0000000000..ea54381e02 --- /dev/null +++ b/plugins/rialto/test/RialtoFileWriterTest.cpp @@ -0,0 +1,197 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "Support.hpp" + +#include + +using namespace pdal; + +TEST(RialtoFileWriterTest, createWriter) +{ + StageFactory f; + std::unique_ptr writer(f.createStage("writers.rialtofile")); + EXPECT_TRUE(writer.get()); +} + + +const struct Data { + double x; + double y; + double z; +} data[8] = { + /*0*/ { -179.0, 89.0, 0.0}, + /*1*/ { -1.0, 89.0, 11.0}, + /*2*/ { -179.0, -89.0, 22.0}, + /*3*/ { -1.0, -89.0, 33.0}, + /*4*/ { 89.0, 1.0, 44.0}, + /*5*/ { 91.0, 1.0, 55.0}, + /*6*/ { 89.0, -1.0, 66.0}, + /*7*/ { 91.0, -1.0, 77.0} +}; + + +static void readBytes(const std::string& filename, uint8_t* buf, uint32_t len) +{ + const char* name = Support::temppath(filename).c_str(); + FILE* fp = fopen(name, "rb"); + EXPECT_TRUE(fp != NULL); + size_t cnt = fread(buf, 1, len, fp); + EXPECT_EQ(cnt, len); + fclose(fp); +} + + +static void verify(const std::string& filename, + const Data* expectedData, + uint8_t expectedMask) +{ + uint32_t actualSize = FileUtils::fileSize(Support::temppath(filename)); + + if (expectedData) { + EXPECT_EQ(actualSize, 25u); + union { + uint8_t buf[25]; + struct { + double x; + double y; + double z; + uint8_t m; + } actualData; + } u; + readBytes(filename, u.buf, 25); + EXPECT_EQ(u.actualData.x, expectedData->x); + EXPECT_EQ(u.actualData.y, expectedData->y); + EXPECT_EQ(u.actualData.z, expectedData->z); + EXPECT_EQ(u.actualData.m, expectedMask); + } else { + EXPECT_EQ(actualSize, 1u); + uint8_t actualMask; + readBytes(filename, &actualMask, 1); + EXPECT_EQ(actualMask, expectedMask); + } +} + + +static void verifyDirectorySize(const std::string& path, uint32_t expectedSize) +{ + boost::filesystem::directory_iterator iter(Support::temppath(path)); + uint32_t cnt = 0; + while (iter != boost::filesystem::directory_iterator()) { + ++cnt; + ++iter; + } + EXPECT_EQ(cnt, expectedSize); +} + + +TEST(RialtoFileWriterTest, testWriter) +{ + //FileUtils::deleteFile(Support::temppath("RialtoTest/header.json")); + + // set up test data + PointTable table; + PointViewPtr inputView(new PointView(table)); + + table.layout()->registerDim(Dimension::Id::X); + table.layout()->registerDim(Dimension::Id::Y); + table.layout()->registerDim(Dimension::Id::Z); + + for (int i=0; i<8; i++) + { + inputView->setField(Dimension::Id::X, i, data[i].x); + inputView->setField(Dimension::Id::Y, i, data[i].y); + inputView->setField(Dimension::Id::Z, i, data[i].z); + } + + + // options + Options readerOptions; + + Options tilerOptions; + tilerOptions.add("maxLevel", 2); + + Options writerOptions; + writerOptions.add("filename", Support::temppath("rialto1")); + writerOptions.add("overwrite", true); + + Options statsOptions; + + // stages + BufferReader reader; + reader.setOptions(readerOptions); + reader.addView(inputView); + reader.setSpatialReference(SpatialReference("EPSG:4326")); + + StatsFilter stats; + stats.setOptions(statsOptions); + stats.setInput(reader); + + TilerFilter tiler; + tiler.setOptions(tilerOptions); + tiler.setInput(stats); + + //RialtoFileWriter writer; + StageFactory f; + std::unique_ptr writer(f.createStage("writers.rialtofile")); + writer->setOptions(writerOptions); + writer->setInput(tiler); + + + // execution + writer->prepare(table); + PointViewSet outputViews = writer->execute(table); + + bool ok = Support::compare_text_files(Support::temppath("rialto1/header.json"), + Support::datapath("io/rialto1-header.json")); + EXPECT_TRUE(ok); + + verify("rialto1/0/0/0.ria", &data[0], 15); + verify("rialto1/0/1/0.ria", NULL, 15); + + verify("rialto1/1/0/0.ria", &data[0], 8); + verify("rialto1/1/0/1.ria", NULL, 1); + verify("rialto1/1/1/0.ria", NULL, 4); + verify("rialto1/1/1/1.ria", NULL, 2); + verify("rialto1/1/2/0.ria", &data[4], 2); + verify("rialto1/1/2/1.ria", NULL, 4); + verify("rialto1/1/3/0.ria", NULL, 1); + verify("rialto1/1/3/1.ria", NULL, 8); + + verify("rialto1/2/0/0.ria", &data[0], 0); + verify("rialto1/2/0/3.ria", &data[2], 0); + verify("rialto1/2/3/0.ria", &data[1], 0); + verify("rialto1/2/3/3.ria", &data[3], 0); + verify("rialto1/2/5/1.ria", &data[4], 0); + verify("rialto1/2/5/2.ria", &data[6], 0); + verify("rialto1/2/6/1.ria", &data[5], 0); + verify("rialto1/2/6/2.ria", &data[7], 0); + + verifyDirectorySize("rialto1", 4); + verifyDirectorySize("rialto1/0", 2); + verifyDirectorySize("rialto1/0/0", 1); + verifyDirectorySize("rialto1/0/1", 1); + verifyDirectorySize("rialto1/1", 4); + verifyDirectorySize("rialto1/1/0", 2); + verifyDirectorySize("rialto1/1/1", 2); + verifyDirectorySize("rialto1/1/2", 2); + verifyDirectorySize("rialto1/1/3", 2); + verifyDirectorySize("rialto1/2", 4); + verifyDirectorySize("rialto1/2/0", 2); + verifyDirectorySize("rialto1/2/3", 2); + verifyDirectorySize("rialto1/2/5", 2); + verifyDirectorySize("rialto1/2/6", 2); + + if (ok) { + //FileUtils::deleteDirectory(Support::temppath("rialto1")); + } +} diff --git a/test/unit/io/rialto/RialtoWriterTest.cpp b/plugins/rialto/test/RialtoWriterTest.cpp similarity index 100% rename from test/unit/io/rialto/RialtoWriterTest.cpp rename to plugins/rialto/test/RialtoWriterTest.cpp diff --git a/src/StageFactory.cpp b/src/StageFactory.cpp index 0a0b72d87c..0dafb079be 100644 --- a/src/StageFactory.cpp +++ b/src/StageFactory.cpp @@ -66,7 +66,6 @@ // writers #include #include -#include #include #include #include @@ -133,7 +132,6 @@ std::string StageFactory::inferWriterDriver(const std::string& filename) drivers["ntf"] = "writers.nitf"; drivers["pcd"] = "writers.pcd"; drivers["pclviz"] = "writers.pclvisualizer"; - drivers["ria"] = "writers.rialto"; drivers["sbet"] = "writers.sbet"; drivers["sqlite"] = "writers.sqlite"; drivers["txt"] = "writers.text"; @@ -214,7 +212,6 @@ StageFactory::StageFactory(bool no_plugins) // writers PluginManager::initializePlugin(BpfWriter_InitPlugin); PluginManager::initializePlugin(LasWriter_InitPlugin); - PluginManager::initializePlugin(RialtoWriter_InitPlugin); PluginManager::initializePlugin(SbetWriter_InitPlugin); PluginManager::initializePlugin(TextWriter_InitPlugin); PluginManager::initializePlugin(NullWriter_InitPlugin); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 8fcd7c5213..797b172e7f 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -79,7 +79,6 @@ PDAL_ADD_TEST(pdal_io_faux_test FILES io/faux/FauxReaderTest.cpp) PDAL_ADD_TEST(pdal_io_las_reader_test FILES io/las/LasReaderTest.cpp) PDAL_ADD_TEST(pdal_io_las_writer_test FILES io/las/LasWriterTest.cpp) PDAL_ADD_TEST(pdal_io_optech_test FILES io/optech/OptechReaderTest.cpp) -PDAL_ADD_TEST(pdal_io_rialto_test FILES io/rialto/RialtoWriterTest.cpp) PDAL_ADD_TEST(pdal_io_qfit_test FILES io/qfit/QFITReaderTest.cpp) PDAL_ADD_TEST(pdal_io_sbet_reader_test FILES io/sbet/SbetReaderTest.cpp) PDAL_ADD_TEST(pdal_io_sbet_writer_test FILES io/sbet/SbetWriterTest.cpp)