Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
lcov --remove coverage.info '/usr/*' --output-file coverage.info
lcov --list coverage.info
- name: Upload coverage to codecov
uses: codecov/codecov-action@5c93f7ab87f1aa9b956609bbc4b50a6e747fe2fb
uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: coverage.info
Expand Down
4 changes: 2 additions & 2 deletions src/las_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,14 @@ class LASReader {
if (record.is_ogc_math_transform_wkt()) {
std::vector<char> wkt(record.record_length_after_header);
LASPP_CHECK_READ(*m_input_stream, wkt.data(), record.record_length_after_header);
std::string wkt_string(wkt.begin(), wkt.end());
std::string wkt_string(las_packed_string(std::string_view(wkt.data(), wkt.size())));
LASPP_ASSERT(!m_math_wkt.has_value(), "Multiple math WKTs found in header");
m_math_wkt.emplace(wkt_string);
}
if (record.is_ogc_coordinate_system_wkt()) {
std::vector<char> wkt(record.record_length_after_header);
LASPP_CHECK_READ(*m_input_stream, wkt.data(), record.record_length_after_header);
std::string wkt_string(wkt.data(), wkt.size() - 1);
std::string wkt_string(las_packed_string(std::string_view(wkt.data(), wkt.size())));
LASPP_ASSERT(!m_coordinate_wkt.has_value(), "Multiple coordinate WKTs found in header");
m_coordinate_wkt.emplace(wkt_string);
}
Expand Down
77 changes: 77 additions & 0 deletions src/tests/test_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,83 @@ int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
}
}

{
// Some LAS writers store WKT without a trailing null byte, using the full
// VLR record length for the WKT text (record_id 2112).
const std::string wkt = "WKT_WITHOUT_NULL_BYTE";
std::stringstream stream;
{
LASWriter writer(stream, 0, 0);

LASVLR wkt_vlr;
wkt_vlr.reserved = 0;
string_to_arr("LASF_Projection", wkt_vlr.user_id);
wkt_vlr.record_id = 2112;
wkt_vlr.record_length_after_header = static_cast<uint16_t>(wkt.size());
string_to_arr("OGC WKT", wkt_vlr.description);
writer.write_vlr(wkt_vlr,
std::span(reinterpret_cast<const std::byte*>(wkt.data()), wkt.size()));

std::vector<LASPointFormat0> points(1);
writer.write_points(std::span<const LASPointFormat0>(points));
}

LASReader reader(stream);
LASPP_ASSERT_EQ(reader.coordinate_wkt().value(), wkt);
LASPP_ASSERT(!reader.math_wkt().has_value());
}

{
// Test math transform WKT (record_id 2111) written via write_wkt with the
// math_transform_wkt flag. The writer includes a trailing null byte.
const std::string math_wkt = "MATH_TRANSFORM_WKT";
std::stringstream stream;
{
LASWriter writer(stream, 0, 0);

// Write coordinate WKT first so we can verify wkt() returns it preferentially
writer.write_wkt("COORDINATE_WKT");
writer.write_wkt(math_wkt, true);

std::vector<LASPointFormat0> points(1);
writer.write_points(std::span<const LASPointFormat0>(points));
}

LASReader reader(stream);
LASPP_ASSERT_EQ(reader.coordinate_wkt().value(), "COORDINATE_WKT");
LASPP_ASSERT_EQ(reader.math_wkt().value(), math_wkt);
// wkt() should return coordinate_wkt when both are present
LASPP_ASSERT_EQ(reader.wkt().value(), "COORDINATE_WKT");
}

{
// Math transform WKT without a trailing null byte (record_id 2111), matching
// the no-null-byte pattern tested for record_id 2112 above.
const std::string math_wkt = "MATH_WKT_NO_NULL";
std::stringstream stream;
{
LASWriter writer(stream, 0, 0);

LASVLR wkt_vlr;
wkt_vlr.reserved = 0;
string_to_arr("LASF_Projection", wkt_vlr.user_id);
wkt_vlr.record_id = 2111;
wkt_vlr.record_length_after_header = static_cast<uint16_t>(math_wkt.size());
string_to_arr("OGC WKT", wkt_vlr.description);
writer.write_vlr(
wkt_vlr, std::span(reinterpret_cast<const std::byte*>(math_wkt.data()), math_wkt.size()));

std::vector<LASPointFormat0> points(1);
writer.write_points(std::span<const LASPointFormat0>(points));
}

LASReader reader(stream);
LASPP_ASSERT_EQ(reader.math_wkt().value(), math_wkt);
LASPP_ASSERT(!reader.coordinate_wkt().has_value());
// wkt() falls back to math_wkt when coordinate_wkt is absent
LASPP_ASSERT_EQ(reader.wkt().value(), math_wkt);
}

{
// Format 5 includes WavePacketData which is not supported in compressed mode
// So we only test uncompressed format 5
Expand Down
2 changes: 2 additions & 0 deletions src/vlr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ class LASGeoKeys {
};

// Fixed-width LAS string (user_id, description, ...): may omit a trailing NUL.
// Also used for WKT VLR payloads where some writers omit the trailing null and
// store the WKT in the full record_length_after_header bytes.
inline std::string_view las_packed_string(std::string_view raw) {
const auto z = raw.find('\0');
return z == std::string_view::npos ? raw : raw.substr(0, z);
Expand Down
Loading