From f58d9dc135bde5f1ac99a03d70c5153adebc0778 Mon Sep 17 00:00:00 2001 From: mwlasiuk Date: Mon, 16 Feb 2026 19:47:29 +0100 Subject: [PATCH] Add laz to txt and add intensityu and timestamp to laz to ply --- apps/console_tools/CMakeLists.txt | 6 +- apps/console_tools/laz_to_ply.cpp | 25 ++++-- apps/console_tools/laz_to_txt.cpp | 136 ++++++++++++++++++++++++++++++ 3 files changed, 161 insertions(+), 6 deletions(-) create mode 100644 apps/console_tools/laz_to_txt.cpp diff --git a/apps/console_tools/CMakeLists.txt b/apps/console_tools/CMakeLists.txt index a97f4a57..84b50a8e 100644 --- a/apps/console_tools/CMakeLists.txt +++ b/apps/console_tools/CMakeLists.txt @@ -38,4 +38,8 @@ target_include_directories(laz_to_pcd PRIVATE ${LASZIP_INCLUDE_DIR}/LASzip/inclu add_executable(pcd_to_laz pcd_to_laz.cpp) target_link_libraries(pcd_to_laz PRIVATE ${PLATFORM_LASZIP_LIB}) -target_include_directories(pcd_to_laz PRIVATE ${LASZIP_INCLUDE_DIR}/LASzip/include ${PROJECT_BINARY_DIR}/include) \ No newline at end of file +target_include_directories(pcd_to_laz PRIVATE ${LASZIP_INCLUDE_DIR}/LASzip/include ${PROJECT_BINARY_DIR}/include) + +add_executable(laz_to_txt laz_to_txt.cpp) +target_link_libraries(laz_to_txt PRIVATE ${PLATFORM_LASZIP_LIB}) +target_include_directories(laz_to_txt PRIVATE ${LASZIP_INCLUDE_DIR}/LASzip/include ${PROJECT_BINARY_DIR}/include) \ No newline at end of file diff --git a/apps/console_tools/laz_to_ply.cpp b/apps/console_tools/laz_to_ply.cpp index 7945cf05..c494820f 100644 --- a/apps/console_tools/laz_to_ply.cpp +++ b/apps/console_tools/laz_to_ply.cpp @@ -6,6 +6,17 @@ #include #include +struct Point +{ + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; + float intensity = 0.0f; + double timestamp = 0.0; +}; + +static_assert(sizeof(Point) == 24, "Invalid Point struct size!"); + bool check_path_ext(const char* path, const char* ext) { return std::filesystem::path(path).extension() == ext; @@ -39,7 +50,7 @@ bool convert_and_save(const char* from, const char* to) laszip_I64 point_count = header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records; - std::vector points(point_count * 3); + std::vector points(point_count); laszip_I64 point_read_count = 0; while (point_read_count < point_count) @@ -49,9 +60,11 @@ bool convert_and_save(const char* from, const char* to) return false; } - points[point_read_count * 3 + 0] = header->x_offset + header->x_scale_factor * static_cast(point->X); - points[point_read_count * 3 + 1] = header->y_offset + header->y_scale_factor * static_cast(point->Y); - points[point_read_count * 3 + 2] = header->z_offset + header->z_scale_factor * static_cast(point->Z); + points[point_read_count].x = header->x_offset + header->x_scale_factor * static_cast(point->X); + points[point_read_count].y = header->y_offset + header->y_scale_factor * static_cast(point->Y); + points[point_read_count].z = header->z_offset + header->z_scale_factor * static_cast(point->Z); + points[point_read_count].intensity = static_cast(point->intensity); + points[point_read_count].timestamp = static_cast(point->gps_time); point_read_count++; } @@ -64,9 +77,11 @@ bool convert_and_save(const char* from, const char* to) to_file << "property float x\n"; to_file << "property float y\n"; to_file << "property float z\n"; + to_file << "property float intensity\n"; + to_file << "property double timestamp\n"; to_file << "end_header\n"; - to_file.write((const char*)points.data(), points.size() * sizeof(float)); + to_file.write((const char*)points.data(), points.size() * sizeof(Point)); } else { diff --git a/apps/console_tools/laz_to_txt.cpp b/apps/console_tools/laz_to_txt.cpp new file mode 100644 index 00000000..03406821 --- /dev/null +++ b/apps/console_tools/laz_to_txt.cpp @@ -0,0 +1,136 @@ +#include + +#include +#include +#include +#include +#include + +struct Point +{ + float x = 0.0f; + float y = 0.0f; + float z = 0.0f; + float intensity = 0.0f; + double timestamp = 0.0; +}; + +static_assert(sizeof(Point) == 24, "Invalid Point struct size!"); + +bool check_path_ext(const char* path, const char* ext) +{ + return std::filesystem::path(path).extension() == ext; +} + +bool convert_and_save(const char* from, const char* to) +{ + laszip_POINTER laszip_reader = nullptr; + if (laszip_create(&laszip_reader)) + { + return false; + } + + laszip_BOOL is_compressed = 0; + if (laszip_open_reader(laszip_reader, from, &is_compressed)) + { + return false; + } + + laszip_header* header = nullptr; + if (laszip_get_header_pointer(laszip_reader, &header)) + { + return false; + } + + laszip_point* point = nullptr; + if (laszip_get_point_pointer(header, &point)) + { + return false; + } + + laszip_I64 point_count = header->number_of_point_records ? header->number_of_point_records : header->extended_number_of_point_records; + + std::vector points(point_count); + + laszip_I64 point_read_count = 0; + while (point_read_count < point_count) + { + if (laszip_read_point(header)) + { + return false; + } + + points[point_read_count].x = header->x_offset + header->x_scale_factor * static_cast(point->X); + points[point_read_count].y = header->y_offset + header->y_scale_factor * static_cast(point->Y); + points[point_read_count].z = header->z_offset + header->z_scale_factor * static_cast(point->Z); + points[point_read_count].intensity = static_cast(point->intensity); + points[point_read_count].timestamp = static_cast(point->gps_time); + + point_read_count++; + } + + if (std::ofstream to_file = std::ofstream(to, std::ios::out)) + { + for (const auto& point : points) + { + to_file << point.x << ' ' << point.y << ' ' << point.z << ' ' << point.intensity << ' ' << point.timestamp << '\n'; + } + + to_file.write((const char*)points.data(), points.size() * sizeof(Point)); + } + else + { + return false; + } + + return true; +} + +int main(const int argc, const char** argv) +{ + const int expected_argc = 3; + + const char* expected_laz_extension = ".laz"; + const char* expected_ply_extension = ".txt"; + + if (argc != expected_argc) + { + std::fprintf(stderr, "Invalid argument count. Got %d expected %d.\n", argc, expected_argc); + std::fprintf(stderr, "Usage : %s \n", argv[0]); + + return EXIT_FAILURE; + } + + const char* from = argv[1]; + const char* to = argv[2]; + + if (!check_path_ext(from, expected_laz_extension)) + { + std::fprintf(stderr, "Invalid extension for input file %s - expected %s\n", from, expected_laz_extension); + + return EXIT_FAILURE; + } + + if (!check_path_ext(to, expected_ply_extension)) + { + std::fprintf(stderr, "Invalid extension for output file %s - expected %s\n", from, expected_ply_extension); + + return EXIT_FAILURE; + } + + if (!std::filesystem::exists(from)) + { + std::fprintf(stderr, "Input file %s - does not exist\n", from); + + return EXIT_FAILURE; + } + + if (!convert_and_save(from, to)) + { + std::fprintf(stderr, "Conversion from %s to %s failed\n", from, to); + + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} \ No newline at end of file