From 7732018c633c81bded3c5fb6edef1803f9f3250a Mon Sep 17 00:00:00 2001 From: cwhite911 Date: Tue, 24 Mar 2026 13:43:10 -0400 Subject: [PATCH] r.in.pdal: Added ability to read COPC data --- raster/r.in.pdal/grassrasterwriter.h | 12 ++++++--- raster/r.in.pdal/info.cpp | 12 +++++++++ raster/r.in.pdal/main.cpp | 37 +++++++++++++++++++++++++--- 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/raster/r.in.pdal/grassrasterwriter.h b/raster/r.in.pdal/grassrasterwriter.h index 4588cda7988..4e0155a85e0 100644 --- a/raster/r.in.pdal/grassrasterwriter.h +++ b/raster/r.in.pdal/grassrasterwriter.h @@ -39,7 +39,13 @@ class GrassRasterWriter : public pdal::NoFilenameWriter, class GrassRasterWriter : public pdal::Writer, public pdal::Streamable { #endif public: - GrassRasterWriter() : n_processed(0) {} + GrassRasterWriter() + : n_processed(0), region_(nullptr), point_binning_(nullptr), + bin_index_nodes_(nullptr), rtype_(FCELL_TYPE), cols_(0), scale_(1.0), + dim_to_import_(pdal::Dimension::Id::Z), base_segment_(nullptr), + input_region_(nullptr), base_raster_data_type_(FCELL_TYPE) + { + } std::string getName() const { return "writers.grassbinning"; } @@ -105,8 +111,8 @@ class GrassRasterWriter : public pdal::Writer, public pdal::Streamable { int arr_col = (int)((x - region_->west) / region_->ew_res); if (arr_row >= region_->rows || arr_col >= region_->cols) { - G_message(_("A point on the edge of computational region detected. " - "Ignoring.")); + G_debug(3, "A point on the edge of computational region detected. " + "Ignoring."); return false; } diff --git a/raster/r.in.pdal/info.cpp b/raster/r.in.pdal/info.cpp index e6e62af587b..0687f1374b5 100644 --- a/raster/r.in.pdal/info.cpp +++ b/raster/r.in.pdal/info.cpp @@ -140,6 +140,14 @@ void print_lasinfo(struct StringList *infiles) const pdal::LasHeader &h = las_reader.header(); pdal::PointLayoutPtr point_layout = table.layout(); const pdal::Dimension::IdList &dims = point_layout->dims(); + pdal::SpatialReference spatial_reference = table.spatialReference(); + /* COPC and some other readers only populate the point table SRS after + * execute(); fall back to reading it from the reader stages directly. + */ + if (spatial_reference.empty()) { + spatial_reference = las_reader.getSpatialReference(); + } + std::string proj_wkt = spatial_reference.getWKT(); std::cout << "File: " << infile << std::endl; std::cout << "File version = " @@ -153,6 +161,10 @@ void print_lasinfo(struct StringList *infiles) std::cout << "Creation DOY: " << h.creationDOY() << "\n"; std::cout << "Creation Year: " << h.creationYear() << "\n"; std::cout << "VLR offset (header size): " << h.vlrOffset() << "\n"; + if (!proj_wkt.empty()) + std::cout << "Projection (WKT): " << proj_wkt << "\n"; + else + std::cout << "Projection: (undefined)" << "\n"; std::cout << "VLR Count: " << h.vlrCount() << "\n"; std::cout << "Point format: " << (int)h.pointFormat() << "\n"; std::cout << "Point offset: " << h.pointOffset() << "\n"; diff --git a/raster/r.in.pdal/main.cpp b/raster/r.in.pdal/main.cpp index fe17e80cb08..7968e3a72ab 100644 --- a/raster/r.in.pdal/main.cpp +++ b/raster/r.in.pdal/main.cpp @@ -371,6 +371,21 @@ int main(int argc, char *argv[]) user_dimension_opt->description = _("PDAL dimension name"); user_dimension_opt->guisection = _("Selection"); + Option *point_table_capacity_opt = G_define_option(); + + point_table_capacity_opt->key = "point_table_capacity"; + point_table_capacity_opt->type = TYPE_INTEGER; + point_table_capacity_opt->required = NO; + point_table_capacity_opt->answer = const_cast("10000"); + + point_table_capacity_opt->description = + _("Set capacity of point table used for buffering points during " + "processing. " + "Increasing this value may improve performance for large datasets, " + "but also increases memory usage. Default is 10,000 points, which " + "should be sufficient for most cases."); + point_table_capacity_opt->guisection = _("Performance"); + Flag *extents_flag = G_define_flag(); extents_flag->key = 'e'; @@ -796,9 +811,13 @@ int main(int argc, char *argv[]) binning_writer.set_output_scale(output_scale); binning_writer.setInput(grass_filter); // stream_filter.setInput(*last_stage); - // there is no difference between 1 and 10k points in memory - // consumption, so using 10k in case it is faster for some cases - pdal::point_count_t point_table_capacity = 10000; + // there is no difference between 1 and 10k points in memory + // consumption, so using 10k in case it is faster for some cases + // Added user option to set point table capacity to a higher value, which + // may improve performance for large datasets but also increases memory + // usage + pdal::point_count_t point_table_capacity = + atoi(point_table_capacity_opt->answer); pdal::FixedPointTable point_table(point_table_capacity); try { binning_writer.prepare(point_table); @@ -815,7 +834,17 @@ int main(int argc, char *argv[]) } else if (!reproject_flag->answer) { pdal::SpatialReference spatial_reference = - merge_filter.getSpatialReference(); + point_table.spatialReference(); + /* COPC and some other readers only populate the point table SRS after + * execute(); fall back to reading it from the reader stages directly. + */ + if (spatial_reference.empty()) { + for (pdal::Stage *reader : readers) { + spatial_reference = reader->getSpatialReference(); + if (!spatial_reference.empty()) + break; + } + } if (spatial_reference.empty()) G_fatal_error(_("The input dataset has undefined projection")); std::string dataset_wkt = spatial_reference.getWKT();