From 614337df426aee81242f6f9b3e191eff855a248a Mon Sep 17 00:00:00 2001 From: Connor Manning Date: Tue, 14 Oct 2025 10:41:13 -0500 Subject: [PATCH] Zero out header point counts when crafting a zero-point file. Closes #328. --- entwine/util/info.cpp | 27 +++++++++++++++++++++------ entwine/util/info.hpp | 10 ++++++++-- entwine/util/io.cpp | 23 +++++++++++++++++++++-- entwine/util/io.hpp | 8 +++++++- 4 files changed, 57 insertions(+), 11 deletions(-) diff --git a/entwine/util/info.cpp b/entwine/util/info.cpp index 7143c9f9..e05859d3 100644 --- a/entwine/util/info.cpp +++ b/entwine/util/info.cpp @@ -268,12 +268,22 @@ bool areStemsUnique(const SourceList& sources) return true; } -SourceInfo analyzeOne(const std::string path, const bool deep, json pipeline) +SourceInfo analyzeOne( + const std::string path, + const bool deep, + json pipeline, + const uint64_t pointCount) { try { pipeline.at(0)["filename"] = path; - return deep ? getDeepInfo(pipeline) : getShallowInfo(pipeline); + SourceInfo info = deep + ? getDeepInfo(pipeline) + : getShallowInfo(pipeline); + + if (!info.points && pointCount) info.points = pointCount; + + return info; } catch (const std::exception& e) { @@ -324,7 +334,7 @@ std::string toLower(std::string s) return s; } -arbiter::LocalHandle localize( +MaybePointlessFile localize( const std::string path, const bool deep, const std::string tmp, @@ -332,7 +342,9 @@ arbiter::LocalHandle localize( { const std::string extension = toLower(arbiter::getExtension(path)); const bool isLas = extension == "las" || extension == "laz"; - if (deep || a.isLocal(path) || !isLas) return a.getLocalHandle(path, tmp); + if (deep || a.isLocal(path) || !isLas) { + return MaybePointlessFile { a.getLocalHandle(path, tmp) }; + } return getPointlessLasFile(path, tmp, a); } @@ -372,11 +384,14 @@ SourceList analyze( { pool.add([&]() { - const auto handle(localize(source.path, deep, tmp, a)); + const auto file(localize(source.path, deep, tmp, a)); + const auto handle = file.handle; + const auto pointCount = file.pointCount; source.info = analyzeOne( handle.localPath(), deep, - pipelineTemplate); + pipelineTemplate, + pointCount); }); } } diff --git a/entwine/util/info.hpp b/entwine/util/info.hpp index 1a3bacb0..b3e823f7 100644 --- a/entwine/util/info.hpp +++ b/entwine/util/info.hpp @@ -13,19 +13,25 @@ #include #include #include +#include #include #include namespace entwine { -arbiter::LocalHandle localize( +MaybePointlessFile localize( std::string path, bool deep, std::string tmp, const arbiter::Arbiter& a); -SourceInfo analyzeOne(std::string path, bool deep, json pipelineTemplate); +SourceInfo analyzeOne( + std::string path, + bool deep, + json pipelineTemplate, + uint64_t pointCount = 0); + Source parseOne(std::string path, const arbiter::Arbiter& a = { }); SourceList analyze( diff --git a/entwine/util/io.cpp b/entwine/util/io.cpp index 094ea194..abb6e8c7 100644 --- a/entwine/util/io.cpp +++ b/entwine/util/io.cpp @@ -191,7 +191,7 @@ arbiter::LocalHandle ensureGetLocalHandle( throw std::runtime_error("Failed to get " + path); } -arbiter::LocalHandle getPointlessLasFile( +MaybePointlessFile getPointlessLasFile( const std::string& path, const std::string& tmp, const arbiter::Arbiter& a) @@ -201,6 +201,8 @@ arbiter::LocalHandle getPointlessLasFile( const uint64_t minorVersionPos(25); const uint64_t headerSizePos(94); const uint64_t pointOffsetPos(96); + const uint64_t legacyPointCountPos(107); + const uint64_t pointCountPos(247); const uint64_t evlrOffsetPos(235); const uint64_t evlrNumberPos(evlrOffsetPos + 8); @@ -208,6 +210,8 @@ arbiter::LocalHandle getPointlessLasFile( uint8_t minorVersion(0); uint16_t headerSize(0); uint32_t pointOffset(0); + uint32_t legacyPointCount(0); + uint64_t pointCount(0); uint64_t evlrOffset(0); uint32_t evlrNumber(0); @@ -238,6 +242,14 @@ arbiter::LocalHandle getPointlessLasFile( is.seek(pointOffsetPos); is >> pointOffset; + // Grab the legacy point count, then set its value in the header to zero. + is.seek(legacyPointCountPos); + is >> legacyPointCount; + pointCount = legacyPointCount; + + os.seek(legacyPointCountPos); + os << static_cast(0); + if (minorVersion >= 4) { is.seek(evlrOffsetPos); @@ -250,6 +262,10 @@ arbiter::LocalHandle getPointlessLasFile( // removing the point data itself. os.seek(evlrOffsetPos); os << pointOffset; + + // And zero out the non-legacy point count. + os.seek(pointCountPos); + os << static_cast(0); } // Extract the modified header, VLRs, and append the EVLRs. @@ -279,6 +295,9 @@ arbiter::LocalHandle getPointlessLasFile( const std::string outputPath = arbiter::join(tmp, basename); a.put(outputPath, data); - return arbiter::LocalHandle(outputPath, true); + return MaybePointlessFile { + arbiter::LocalHandle(outputPath, true), + pointCount + }; } } // namespace entwine diff --git a/entwine/util/io.hpp b/entwine/util/io.hpp index 97d2dcdd..2388a465 100644 --- a/entwine/util/io.hpp +++ b/entwine/util/io.hpp @@ -10,6 +10,7 @@ #pragma once +#include #include #include #include @@ -76,7 +77,12 @@ arbiter::LocalHandle ensureGetLocalHandle( const std::string& path, int tries = defaultTries); -arbiter::LocalHandle getPointlessLasFile( +struct MaybePointlessFile +{ + arbiter::LocalHandle handle; + uint64_t pointCount = 0; +}; +MaybePointlessFile getPointlessLasFile( const std::string& path, const std::string& tmp, const arbiter::Arbiter& a);