From 17d4cccb0051759a66c0bc151180b77bb5061d2a Mon Sep 17 00:00:00 2001 From: Connor Manning Date: Wed, 3 Apr 2024 11:31:44 -0500 Subject: [PATCH] Update to PDAL 2.6, which changed classification flags behavior: pdal/pdal#4186. --- cmake/pdal.cmake | 2 +- entwine/builder/builder.cpp | 8 ++++++-- entwine/builder/chunk.cpp | 8 ++++++-- entwine/io/binary.cpp | 6 +++--- entwine/types/dimension.cpp | 25 ++++++++++++++++++++++--- entwine/types/dimension.hpp | 4 ++-- entwine/util/info.cpp | 2 +- test/unit/build.cpp | 33 ++++++++++++++++++++++++++++++++- test/unit/srs.cpp | 5 ++--- test/unit/verify.hpp | 4 ++++ 10 files changed, 79 insertions(+), 18 deletions(-) diff --git a/cmake/pdal.cmake b/cmake/pdal.cmake index 9697e406..713d0ef1 100644 --- a/cmake/pdal.cmake +++ b/cmake/pdal.cmake @@ -1,2 +1,2 @@ -find_package(PDAL 2.4.0 REQUIRED CONFIG NO_POLICY_SCOPE) +find_package(PDAL 2.6.0 REQUIRED CONFIG NO_POLICY_SCOPE) diff --git a/entwine/builder/builder.cpp b/entwine/builder/builder.cpp index a3ba3b21..cb032f57 100644 --- a/entwine/builder/builder.cpp +++ b/entwine/builder/builder.cpp @@ -276,7 +276,9 @@ void Builder::insert( // won't count them. info.points = 0; - auto layout = toLayout(metadata.absoluteSchema); + auto layout = toLayout( + metadata.absoluteSchema, + metadata.dataType == io::Type::Laszip); VectorPointTable table(layout); table.setProcess([&]() { @@ -736,7 +738,9 @@ void mergeOne(Builder& dst, const Builder& src, ChunkCache& cache) } else { - auto layout = toLayout(metadata.absoluteSchema); + auto layout = toLayout( + metadata.absoluteSchema, + metadata.dataType == io::Type::Laszip); VectorPointTable table(layout, count); table.setProcess([&]() { diff --git a/entwine/builder/chunk.cpp b/entwine/builder/chunk.cpp index 23dd4c7f..12d38df6 100644 --- a/entwine/builder/chunk.cpp +++ b/entwine/builder/chunk.cpp @@ -169,7 +169,9 @@ uint64_t Chunk::save(const Endpoints& endpoints) const uint64_t np(m_gridBlock.size()); for (const auto& o : m_overflows) if (o) np += o->block.size(); - auto layout = toLayout(m_metadata.absoluteSchema); + auto layout = toLayout( + m_metadata.absoluteSchema, + m_metadata.dataType == io::Type::Laszip); BlockPointTable table(layout); table.reserve(np); table.insert(m_gridBlock); @@ -189,7 +191,9 @@ void Chunk::load( const Endpoints& endpoints, const uint64_t np) { - auto layout = toLayout(m_metadata.absoluteSchema); + auto layout = toLayout( + m_metadata.absoluteSchema, + m_metadata.dataType == io::Type::Laszip); VectorPointTable table(layout, np); table.setProcess([&]() { diff --git a/entwine/io/binary.cpp b/entwine/io/binary.cpp index 8c725db3..31b416b4 100644 --- a/entwine/io/binary.cpp +++ b/entwine/io/binary.cpp @@ -46,7 +46,7 @@ std::vector pack(const Metadata& m, BlockPointTable& src) { const uint64_t np(src.size()); - auto layout = toLayout(m.schema); + auto layout = toLayout(m.schema, false); VectorPointTable dst(layout, np); // Handle XYZ separately since we might need to scale/offset them. @@ -102,7 +102,7 @@ void unpack( VectorPointTable& dst, std::vector&& packed) { - auto scaledLayout = toLayout(m.schema); + auto scaledLayout = toLayout(m.schema, false); VectorPointTable src(scaledLayout, std::move(packed)); const uint64_t np(src.capacity()); @@ -111,7 +111,7 @@ void unpack( // For reading, our destination schema will always be normalized (i.e. XYZ // as doubles). So we can just copy the full dimension list and then // transform XYZ in place, if necessary. - auto absoluteLayout = toLayout(m.absoluteSchema); + auto absoluteLayout = toLayout(m.absoluteSchema, false); pdal::DimTypeList dimTypes(absoluteLayout.dimTypes()); pdal::PointRef srcPr(src, 0); diff --git a/entwine/types/dimension.cpp b/entwine/types/dimension.cpp index eae4e894..c266bc50 100644 --- a/entwine/types/dimension.cpp +++ b/entwine/types/dimension.cpp @@ -228,22 +228,41 @@ Schema combine(Schema agg, const Schema& cur, const bool fixed) return agg; } -Schema fromLayout(const pdal::PointLayout& layout) +Schema fromLayout(const pdal::PointLayout& layout, const bool islas) { Schema list; for (const DimId id : layout.dims()) { - list.push_back(Dimension(layout.dimName(id), layout.dimType(id))); + if (islas) + { + // If we're writing to LAS, then we don't write these values in the + // schema since they all get packed into Classification. + if (id != DimId::Synthetic && id != DimId::KeyPoint && + id != DimId::Withheld && id != DimId::Overlap) + { + list.push_back(Dimension(layout.dimName(id), layout.dimType(id))); + } + } + else list.push_back(Dimension(layout.dimName(id), layout.dimType(id))); } return list; } -FixedPointLayout toLayout(const Schema& list) +FixedPointLayout toLayout(const Schema& list, const bool islas) { FixedPointLayout layout; for (const auto& dim : list) { layout.registerOrAssignFixedDim(dim.name, dim.type); + // If this is from LAS, then we have these values packed into + // Classification. + if (islas && dim.name == "Classification") + { + layout.registerOrAssignFixedDim("Synthetic", pdal::Dimension::Type::Unsigned8); + layout.registerOrAssignFixedDim("KeyPoint", pdal::Dimension::Type::Unsigned8); + layout.registerOrAssignFixedDim("Withheld", pdal::Dimension::Type::Unsigned8); + layout.registerOrAssignFixedDim("Overlap", pdal::Dimension::Type::Unsigned8); + } } layout.finalize(); return layout; diff --git a/entwine/types/dimension.hpp b/entwine/types/dimension.hpp index 4b7cf0eb..b3962640 100644 --- a/entwine/types/dimension.hpp +++ b/entwine/types/dimension.hpp @@ -78,8 +78,8 @@ Dimension combine(Dimension agg, const Dimension& dim); Schema combine(Schema agg, const Schema& list, bool fixed = false); Schema makeAbsolute(Schema list); -Schema fromLayout(const pdal::PointLayout& layout); -FixedPointLayout toLayout(const Schema& list); +Schema fromLayout(const pdal::PointLayout& layout, bool islas); +FixedPointLayout toLayout(const Schema& list, bool islas); Schema setScaleOffset(Schema dims, ScaleOffset so); optional getScaleOffset(const Schema& dims); diff --git a/entwine/util/info.cpp b/entwine/util/info.cpp index 174b07dd..7143c9f9 100644 --- a/entwine/util/info.cpp +++ b/entwine/util/info.cpp @@ -100,7 +100,7 @@ SourceInfo getShallowInfo(const json pipeline) lock.unlock(); - info.schema = fromLayout(*table.layout()); + info.schema = fromLayout(*table.layout(), false); if (const auto so = getScaleOffset(reader)) { info.schema = setScaleOffset(info.schema, *so); diff --git a/test/unit/build.cpp b/test/unit/build.cpp index 9f31ff40..94415384 100644 --- a/test/unit/build.cpp +++ b/test/unit/build.cpp @@ -63,7 +63,7 @@ namespace EXPECT_EQ(ept.at("hierarchyType").get(), "json"); EXPECT_EQ(ept.at("points").get(), 100000); EXPECT_EQ(ept.at("span").get(), 32); - EXPECT_EQ(Srs(ept.at("srs")), srs); + EXPECT_EQ(ept.at("srs").get(), srs); EXPECT_EQ(ept.at("version").get(), "1.1.0"); const Schema schema = ept.at("schema").get(); EXPECT_TRUE(hasStats(schema)); @@ -116,6 +116,37 @@ TEST(build, laszip) checkData(*view); } +TEST(build, laszip14) +{ + run({ { "input", test::dataPath() + "ellipsoid14.laz" } }); + const json ept = checkEpt(); + // By default, since this is laszip input, our output will be laszip. + EXPECT_EQ(ept.at("dataType").get(), "laszip"); + + const auto stuff = execute(); + auto& view = stuff->view; + ASSERT_TRUE(view); + checkData(*view); +} + +TEST(build, withflags) +{ + run({ { "input", test::dataPath() + "ellipsoid14.laz" } }); + const json ept = checkEpt(); + // By default, since this is laszip input, our output will be laszip. + EXPECT_EQ(ept.at("dataType").get(), "laszip"); + + const auto stuff = execute({ outDir + "ept-data/0-0-0-0.laz" }); + + auto& view = stuff->view; + ASSERT_TRUE(view); + checkData(*view); + for (const auto pr : *view) + { + ASSERT_TRUE(pr.getFieldAs(pdal::Dimension::Id::KeyPoint)); + } +} + TEST(build, failedWrite) { struct FailIo : public io::Laszip diff --git a/test/unit/srs.cpp b/test/unit/srs.cpp index 2b01d0f8..dd7ad9ca 100644 --- a/test/unit/srs.cpp +++ b/test/unit/srs.cpp @@ -96,8 +96,6 @@ TEST(srs, fromHorizontalWkt) TEST(srs, fromCompoundWkt) { - // Unfortunately GDAL's auto-identify-vertical-EPSG doesn't actually return - // the vertical in this case. const std::string s("EPSG:26915+5703"); pdal::SpatialReference ref(s); Srs srs(ref.getWKT()); @@ -105,13 +103,14 @@ TEST(srs, fromCompoundWkt) EXPECT_FALSE(srs.empty()); EXPECT_EQ(srs.authority(), "EPSG"); EXPECT_EQ(srs.horizontal(), "26915"); - EXPECT_EQ(srs.vertical(), ""); + EXPECT_EQ(srs.vertical(), "5703"); EXPECT_EQ(srs.wkt(), ref.getWKT()); const json j(srs); const json v { { "authority", "EPSG" }, { "horizontal", "26915" }, + { "vertical", "5703" }, { "wkt", ref.getWKT() } }; EXPECT_EQ(j, v) << j.dump(2) << " != " << v.dump(2) << std::endl; diff --git a/test/unit/verify.hpp b/test/unit/verify.hpp index 068a2072..74656151 100644 --- a/test/unit/verify.hpp +++ b/test/unit/verify.hpp @@ -24,6 +24,10 @@ struct Verify {"ScanDirectionFlag"}, {"EdgeOfFlightLine"}, {"Classification"}, + {"Synthetic"}, + {"KeyPoint"}, + {"Withheld"}, + {"Overlap"}, {"ScanAngleRank"}, {"UserData"}, {"PointSourceId"},