diff --git a/DESCRIPTION b/DESCRIPTION index 163fecd..78056e1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: rlas Type: Package Title: Read and Write 'las' and 'laz' Binary File Formats Used for Remote Sensing Data -Version: 1.6.4 +Version: 1.7.0 Authors@R: c( person("Jean-Romain", "Roussel", email = "jean-romain.roussel.1@ulaval.ca", role = c("aut", "cre", "cph")), person("Florian", "De Boissieu", email = "", role = c("aut", "ctb"), comment = "Enable the support of .lax file and extra byte attributes"), diff --git a/NEWS.md b/NEWS.md index 876ef6c..feffdf3 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,7 @@ -### rlas v1.6.4 +### rlas v1.7.0 - support of Text Area Description [#64](https://github.com/r-lidar/rlas/pull/64) +- support of COPC spatial indexed files ### rlas v1.6.3 diff --git a/src/LASlib/lasdefinitions.hpp b/src/LASlib/lasdefinitions.hpp index a3570f7..397400e 100644 --- a/src/LASlib/lasdefinitions.hpp +++ b/src/LASlib/lasdefinitions.hpp @@ -16,11 +16,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2005-2018, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2005-2018, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -31,6 +31,7 @@ CHANGE HISTORY: + 9 November 2022 -- support of COPC VLR and EVLR 19 April 2017 -- support for selective decompression for new LAS 1.4 points 1 February 2017 -- better support for OGC WKT strings in VLRs or EVLRs 22 June 2016 -- set default of VLR header "reserved" to 0 instead of 0xAABB @@ -49,7 +50,7 @@ #ifndef LAS_DEFINITIONS_HPP #define LAS_DEFINITIONS_HPP -#define LAS_TOOLS_VERSION 210117 +#define LAS_TOOLS_VERSION 221128 #include #include @@ -84,6 +85,10 @@ #define LAS_TOOLS_IO_IBUFFER_SIZE 262144 #define LAS_TOOLS_IO_OBUFFER_SIZE 262144 +#ifndef MAX_PATH // linux +#define MAX_PATH 256 +#endif + class LASvlr { public: @@ -154,6 +159,39 @@ class LASvlr_wave_packet_descr U8 data[26]; }; +class LASvlr_copc_info +{ +public: + F64 center_x; // Actual (unscaled) X coordinate of center of octree + F64 center_y; // Actual (unscaled) Y coordinate of center of octree + F64 center_z; // Actual (unscaled) Z coordinate of center of octree + F64 halfsize; // Perpendicular distance from the center to any side of the root node. + F64 spacing; // Space between points at the root node. This value is halved at each octree level + U64 root_hier_offset; // File offset to the first hierarchy page + U64 root_hier_size; // Size of the first hierarchy page in bytes + F64 gpstime_minimum; // Minimum of GPSTime + F64 gpstime_maximum; // Maximum of GPSTime + U64 reserved[11]; // Must be 0 +}; + +class LAScopc_voxelkey +{ +public: + I32 depth; + I32 x; + I32 y; + I32 z; +}; + +class LASvlr_copc_entry +{ +public: + LAScopc_voxelkey key; + U64 offset; + I32 byte_size; + I32 point_count; +}; + class LASheader : public LASquantizer, public LASattributer { public: @@ -207,6 +245,11 @@ class LASheader : public LASquantizer, public LASattributer LASvlr_classification* vlr_classification; LASvlr_wave_packet_descr** vlr_wave_packet_descr; + // LAZ 1.4 format 6 7 8 with COPC only + U32 number_of_copc_entries; + LASvlr_copc_info* vlr_copc_info; + LASvlr_copc_entry* vlr_copc_entries; + LASzip* laszip; LASvlr_lastiling* vlr_lastiling; LASvlr_lasoriginal* vlr_lasoriginal; @@ -327,6 +370,10 @@ class LASheader : public LASquantizer, public LASattributer vlr_classification = 0; if (vlr_wave_packet_descr) delete [] vlr_wave_packet_descr; vlr_wave_packet_descr = 0; + if (vlr_copc_info) delete vlr_copc_info; + vlr_copc_info = 0; + if (vlr_copc_entries) delete [] vlr_copc_entries; + vlr_copc_entries = 0; number_of_variable_length_records = 0; } }; @@ -640,11 +687,11 @@ class LASheader : public LASquantizer, public LASattributer { if (keep_existing) { - i = number_of_variable_length_records; + i = number_of_extended_variable_length_records; } else { - for (i = 0; i < number_of_variable_length_records; i++) + for (i = 0; i < number_of_extended_variable_length_records; i++) { if ((strcmp(evlrs[i].user_id, user_id) == 0) && (evlrs[i].record_id == record_id)) { @@ -925,6 +972,23 @@ class LASheader : public LASquantizer, public LASattributer } } + void del_copc() + { + if (vlr_copc_info) + { + remove_vlr("copc", 1); + delete vlr_copc_info; + vlr_copc_info = 0; + } + + if (vlr_copc_entries) + { + remove_evlr("copc", 1000); + delete[] vlr_copc_entries; + vlr_copc_entries = 0; + } + } + void set_geo_ogc_wkt(const I32 num_geo_ogc_wkt, const CHAR* geo_ogc_wkt, BOOL in_evlr=FALSE) { I32 null_terminator = 0; diff --git a/src/LASlib/lasreader.cpp b/src/LASlib/lasreader.cpp index 42f1904..68bdf91 100644 --- a/src/LASlib/lasreader.cpp +++ b/src/LASlib/lasreader.cpp @@ -1,37 +1,33 @@ /* =============================================================================== - FILE: lasreader.cpp + FILE: lasreader.cpp - CONTENTS: + CONTENTS: - see corresponding header file + see corresponding header file - PROGRAMMERS: + PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de - COPYRIGHT: + COPYRIGHT: - (c) 2005-2019, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2005-2019, rapidlasso GmbH - fast tools to catch reality - This is free software; you can redistribute and/or modify it under the - terms of the GNU Lesser General Licence as published by the Free Software - Foundation. See the LICENSE.txt file for more information. + This is free software; you can redistribute and/or modify it under the + terms of the GNU Lesser General Licence as published by the Free Software + Foundation. See the LICENSE.txt file for more information. - This software is distributed WITHOUT ANY WARRANTY and without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + This software is distributed WITHOUT ANY WARRANTY and without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - CHANGE HISTORY: + CHANGE HISTORY: - see corresponding header file + see corresponding header file =============================================================================== */ -#ifdef _WIN32 -#include -#endif - #include "lasreader.hpp" #include "lasindex.hpp" @@ -53,2410 +49,2628 @@ #include "lasreaderbuffered.hpp" #include "lasreaderstored.hpp" #include "lasreaderpipeon.hpp" +#include "lascopc.hpp" #include #include LASreader::LASreader() { - npoints = 0; - p_count = 0; - read_simple = &LASreader::read_point_default; - read_complex = 0; - index = 0; - filter = 0; - transform = 0; - ignore = 0; - inside = 0; - t_ll_x = 0; - t_ll_y = 0; - t_size = 0; - t_ur_x = 0; - t_ur_y = 0; - c_center_x = 0; - c_center_y = 0; - c_radius = 0; - c_radius_squared = 0; - r_min_x = 0; - r_min_y = 0; - r_max_x = 0; - r_max_y = 0; - orig_min_x = 0; - orig_min_y = 0; - orig_max_x = 0; - orig_max_y = 0; + npoints = 0; + p_count = 0; + read_simple = &LASreader::read_point_default; + read_complex = 0; + index = 0; + copc_index = 0; + filter = 0; + transform = 0; + ignore = 0; + inside = 0; + t_ll_x = 0; + t_ll_y = 0; + t_size = 0; + t_ur_x = 0; + t_ur_y = 0; + c_center_x = 0; + c_center_y = 0; + c_radius = 0; + c_radius_squared = 0; + r_min_x = 0; + r_min_y = 0; + r_max_x = 0; + r_max_y = 0; + orig_min_x = 0; + orig_min_y = 0; + orig_max_x = 0; + orig_max_y = 0; } LASreader::~LASreader() { - if (index) delete index; - if (transform) transform->check_for_overflow(); + if (index) delete index; + if (copc_index) delete copc_index; + if (transform) transform->check_for_overflow(); } void LASreader::dealloc() { - delete this; + delete this; } void LASreader::set_index(LASindex* index) { - if (this->index) delete this->index; - this->index = index; + if (this->index) delete this->index; + this->index = index; } -void LASreader::set_filter(LASfilter* filter) +void LASreader::set_copcindex(COPCindex* copc_index) { - this->filter = filter; - if (filter && transform) - { - read_simple = &LASreader::read_point_filtered_and_transformed; - } - else if (filter) - { - read_simple = &LASreader::read_point_filtered; - } - else if (transform) - { - read_simple = &LASreader::read_point_transformed; - } - else + if (!this->copc_index) { - read_simple = &LASreader::read_point_default; + if (this->copc_index) delete this->copc_index; + this->copc_index = copc_index; } - read_complex = &LASreader::read_point_default; +} + +void LASreader::set_filter(LASfilter* filter) +{ + this->filter = filter; + if (filter && transform) + { + read_simple = &LASreader::read_point_filtered_and_transformed; + } + else if (filter) + { + read_simple = &LASreader::read_point_filtered; + } + else if (transform) + { + read_simple = &LASreader::read_point_transformed; + } + else + { + read_simple = &LASreader::read_point_default; + } + read_complex = &LASreader::read_point_default; } void LASreader::set_transform(LAStransform* transform) { - this->transform = transform; - if (filter && transform) - { - read_simple = &LASreader::read_point_filtered_and_transformed; - } - else if (filter) - { - read_simple = &LASreader::read_point_filtered; - } - else if (transform) - { - read_simple = &LASreader::read_point_transformed; - } - else - { - read_simple = &LASreader::read_point_default; - } - read_complex = &LASreader::read_point_default; + this->transform = transform; + if (filter && transform) + { + read_simple = &LASreader::read_point_filtered_and_transformed; + } + else if (filter) + { + read_simple = &LASreader::read_point_filtered; + } + else if (transform) + { + read_simple = &LASreader::read_point_transformed; + } + else + { + read_simple = &LASreader::read_point_default; + } + read_complex = &LASreader::read_point_default; } void LASreader::set_ignore(LASignore* ignore) { - this->ignore = ignore; + this->ignore = ignore; } BOOL LASreader::inside_none() { - if (filter || transform) - { - read_complex = &LASreader::read_point_default; - } - else - { - read_simple = &LASreader::read_point_default; - } - if (inside) - { - header.min_x = orig_min_x; - header.min_y = orig_min_y; - header.max_x = orig_max_x; - header.max_y = orig_max_y; - inside = 0; - } - return TRUE; + if (filter || transform) + { + read_complex = &LASreader::read_point_default; + } + else + { + read_simple = &LASreader::read_point_default; + } + if (inside) + { + header.min_x = orig_min_x; + header.min_y = orig_min_y; + header.max_x = orig_max_x; + header.max_y = orig_max_y; + inside = 0; + } + return TRUE; } BOOL LASreader::inside_tile(const F32 ll_x, const F32 ll_y, const F32 size) { - inside = 1; - t_ll_x = ll_x; - t_ll_y = ll_y; - t_size = size; - t_ur_x = ll_x + size; - t_ur_y = ll_y + size; - orig_min_x = header.min_x; - orig_min_y = header.min_y; - orig_max_x = header.max_x; - orig_max_y = header.max_y; - header.min_x = ll_x; - header.min_y = ll_y; - header.max_x = ll_x + size; - header.max_y = ll_y + size; - header.max_x -= header.x_scale_factor; - header.max_y -= header.y_scale_factor; - if (((orig_min_x > header.max_x) || (orig_min_y > header.max_y) || (orig_max_x < header.min_x) || (orig_max_y < header.min_y))) - { - if (filter || transform) - { - read_complex = &LASreader::read_point_none; - } - else - { - read_simple = &LASreader::read_point_none; - } - } - else if (filter || transform) - { - if (index) - { - if (index) index->intersect_tile(ll_x, ll_y, size); - read_complex = &LASreader::read_point_inside_tile_indexed; - } - else - { - read_complex = &LASreader::read_point_inside_tile; - } - } - else - { - if (index) - { - if (index) index->intersect_tile(ll_x, ll_y, size); - read_simple = &LASreader::read_point_inside_tile_indexed; - } - else - { - read_simple = &LASreader::read_point_inside_tile; - } - } - return TRUE; + inside = 1; + t_ll_x = ll_x; + t_ll_y = ll_y; + t_size = size; + t_ur_x = ll_x + size; + t_ur_y = ll_y + size; + orig_min_x = header.min_x; + orig_min_y = header.min_y; + orig_max_x = header.max_x; + orig_max_y = header.max_y; + header.min_x = ll_x; + header.min_y = ll_y; + header.max_x = ll_x + size; + header.max_y = ll_y + size; + header.max_x -= header.x_scale_factor; + header.max_y -= header.y_scale_factor; + if (((orig_min_x > header.max_x) || (orig_min_y > header.max_y) || (orig_max_x < header.min_x) || (orig_max_y < header.min_y))) + { + if (filter || transform) + { + read_complex = &LASreader::read_point_none; + } + else + { + read_simple = &LASreader::read_point_none; + } + } + else if (filter || transform) + { + if (index) + { + if (index) index->intersect_tile(ll_x, ll_y, size); + read_complex = &LASreader::read_point_inside_tile_indexed; + } + else + { + read_complex = &LASreader::read_point_inside_tile; + } + } + else + { + if (index) + { + if (index) index->intersect_tile(ll_x, ll_y, size); + read_simple = &LASreader::read_point_inside_tile_indexed; + } + else + { + read_simple = &LASreader::read_point_inside_tile; + } + } + return TRUE; } BOOL LASreader::inside_circle(const F64 center_x, const F64 center_y, const F64 radius) { - inside = 2; - c_center_x = center_x; - c_center_y = center_y; - c_radius = radius; - c_radius_squared = radius*radius; - orig_min_x = header.min_x; - orig_min_y = header.min_y; - orig_max_x = header.max_x; - orig_max_y = header.max_y; - header.min_x = center_x - radius; - header.min_y = center_y - radius; - header.max_x = center_x + radius; - header.max_y = center_y + radius; - if (((orig_min_x > header.max_x) || (orig_min_y > header.max_y) || (orig_max_x < header.min_x) || (orig_max_y < header.min_y))) - { - if (filter || transform) - { - read_complex = &LASreader::read_point_none; - } - else - { - read_simple = &LASreader::read_point_none; - } - } - else if (filter || transform) - { - if (index) - { - if (index) index->intersect_circle(center_x, center_y, radius); - read_complex = &LASreader::read_point_inside_circle_indexed; - } - else - { - read_complex = &LASreader::read_point_inside_circle; - } - } - else - { - if (index) - { - if (index) index->intersect_circle(center_x, center_y, radius); - read_simple = &LASreader::read_point_inside_circle_indexed; - } - else - { - read_simple = &LASreader::read_point_inside_circle; - } - } - return TRUE; + inside = 2; + c_center_x = center_x; + c_center_y = center_y; + c_radius = radius; + c_radius_squared = radius * radius; + orig_min_x = header.min_x; + orig_min_y = header.min_y; + orig_max_x = header.max_x; + orig_max_y = header.max_y; + header.min_x = center_x - radius; + header.min_y = center_y - radius; + header.max_x = center_x + radius; + header.max_y = center_y + radius; + if (((orig_min_x > header.max_x) || (orig_min_y > header.max_y) || (orig_max_x < header.min_x) || (orig_max_y < header.min_y))) + { + if (filter || transform) + { + read_complex = &LASreader::read_point_none; + } + else + { + read_simple = &LASreader::read_point_none; + } + } + else if (filter || transform) + { + if (index) + { + if (index) index->intersect_circle(center_x, center_y, radius); + read_complex = &LASreader::read_point_inside_circle_indexed; + } + else if (copc_index) + { + copc_index->intersect_circle(center_x, center_y, radius); + read_complex = &LASreader::read_point_inside_circle_copc_indexed; + } + else + { + read_complex = &LASreader::read_point_inside_circle; + } + } + else + { + if (index) + { + if (index) index->intersect_circle(center_x, center_y, radius); + read_simple = &LASreader::read_point_inside_circle_indexed; + } + else if (copc_index) + { + copc_index->intersect_circle(center_x, center_y, radius); + read_simple = &LASreader::read_point_inside_circle_copc_indexed; + } + else + { + read_simple = &LASreader::read_point_inside_circle; + } + } + return TRUE; } BOOL LASreader::inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y) { - inside = 3; - r_min_x = min_x; - r_min_y = min_y; - r_max_x = max_x; - r_max_y = max_y; - orig_min_x = header.min_x; - orig_min_y = header.min_y; - orig_max_x = header.max_x; - orig_max_y = header.max_y; - header.min_x = min_x; - header.min_y = min_y; - header.max_x = max_x; - header.max_y = max_y; - if (((orig_min_x > max_x) || (orig_min_y > max_y) || (orig_max_x < min_x) || (orig_max_y < min_y))) - { - if (filter || transform) - { - read_complex = &LASreader::read_point_none; - } - else - { - read_simple = &LASreader::read_point_none; - } - } - else if (filter || transform) - { - if (index) - { - index->intersect_rectangle(min_x, min_y, max_x, max_y); - read_complex = &LASreader::read_point_inside_rectangle_indexed; - } - else - { - read_complex = &LASreader::read_point_inside_rectangle; - } - } - else - { - if (index) - { - index->intersect_rectangle(min_x, min_y, max_x, max_y); - read_simple = &LASreader::read_point_inside_rectangle_indexed; - } - else - { - read_simple = &LASreader::read_point_inside_rectangle; - } - } - return TRUE; + inside = 3; + r_min_x = min_x; + r_min_y = min_y; + r_max_x = max_x; + r_max_y = max_y; + orig_min_x = header.min_x; + orig_min_y = header.min_y; + orig_max_x = header.max_x; + orig_max_y = header.max_y; + header.min_x = min_x; + header.min_y = min_y; + header.max_x = max_x; + header.max_y = max_y; + if (((orig_min_x > max_x) || (orig_min_y > max_y) || (orig_max_x < min_x) || (orig_max_y < min_y))) + { + if (filter || transform) + { + read_complex = &LASreader::read_point_none; + } + else + { + read_simple = &LASreader::read_point_none; + } + } + else if (filter || transform) + { + if (index) + { + index->intersect_rectangle(min_x, min_y, max_x, max_y); + read_complex = &LASreader::read_point_inside_rectangle_indexed; + } + else if (copc_index) + { + copc_index->intersect_rectangle(min_x, min_y, max_x, max_y); + read_complex = &LASreader::read_point_inside_rectangle_copc_indexed; + } + else + { + read_complex = &LASreader::read_point_inside_rectangle; + } + } + else + { + if (index) + { + index->intersect_rectangle(min_x, min_y, max_x, max_y); + read_simple = &LASreader::read_point_inside_rectangle_indexed; + } + else if (copc_index) + { + copc_index->intersect_rectangle(min_x, min_y, max_x, max_y); + read_simple = &LASreader::read_point_inside_rectangle_copc_indexed; + } + else + { + read_simple = &LASreader::read_point_inside_rectangle; + } + } + return TRUE; +} + +BOOL LASreader::inside_copc_depth(const U8 mode, const I32 depth, const F32 resolution) +{ + if (!header.vlr_copc_info) + return FALSE; + + inside_depth = mode; + copc_depth = depth; + copc_resolution = resolution; + + if (mode == 0) + return FALSE; + else if (mode == 1) + copc_index->set_depth_limit(depth); + else if (mode == 2) + copc_index->set_resolution(resolution); + else + return FALSE; + + // If inside we are already using read_point_inside_[rectangle|circle]_copc_indexed + // We do not overwrite read_[simple|complex] with a non spatial aware reader. + if (inside) + return TRUE; + + if (filter || transform) + read_complex = &LASreader::read_point_inside_depth_copc_indexed; + else + read_simple = &LASreader::read_point_inside_depth_copc_indexed; + + return TRUE; } BOOL LASreader::read_point_inside_tile() { - while (read_point_default()) - { - if (point.inside_tile(t_ll_x, t_ll_y, t_ur_x, t_ur_y)) return TRUE; - } - return FALSE; + while (read_point_default()) + { + if (point.inside_tile(t_ll_x, t_ll_y, t_ur_x, t_ur_y)) return TRUE; + } + return FALSE; } BOOL LASreader::read_point_inside_tile_indexed() { - while (index->seek_next((LASreader*)this)) - { - if (read_point_default() && point.inside_tile(t_ll_x, t_ll_y, t_ur_x, t_ur_y)) return TRUE; - } - return FALSE; + while (index->seek_next((LASreader*)this)) + { + if (read_point_default() && point.inside_tile(t_ll_x, t_ll_y, t_ur_x, t_ur_y)) return TRUE; + } + return FALSE; } BOOL LASreader::read_point_inside_circle() { - while (read_point_default()) - { - if (point.inside_circle(c_center_x, c_center_y, c_radius_squared)) return TRUE; - } - return FALSE; + while (read_point_default()) + { + if (point.inside_circle(c_center_x, c_center_y, c_radius_squared)) return TRUE; + } + return FALSE; } BOOL LASreader::read_point_inside_circle_indexed() { - while (index->seek_next((LASreader*)this)) - { - if (read_point_default() && point.inside_circle(c_center_x, c_center_y, c_radius_squared)) return TRUE; - } - return FALSE; + while (index->seek_next((LASreader*)this)) + { + if (read_point_default() && point.inside_circle(c_center_x, c_center_y, c_radius_squared)) return TRUE; + } + return FALSE; +} + +BOOL LASreader::read_point_inside_circle_copc_indexed() +{ + while (copc_index->seek_next((LASreader*)this)) + { + if (read_point_default() && point.inside_circle(c_center_x, c_center_y, c_radius_squared)) return TRUE; + } + return FALSE; } BOOL LASreader::read_point_inside_rectangle() { - while (read_point_default()) - { - if (point.inside_rectangle(r_min_x, r_min_y, r_max_x, r_max_y)) return TRUE; - } - return FALSE; + while (read_point_default()) + { + if (point.inside_rectangle(r_min_x, r_min_y, r_max_x, r_max_y)) return TRUE; + } + return FALSE; } BOOL LASreader::read_point_inside_rectangle_indexed() { - bool inrect; - while (index->seek_next((LASreader*)this)) - { - inrect = point.get_x() >= r_min_x && point.get_x() <= r_max_x && point.get_y() >= r_min_y && point.get_y() <= r_max_y; + while (index->seek_next((LASreader*)this)) + { + if (read_point_default() && point.inside_rectangle(r_min_x, r_min_y, r_max_x, r_max_y)) return TRUE; + } + return FALSE; +} - if (read_point_default() && point.inside_rectangle(r_min_x, r_min_y, r_max_x, r_max_y)) - { - return TRUE; - } - } - return FALSE; +BOOL LASreader::read_point_inside_rectangle_copc_indexed() +{ + bool inrect; + while (copc_index->seek_next((LASreader*)this)) + { + inrect = point.get_x() >= r_min_x && point.get_x() <= r_max_x && point.get_y() >= r_min_y && point.get_y() <= r_max_y; + + if (read_point_default() && point.inside_rectangle(r_min_x, r_min_y, r_max_x, r_max_y)) + { + return TRUE; + } + } + return FALSE; +} + +BOOL LASreader::read_point_inside_depth_copc_indexed() +{ + while (copc_index->seek_next((LASreader*)this)) + { + if (read_point_default()) + { + return TRUE; + } + } + return FALSE; } BOOL LASreader::read_point_none() { - return FALSE; + return FALSE; } BOOL LASreader::read_point_filtered() { - while ((this->*read_complex)()) - { - if (!filter->filter(&point)) return TRUE; - } - return FALSE; + while ((this->*read_complex)()) + { + if (!filter->filter(&point)) return TRUE; + } + return FALSE; } BOOL LASreader::read_point_transformed() { - if ((this->*read_complex)()) - { - transform->transform(&point); - return TRUE; - } - return FALSE; + if ((this->*read_complex)()) + { + transform->transform(&point); + return TRUE; + } + return FALSE; } BOOL LASreader::read_point_filtered_and_transformed() { - if (read_point_filtered()) - { - transform->transform(&point); - return TRUE; - } - return FALSE; + if (read_point_filtered()) + { + transform->transform(&point); + return TRUE; + } + return FALSE; } BOOL LASreadOpener::is_piped() const { - return (!file_names && use_stdin); + return (!file_names && use_stdin); } BOOL LASreadOpener::is_inside() const { - return (inside_tile != 0 || inside_circle != 0 || inside_rectangle != 0); + return (inside_tile != 0 || inside_circle != 0 || inside_rectangle != 0); } I32 LASreadOpener::unparse(CHAR* string) const { - I32 n = 0; - if (inside_tile) - { - n = snprintf(string, 0, "-inside_tile %g %g %g ", inside_tile[0], inside_tile[1], inside_tile[2]); - } - else if (inside_circle) - { - n = snprintf(string, 0, "-inside_circle %lf %lf %lf ", inside_circle[0], inside_circle[1], inside_circle[2]); - } - else if (inside_rectangle) - { - n = snprintf(string, 0, "-inside_rectangle %lf %lf %lf %lf ", inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - } - if (stored) - { - n += snprintf(string + n, 0, "-stored "); - } - if (merged) - { - n += snprintf(string + n, 0, "-merged "); - } - if (files_are_flightlines) - { - if (files_are_flightlines == 1) - { - n += snprintf(string + n, 0, "-faf "); - } - else - { - n += snprintf(string + n, 0, "-faf %d ", files_are_flightlines); - } - } - if (apply_file_source_ID) - { - n += snprintf(string + n, 0, "-apply_file_source_ID "); - } - if (scale_factor) - { - if (scale_factor[2] == 0.0) - { - if ((scale_factor[0] != 0.0) && (scale_factor[1] != 0.0)) - { - n += snprintf(string + n, 0, "-rescale_xy %lf %lf ", scale_factor[0], scale_factor[1]); - } - } - else - { - if ((scale_factor[0] == 0.0) && (scale_factor[1] == 0.0)) - { - n += snprintf(string + n, 0, "-rescale_z %lf ", scale_factor[2]); - } - else - { - n += snprintf(string + n, 0, "-rescale %lf %lf %lf ", scale_factor[0], scale_factor[1], scale_factor[2]); - } - } - } - if (offset) - { - n += snprintf(string + n, 0, "-reoffset %lf %lf %lf ", offset[0], offset[1], offset[2]); - } - else if (auto_reoffset) - { - n += snprintf(string + n, 0, "-auto_reoffset "); - } - if (populate_header) - { - n += snprintf(string + n, 0, "-populate "); - } - if (io_ibuffer_size != LAS_TOOLS_IO_IBUFFER_SIZE) - { - n += snprintf(string + n, 0, "-io_ibuffer %u ", io_ibuffer_size); - } - if (temp_file_base) - { - n += snprintf(string + n, 0, "-temp_files \"%s\" ", temp_file_base); - } - return n; + I32 n = 0; + if (inside_tile) + { + n = snprintf(string, 0, "-inside_tile %g %g %g ", inside_tile[0], inside_tile[1], inside_tile[2]); + } + else if (inside_circle) + { + n = snprintf(string, 0, "-inside_circle %lf %lf %lf ", inside_circle[0], inside_circle[1], inside_circle[2]); + } + else if (inside_rectangle) + { + n = snprintf(string, 0, "-inside_rectangle %lf %lf %lf %lf ", inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + } + if (stored) + { + n += snprintf(string + n, 0, "-stored "); + } + if (merged) + { + n += snprintf(string + n, 0, "-merged "); + } + if (files_are_flightlines) + { + if (files_are_flightlines == 1) + { + n += snprintf(string + n, 0, "-faf "); + } + else + { + n += snprintf(string + n, 0, "-faf %d ", files_are_flightlines); + } + } + if (apply_file_source_ID) + { + n += snprintf(string + n, 0, "-apply_file_source_ID "); + } + if (scale_factor) + { + if (scale_factor[2] == 0.0) + { + if ((scale_factor[0] != 0.0) && (scale_factor[1] != 0.0)) + { + n += snprintf(string + n, 0,"-rescale_xy %lf %lf ", scale_factor[0], scale_factor[1]); + } + } + else + { + if ((scale_factor[0] == 0.0) && (scale_factor[1] == 0.0)) + { + n += snprintf(string + n, 0, "-rescale_z %lf ", scale_factor[2]); + } + else + { + n += snprintf(string + n, 0, "-rescale %lf %lf %lf ", scale_factor[0], scale_factor[1], scale_factor[2]); + } + } + } + if (offset) + { + n += snprintf(string + n, 0, "-reoffset %lf %lf %lf ", offset[0], offset[1], offset[2]); + } + else if (auto_reoffset) + { + n += snprintf(string + n, 0, "-auto_reoffset "); + } + if (populate_header) + { + n += snprintf(string + n, 0, "-populate "); + } + if (io_ibuffer_size != LAS_TOOLS_IO_IBUFFER_SIZE) + { + n += snprintf(string + n, 0, "-io_ibuffer %u ", io_ibuffer_size); + } + if (temp_file_base) + { + n += snprintf(string + n, 0, "-temp_files \"%s\" ", temp_file_base); + } + return n; } BOOL LASreadOpener::is_buffered() const { - return ((buffer_size > 0) && ((file_name_number > 1) || (neighbor_file_name_number > 0))); + return ((buffer_size > 0) && ((file_name_number > 1) || (neighbor_file_name_number > 0))); } BOOL LASreadOpener::is_header_populated() const { - return (populate_header || (file_name && (strstr(file_name, ".las") || strstr(file_name, ".laz") || strstr(file_name, ".LAS") || strstr(file_name, ".LAZ")))); + return (populate_header || (file_name && (strstr(file_name, ".las") || strstr(file_name, ".laz") || strstr(file_name, ".LAS") || strstr(file_name, ".LAZ")))); } void LASreadOpener::reset() { - file_name_current = 0; - file_name = 0; + file_name_current = 0; + file_name = 0; } LASreader* LASreadOpener::open(const CHAR* other_file_name, BOOL reset_after_other) { - if (filter) filter->reset(); - if (transform) transform->reset(); - - if (file_names || other_file_name) - { - use_stdin = FALSE; - if (file_name_current == file_name_number && other_file_name == 0) return 0; - if ((other_file_name == 0) && ((file_name_number > 1) || (file_names_ID)) && merged) - { - LASreaderMerged* lasreadermerged = new LASreaderMerged(); - lasreadermerged->set_scale_factor(scale_factor); - lasreadermerged->set_offset(offset); - lasreadermerged->set_parse_string(parse_string); - lasreadermerged->set_skip_lines(skip_lines); - lasreadermerged->set_populate_header(populate_header); - lasreadermerged->set_keep_lastiling(keep_lastiling); - lasreadermerged->set_translate_intensity(translate_intensity); - lasreadermerged->set_scale_intensity(scale_intensity); - lasreadermerged->set_translate_scan_angle(translate_scan_angle); - lasreadermerged->set_scale_scan_angle(scale_scan_angle); - lasreadermerged->set_io_ibuffer_size(io_ibuffer_size); - if (file_names_ID) - { - for (file_name_current = 0; file_name_current < file_name_number; file_name_current++) lasreadermerged->add_file_name(file_names[file_name_current], file_names_ID[file_name_current]); - } - else - { - for (file_name_current = 0; file_name_current < file_name_number; file_name_current++) lasreadermerged->add_file_name(file_names[file_name_current]); - } - if (!lasreadermerged->open()) - { - REprintf("ERROR: cannot open lasreadermerged with %d file names\n", file_name_number); - delete lasreadermerged; - return 0; - } - if (files_are_flightlines) lasreadermerged->set_files_are_flightlines(files_are_flightlines); - if (apply_file_source_ID) lasreadermerged->set_apply_file_source_ID(TRUE); - if (filter) lasreadermerged->set_filter(filter); - if (transform) lasreadermerged->set_transform(transform); - if (ignore) lasreadermerged->set_ignore(ignore); - if (inside_tile) lasreadermerged->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreadermerged->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreadermerged->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreadermerged)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreadermerged\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreadermerged; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreadermerged\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else if ((buffer_size > 0) && ((file_name_number > 1) || (neighbor_file_name_number > 0))) - { - U32 i; - LASreaderBuffered* lasreaderbuffered = new LASreaderBuffered(); - lasreaderbuffered->set_buffer_size(buffer_size); - lasreaderbuffered->set_scale_factor(scale_factor); - lasreaderbuffered->set_offset(offset); - lasreaderbuffered->set_parse_string(parse_string); - lasreaderbuffered->set_skip_lines(skip_lines); - lasreaderbuffered->set_populate_header(populate_header); - lasreaderbuffered->set_translate_intensity(translate_intensity); - lasreaderbuffered->set_scale_intensity(scale_intensity); - lasreaderbuffered->set_translate_scan_angle(translate_scan_angle); - lasreaderbuffered->set_scale_scan_angle(scale_scan_angle); - if (other_file_name) // special case when other file name was specified - { - file_name = other_file_name; - lasreaderbuffered->set_file_name(other_file_name); - if (reset_after_other) - { - file_name_current = 0; - } - for (i = 0; i < file_name_number; i++) - { - if (strcmp(other_file_name, file_names[i])) - { - lasreaderbuffered->add_neighbor_file_name(file_names[i]); - } - } - if (neighbor_file_name_number) - { - for (i = 0; i < neighbor_file_name_number; i++) - { - if (strcmp(other_file_name, neighbor_file_names[i])) - { - lasreaderbuffered->add_neighbor_file_name(neighbor_file_names[i]); - } - } - } - } - else // usual case for processing on-the-fly buffered files - { - file_name = file_names[file_name_current]; - lasreaderbuffered->set_file_name(file_name); - if (kdtree_rectangles) - { - if (!kdtree_rectangles->was_built()) - { - kdtree_rectangles->build(); - } - kdtree_rectangles->overlap(file_names_min_x[file_name_current]-buffer_size, file_names_min_y[file_name_current]-buffer_size, file_names_max_x[file_name_current]+buffer_size, file_names_max_y[file_name_current]+buffer_size); - if (kdtree_rectangles->has_overlaps()) - { - U32 index; - while (kdtree_rectangles->get_overlap(index)) - { - if (file_name != file_names[index]) - { - lasreaderbuffered->add_neighbor_file_name(file_names[index]); - } - } - } - } - else - { - for (i = 0; i < file_name_number; i++) - { - if (file_name != file_names[i]) - { - lasreaderbuffered->add_neighbor_file_name(file_names[i]); - } - } - } - if (neighbor_file_name_number) - { - if (neighbor_kdtree_rectangles) - { - if (!neighbor_kdtree_rectangles->was_built()) - { - neighbor_kdtree_rectangles->build(); - } - neighbor_kdtree_rectangles->overlap(file_names_min_x[file_name_current]-buffer_size, file_names_min_y[file_name_current]-buffer_size, file_names_max_x[file_name_current]+buffer_size, file_names_max_y[file_name_current]+buffer_size); - if (neighbor_kdtree_rectangles->has_overlaps()) - { - U32 index; - while (neighbor_kdtree_rectangles->get_overlap(index)) - { - if (strcmp(file_name, neighbor_file_names[index])) - { - lasreaderbuffered->add_neighbor_file_name(neighbor_file_names[index]); - } - } - } - } - else - { - for (i = 0; i < neighbor_file_name_number; i++) - { - if (strcmp(file_name, neighbor_file_names[i])) - { - lasreaderbuffered->add_neighbor_file_name(neighbor_file_names[i]); - } - } - } - } - file_name_current++; - } - if (filter) lasreaderbuffered->set_filter(filter); - if (transform) lasreaderbuffered->set_transform(transform); - if (ignore) lasreaderbuffered->set_ignore(ignore); - if (!lasreaderbuffered->open()) - { - REprintf("ERROR: cannot open lasreaderbuffered with %d file names\n", file_name_number+neighbor_file_name_number); - delete lasreaderbuffered; - return 0; - } - if (inside_tile) lasreaderbuffered->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreaderbuffered->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreaderbuffered->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderbuffered)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderbuffered\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderbuffered; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderbuffered\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else - { - if (other_file_name) - { - file_name = other_file_name; - if (reset_after_other) - { - file_name_current = 0; - } - } - else - { - file_name = file_names[file_name_current]; - file_name_current++; - } - if (files_are_flightlines) - { - transform->setPointSource(file_name_current + files_are_flightlines + files_are_flightlines_index); - } - if (strstr(file_name, ".las") || strstr(file_name, ".laz") || strstr(file_name, ".LAS") || strstr(file_name, ".LAZ")) - { - LASreaderLAS* lasreaderlas; - if (scale_factor == 0 && offset == 0) - { - if (auto_reoffset) - lasreaderlas = new LASreaderLASreoffset(); - else - lasreaderlas = new LASreaderLAS(); - } - else if (scale_factor != 0 && offset == 0) - { - if (auto_reoffset) - lasreaderlas = new LASreaderLASrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2]); - else - lasreaderlas = new LASreaderLASrescale(scale_factor[0], scale_factor[1], scale_factor[2]); - } - else if (scale_factor == 0 && offset != 0) - lasreaderlas = new LASreaderLASreoffset(offset[0], offset[1], offset[2]); - else - lasreaderlas = new LASreaderLASrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); - if (!lasreaderlas->open(file_name, io_ibuffer_size, FALSE, decompress_selective)) - { - REprintf("ERROR: cannot open lasreaderlas with file name '%s'\n", file_name); - delete lasreaderlas; - return 0; - } - LASindex* index = new LASindex(); - if (index->read(file_name)) - lasreaderlas->set_index(index); - else - delete index; - if (files_are_flightlines) - { - lasreaderlas->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - } - else if (apply_file_source_ID) - { - transform->setPointSource(lasreaderlas->header.file_source_ID); - } - if (filter) lasreaderlas->set_filter(filter); - if (transform) lasreaderlas->set_transform(transform); - if (ignore) lasreaderlas->set_ignore(ignore); - if (inside_rectangle) lasreaderlas->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreaderlas->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else if (inside_circle) lasreaderlas->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderlas)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderlas\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderlas; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderlas\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else if (strstr(file_name, ".bin") || strstr(file_name, ".BIN")) - { - LASreaderBIN* lasreaderbin; - if (scale_factor == 0 && offset == 0) - lasreaderbin = new LASreaderBIN(); - else if (scale_factor != 0 && offset == 0) - lasreaderbin = new LASreaderBINrescale(scale_factor[0], scale_factor[1], scale_factor[2]); - else if (scale_factor == 0 && offset != 0) - lasreaderbin = new LASreaderBINreoffset(offset[0], offset[1], offset[2]); - else - lasreaderbin = new LASreaderBINrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); - if (!lasreaderbin->open(file_name)) - { - REprintf("ERROR: cannot open lasreaderbin with file name '%s'\n", file_name); - delete lasreaderbin; - return 0; - } - LASindex* index = new LASindex(); - if (index->read(file_name)) - lasreaderbin->set_index(index); - else - delete index; - if (files_are_flightlines) lasreaderbin->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreaderbin->set_filter(filter); - if (transform) lasreaderbin->set_transform(transform); - if (ignore) lasreaderbin->set_ignore(ignore); - if (inside_tile) lasreaderbin->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreaderbin->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreaderbin->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderbin)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderbin\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderbin; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderbin\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else if (strstr(file_name, ".shp") || strstr(file_name, ".SHP")) - { - LASreaderSHP* lasreadershp; - if (scale_factor == 0 && offset == 0) - lasreadershp = new LASreaderSHP(); - else if (scale_factor != 0 && offset == 0) - lasreadershp = new LASreaderSHPrescale(scale_factor[0], scale_factor[1], scale_factor[2]); - else if (scale_factor == 0 && offset != 0) - lasreadershp = new LASreaderSHPreoffset(offset[0], offset[1], offset[2]); - else - lasreadershp = new LASreaderSHPrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); - if (!lasreadershp->open(file_name)) - { - REprintf("ERROR: cannot open lasreadershp with file name '%s'\n", file_name); - delete lasreadershp; - return 0; - } - if (files_are_flightlines) lasreadershp->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreadershp->set_filter(filter); - if (transform) lasreadershp->set_transform(transform); - if (ignore) lasreadershp->set_ignore(ignore); - if (inside_tile) lasreadershp->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreadershp->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreadershp->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreadershp)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreadershp\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreadershp; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreadershp\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else if (strstr(file_name, ".asc") || strstr(file_name, ".ASC")) - { - LASreaderASC* lasreaderasc; - if (scale_factor == 0 && offset == 0) - lasreaderasc = new LASreaderASC(); - else if (scale_factor != 0 && offset == 0) - lasreaderasc = new LASreaderASCrescale(scale_factor[0], scale_factor[1], scale_factor[2]); - else if (scale_factor == 0 && offset != 0) - lasreaderasc = new LASreaderASCreoffset(offset[0], offset[1], offset[2]); - else - lasreaderasc = new LASreaderASCrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); - if (!lasreaderasc->open(file_name, comma_not_point)) - { - REprintf("ERROR: cannot open lasreaderasc with file name '%s'\n", file_name); - delete lasreaderasc; - return 0; - } - if (files_are_flightlines) lasreaderasc->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreaderasc->set_filter(filter); - if (transform) lasreaderasc->set_transform(transform); - if (ignore) lasreaderasc->set_ignore(ignore); - if (inside_tile) lasreaderasc->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreaderasc->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreaderasc->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderasc)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderasc\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderasc; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderasc\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else if (strstr(file_name, ".bil") || strstr(file_name, ".BIL")) - { - LASreaderBIL* lasreaderbil; - if (scale_factor == 0 && offset == 0) - lasreaderbil = new LASreaderBIL(); - else if (scale_factor != 0 && offset == 0) - lasreaderbil = new LASreaderBILrescale(scale_factor[0], scale_factor[1], scale_factor[2]); - else if (scale_factor == 0 && offset != 0) - lasreaderbil = new LASreaderBILreoffset(offset[0], offset[1], offset[2]); - else - lasreaderbil = new LASreaderBILrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); - if (!lasreaderbil->open(file_name)) - { - REprintf("ERROR: cannot open lasreaderbil with file name '%s'\n", file_name); - delete lasreaderbil; - return 0; - } - if (files_are_flightlines) lasreaderbil->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreaderbil->set_filter(filter); - if (transform) lasreaderbil->set_transform(transform); - if (ignore) lasreaderbil->set_ignore(ignore); - if (inside_tile) lasreaderbil->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreaderbil->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreaderbil->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderbil)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderbil\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderbil; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderbil\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else if (strstr(file_name, ".dtm") || strstr(file_name, ".DTM")) - { - LASreaderDTM* lasreaderdtm; - if (scale_factor == 0 && offset == 0) - lasreaderdtm = new LASreaderDTM(); - else if (scale_factor != 0 && offset == 0) - lasreaderdtm = new LASreaderDTMrescale(scale_factor[0], scale_factor[1], scale_factor[2]); - else if (scale_factor == 0 && offset != 0) - lasreaderdtm = new LASreaderDTMreoffset(offset[0], offset[1], offset[2]); - else - lasreaderdtm = new LASreaderDTMrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); - if (!lasreaderdtm->open(file_name)) - { - REprintf("ERROR: cannot open lasreaderdtm with file name '%s'\n", file_name); - delete lasreaderdtm; - return 0; - } - if (files_are_flightlines) lasreaderdtm->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreaderdtm->set_filter(filter); - if (transform) lasreaderdtm->set_transform(transform); - if (ignore) lasreaderdtm->set_ignore(ignore); - if (inside_tile) lasreaderdtm->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreaderdtm->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreaderdtm->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderdtm)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderdtm\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderdtm; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderdtm\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else if (strstr(file_name, ".ply") || strstr(file_name, ".PLY")) - { - LASreaderPLY* lasreaderply = new LASreaderPLY(); - if (translate_intensity != 0.0f) lasreaderply->set_translate_intensity(translate_intensity); - if (scale_intensity != 1.0f) lasreaderply->set_scale_intensity(scale_intensity); - lasreaderply->set_scale_factor(scale_factor); - lasreaderply->set_offset(offset); - if (!lasreaderply->open(file_name, point_type, populate_header)) - { - REprintf("ERROR: cannot open lasreaderply with file name '%s'\n", file_name); - delete lasreaderply; - return 0; - } - if (files_are_flightlines) lasreaderply->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreaderply->set_filter(filter); - if (transform) lasreaderply->set_transform(transform); - if (ignore) lasreaderply->set_ignore(ignore); - if (inside_tile) lasreaderply->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreaderply->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreaderply->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderply)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderply\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderply; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderply\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else if (strstr(file_name, ".qi") || strstr(file_name, ".QI")) - { - LASreaderQFIT* lasreaderqfit; - if (scale_factor == 0 && offset == 0) - lasreaderqfit = new LASreaderQFIT(); - else if (scale_factor != 0 && offset == 0) - lasreaderqfit = new LASreaderQFITrescale(scale_factor[0], scale_factor[1], scale_factor[2]); - else if (scale_factor == 0 && offset != 0) - lasreaderqfit = new LASreaderQFITreoffset(offset[0], offset[1], offset[2]); - else - lasreaderqfit = new LASreaderQFITrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); - if (!lasreaderqfit->open(file_name)) - { - REprintf("ERROR: cannot open lasreaderqfit with file name '%s'\n", file_name); - delete lasreaderqfit; - return 0; - } - LASindex* index = new LASindex(); - if (index->read(file_name)) - lasreaderqfit->set_index(index); - else - delete index; - if (files_are_flightlines) lasreaderqfit->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreaderqfit->set_filter(filter); - if (transform) lasreaderqfit->set_transform(transform); - if (ignore) lasreaderqfit->set_ignore(ignore); - if (inside_tile) lasreaderqfit->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreaderqfit->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreaderqfit->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderqfit)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderqfit\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderqfit; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderqfit\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else - { - LASreaderTXT* lasreadertxt = new LASreaderTXT(); - if (ipts) lasreadertxt->set_pts(TRUE); - else if (iptx) lasreadertxt->set_ptx(TRUE); - if (translate_intensity != 0.0f) lasreadertxt->set_translate_intensity(translate_intensity); - if (scale_intensity != 1.0f) lasreadertxt->set_scale_intensity(scale_intensity); - if (translate_scan_angle != 0.0f) lasreadertxt->set_translate_scan_angle(translate_scan_angle); - if (scale_scan_angle != 1.0f) lasreadertxt->set_scale_scan_angle(scale_scan_angle); - lasreadertxt->set_scale_factor(scale_factor); - lasreadertxt->set_offset(offset); - if (number_attributes) - { - for (I32 i = 0; i < number_attributes; i++) - { - lasreadertxt->add_attribute(attribute_data_types[i], attribute_names[i], attribute_descriptions[i], attribute_scales[i], attribute_offsets[i], attribute_pre_scales[i], attribute_pre_offsets[i], attribute_no_datas[i]); - } - } - if (!lasreadertxt->open(file_name, point_type, parse_string, skip_lines, populate_header)) - { - REprintf("ERROR: cannot open lasreadertxt with file name '%s'\n", file_name); - delete lasreadertxt; - return 0; - } - if (files_are_flightlines) lasreadertxt->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreadertxt->set_filter(filter); - if (transform) lasreadertxt->set_transform(transform); - if (ignore) lasreadertxt->set_ignore(ignore); - if (inside_tile) lasreadertxt->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreadertxt->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreadertxt->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreadertxt)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreadertxt\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreadertxt; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreadertxt\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - } - } - else if (use_stdin) - { - use_stdin = FALSE; populate_header = TRUE; - if (itxt) - { - LASreaderTXT* lasreadertxt = new LASreaderTXT(); - if (ipts) lasreadertxt->set_pts(TRUE); - else if (iptx) lasreadertxt->set_ptx(TRUE); - if (translate_intensity != 0.0f) lasreadertxt->set_translate_intensity(translate_intensity); - if (scale_intensity != 1.0f) lasreadertxt->set_scale_intensity(scale_intensity); - if (translate_scan_angle != 0.0f) lasreadertxt->set_translate_scan_angle(translate_scan_angle); - if (scale_scan_angle != 1.0f) lasreadertxt->set_scale_scan_angle(scale_scan_angle); - lasreadertxt->set_scale_factor(scale_factor); - lasreadertxt->set_offset(offset); - if (number_attributes) - { - for (I32 i = 0; i < number_attributes; i++) - { - lasreadertxt->add_attribute(attribute_data_types[i], attribute_names[i], attribute_descriptions[i], attribute_scales[i], attribute_offsets[i], attribute_pre_scales[i], attribute_pre_offsets[i], attribute_no_datas[i]); - } - } - if (!lasreadertxt->open(stdin, 0, point_type, parse_string, skip_lines, FALSE)) - { - REprintf("ERROR: cannot open lasreadertxt with file name '%s'\n", file_name); - delete lasreadertxt; - return 0; - } - if (files_are_flightlines) lasreadertxt->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; - if (filter) lasreadertxt->set_filter(filter); - if (transform) lasreadertxt->set_transform(transform); - if (ignore) lasreadertxt->set_ignore(ignore); - if (inside_tile) lasreadertxt->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreadertxt->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreadertxt->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreadertxt)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreadertxt\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreadertxt; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreadertxt\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - else - { - LASreaderLAS* lasreaderlas; - if (scale_factor == 0 && offset == 0) - lasreaderlas = new LASreaderLAS(); - else if (scale_factor != 0 && offset == 0) - lasreaderlas = new LASreaderLASrescale(scale_factor[0], scale_factor[1], scale_factor[2]); - else if (scale_factor == 0 && offset != 0) - lasreaderlas = new LASreaderLASreoffset(offset[0], offset[1], offset[2]); - else - lasreaderlas = new LASreaderLASrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); - if (!lasreaderlas->open(stdin)) - { - REprintf("ERROR: cannot open lasreaderlas from stdin \n"); - delete lasreaderlas; - return 0; - } - if (filter) lasreaderlas->set_filter(filter); - if (transform) lasreaderlas->set_transform(transform); - if (ignore) lasreaderlas->set_ignore(ignore); - if (inside_tile) lasreaderlas->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - if (inside_circle) lasreaderlas->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - if (inside_rectangle) lasreaderlas->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - LASreader* lasreader = 0; - if (stored) - { - LASreaderStored* lasreaderstored = new LASreaderStored(); - if (!lasreaderstored->open(lasreaderlas)) - { - REprintf( "ERROR: could not open lasreaderstored with lasreaderlas\n"); - delete lasreaderstored; - return 0; - } - lasreader = lasreaderstored; - } - else - { - lasreader = lasreaderlas; - } - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); - if (!lasreaderpipeon->open(lasreader)) - { - REprintf("ERROR: cannot open lasreaderpipeon with lasreaderlas from stdin\n"); - delete lasreaderpipeon; - return 0; - } - return lasreaderpipeon; - } - else - { - return lasreader; - } - } - } - else - { - return 0; - } + if (filter) filter->reset(); + if (transform) transform->reset(); + + if (file_names || other_file_name) + { + use_stdin = FALSE; + if (file_name_current == file_name_number && other_file_name == 0) return 0; + if ((other_file_name == 0) && ((file_name_number > 1) || (file_names_ID)) && merged) + { + LASreaderMerged* lasreadermerged = new LASreaderMerged(); + lasreadermerged->set_scale_factor(scale_factor); + lasreadermerged->set_offset(offset); + lasreadermerged->set_parse_string(parse_string); + lasreadermerged->set_skip_lines(skip_lines); + lasreadermerged->set_populate_header(populate_header); + lasreadermerged->set_keep_lastiling(keep_lastiling); + lasreadermerged->set_translate_intensity(translate_intensity); + lasreadermerged->set_scale_intensity(scale_intensity); + lasreadermerged->set_translate_scan_angle(translate_scan_angle); + lasreadermerged->set_scale_scan_angle(scale_scan_angle); + lasreadermerged->set_io_ibuffer_size(io_ibuffer_size); + if (file_names_ID) + { + for (file_name_current = 0; file_name_current < file_name_number; file_name_current++) lasreadermerged->add_file_name(file_names[file_name_current], file_names_ID[file_name_current]); + } + else + { + for (file_name_current = 0; file_name_current < file_name_number; file_name_current++) lasreadermerged->add_file_name(file_names[file_name_current]); + } + if (!lasreadermerged->open()) + { + REprintf("ERROR: cannot open lasreadermerged with %d file names\n", file_name_number); + delete lasreadermerged; + return 0; + } + if (files_are_flightlines) lasreadermerged->set_files_are_flightlines(files_are_flightlines); + if (apply_file_source_ID) lasreadermerged->set_apply_file_source_ID(TRUE); + if (filter) lasreadermerged->set_filter(filter); + if (transform) lasreadermerged->set_transform(transform); + if (ignore) lasreadermerged->set_ignore(ignore); + if (inside_tile) lasreadermerged->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreadermerged->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreadermerged->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + if (inside_depth) lasreadermerged->inside_copc_depth(inside_depth, copc_depth, copc_resolution); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreadermerged)) + { + REprintf("ERROR: could not open lasreaderstored with lasreadermerged\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreadermerged; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreadermerged\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else if ((buffer_size > 0) && ((file_name_number > 1) || (neighbor_file_name_number > 0))) + { + U32 i; + LASreaderBuffered* lasreaderbuffered = new LASreaderBuffered(); + lasreaderbuffered->set_buffer_size(buffer_size); + lasreaderbuffered->set_scale_factor(scale_factor); + lasreaderbuffered->set_offset(offset); + lasreaderbuffered->set_parse_string(parse_string); + lasreaderbuffered->set_skip_lines(skip_lines); + lasreaderbuffered->set_populate_header(populate_header); + lasreaderbuffered->set_translate_intensity(translate_intensity); + lasreaderbuffered->set_scale_intensity(scale_intensity); + lasreaderbuffered->set_translate_scan_angle(translate_scan_angle); + lasreaderbuffered->set_scale_scan_angle(scale_scan_angle); + if (other_file_name) // special case when other file name was specified + { + file_name = other_file_name; + lasreaderbuffered->set_file_name(other_file_name); + if (reset_after_other) + { + file_name_current = 0; + } + for (i = 0; i < file_name_number; i++) + { + if (strcmp(other_file_name, file_names[i])) + { + lasreaderbuffered->add_neighbor_file_name(file_names[i]); + } + } + if (neighbor_file_name_number) + { + for (i = 0; i < neighbor_file_name_number; i++) + { + if (strcmp(other_file_name, neighbor_file_names[i])) + { + lasreaderbuffered->add_neighbor_file_name(neighbor_file_names[i]); + } + } + } + } + else // usual case for processing on-the-fly buffered files + { + file_name = file_names[file_name_current]; + lasreaderbuffered->set_file_name(file_name); + if (kdtree_rectangles) + { + if (!kdtree_rectangles->was_built()) + { + kdtree_rectangles->build(); + } + kdtree_rectangles->overlap(file_names_min_x[file_name_current] - buffer_size, file_names_min_y[file_name_current] - buffer_size, file_names_max_x[file_name_current] + buffer_size, file_names_max_y[file_name_current] + buffer_size); + if (kdtree_rectangles->has_overlaps()) + { + U32 index; + while (kdtree_rectangles->get_overlap(index)) + { + if (file_name != file_names[index]) + { + lasreaderbuffered->add_neighbor_file_name(file_names[index]); + } + } + } + } + else + { + for (i = 0; i < file_name_number; i++) + { + if (file_name != file_names[i]) + { + lasreaderbuffered->add_neighbor_file_name(file_names[i]); + } + } + } + if (neighbor_file_name_number) + { + if (neighbor_kdtree_rectangles) + { + if (!neighbor_kdtree_rectangles->was_built()) + { + neighbor_kdtree_rectangles->build(); + } + neighbor_kdtree_rectangles->overlap(file_names_min_x[file_name_current] - buffer_size, file_names_min_y[file_name_current] - buffer_size, file_names_max_x[file_name_current] + buffer_size, file_names_max_y[file_name_current] + buffer_size); + if (neighbor_kdtree_rectangles->has_overlaps()) + { + U32 index; + while (neighbor_kdtree_rectangles->get_overlap(index)) + { + if (strcmp(file_name, neighbor_file_names[index])) + { + lasreaderbuffered->add_neighbor_file_name(neighbor_file_names[index]); + } + } + } + } + else + { + for (i = 0; i < neighbor_file_name_number; i++) + { + if (strcmp(file_name, neighbor_file_names[i])) + { + lasreaderbuffered->add_neighbor_file_name(neighbor_file_names[i]); + } + } + } + } + file_name_current++; + } + if (filter) lasreaderbuffered->set_filter(filter); + if (transform) lasreaderbuffered->set_transform(transform); + if (ignore) lasreaderbuffered->set_ignore(ignore); + if (!lasreaderbuffered->open()) + { + REprintf("ERROR: cannot open lasreaderbuffered with %d file names\n", file_name_number + neighbor_file_name_number); + delete lasreaderbuffered; + return 0; + } + if (inside_tile) lasreaderbuffered->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreaderbuffered->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreaderbuffered->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderbuffered)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderbuffered\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderbuffered; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderbuffered\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else + { + if (other_file_name) + { + file_name = other_file_name; + if (reset_after_other) + { + file_name_current = 0; + } + } + else + { + file_name = file_names[file_name_current]; + file_name_current++; + } + if (files_are_flightlines) + { + transform->setPointSource(file_name_current + files_are_flightlines + files_are_flightlines_index); + } + if (strstr(file_name, ".las") || strstr(file_name, ".laz") || strstr(file_name, ".LAS") || strstr(file_name, ".LAZ")) + { + LASreaderLAS* lasreaderlas; + if (scale_factor == 0 && offset == 0) + { + if (auto_reoffset) + lasreaderlas = new LASreaderLASreoffset(); + else + lasreaderlas = new LASreaderLAS(); + } + else if (scale_factor != 0 && offset == 0) + { + if (auto_reoffset) + lasreaderlas = new LASreaderLASrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2]); + else + lasreaderlas = new LASreaderLASrescale(scale_factor[0], scale_factor[1], scale_factor[2]); + } + else if (scale_factor == 0 && offset != 0) + lasreaderlas = new LASreaderLASreoffset(offset[0], offset[1], offset[2]); + else + lasreaderlas = new LASreaderLASrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); + + lasreaderlas->set_keep_copc(keep_copc); + if (!lasreaderlas->open(file_name, io_ibuffer_size, FALSE, decompress_selective)) + { + REprintf("ERROR: cannot open lasreaderlas with file name '%s'\n", file_name); + delete lasreaderlas; + return 0; + } + LASindex* index = new LASindex(); + if (index->read(file_name)) + lasreaderlas->set_index(index); + else + { + delete index; + index = 0; + } + + // Creation of the COPC index + if (lasreaderlas->header.vlr_copc_entries) + { + if (index) + { + REprintf("WARNING: both LAX file and COPC spatial indexing registered. COPC has the precedence.\n"); + delete index; + index = 0; + } + + COPCindex *copc_index = new COPCindex(lasreaderlas->header); + if (copc_stream_order == 0) copc_index->set_stream_ordered_by_chunk(); + else if (copc_stream_order == 1) copc_index->set_stream_ordered_spatially(); + else if (copc_stream_order == 2) copc_index->set_stream_ordered_by_depth(); + lasreaderlas->set_copcindex(copc_index); + + // If no user-defined query we force a query anyway to never read a copc file in order but + // instead we enforce the use of the index to read in a spatially coherent order. + if (!inside_circle && !inside_rectangle && !inside_depth) set_max_depth(I32_MAX); + } + if (files_are_flightlines) + { + lasreaderlas->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + } + else if (apply_file_source_ID) + { + transform->setPointSource(lasreaderlas->header.file_source_ID); + } + if (filter) lasreaderlas->set_filter(filter); + if (transform) lasreaderlas->set_transform(transform); + if (ignore) lasreaderlas->set_ignore(ignore); + if (inside_rectangle) lasreaderlas->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreaderlas->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else if (inside_circle) lasreaderlas->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_depth) + { + if (!lasreaderlas->get_copcindex()) + { + REprintf("ERROR: queries with a depth limit are restrited to COPC files.\n"); + delete lasreaderlas; + return 0; + } + + lasreaderlas->inside_copc_depth(inside_depth, copc_depth, copc_resolution); + } + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderlas)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderlas\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderlas; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderlas\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else if (strstr(file_name, ".bin") || strstr(file_name, ".BIN")) + { + LASreaderBIN* lasreaderbin; + if (scale_factor == 0 && offset == 0) + lasreaderbin = new LASreaderBIN(); + else if (scale_factor != 0 && offset == 0) + lasreaderbin = new LASreaderBINrescale(scale_factor[0], scale_factor[1], scale_factor[2]); + else if (scale_factor == 0 && offset != 0) + lasreaderbin = new LASreaderBINreoffset(offset[0], offset[1], offset[2]); + else + lasreaderbin = new LASreaderBINrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); + if (!lasreaderbin->open(file_name)) + { + REprintf("ERROR: cannot open lasreaderbin with file name '%s'\n", file_name); + delete lasreaderbin; + return 0; + } + LASindex* index = new LASindex(); + if (index->read(file_name)) + lasreaderbin->set_index(index); + else + delete index; + if (files_are_flightlines) lasreaderbin->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreaderbin->set_filter(filter); + if (transform) lasreaderbin->set_transform(transform); + if (ignore) lasreaderbin->set_ignore(ignore); + if (inside_tile) lasreaderbin->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreaderbin->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreaderbin->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderbin)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderbin\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderbin; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderbin\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else if (strstr(file_name, ".shp") || strstr(file_name, ".SHP")) + { + LASreaderSHP* lasreadershp; + if (scale_factor == 0 && offset == 0) + lasreadershp = new LASreaderSHP(); + else if (scale_factor != 0 && offset == 0) + lasreadershp = new LASreaderSHPrescale(scale_factor[0], scale_factor[1], scale_factor[2]); + else if (scale_factor == 0 && offset != 0) + lasreadershp = new LASreaderSHPreoffset(offset[0], offset[1], offset[2]); + else + lasreadershp = new LASreaderSHPrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); + if (!lasreadershp->open(file_name)) + { + REprintf("ERROR: cannot open lasreadershp with file name '%s'\n", file_name); + delete lasreadershp; + return 0; + } + if (files_are_flightlines) lasreadershp->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreadershp->set_filter(filter); + if (transform) lasreadershp->set_transform(transform); + if (ignore) lasreadershp->set_ignore(ignore); + if (inside_tile) lasreadershp->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreadershp->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreadershp->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreadershp)) + { + REprintf("ERROR: could not open lasreaderstored with lasreadershp\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreadershp; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreadershp\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else if (strstr(file_name, ".asc") || strstr(file_name, ".ASC")) + { + LASreaderASC* lasreaderasc; + if (scale_factor == 0 && offset == 0) + lasreaderasc = new LASreaderASC(); + else if (scale_factor != 0 && offset == 0) + lasreaderasc = new LASreaderASCrescale(scale_factor[0], scale_factor[1], scale_factor[2]); + else if (scale_factor == 0 && offset != 0) + lasreaderasc = new LASreaderASCreoffset(offset[0], offset[1], offset[2]); + else + lasreaderasc = new LASreaderASCrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); + if (!lasreaderasc->open(file_name, comma_not_point)) + { + REprintf("ERROR: cannot open lasreaderasc with file name '%s'\n", file_name); + delete lasreaderasc; + return 0; + } + if (files_are_flightlines) lasreaderasc->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreaderasc->set_filter(filter); + if (transform) lasreaderasc->set_transform(transform); + if (ignore) lasreaderasc->set_ignore(ignore); + if (inside_tile) lasreaderasc->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreaderasc->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreaderasc->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderasc)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderasc\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderasc; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderasc\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else if (strstr(file_name, ".bil") || strstr(file_name, ".BIL")) + { + LASreaderBIL* lasreaderbil; + if (scale_factor == 0 && offset == 0) + lasreaderbil = new LASreaderBIL(); + else if (scale_factor != 0 && offset == 0) + lasreaderbil = new LASreaderBILrescale(scale_factor[0], scale_factor[1], scale_factor[2]); + else if (scale_factor == 0 && offset != 0) + lasreaderbil = new LASreaderBILreoffset(offset[0], offset[1], offset[2]); + else + lasreaderbil = new LASreaderBILrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); + if (!lasreaderbil->open(file_name)) + { + REprintf("ERROR: cannot open lasreaderbil with file name '%s'\n", file_name); + delete lasreaderbil; + return 0; + } + if (files_are_flightlines) lasreaderbil->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreaderbil->set_filter(filter); + if (transform) lasreaderbil->set_transform(transform); + if (ignore) lasreaderbil->set_ignore(ignore); + if (inside_tile) lasreaderbil->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreaderbil->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreaderbil->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderbil)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderbil\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderbil; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderbil\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else if (strstr(file_name, ".dtm") || strstr(file_name, ".DTM")) + { + LASreaderDTM* lasreaderdtm; + if (scale_factor == 0 && offset == 0) + lasreaderdtm = new LASreaderDTM(); + else if (scale_factor != 0 && offset == 0) + lasreaderdtm = new LASreaderDTMrescale(scale_factor[0], scale_factor[1], scale_factor[2]); + else if (scale_factor == 0 && offset != 0) + lasreaderdtm = new LASreaderDTMreoffset(offset[0], offset[1], offset[2]); + else + lasreaderdtm = new LASreaderDTMrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); + if (!lasreaderdtm->open(file_name)) + { + REprintf("ERROR: cannot open lasreaderdtm with file name '%s'\n", file_name); + delete lasreaderdtm; + return 0; + } + if (files_are_flightlines) lasreaderdtm->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreaderdtm->set_filter(filter); + if (transform) lasreaderdtm->set_transform(transform); + if (ignore) lasreaderdtm->set_ignore(ignore); + if (inside_tile) lasreaderdtm->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreaderdtm->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreaderdtm->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderdtm)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderdtm\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderdtm; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderdtm\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else if (strstr(file_name, ".ply") || strstr(file_name, ".PLY")) + { + LASreaderPLY* lasreaderply = new LASreaderPLY(); + if (translate_intensity != 0.0f) lasreaderply->set_translate_intensity(translate_intensity); + if (scale_intensity != 1.0f) lasreaderply->set_scale_intensity(scale_intensity); + lasreaderply->set_scale_factor(scale_factor); + lasreaderply->set_offset(offset); + if (!lasreaderply->open(file_name, point_type, populate_header)) + { + REprintf("ERROR: cannot open lasreaderply with file name '%s'\n", file_name); + delete lasreaderply; + return 0; + } + if (files_are_flightlines) lasreaderply->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreaderply->set_filter(filter); + if (transform) lasreaderply->set_transform(transform); + if (ignore) lasreaderply->set_ignore(ignore); + if (inside_tile) lasreaderply->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreaderply->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreaderply->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderply)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderply\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderply; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderply\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else if (strstr(file_name, ".qi") || strstr(file_name, ".QI")) + { + LASreaderQFIT* lasreaderqfit; + if (scale_factor == 0 && offset == 0) + lasreaderqfit = new LASreaderQFIT(); + else if (scale_factor != 0 && offset == 0) + lasreaderqfit = new LASreaderQFITrescale(scale_factor[0], scale_factor[1], scale_factor[2]); + else if (scale_factor == 0 && offset != 0) + lasreaderqfit = new LASreaderQFITreoffset(offset[0], offset[1], offset[2]); + else + lasreaderqfit = new LASreaderQFITrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); + if (!lasreaderqfit->open(file_name)) + { + REprintf("ERROR: cannot open lasreaderqfit with file name '%s'\n", file_name); + delete lasreaderqfit; + return 0; + } + LASindex* index = new LASindex(); + if (index->read(file_name)) + lasreaderqfit->set_index(index); + else + delete index; + if (files_are_flightlines) lasreaderqfit->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreaderqfit->set_filter(filter); + if (transform) lasreaderqfit->set_transform(transform); + if (ignore) lasreaderqfit->set_ignore(ignore); + if (inside_tile) lasreaderqfit->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreaderqfit->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreaderqfit->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderqfit)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderqfit\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderqfit; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderqfit\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else + { + LASreaderTXT* lasreadertxt = new LASreaderTXT(); + if (ipts) lasreadertxt->set_pts(TRUE); + else { + if (iptx) lasreadertxt->set_ptx(TRUE); + if (iptx_transform) lasreadertxt->set_ptx_transform(TRUE); + } + if (translate_intensity != 0.0f) lasreadertxt->set_translate_intensity(translate_intensity); + if (scale_intensity != 1.0f) lasreadertxt->set_scale_intensity(scale_intensity); + if (translate_scan_angle != 0.0f) lasreadertxt->set_translate_scan_angle(translate_scan_angle); + if (scale_scan_angle != 1.0f) lasreadertxt->set_scale_scan_angle(scale_scan_angle); + lasreadertxt->set_scale_factor(scale_factor); + lasreadertxt->set_offset(offset); + if (number_attributes) + { + for (I32 i = 0; i < number_attributes; i++) + { + lasreadertxt->add_attribute(attribute_data_types[i], attribute_names[i], attribute_descriptions[i], attribute_scales[i], attribute_offsets[i], attribute_pre_scales[i], attribute_pre_offsets[i], attribute_no_datas[i]); + } + } + if (!lasreadertxt->open(file_name, point_type, parse_string, skip_lines, populate_header)) + { + REprintf("ERROR: cannot open lasreadertxt with file name '%s'\n", file_name); + delete lasreadertxt; + return 0; + } + if (files_are_flightlines) lasreadertxt->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreadertxt->set_filter(filter); + // we may have a ptx_transform defined in the reader params: add them to the transformations + if (lasreadertxt->iptx_transform) + { + if (transform == 0) transform = new LAStransform(); + transform->add_operation(new LASoperationTransformMatrix(lasreadertxt->transform_matrix)); + } + if (transform) lasreadertxt->set_transform(transform); + if (ignore) lasreadertxt->set_ignore(ignore); + if (inside_tile) lasreadertxt->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreadertxt->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreadertxt->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreadertxt)) + { + REprintf("ERROR: could not open lasreaderstored with lasreadertxt\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreadertxt; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreadertxt\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + } + } + else if (use_stdin) + { + use_stdin = FALSE; populate_header = TRUE; + if (itxt) + { + LASreaderTXT* lasreadertxt = new LASreaderTXT(); + if (ipts) lasreadertxt->set_pts(TRUE); + else { + if (iptx) lasreadertxt->set_ptx(TRUE); + if (iptx_transform) lasreadertxt->set_ptx_transform(TRUE); + } + if (translate_intensity != 0.0f) lasreadertxt->set_translate_intensity(translate_intensity); + if (scale_intensity != 1.0f) lasreadertxt->set_scale_intensity(scale_intensity); + if (translate_scan_angle != 0.0f) lasreadertxt->set_translate_scan_angle(translate_scan_angle); + if (scale_scan_angle != 1.0f) lasreadertxt->set_scale_scan_angle(scale_scan_angle); + lasreadertxt->set_scale_factor(scale_factor); + lasreadertxt->set_offset(offset); + if (number_attributes) + { + for (I32 i = 0; i < number_attributes; i++) + { + lasreadertxt->add_attribute(attribute_data_types[i], attribute_names[i], attribute_descriptions[i], attribute_scales[i], attribute_offsets[i], attribute_pre_scales[i], attribute_pre_offsets[i], attribute_no_datas[i]); + } + } + if (!lasreadertxt->open(stdin, 0, point_type, parse_string, skip_lines, FALSE)) + { + REprintf("ERROR: cannot open lasreadertxt with file name '%s'\n", file_name); + delete lasreadertxt; + return 0; + } + if (files_are_flightlines) lasreadertxt->header.file_source_ID = file_name_current + files_are_flightlines + files_are_flightlines_index; + if (filter) lasreadertxt->set_filter(filter); + if (transform) lasreadertxt->set_transform(transform); + if (ignore) lasreadertxt->set_ignore(ignore); + if (inside_tile) lasreadertxt->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreadertxt->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreadertxt->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreadertxt)) + { + REprintf("ERROR: could not open lasreaderstored with lasreadertxt\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreadertxt; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreadertxt\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + else + { + LASreaderLAS* lasreaderlas; + if (scale_factor == 0 && offset == 0) + lasreaderlas = new LASreaderLAS(); + else if (scale_factor != 0 && offset == 0) + lasreaderlas = new LASreaderLASrescale(scale_factor[0], scale_factor[1], scale_factor[2]); + else if (scale_factor == 0 && offset != 0) + lasreaderlas = new LASreaderLASreoffset(offset[0], offset[1], offset[2]); + else + lasreaderlas = new LASreaderLASrescalereoffset(scale_factor[0], scale_factor[1], scale_factor[2], offset[0], offset[1], offset[2]); + if (!lasreaderlas->open(stdin)) + { + REprintf("ERROR: cannot open lasreaderlas from stdin \n"); + delete lasreaderlas; + return 0; + } + if (filter) lasreaderlas->set_filter(filter); + if (transform) lasreaderlas->set_transform(transform); + if (ignore) lasreaderlas->set_ignore(ignore); + if (inside_tile) lasreaderlas->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + if (inside_circle) lasreaderlas->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + if (inside_rectangle) lasreaderlas->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + if (inside_depth) lasreaderlas->inside_copc_depth(inside_depth, copc_depth, copc_resolution); + LASreader* lasreader = 0; + if (stored) + { + LASreaderStored* lasreaderstored = new LASreaderStored(); + if (!lasreaderstored->open(lasreaderlas)) + { + REprintf("ERROR: could not open lasreaderstored with lasreaderlas\n"); + delete lasreaderstored; + return 0; + } + lasreader = lasreaderstored; + } + else + { + lasreader = lasreaderlas; + } + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = new LASreaderPipeOn(); + if (!lasreaderpipeon->open(lasreader)) + { + REprintf("ERROR: cannot open lasreaderpipeon with lasreaderlas from stdin\n"); + delete lasreaderpipeon; + return 0; + } + return lasreaderpipeon; + } + else + { + return lasreader; + } + } + } + else + { + return 0; + } } BOOL LASreadOpener::reopen(LASreader* lasreader, BOOL remain_buffered) { - if (lasreader == 0) - { - REprintf("ERROR: pointer to LASreader is NULL\n"); - } - - // make sure the LASreader was closed - - lasreader->close(); - - if (filter) filter->reset(); - if (transform) transform->reset(); - - if (pipe_on) - { - LASreaderPipeOn* lasreaderpipeon = (LASreaderPipeOn*)lasreader; - lasreaderpipeon->p_count = 0; - lasreader = lasreaderpipeon->get_lasreader(); - } - - if (stored) - { - LASreaderStored* lasreaderstored = (LASreaderStored*)lasreader; - if (!lasreaderstored->reopen()) - { - REprintf( "ERROR: could not reopen lasreaderstored for stored input\n"); - return FALSE; - } - return TRUE; - } - else if (file_names) - { - if ((file_name_number > 1) && merged) - { - LASreaderMerged* lasreadermerged = (LASreaderMerged*)lasreader; - if (!lasreadermerged->reopen()) - { - REprintf("ERROR: cannot reopen lasreadermerged\n"); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreadermerged->inside_none(); - if (inside_rectangle) lasreadermerged->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreadermerged->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreadermerged->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - else if ((buffer_size > 0) && ((file_name_number > 1) || (neighbor_file_name_number > 0))) - { - LASreaderBuffered* lasreaderbuffered = (LASreaderBuffered*)lasreader; - if (!lasreaderbuffered->reopen()) - { - REprintf("ERROR: cannot reopen lasreaderbuffered\n"); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreaderbuffered->inside_none(); - if (inside_rectangle) lasreaderbuffered->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreaderbuffered->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreaderbuffered->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - if (!remain_buffered) lasreaderbuffered->remove_buffer(); - return TRUE; - } - else - { - if (!file_name) return FALSE; - if (strstr(file_name, ".las") || strstr(file_name, ".laz") || strstr(file_name, ".LAS") || strstr(file_name, ".LAZ")) - { - LASreaderLAS* lasreaderlas = (LASreaderLAS*)lasreader; - if (!lasreaderlas->open(file_name, io_ibuffer_size, FALSE, decompress_selective)) - { - REprintf("ERROR: cannot reopen lasreaderlas with file name '%s'\n", file_name); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreaderlas->inside_none(); - if (inside_rectangle) lasreaderlas->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreaderlas->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreaderlas->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - else if (strstr(file_name, ".bin") || strstr(file_name, ".BIN")) - { - LASreaderBIN* lasreaderbin = (LASreaderBIN*)lasreader; - if (!lasreaderbin->open(file_name)) - { - REprintf("ERROR: cannot reopen lasreaderbin with file name '%s'\n", file_name); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreaderbin->inside_none(); - if (inside_rectangle) lasreaderbin->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreaderbin->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreaderbin->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - else if (strstr(file_name, ".shp") || strstr(file_name, ".SHP")) - { - LASreaderSHP* lasreadershp = (LASreaderSHP*)lasreader; - if (!lasreadershp->reopen(file_name)) - { - REprintf("ERROR: cannot reopen lasreadershp with file name '%s'\n", file_name); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreadershp->inside_none(); - if (inside_rectangle) lasreadershp->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreadershp->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreadershp->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - else if (strstr(file_name, ".qi") || strstr(file_name, ".QI")) - { - LASreaderQFIT* lasreaderqfit = (LASreaderQFIT*)lasreader; - if (!lasreaderqfit->reopen(file_name)) - { - REprintf("ERROR: cannot reopen lasreaderqfit with file name '%s'\n", file_name); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreaderqfit->inside_none(); - if (inside_rectangle) lasreaderqfit->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreaderqfit->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreaderqfit->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - else if (strstr(file_name, ".asc") || strstr(file_name, ".ASC")) - { - LASreaderASC* lasreaderasc = (LASreaderASC*)lasreader; - if (!lasreaderasc->reopen(file_name)) - { - REprintf("ERROR: cannot reopen lasreaderasc with file name '%s'\n", file_name); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreaderasc->inside_none(); - if (inside_rectangle) lasreaderasc->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreaderasc->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreaderasc->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - else if (strstr(file_name, ".bil") || strstr(file_name, ".BIL")) - { - LASreaderBIL* lasreaderbil = (LASreaderBIL*)lasreader; - if (!lasreaderbil->reopen(file_name)) - { - REprintf("ERROR: cannot reopen lasreaderbil with file name '%s'\n", file_name); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreaderbil->inside_none(); - if (inside_rectangle) lasreaderbil->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreaderbil->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreaderbil->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - else if (strstr(file_name, ".dtm") || strstr(file_name, ".DTM")) - { - LASreaderDTM* lasreaderdtm = (LASreaderDTM*)lasreader; - if (!lasreaderdtm->reopen(file_name)) - { - REprintf("ERROR: cannot reopen lasreaderdtm with file name '%s'\n", file_name); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreaderdtm->inside_none(); - if (inside_rectangle) lasreaderdtm->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreaderdtm->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreaderdtm->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - else - { - LASreaderTXT* lasreadertxt = (LASreaderTXT*)lasreader; - if (!lasreadertxt->reopen(file_name)) - { - REprintf("ERROR: cannot reopen lasreadertxt with file name '%s'\n", file_name); - return FALSE; - } - if (inside_rectangle || inside_tile || inside_circle) - { - lasreadertxt->inside_none(); - if (inside_rectangle) lasreadertxt->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); - else if (inside_tile) lasreadertxt->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); - else lasreadertxt->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); - } - return TRUE; - } - } - } - else - { - REprintf("ERROR: no lasreader input specified\n"); - return FALSE; - } + if (lasreader == 0) + { + REprintf("ERROR: pointer to LASreader is NULL\n"); + } + + // make sure the LASreader was closed + + lasreader->close(); + + if (filter) filter->reset(); + if (transform) transform->reset(); + + if (pipe_on) + { + LASreaderPipeOn* lasreaderpipeon = (LASreaderPipeOn*)lasreader; + lasreaderpipeon->p_count = 0; + lasreader = lasreaderpipeon->get_lasreader(); + } + + if (stored) + { + LASreaderStored* lasreaderstored = (LASreaderStored*)lasreader; + if (!lasreaderstored->reopen()) + { + REprintf("ERROR: could not reopen lasreaderstored for stored input\n"); + return FALSE; + } + return TRUE; + } + else if (file_names) + { + if ((file_name_number > 1) && merged) + { + LASreaderMerged* lasreadermerged = (LASreaderMerged*)lasreader; + if (!lasreadermerged->reopen()) + { + REprintf("ERROR: cannot reopen lasreadermerged\n"); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreadermerged->inside_none(); + if (inside_rectangle) lasreadermerged->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreadermerged->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreadermerged->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + if (inside_depth) lasreadermerged->inside_copc_depth(inside_depth, copc_depth, copc_resolution); + return TRUE; + } + else if ((buffer_size > 0) && ((file_name_number > 1) || (neighbor_file_name_number > 0))) + { + LASreaderBuffered* lasreaderbuffered = (LASreaderBuffered*)lasreader; + if (!lasreaderbuffered->reopen()) + { + REprintf("ERROR: cannot reopen lasreaderbuffered\n"); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreaderbuffered->inside_none(); + if (inside_rectangle) lasreaderbuffered->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreaderbuffered->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreaderbuffered->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + if (inside_depth) lasreaderbuffered->inside_copc_depth(inside_depth, copc_depth, copc_resolution); + if (!remain_buffered) lasreaderbuffered->remove_buffer(); + return TRUE; + } + else + { + if (!file_name) return FALSE; + if (strstr(file_name, ".las") || strstr(file_name, ".laz") || strstr(file_name, ".LAS") || strstr(file_name, ".LAZ")) + { + LASreaderLAS* lasreaderlas = (LASreaderLAS*)lasreader; + if (!lasreaderlas->open(file_name, io_ibuffer_size, FALSE, decompress_selective)) + { + REprintf("ERROR: cannot reopen lasreaderlas with file name '%s'\n", file_name); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreaderlas->inside_none(); + if (inside_rectangle) lasreaderlas->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreaderlas->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreaderlas->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + if (inside_depth) lasreaderlas->inside_copc_depth(inside_depth, copc_depth, copc_resolution); + return TRUE; + } + else if (strstr(file_name, ".bin") || strstr(file_name, ".BIN")) + { + LASreaderBIN* lasreaderbin = (LASreaderBIN*)lasreader; + if (!lasreaderbin->open(file_name)) + { + REprintf("ERROR: cannot reopen lasreaderbin with file name '%s'\n", file_name); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreaderbin->inside_none(); + if (inside_rectangle) lasreaderbin->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreaderbin->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreaderbin->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + return TRUE; + } + else if (strstr(file_name, ".shp") || strstr(file_name, ".SHP")) + { + LASreaderSHP* lasreadershp = (LASreaderSHP*)lasreader; + if (!lasreadershp->reopen(file_name)) + { + REprintf("ERROR: cannot reopen lasreadershp with file name '%s'\n", file_name); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreadershp->inside_none(); + if (inside_rectangle) lasreadershp->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreadershp->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreadershp->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + return TRUE; + } + else if (strstr(file_name, ".qi") || strstr(file_name, ".QI")) + { + LASreaderQFIT* lasreaderqfit = (LASreaderQFIT*)lasreader; + if (!lasreaderqfit->reopen(file_name)) + { + REprintf("ERROR: cannot reopen lasreaderqfit with file name '%s'\n", file_name); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreaderqfit->inside_none(); + if (inside_rectangle) lasreaderqfit->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreaderqfit->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreaderqfit->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + return TRUE; + } + else if (strstr(file_name, ".asc") || strstr(file_name, ".ASC")) + { + LASreaderASC* lasreaderasc = (LASreaderASC*)lasreader; + if (!lasreaderasc->reopen(file_name)) + { + REprintf("ERROR: cannot reopen lasreaderasc with file name '%s'\n", file_name); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreaderasc->inside_none(); + if (inside_rectangle) lasreaderasc->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreaderasc->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreaderasc->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + return TRUE; + } + else if (strstr(file_name, ".bil") || strstr(file_name, ".BIL")) + { + LASreaderBIL* lasreaderbil = (LASreaderBIL*)lasreader; + if (!lasreaderbil->reopen(file_name)) + { + REprintf("ERROR: cannot reopen lasreaderbil with file name '%s'\n", file_name); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreaderbil->inside_none(); + if (inside_rectangle) lasreaderbil->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreaderbil->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreaderbil->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + return TRUE; + } + else if (strstr(file_name, ".dtm") || strstr(file_name, ".DTM")) + { + LASreaderDTM* lasreaderdtm = (LASreaderDTM*)lasreader; + if (!lasreaderdtm->reopen(file_name)) + { + REprintf("ERROR: cannot reopen lasreaderdtm with file name '%s'\n", file_name); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreaderdtm->inside_none(); + if (inside_rectangle) lasreaderdtm->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreaderdtm->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreaderdtm->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + return TRUE; + } + else + { + LASreaderTXT* lasreadertxt = (LASreaderTXT*)lasreader; + if (!lasreadertxt->reopen(file_name)) + { + REprintf("ERROR: cannot reopen lasreadertxt with file name '%s'\n", file_name); + return FALSE; + } + if (inside_rectangle || inside_tile || inside_circle) + { + lasreadertxt->inside_none(); + if (inside_rectangle) lasreadertxt->inside_rectangle(inside_rectangle[0], inside_rectangle[1], inside_rectangle[2], inside_rectangle[3]); + else if (inside_tile) lasreadertxt->inside_tile(inside_tile[0], inside_tile[1], inside_tile[2]); + else lasreadertxt->inside_circle(inside_circle[0], inside_circle[1], inside_circle[2]); + } + return TRUE; + } + } + } + else + { + REprintf("ERROR: no lasreader input specified\n"); + return FALSE; + } } LASwaveform13reader* LASreadOpener::open_waveform13(const LASheader* lasheader) { - if (lasheader->point_data_format < 4) return 0; - if ((lasheader->point_data_format > 5) && (lasheader->point_data_format < 9)) return 0; - if (lasheader->vlr_wave_packet_descr == 0) return 0; - if (get_file_name() == 0) return 0; - LASwaveform13reader* waveform13reader = new LASwaveform13reader(); - if ((lasheader->global_encoding & 2) && (lasheader->start_of_waveform_data_packet_record > lasheader->offset_to_point_data)) - { - if (waveform13reader->open(get_file_name(), lasheader->start_of_waveform_data_packet_record, lasheader->vlr_wave_packet_descr)) - { - return waveform13reader; - } - } - else - { - if (waveform13reader->open(get_file_name(), 0, lasheader->vlr_wave_packet_descr)) - { - return waveform13reader; - } - } - delete waveform13reader; - return 0; + if (lasheader->point_data_format < 4) return 0; + if ((lasheader->point_data_format > 5) && (lasheader->point_data_format < 9)) return 0; + if (lasheader->vlr_wave_packet_descr == 0) return 0; + if (get_file_name() == 0) return 0; + LASwaveform13reader* waveform13reader = new LASwaveform13reader(); + if ((lasheader->global_encoding & 2) && (lasheader->start_of_waveform_data_packet_record > lasheader->offset_to_point_data)) + { + if (waveform13reader->open(get_file_name(), lasheader->start_of_waveform_data_packet_record, lasheader->vlr_wave_packet_descr)) + { + return waveform13reader; + } + } + else + { + if (waveform13reader->open(get_file_name(), 0, lasheader->vlr_wave_packet_descr)) + { + return waveform13reader; + } + } + delete waveform13reader; + return 0; } void LASreadOpener::usage() const { - REprintf("Supported LAS Inputs\n"); - REprintf(" -i lidar.las\n"); - REprintf(" -i lidar.laz\n"); - REprintf(" -i lidar1.las lidar2.las lidar3.las -merged\n"); - REprintf(" -i *.las - merged\n"); - REprintf(" -i flight0??.laz flight1??.laz\n"); - REprintf(" -i terrasolid.bin\n"); - REprintf(" -i esri.shp\n"); - REprintf(" -i nasa.qi\n"); - REprintf(" -i lidar.txt -iparse xyzti -iskip 2 (on-the-fly from ASCII)\n"); - REprintf(" -i lidar.txt -iparse xyzi -itranslate_intensity 1024\n"); - REprintf(" -lof file_list.txt\n"); - REprintf(" -stdin (pipe from stdin)\n"); - REprintf(" -rescale 0.01 0.01 0.001\n"); - REprintf(" -rescale_xy 0.01 0.01\n"); - REprintf(" -rescale_z 0.01\n"); - REprintf(" -reoffset 600000 4000000 0\n"); - REprintf("Fast AOI Queries for LAS/LAZ with spatial indexing LAX files\n"); - REprintf(" -inside min_x min_y max_x max_y\n"); - REprintf(" -inside_tile ll_x ll_y size\n"); - REprintf(" -inside_circle center_x center_y radius\n"); + REprintf("Supported LAS Inputs\n"); + REprintf(" -i lidar.las\n"); + REprintf(" -i lidar.laz\n"); + REprintf(" -i lidar1.las lidar2.las lidar3.las -merged\n"); + REprintf(" -i *.las - merged\n"); + REprintf(" -i flight0??.laz flight1??.laz\n"); + REprintf(" -i terrasolid.bin\n"); + REprintf(" -i esri.shp\n"); + REprintf(" -i lidar.txt -iparse xyzti -iskip 2 (on-the-fly from ASCII)\n"); + REprintf(" -i lidar.txt -iparse xyzi -itranslate_intensity 1024\n"); + REprintf(" -lof file_list.txt\n"); + REprintf(" -stdin (pipe from stdin)\n"); + REprintf(" -rescale 0.01 0.01 0.001\n"); + REprintf(" -rescale_xy 0.01 0.01\n"); + REprintf(" -rescale_z 0.01\n"); + REprintf(" -reoffset 600000 4000000 0\n"); + REprintf("Fast AOI Queries for LAS/LAZ with spatial indexing LAX files\n"); + REprintf(" -inside min_x min_y max_x max_y\n"); + REprintf(" -inside_tile ll_x ll_y size\n"); + REprintf(" -inside_circle center_x center_y radius\n"); + REprintf("Fast AOI Queries for LAZ 1.4 with spatial indexing COPC VLR\n"); + REprintf(" -inside min_x min_y max_x max_y\n"); + REprintf(" -inside_circle center_x center_y radius\n"); + REprintf(" -max_depth 3\n"); + REprintf(" -resolution 0.1\n"); } BOOL LASreadOpener::parse(int argc, char* argv[], BOOL parse_ignore) { - int i; - for (i = 1; i < argc; i++) - { - if (argv[i][0] == '\0') - { - continue; - } - else if (strcmp(argv[i],"-h") == 0) - { - LASfilter().usage(); - LAStransform().usage(); - LASignore().usage(); - usage(); - return TRUE; - } - else if (strncmp(argv[i], "-i", 2) == 0) - { - if (strcmp(argv[i],"-i") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs at least 1 argument: file_name or wild_card\n", argv[i]); - return FALSE; - } - *argv[i]='\0'; - i+=1; - do - { - add_file_name(argv[i], unique); - *argv[i]='\0'; - i+=1; - } while ((i < argc) && (*argv[i] != '-') && (*argv[i] != '\0')); - i-=1; - } - else if (strncmp(argv[i],"-ignore_", 8) == 0) - { - if (parse_ignore) - { - if (ignore == 0) - { - ignore = new LASignore(); - } - if (!ignore->parse(i, argc, argv)) - { - delete ignore; - ignore = 0; - return FALSE; - } - } - else - { - REprintf("ERROR: this tool does not process '-ignore_xxxx' options\n"); - return FALSE; - } - } - else if (strncmp(argv[i],"-inside", 7) == 0) - { - if (strcmp(argv[i],"-inside_tile") == 0) - { - if ((i+3) >= argc) - { - REprintf("ERROR: '%s' needs 3 arguments: ll_x ll_y size\n", argv[i]); - return FALSE; - } - F32 ll_x; - if (sscanf(argv[i+1], "%f", &ll_x) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: ll_x ll_y size, but '%s' is not a valid ll_x.\n", argv[i], argv[i+1]); - return FALSE; - } - F32 ll_y; - if (sscanf(argv[i+2], "%f", &ll_y) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: ll_x ll_y size, but '%s' is not a valid ll_y.\n", argv[i], argv[i+2]); - return FALSE; - } - F32 size; - if (sscanf(argv[i+3], "%f", &size) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: ll_x ll_y size, but '%s' is not a valid size.\n", argv[i], argv[i+3]); - return FALSE; - } - if (size <= 0.0f) - { - REprintf( "ERROR: '%s' needs 3 arguments: ll_x ll_y size, but %f is not valid a size.\n", argv[i], size); - return FALSE; - } - set_inside_tile(ll_x, ll_y, size); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; i+=3; - } - else if (strcmp(argv[i],"-inside_circle") == 0) - { - if ((i+3) >= argc) - { - REprintf("ERROR: '%s' needs 3 arguments: center_x center_y radius\n", argv[i]); - return FALSE; - } - F64 center_x; - if (sscanf(argv[i+1], "%lf", ¢er_x) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: center_x center_y radius, but '%s' is not a valid center_x.\n", argv[i], argv[i+1]); - return FALSE; - } - F64 center_y; - if (sscanf(argv[i+2], "%lf", ¢er_y) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: center_x center_y radius, but '%s' is not a valid center_y.\n", argv[i], argv[i+2]); - return FALSE; - } - F64 radius; - if (sscanf(argv[i+3], "%lf", &radius) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: center_x center_y radius, but '%s' is not a valid radius.\n", argv[i], argv[i+3]); - return FALSE; - } - if (radius <= 0.0f) - { - REprintf( "ERROR: '%s' needs 3 arguments: center_x center_y radius, but %lf is not valid a radius.\n", argv[i], radius); - return FALSE; - } - set_inside_circle(center_x, center_y, radius); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; i+=3; - } - else if (strcmp(argv[i],"-inside") == 0 || strcmp(argv[i],"-inside_rectangle") == 0) - { - if ((i+4) >= argc) - { - REprintf("ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y\n", argv[i]); - return FALSE; - } - F64 min_x; - if (sscanf(argv[i+1], "%lf", &min_x) != 1) - { - REprintf( "ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but '%s' is not a valid min_x.\n", argv[i], argv[i+1]); - return FALSE; - } - F64 min_y; - if (sscanf(argv[i+2], "%lf", &min_y) != 1) - { - REprintf( "ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but '%s' is not a valid min_y.\n", argv[i], argv[i+2]); - return FALSE; - } - F64 max_x; - if (sscanf(argv[i+3], "%lf", &max_x) != 1) - { - REprintf( "ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but '%s' is not a valid max_x.\n", argv[i], argv[i+3]); - return FALSE; - } - F64 max_y; - if (sscanf(argv[i+4], "%lf", &max_y) != 1) - { - REprintf( "ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but '%s' is not a valid max_y.\n", argv[i], argv[i+4]); - return FALSE; - } - if ((min_x != 0 || max_x != 0) && min_x >= max_x) - { - REprintf( "ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but %lf / %lf are not a valid min_x / max_x pair.\n", argv[i], min_x, max_x); - return FALSE; - } - if ((min_y != 0 || max_y != 0) && min_y >= max_y) - { - REprintf( "ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but %lf / %lf are not a valid min_y / max_y pair.\n", argv[i], min_y, max_y); - return FALSE; - } - set_inside_rectangle(min_x, min_y, max_x, max_y); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; *argv[i+4]='\0'; i+=4; - } - else - { - REprintf("ERROR: unknown '-inside' option '%s'\n", argv[i]); - return FALSE; - } - } - else if (strcmp(argv[i],"-iadd_extra") == 0 || strcmp(argv[i],"-iadd_attribute") == 0) - { - if ((i+3) >= argc) - { - REprintf("ERROR: '%s' needs 3 arguments: data_type name description\n", argv[i]); - return FALSE; - } - if (((i+4) < argc) && (atof(argv[i+4]) != 0.0)) - { - if (((i+5) < argc) && ((atof(argv[i+5]) != 0.0) || (strcmp(argv[i+5], "0") == 0) || (strcmp(argv[i+5], "0.0") == 0))) - { - if (((i+6) < argc) && (atof(argv[i+6]) != 0.0)) - { - if (((i+7) < argc) && ((atof(argv[i+7]) != 0.0) || (strcmp(argv[i+7], "0") == 0) || (strcmp(argv[i+7], "0.0") == 0))) - { - if (((i+8) < argc) && ((atof(argv[i+8]) != 0.0) || (strcmp(argv[i+8], "0") == 0) || (strcmp(argv[i+8], "0.0") == 0))) - { - add_attribute(atoi(argv[i+1]), argv[i+2], argv[i+3], atof(argv[i+4]), atof(argv[i+5]), atof(argv[i+6]), atof(argv[i+7]), atof(argv[i+8])); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; *argv[i+4]='\0'; *argv[i+5]='\0'; *argv[i+6]='\0'; *argv[i+7]='\0'; *argv[i+8]='\0'; i+=8; - } - else - { - add_attribute(atoi(argv[i+1]), argv[i+2], argv[i+3], atof(argv[i+4]), atof(argv[i+5]), atof(argv[i+6]), atof(argv[i+7])); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; *argv[i+4]='\0'; *argv[i+5]='\0'; *argv[i+6]='\0'; *argv[i+7]='\0'; i+=7; - } - } - else - { - add_attribute(atoi(argv[i+1]), argv[i+2], argv[i+3], atof(argv[i+4]), atof(argv[i+5]), atof(argv[i+6])); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; *argv[i+4]='\0'; *argv[i+5]='\0'; *argv[i+6]='\0'; i+=6; - } - } - else - { - add_attribute(atoi(argv[i+1]), argv[i+2], argv[i+3], atof(argv[i+4]), atof(argv[i+5])); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; *argv[i+4]='\0'; *argv[i+5]='\0'; i+=5; - } - } - else - { - add_attribute(atoi(argv[i+1]), argv[i+2], argv[i+3], atof(argv[i+4])); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; *argv[i+4]='\0'; i+=4; - } - } - else - { - add_attribute(atoi(argv[i+1]), argv[i+2], argv[i+3]); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; i+=3; - } - } - else if (strcmp(argv[i],"-iparse") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: string\n", argv[i]); - return FALSE; - } - set_parse_string(argv[i+1]); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-iskip") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: number_of_lines\n", argv[i]); - return FALSE; - } - U32 number_of_lines; - if (sscanf(argv[i+1], "%u", &number_of_lines) != 1) - { - REprintf( "ERROR: '%s' needs 1 argument: number_of_lines but '%s' is not a valid number.\n", argv[i], argv[i+1]); - return FALSE; - } - if (number_of_lines == 0) - { - REprintf( "ERROR: '%s' needs 1 argument: number_of_lines but %u is not valid.\n", argv[i], number_of_lines); - return FALSE; - } - set_skip_lines(number_of_lines); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-io_ibuffer") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: size\n", argv[i]); - return FALSE; - } - U32 buffer_size; - if (sscanf(argv[i+1], "%u", &buffer_size) != 1) - { - REprintf( "ERROR: '%s' needs 1 argument: size but '%s' is not a valid size.\n", argv[i], argv[i+1]); - return FALSE; - } - if (buffer_size == 0) - { - REprintf( "ERROR: '%s' needs 1 argument: size but %u is not valid.\n", argv[i], buffer_size); - return FALSE; - } - set_io_ibuffer_size(buffer_size); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-itranslate_intensity") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: translation\n", argv[i]); - return FALSE; - } - F32 translation; - if (sscanf(argv[i+1], "%f", &translation) != 1) - { - REprintf( "ERROR: '%s' needs 1 argument: translation but '%s' is not valid.\n", argv[i], argv[i+1]); - return FALSE; - } - if (translation == 0.0f) - { - REprintf( "ERROR: '%s' needs 1 argument: translation but %f is not valid.\n", argv[i], translation); - return FALSE; - } - set_translate_intensity(translation); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-iscale_intensity") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: scale\n", argv[i]); - return FALSE; - } - F32 scale; - if (sscanf(argv[i+1], "%f", &scale) != 1) - { - REprintf( "ERROR: '%s' needs 1 argument: scale but '%s' is not valid.\n", argv[i], argv[i+1]); - return FALSE; - } - if (scale == 0.0f) - { - REprintf( "ERROR: '%s' needs 1 argument: scale but %f is not valid.\n", argv[i], scale); - return FALSE; - } - set_scale_intensity(scale); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-itranslate_scan_angle") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: translation\n", argv[i]); - return FALSE; - } - F32 translation; - if (sscanf(argv[i+1], "%f", &translation) != 1) - { - REprintf( "ERROR: '%s' needs 1 argument: translation but '%s' is not valid.\n", argv[i], argv[i+1]); - return FALSE; - } - if (translation == 0.0f) - { - REprintf( "ERROR: '%s' needs 1 argument: translation but %f is not valid.\n", argv[i], translation); - return FALSE; - } - set_translate_scan_angle(translation); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-iscale_scan_angle") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: scale\n", argv[i]); - return FALSE; - } - F32 scale; - if (sscanf(argv[i+1], "%f", &scale) != 1) - { - REprintf( "ERROR: '%s' needs 1 argument: scale but '%s' is not valid.\n", argv[i], argv[i+1]); - return FALSE; - } - if (scale == 0.0f) - { - REprintf( "ERROR: '%s' needs 1 argument: scale but %f is not valid.\n", argv[i], scale); - return FALSE; - } - set_scale_scan_angle(scale); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-ipts") == 0) - { - itxt = TRUE; - ipts = TRUE; - *argv[i]='\0'; - } - else if (strcmp(argv[i],"-iptx") == 0) - { - itxt = TRUE; - iptx = TRUE; - *argv[i]='\0'; - } - else if (strcmp(argv[i],"-itxt") == 0) - { - itxt = TRUE; - *argv[i]='\0'; - } - } - else if (strncmp(argv[i], "-r", 2) == 0) - { - if (strcmp(argv[i],"-rescale") == 0) - { - if ((i+3) >= argc) - { - REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z\n", argv[i]); - return FALSE; - } - F64 scale_factor[3]; - if (sscanf(argv[i+1], "%lf", &(scale_factor[0])) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but '%s' is not a valid rescale_x", argv[i], argv[i+1]); - return FALSE; - } - if (scale_factor[0] == 0.0) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but %lf is not a valid rescale_x", argv[i], scale_factor[0]); - return FALSE; - } - if (sscanf(argv[i+2], "%lf", &(scale_factor[1])) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but '%s' is not a valid rescale_y", argv[i], argv[i+2]); - return FALSE; - } - if (scale_factor[1] == 0.0) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but %lf is not a valid rescale_y", argv[i], scale_factor[1]); - return FALSE; - } - if (sscanf(argv[i+3], "%lf", &(scale_factor[2])) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but '%s' is not a valid rescale_z", argv[i], argv[i+3]); - return FALSE; - } - if (scale_factor[2] == 0.0) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but %lf is not a valid rescale_z", argv[i], scale_factor[2]); - return FALSE; - } - set_scale_factor(scale_factor); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; i+=3; - } - else if (strcmp(argv[i],"-rescale_xy") == 0) - { - if ((i+2) >= argc) - { - REprintf("ERROR: '%s' needs 2 argument: rescale_x rescale_y\n", argv[i]); - return FALSE; - } - F64 scale_factor[3]; - if (sscanf(argv[i+1], "%lf", &(scale_factor[0])) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y, but '%s' is not a valid rescale_x", argv[i], argv[i+1]); - return FALSE; - } - if (scale_factor[0] == 0.0) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y, but %lf is not a valid rescale_x", argv[i], scale_factor[0]); - return FALSE; - } - if (sscanf(argv[i+2], "%lf", &(scale_factor[1])) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y, but '%s' is not a valid rescale_y", argv[i], argv[i+2]); - return FALSE; - } - if (scale_factor[1] == 0.0) - { - REprintf( "ERROR: '%s' needs 3 arguments: rescale_x rescale_y, but %lf is not a valid rescale_y", argv[i], scale_factor[1]); - return FALSE; - } - scale_factor[2] = 0.0; - set_scale_factor(scale_factor); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; i+=2; - } - else if (strcmp(argv[i],"-rescale_z") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: rescale_z\n", argv[i]); - return FALSE; - } - F64 scale_factor[3]; - scale_factor[0] = 0.0; - scale_factor[1] = 0.0; - if (sscanf(argv[i+1], "%lf", &(scale_factor[2])) != 1) - { - REprintf( "ERROR: '%s' needs 1 argument: rescale_z, but '%s' is not a valid rescale_z", argv[i], argv[i+1]); - return FALSE; - } - if (scale_factor[2] == 0.0) - { - REprintf( "ERROR: '%s' needs 1 argument: rescale_z, but %lf is not a valid rescale_z", argv[i], scale_factor[2]); - return FALSE; - } - set_scale_factor(scale_factor); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-reoffset") == 0) - { - if ((i+3) >= argc) - { - REprintf("ERROR: '%s' needs 3 arguments: reoffset_x, reoffset_y, reoffset_z\n", argv[i]); - return FALSE; - } - F64 offset[3]; - if (sscanf(argv[i+1], "%lf", &(offset[0])) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: reoffset_x, reoffset_y, reoffset_z, but '%s' is not a valid reoffset_x", argv[i], argv[i+1]); - return FALSE; - } - if (sscanf(argv[i+2], "%lf", &(offset[1])) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: reoffset_x, reoffset_y, reoffset_z, but '%s' is not a valid reoffset_y", argv[i], argv[i+2]); - return FALSE; - } - if (sscanf(argv[i+3], "%lf", &(offset[2])) != 1) - { - REprintf( "ERROR: '%s' needs 3 arguments: reoffset_x, reoffset_y, reoffset_z, but '%s' is not a valid reoffset_z", argv[i], argv[i+3]); - return FALSE; - } - set_offset(offset); - *argv[i]='\0'; *argv[i+1]='\0'; *argv[i+2]='\0'; *argv[i+3]='\0'; i+=3; - } - } - else if (strcmp(argv[i],"-unique") == 0) - { - unique = TRUE; - *argv[i]='\0'; - } - else if (strcmp(argv[i],"-comma_not_point") == 0) - { - comma_not_point = TRUE; - *argv[i]='\0'; - } - else if (strncmp(argv[i], "-s", 2) == 0) - { - if (strcmp(argv[i],"-stdin") == 0) - { - use_stdin = TRUE; - *argv[i]='\0'; - } - else if (strcmp(argv[i],"-stored") == 0) - { - set_stored(TRUE); - *argv[i]='\0'; - } - } - else if (strcmp(argv[i],"-lof") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: list_of_files\n", argv[i]); - return FALSE; - } - if (!add_list_of_files(argv[i+1], unique)) - { - REprintf( "ERROR: cannot load list of files '%s'\n", argv[i+1]); - return FALSE; - } - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strncmp(argv[i], "-a", 2) == 0) - { - if (strcmp(argv[i],"-auto_reoffset") == 0) - { - set_auto_reoffset(TRUE); - *argv[i]='\0'; - } - else if (strcmp(argv[i],"-apply_file_source_ID") == 0) - { - set_apply_file_source_ID(TRUE); - *argv[i]='\0'; - } - } - else if (strncmp(argv[i], "-f", 2) == 0) - { - if (strcmp(argv[i],"-files_are_flightlines") == 0 || strcmp(argv[i],"-faf") == 0) - { - if (((i+1) < argc) && ('1' <= argv[i+1][0]) && (argv[i+1][0] <= '9')) - { - set_files_are_flightlines(atoi(argv[i+1])); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else - { - set_files_are_flightlines(1); - *argv[i]='\0'; - } - } - else if (strcmp(argv[i],"-faf_index") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: index\n", argv[i]); - return FALSE; - } - set_files_are_flightlines_index(atoi(argv[i+1])); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - } - else if (strcmp(argv[i],"-merged") == 0) - { - set_merged(TRUE); - *argv[i]='\0'; - } - else if (strcmp(argv[i],"-buffered") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: buffer_size\n", argv[i]); - return FALSE; - } - F32 buffer_size; - if (sscanf(argv[i+1], "%f", &buffer_size) != 1) - { - REprintf( "ERROR: '%s' needs 1 argument: buffer_size. but '%s' is not a valid buffer_size", argv[i], argv[i+1]); - return FALSE; - } - if (buffer_size <= 0.0f) - { - REprintf( "ERROR: '%s' needs 1 argument: buffer_size, but %f is not valid", argv[i], buffer_size); - return FALSE; - } - set_buffer_size(buffer_size); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strcmp(argv[i],"-temp_files") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs 1 argument: base name\n", argv[i]); - return FALSE; - } - temp_file_base = LASCopyString(argv[i+1]); - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - else if (strncmp(argv[i], "-n", 2) == 0) - { - if (strcmp(argv[i],"-neighbors") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs at least 1 argument: file_name or wild_card\n", argv[i]); - return FALSE; - } - *argv[i]='\0'; - i+=1; - do - { - add_neighbor_file_name(argv[i]); - *argv[i]='\0'; - i+=1; - } while ((i < argc) && (*argv[i] != '-') && (*argv[i] != '\0')); - i-=1; - } - else if (strcmp(argv[i],"-neighbors_lof") == 0) - { - if ((i+1) >= argc) - { - REprintf("ERROR: '%s' needs at least 1 argument: file_name\n", argv[i]); - return FALSE; - } - if (!add_neighbor_list_of_files(argv[i+1], unique)) - { - REprintf( "ERROR: cannot load neighbor list of files '%s'\n", argv[i+1]); - return FALSE; - } - *argv[i]='\0'; *argv[i+1]='\0'; i+=1; - } - } - else if (strncmp(argv[i], "-p", 2) == 0) - { - if (strcmp(argv[i],"-pipe_on") == 0) - { - set_pipe_on(TRUE); - *argv[i]='\0'; - } - else if (strcmp(argv[i],"-populate") == 0) - { - set_populate_header(TRUE); - *argv[i]='\0'; - } - } - else if (strcmp(argv[i],"-do_not_populate") == 0) - { - set_populate_header(FALSE); - *argv[i]='\0'; - } - } - - // check that there are only buffered neighbors for single files - - if (neighbor_file_name_number) - { - if (file_name_number > 1) - { - REprintf( "ERROR: neighbors only supported for one buffered input file, not for %d\n", file_name_number); - return FALSE; - } - if (buffer_size == 0.0f) - { - REprintf( "ERROR: neighbors only make sense when used with '-buffered 50' or similar\n"); - return FALSE; - } - } - - if (filter) filter->clean(); - else filter = new LASfilter(); - if (!filter->parse(argc, argv)) - { - delete filter; - filter = 0; - return FALSE; - } - if (!filter->active()) - { - delete filter; - filter = 0; - } - - if (transform) transform->clean(); - else transform = new LAStransform(); - if (!transform->parse(argc, argv)) - { - delete transform; - transform = 0; - return FALSE; - } - if (!transform->active()) - { - if (transform->filtered()) - { - REprintf( "WARNING: no LAStransform specified. '-filtered_transform' has no effect.\n"); - } - delete transform; - transform = 0; - } - else if (transform->filtered()) - { - if (filter == 0) - { - REprintf( "WARNING: no LASfilter specified. '-filtered_transform' has no effect.\n"); - } - else - { - transform->setFilter(filter); - filter = 0; - } - } - - if (files_are_flightlines || apply_file_source_ID) - { - if (transform == 0) transform = new LAStransform(); - transform->setPointSource(0); - } - - return TRUE; + int i; + for (i = 1; i < argc; i++) + { + if (argv[i][0] == '\0') + { + continue; + } + else if (strcmp(argv[i], "-h") == 0) + { + LASfilter().usage(); + LAStransform().usage(); + LASignore().usage(); + usage(); + return TRUE; + } + else if (strncmp(argv[i], "-i", 2) == 0) + { + if (strcmp(argv[i], "-i") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs at least 1 argument: file_name or wild_card\n", argv[i]); + return FALSE; + } + *argv[i] = '\0'; + i += 1; + do + { + add_file_name(argv[i], unique); + *argv[i] = '\0'; + i += 1; + } while ((i < argc) && (*argv[i] != '-') && (*argv[i] != '\0')); + i -= 1; + } + else if (strncmp(argv[i], "-ignore_", 8) == 0) + { + if (parse_ignore) + { + if (ignore == 0) + { + ignore = new LASignore(); + } + if (!ignore->parse(i, argc, argv)) + { + delete ignore; + ignore = 0; + return FALSE; + } + } + else + { + REprintf("ERROR: this tool does not process '-ignore_xxxx' options\n"); + return FALSE; + } + } + else if (strncmp(argv[i], "-inside", 7) == 0) + { + if (strcmp(argv[i], "-inside_tile") == 0) + { + if ((i + 3) >= argc) + { + REprintf("ERROR: '%s' needs 3 arguments: ll_x ll_y size\n", argv[i]); + return FALSE; + } + F32 ll_x; + if (sscanf(argv[i + 1], "%f", &ll_x) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: ll_x ll_y size, but '%s' is not a valid ll_x.\n", argv[i], argv[i + 1]); + return FALSE; + } + F32 ll_y; + if (sscanf(argv[i + 2], "%f", &ll_y) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: ll_x ll_y size, but '%s' is not a valid ll_y.\n", argv[i], argv[i + 2]); + return FALSE; + } + F32 size; + if (sscanf(argv[i + 3], "%f", &size) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: ll_x ll_y size, but '%s' is not a valid size.\n", argv[i], argv[i + 3]); + return FALSE; + } + if (size <= 0.0f) + { + REprintf("ERROR: '%s' needs 3 arguments: ll_x ll_y size, but %f is not valid a size.\n", argv[i], size); + return FALSE; + } + set_inside_tile(ll_x, ll_y, size); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; i += 3; + } + else if (strcmp(argv[i], "-inside_circle") == 0) + { + if ((i + 3) >= argc) + { + REprintf("ERROR: '%s' needs 3 arguments: center_x center_y radius\n", argv[i]); + return FALSE; + } + F64 center_x; + if (sscanf(argv[i + 1], "%lf", ¢er_x) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: center_x center_y radius, but '%s' is not a valid center_x.\n", argv[i], argv[i + 1]); + return FALSE; + } + F64 center_y; + if (sscanf(argv[i + 2], "%lf", ¢er_y) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: center_x center_y radius, but '%s' is not a valid center_y.\n", argv[i], argv[i + 2]); + return FALSE; + } + F64 radius; + if (sscanf(argv[i + 3], "%lf", &radius) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: center_x center_y radius, but '%s' is not a valid radius.\n", argv[i], argv[i + 3]); + return FALSE; + } + if (radius <= 0.0f) + { + REprintf("ERROR: '%s' needs 3 arguments: center_x center_y radius, but %lf is not valid a radius.\n", argv[i], radius); + return FALSE; + } + set_inside_circle(center_x, center_y, radius); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; i += 3; + } + else if (strcmp(argv[i], "-inside") == 0 || strcmp(argv[i], "-inside_rectangle") == 0) + { + if ((i + 4) >= argc) + { + REprintf("ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y\n", argv[i]); + return FALSE; + } + F64 min_x; + if (sscanf(argv[i + 1], "%lf", &min_x) != 1) + { + REprintf("ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but '%s' is not a valid min_x.\n", argv[i], argv[i + 1]); + return FALSE; + } + F64 min_y; + if (sscanf(argv[i + 2], "%lf", &min_y) != 1) + { + REprintf("ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but '%s' is not a valid min_y.\n", argv[i], argv[i + 2]); + return FALSE; + } + F64 max_x; + if (sscanf(argv[i + 3], "%lf", &max_x) != 1) + { + REprintf("ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but '%s' is not a valid max_x.\n", argv[i], argv[i + 3]); + return FALSE; + } + F64 max_y; + if (sscanf(argv[i + 4], "%lf", &max_y) != 1) + { + REprintf("ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but '%s' is not a valid max_y.\n", argv[i], argv[i + 4]); + return FALSE; + } + if ((min_x != 0 || max_x != 0) && min_x >= max_x) + { + REprintf( "ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but %lf / %lf are not a valid min_x / max_x pair.\n", argv[i], min_x, max_x); + return FALSE; + } + if ((min_y != 0 || max_y != 0) && min_y >= max_y) + { + REprintf( "ERROR: '%s' needs 4 arguments: min_x min_y max_x max_y, but %lf / %lf are not a valid min_y / max_y pair.\n", argv[i], min_y, max_y); + return FALSE; + } + set_inside_rectangle(min_x, min_y, max_x, max_y); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; *argv[i + 4] = '\0'; i += 4; + } + else + { + REprintf("ERROR: unknown '-inside' option '%s'\n", argv[i]); + return FALSE; + } + } + else if (strcmp(argv[i], "-iadd_extra") == 0 || strcmp(argv[i], "-iadd_attribute") == 0) + { + if ((i + 3) >= argc) + { + REprintf("ERROR: '%s' needs 3 arguments: data_type name description\n", argv[i]); + return FALSE; + } + if (((i + 4) < argc) && (atof(argv[i + 4]) != 0.0)) + { + if (((i + 5) < argc) && ((atof(argv[i + 5]) != 0.0) || (strcmp(argv[i + 5], "0") == 0) || (strcmp(argv[i + 5], "0.0") == 0))) + { + if (((i + 6) < argc) && (atof(argv[i + 6]) != 0.0)) + { + if (((i + 7) < argc) && ((atof(argv[i + 7]) != 0.0) || (strcmp(argv[i + 7], "0") == 0) || (strcmp(argv[i + 7], "0.0") == 0))) + { + if (((i + 8) < argc) && ((atof(argv[i + 8]) != 0.0) || (strcmp(argv[i + 8], "0") == 0) || (strcmp(argv[i + 8], "0.0") == 0))) + { + add_attribute(atoi(argv[i + 1]), argv[i + 2], argv[i + 3], atof(argv[i + 4]), atof(argv[i + 5]), atof(argv[i + 6]), atof(argv[i + 7]), atof(argv[i + 8])); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; *argv[i + 4] = '\0'; *argv[i + 5] = '\0'; *argv[i + 6] = '\0'; *argv[i + 7] = '\0'; *argv[i + 8] = '\0'; i += 8; + } + else + { + add_attribute(atoi(argv[i + 1]), argv[i + 2], argv[i + 3], atof(argv[i + 4]), atof(argv[i + 5]), atof(argv[i + 6]), atof(argv[i + 7])); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; *argv[i + 4] = '\0'; *argv[i + 5] = '\0'; *argv[i + 6] = '\0'; *argv[i + 7] = '\0'; i += 7; + } + } + else + { + add_attribute(atoi(argv[i + 1]), argv[i + 2], argv[i + 3], atof(argv[i + 4]), atof(argv[i + 5]), atof(argv[i + 6])); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; *argv[i + 4] = '\0'; *argv[i + 5] = '\0'; *argv[i + 6] = '\0'; i += 6; + } + } + else + { + add_attribute(atoi(argv[i + 1]), argv[i + 2], argv[i + 3], atof(argv[i + 4]), atof(argv[i + 5])); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; *argv[i + 4] = '\0'; *argv[i + 5] = '\0'; i += 5; + } + } + else + { + add_attribute(atoi(argv[i + 1]), argv[i + 2], argv[i + 3], atof(argv[i + 4])); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; *argv[i + 4] = '\0'; i += 4; + } + } + else + { + add_attribute(atoi(argv[i + 1]), argv[i + 2], argv[i + 3]); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; i += 3; + } + } + else if (strcmp(argv[i], "-iparse") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: string\n", argv[i]); + return FALSE; + } + set_parse_string(argv[i + 1]); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-iskip") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: number_of_lines\n", argv[i]); + return FALSE; + } + U32 number_of_lines; + if (sscanf(argv[i + 1], "%u", &number_of_lines) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: number_of_lines but '%s' is not a valid number.\n", argv[i], argv[i + 1]); + return FALSE; + } + if (number_of_lines == 0) + { + REprintf("ERROR: '%s' needs 1 argument: number_of_lines but %u is not valid.\n", argv[i], number_of_lines); + return FALSE; + } + set_skip_lines(number_of_lines); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-io_ibuffer") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: size\n", argv[i]); + return FALSE; + } + U32 buffer_size; + if (sscanf(argv[i + 1], "%u", &buffer_size) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: size but '%s' is not a valid size.\n", argv[i], argv[i + 1]); + return FALSE; + } + if (buffer_size == 0) + { + REprintf("ERROR: '%s' needs 1 argument: size but %u is not valid.\n", argv[i], buffer_size); + return FALSE; + } + set_io_ibuffer_size(buffer_size); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-itranslate_intensity") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: translation\n", argv[i]); + return FALSE; + } + F32 translation; + if (sscanf(argv[i + 1], "%f", &translation) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: translation but '%s' is not valid.\n", argv[i], argv[i + 1]); + return FALSE; + } + if (translation == 0.0f) + { + REprintf("ERROR: '%s' needs 1 argument: translation but %f is not valid.\n", argv[i], translation); + return FALSE; + } + set_translate_intensity(translation); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-iscale_intensity") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: scale\n", argv[i]); + return FALSE; + } + F32 scale; + if (sscanf(argv[i + 1], "%f", &scale) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: scale but '%s' is not valid.\n", argv[i], argv[i + 1]); + return FALSE; + } + if (scale == 0.0f) + { + REprintf("ERROR: '%s' needs 1 argument: scale but %f is not valid.\n", argv[i], scale); + return FALSE; + } + set_scale_intensity(scale); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-itranslate_scan_angle") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: translation\n", argv[i]); + return FALSE; + } + F32 translation; + if (sscanf(argv[i + 1], "%f", &translation) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: translation but '%s' is not valid.\n", argv[i], argv[i + 1]); + return FALSE; + } + if (translation == 0.0f) + { + REprintf("ERROR: '%s' needs 1 argument: translation but %f is not valid.\n", argv[i], translation); + return FALSE; + } + set_translate_scan_angle(translation); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-iscale_scan_angle") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: scale\n", argv[i]); + return FALSE; + } + F32 scale; + if (sscanf(argv[i + 1], "%f", &scale) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: scale but '%s' is not valid.\n", argv[i], argv[i + 1]); + return FALSE; + } + if (scale == 0.0f) + { + REprintf("ERROR: '%s' needs 1 argument: scale but %f is not valid.\n", argv[i], scale); + return FALSE; + } + set_scale_scan_angle(scale); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-ipts") == 0) + { + itxt = TRUE; + ipts = TRUE; + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-iptx") == 0) + { + itxt = TRUE; + iptx = TRUE; + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-iptx_transform") == 0) + { + itxt = TRUE; + iptx_transform = TRUE; + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-itxt") == 0) + { + itxt = TRUE; + *argv[i] = '\0'; + } + } + else if (strncmp(argv[i], "-r", 2) == 0) + { + if (strcmp(argv[i], "-rescale") == 0) + { + if ((i + 3) >= argc) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z\n", argv[i]); + return FALSE; + } + F64 scale_factor[3]; + if (sscanf(argv[i + 1], "%lf", &(scale_factor[0])) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but '%s' is not a valid rescale_x", argv[i], argv[i + 1]); + return FALSE; + } + if (scale_factor[0] == 0.0) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but %lf is not a valid rescale_x", argv[i], scale_factor[0]); + return FALSE; + } + if (sscanf(argv[i + 2], "%lf", &(scale_factor[1])) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but '%s' is not a valid rescale_y", argv[i], argv[i + 2]); + return FALSE; + } + if (scale_factor[1] == 0.0) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but %lf is not a valid rescale_y", argv[i], scale_factor[1]); + return FALSE; + } + if (sscanf(argv[i + 3], "%lf", &(scale_factor[2])) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but '%s' is not a valid rescale_z", argv[i], argv[i + 3]); + return FALSE; + } + if (scale_factor[2] == 0.0) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y rescale_z, but %lf is not a valid rescale_z", argv[i], scale_factor[2]); + return FALSE; + } + set_scale_factor(scale_factor); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; i += 3; + } + else if (strcmp(argv[i], "-rescale_xy") == 0) + { + if ((i + 2) >= argc) + { + REprintf("ERROR: '%s' needs 2 argument: rescale_x rescale_y\n", argv[i]); + return FALSE; + } + F64 scale_factor[3]; + if (sscanf(argv[i + 1], "%lf", &(scale_factor[0])) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y, but '%s' is not a valid rescale_x", argv[i], argv[i + 1]); + return FALSE; + } + if (scale_factor[0] == 0.0) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y, but %lf is not a valid rescale_x", argv[i], scale_factor[0]); + return FALSE; + } + if (sscanf(argv[i + 2], "%lf", &(scale_factor[1])) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y, but '%s' is not a valid rescale_y", argv[i], argv[i + 2]); + return FALSE; + } + if (scale_factor[1] == 0.0) + { + REprintf("ERROR: '%s' needs 3 arguments: rescale_x rescale_y, but %lf is not a valid rescale_y", argv[i], scale_factor[1]); + return FALSE; + } + scale_factor[2] = 0.0; + set_scale_factor(scale_factor); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; i += 2; + } + else if (strcmp(argv[i], "-rescale_z") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: rescale_z\n", argv[i]); + return FALSE; + } + F64 scale_factor[3]; + scale_factor[0] = 0.0; + scale_factor[1] = 0.0; + if (sscanf(argv[i + 1], "%lf", &(scale_factor[2])) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: rescale_z, but '%s' is not a valid rescale_z", argv[i], argv[i + 1]); + return FALSE; + } + if (scale_factor[2] == 0.0) + { + REprintf("ERROR: '%s' needs 1 argument: rescale_z, but %lf is not a valid rescale_z", argv[i], scale_factor[2]); + return FALSE; + } + set_scale_factor(scale_factor); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-reoffset") == 0) + { + if ((i + 3) >= argc) + { + REprintf("ERROR: '%s' needs 3 arguments: reoffset_x, reoffset_y, reoffset_z\n", argv[i]); + return FALSE; + } + F64 offset[3]; + if (sscanf(argv[i + 1], "%lf", &(offset[0])) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: reoffset_x, reoffset_y, reoffset_z, but '%s' is not a valid reoffset_x", argv[i], argv[i + 1]); + return FALSE; + } + if (sscanf(argv[i + 2], "%lf", &(offset[1])) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: reoffset_x, reoffset_y, reoffset_z, but '%s' is not a valid reoffset_y", argv[i], argv[i + 2]); + return FALSE; + } + if (sscanf(argv[i + 3], "%lf", &(offset[2])) != 1) + { + REprintf("ERROR: '%s' needs 3 arguments: reoffset_x, reoffset_y, reoffset_z, but '%s' is not a valid reoffset_z", argv[i], argv[i + 3]); + return FALSE; + } + set_offset(offset); + *argv[i] = '\0'; *argv[i + 1] = '\0'; *argv[i + 2] = '\0'; *argv[i + 3] = '\0'; i += 3; + } + else if (strcmp(argv[i],"-resolution") == 0) // copc + { + if ((i+1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: resolution\n", argv[i]); + return FALSE; + } + F32 resolution; + if (sscanf(argv[i+1], "%f", &(resolution)) != 1) + { + REprintf( "ERROR: '%s' needs 1 argument: resolution, but '%s' is not a valid resolution", argv[i], argv[i+1]); + return FALSE; + } + if (resolution <= 0) + { + REprintf( "ERROR: '%s' needs 1 argument: resolution, but %lf is not a valid resolution", argv[i], resolution); + return FALSE; + } + + set_resolution(resolution); + *argv[i]='\0'; *argv[i+1]='\0'; i+=1; + } + } + else if (strcmp(argv[i], "-unique") == 0) + { + unique = TRUE; + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-comma_not_point") == 0) + { + comma_not_point = TRUE; + *argv[i] = '\0'; + } + else if (strncmp(argv[i], "-s", 2) == 0) + { + if (strcmp(argv[i], "-stdin") == 0) + { + use_stdin = TRUE; + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-stored") == 0) + { + set_stored(TRUE); + *argv[i] = '\0'; + } + else if (strcmp(argv[i],"-stream_order_spatial") == 0) // COPC only + { + set_copc_stream_ordered_spatially(); + *argv[i]='\0'; + } + else if (strcmp(argv[i],"-stream_order_normal") == 0) // COPC only + { + set_copc_stream_ordered_by_chunk(); + *argv[i]='\0'; + } + else if (strcmp(argv[i],"-stream_order_level") == 0) // COPC only + { + set_copc_stream_ordered_by_level(); + *argv[i]='\0'; + } + } + else if (strcmp(argv[i], "-lof") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: list_of_files\n", argv[i]); + return FALSE; + } + if (!add_list_of_files(argv[i + 1], unique)) + { + REprintf("ERROR: cannot load list of files '%s'\n", argv[i + 1]); + return FALSE; + } + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strncmp(argv[i], "-a", 2) == 0) + { + if (strcmp(argv[i], "-auto_reoffset") == 0) + { + set_auto_reoffset(TRUE); + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-apply_file_source_ID") == 0) + { + set_apply_file_source_ID(TRUE); + *argv[i] = '\0'; + } + } + else if (strncmp(argv[i], "-f", 2) == 0) + { + if (strcmp(argv[i], "-files_are_flightlines") == 0 || strcmp(argv[i], "-faf") == 0) + { + if (((i + 1) < argc) && ('1' <= argv[i + 1][0]) && (argv[i + 1][0] <= '9')) + { + set_files_are_flightlines(atoi(argv[i + 1])); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else + { + set_files_are_flightlines(1); + *argv[i] = '\0'; + } + } + else if (strcmp(argv[i], "-faf_index") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: index\n", argv[i]); + return FALSE; + } + set_files_are_flightlines_index(atoi(argv[i + 1])); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + } + else if (strcmp(argv[i], "-merged") == 0) + { + set_merged(TRUE); + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-buffered") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: buffer_size\n", argv[i]); + return FALSE; + } + F32 buffer_size; + if (sscanf(argv[i + 1], "%f", &buffer_size) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: buffer_size. but '%s' is not a valid buffer_size", argv[i], argv[i + 1]); + return FALSE; + } + if (buffer_size <= 0.0f) + { + REprintf("ERROR: '%s' needs 1 argument: buffer_size, but %f is not valid", argv[i], buffer_size); + return FALSE; + } + set_buffer_size(buffer_size); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strcmp(argv[i], "-temp_files") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: base name\n", argv[i]); + return FALSE; + } + temp_file_base = LASCopyString(argv[i + 1]); + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + else if (strncmp(argv[i], "-n", 2) == 0) + { + if (strcmp(argv[i], "-neighbors") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs at least 1 argument: file_name or wild_card\n", argv[i]); + return FALSE; + } + *argv[i] = '\0'; + i += 1; + do + { + add_neighbor_file_name(argv[i]); + *argv[i] = '\0'; + i += 1; + } while ((i < argc) && (*argv[i] != '-') && (*argv[i] != '\0')); + i -= 1; + } + else if (strcmp(argv[i], "-neighbors_lof") == 0) + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs at least 1 argument: file_name\n", argv[i]); + return FALSE; + } + if (!add_neighbor_list_of_files(argv[i + 1], unique)) + { + REprintf("ERROR: cannot load neighbor list of files '%s'\n", argv[i + 1]); + return FALSE; + } + *argv[i] = '\0'; *argv[i + 1] = '\0'; i += 1; + } + } + else if (strncmp(argv[i], "-p", 2) == 0) + { + if (strcmp(argv[i], "-pipe_on") == 0) + { + set_pipe_on(TRUE); + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-populate") == 0) + { + set_populate_header(TRUE); + *argv[i] = '\0'; + } + } + else if (strcmp(argv[i], "-do_not_populate") == 0) + { + set_populate_header(FALSE); + *argv[i] = '\0'; + } + else if (strcmp(argv[i], "-max_depth") == 0) // copc + { + if ((i + 1) >= argc) + { + REprintf("ERROR: '%s' needs 1 argument: depth\n", argv[i]); + return FALSE; + } + I32 depth; + if (sscanf(argv[i + 1], "%d", &(depth)) != 1) + { + REprintf("ERROR: '%s' needs 1 argument: depth, but '%s' is not a valid depth\n", argv[i], argv[i + 1]); + return FALSE; + } + if (depth < 0) + { + REprintf("ERROR: '%s' needs 1 argument: depth, but %d is not a valid depth\n", argv[i], depth); + return FALSE; + } + + set_max_depth(depth); + *argv[i] = '\0'; + *argv[i + 1] = '\0'; + i += 1; + } + } + + // check that there are only buffered neighbors for single files + + if (neighbor_file_name_number) + { + if (file_name_number > 1) + { + REprintf("ERROR: neighbors only supported for one buffered input file, not for %d\n", file_name_number); + return FALSE; + } + if (buffer_size == 0.0f) + { + REprintf("ERROR: neighbors only make sense when used with '-buffered 50' or similar\n"); + return FALSE; + } + } + + if (filter) filter->clean(); + else filter = new LASfilter(); + if (!filter->parse(argc, argv)) + { + delete filter; + filter = 0; + return FALSE; + } + if (!filter->active()) + { + delete filter; + filter = 0; + } + + if (transform) transform->clean(); + else transform = new LAStransform(); + if (!transform->parse(argc, argv)) + { + delete transform; + transform = 0; + return FALSE; + } + if (!transform->active()) + { + if (transform->filtered()) + { + REprintf("WARNING: no LAStransform specified. '-filtered_transform' has no effect.\n"); + } + delete transform; + transform = 0; + } + else if (transform->filtered()) + { + if (filter == 0) + { + REprintf("WARNING: no LASfilter specified. '-filtered_transform' has no effect.\n"); + } + else + { + transform->setFilter(filter); + filter = 0; + } + } + + if (files_are_flightlines || apply_file_source_ID) + { + if (transform == 0) transform = new LAStransform(); + transform->setPointSource(0); + } + + return TRUE; } BOOL LASreadOpener::parse_str(CHAR* string) @@ -2484,290 +2698,290 @@ BOOL LASreadOpener::parse_str(CHAR* string) U32 LASreadOpener::get_file_name_number() const { - return file_name_number; + return file_name_number; } U32 LASreadOpener::get_file_name_current() const { - return file_name_current; + return file_name_current; } const CHAR* LASreadOpener::get_file_name() const { - if (file_name) - return file_name; - if (file_name_number) - return file_names[0]; - return 0; + if (file_name) + return file_name; + if (file_name_number) + return file_names[0]; + return 0; } const CHAR* LASreadOpener::get_file_name_only() const { - const CHAR* file_name_only = 0; - const CHAR* file_name_curr = get_file_name(); + const CHAR* file_name_only = 0; + const CHAR* file_name_curr = get_file_name(); - if (file_name_curr) - { - I32 len = (I32)strlen(file_name_curr); - while ((len > 0) && (file_name_curr[len] != '\\') && (file_name_curr[len] != '/') && (file_name_curr[len] != ':')) len--; - if (len) - { - file_name_only = file_name_curr + len + 1; - } - else - { - file_name_only = file_name_curr; - } - } + if (file_name_curr) + { + I32 len = (I32)strlen(file_name_curr); + while ((len > 0) && (file_name_curr[len] != '\\') && (file_name_curr[len] != '/') && (file_name_curr[len] != ':')) len--; + if (len) + { + file_name_only = file_name_curr + len + 1; + } + else + { + file_name_only = file_name_curr; + } + } - return file_name_only; + return file_name_only; } const CHAR* LASreadOpener::get_file_extension_only() const { - const CHAR* file_extension_only = 0; - const CHAR* file_name_curr = get_file_name(); + const CHAR* file_extension_only = 0; + const CHAR* file_name_curr = get_file_name(); - if (file_name_curr) - { - I32 len = (I32)strlen(file_name_curr); - while ((len > 0) && (file_name_curr[len] != '.')) len--; - if (len) - { - file_extension_only = file_name_curr + len + 1; - } - } + if (file_name_curr) + { + I32 len = (I32)strlen(file_name_curr); + while ((len > 0) && (file_name_curr[len] != '.')) len--; + if (len) + { + file_extension_only = file_name_curr + len + 1; + } + } - return file_extension_only; + return file_extension_only; } const CHAR* LASreadOpener::get_file_name(U32 number) const { - return file_names[number]; + return file_names[number]; } const CHAR* LASreadOpener::get_file_name_only(U32 number) const { - const CHAR* file_name_only = 0; - const CHAR* file_name_curr = get_file_name(number); + const CHAR* file_name_only = 0; + const CHAR* file_name_curr = get_file_name(number); - if (file_name_curr) - { - I32 len = (I32)strlen(file_name_curr); - while ((len > 0) && (file_name_curr[len] != '\\') && (file_name_curr[len] != '/') && (file_name_curr[len] != ':')) len--; - if (len) - { - file_name_only = file_name_curr + len + 1; - } - else - { - file_name_only = file_name_curr; - } - } + if (file_name_curr) + { + I32 len = (I32)strlen(file_name_curr); + while ((len > 0) && (file_name_curr[len] != '\\') && (file_name_curr[len] != '/') && (file_name_curr[len] != ':')) len--; + if (len) + { + file_name_only = file_name_curr + len + 1; + } + else + { + file_name_only = file_name_curr; + } + } - return file_name_only; + return file_name_only; } const CHAR* LASreadOpener::get_file_extension_only(U32 number) const { - const CHAR* file_extension_only = 0; - const CHAR* file_name_curr = get_file_name(number); + const CHAR* file_extension_only = 0; + const CHAR* file_name_curr = get_file_name(number); - if (file_name_curr) - { - I32 len = (I32)strlen(file_name_curr); - while ((len > 0) && (file_name_curr[len] != '.')) len--; - if (len) - { - file_extension_only = file_name_curr + len + 1; - } - } + if (file_name_curr) + { + I32 len = (I32)strlen(file_name_curr); + while ((len > 0) && (file_name_curr[len] != '.')) len--; + if (len) + { + file_extension_only = file_name_curr + len + 1; + } + } - return file_extension_only; + return file_extension_only; } I32 LASreadOpener::get_file_format(U32 number) const { - if (strstr(file_names[number], ".las") || strstr(file_names[number], ".LAS")) - { - return LAS_TOOLS_FORMAT_LAS; - } - else if (strstr(file_names[number], ".laz") || strstr(file_names[number], ".LAZ")) - { - return LAS_TOOLS_FORMAT_LAZ; - } - else if (strstr(file_names[number], ".bin") || strstr(file_names[number], ".BIN")) - { - return LAS_TOOLS_FORMAT_BIN; - } - else if (strstr(file_names[number], ".shp") || strstr(file_names[number], ".SHP")) - { - return LAS_TOOLS_FORMAT_SHP; - } - else if (strstr(file_names[number], ".qi") || strstr(file_names[number], ".QI")) - { - return LAS_TOOLS_FORMAT_QFIT; - } - else if (strstr(file_names[number], ".asc") || strstr(file_names[number], ".ASC")) - { - return LAS_TOOLS_FORMAT_ASC; - } - else if (strstr(file_names[number], ".bil") || strstr(file_names[number], ".BIL")) - { - return LAS_TOOLS_FORMAT_BIL; - } - else if (strstr(file_names[number], ".dtm") || strstr(file_names[number], ".DTM")) - { - return LAS_TOOLS_FORMAT_DTM; - } - else - { - return LAS_TOOLS_FORMAT_TXT; - } + if (strstr(file_names[number], ".las") || strstr(file_names[number], ".LAS")) + { + return LAS_TOOLS_FORMAT_LAS; + } + else if (strstr(file_names[number], ".laz") || strstr(file_names[number], ".LAZ")) + { + return LAS_TOOLS_FORMAT_LAZ; + } + else if (strstr(file_names[number], ".bin") || strstr(file_names[number], ".BIN")) + { + return LAS_TOOLS_FORMAT_BIN; + } + else if (strstr(file_names[number], ".shp") || strstr(file_names[number], ".SHP")) + { + return LAS_TOOLS_FORMAT_SHP; + } + else if (strstr(file_names[number], ".qi") || strstr(file_names[number], ".QI")) + { + return LAS_TOOLS_FORMAT_QFIT; + } + else if (strstr(file_names[number], ".asc") || strstr(file_names[number], ".ASC")) + { + return LAS_TOOLS_FORMAT_ASC; + } + else if (strstr(file_names[number], ".bil") || strstr(file_names[number], ".BIL")) + { + return LAS_TOOLS_FORMAT_BIL; + } + else if (strstr(file_names[number], ".dtm") || strstr(file_names[number], ".DTM")) + { + return LAS_TOOLS_FORMAT_DTM; + } + else + { + return LAS_TOOLS_FORMAT_TXT; + } } CHAR* LASreadOpener::get_file_name_base() const { - CHAR* file_name_base = 0; + CHAR* file_name_base = 0; - if (file_name) - { - file_name_base = LASCopyString(file_name); - // remove extension - I32 len = (I32)strlen(file_name_base); - while ((len > 0) && (file_name_base[len] != '\\') && (file_name_base[len] != '/') && (file_name_base[len] != ':')) len--; - file_name_base[len] = '\0'; - } + if (file_name) + { + file_name_base = LASCopyString(file_name); + // remove extension + I32 len = (I32)strlen(file_name_base); + while ((len > 0) && (file_name_base[len] != '\\') && (file_name_base[len] != '/') && (file_name_base[len] != ':')) len--; + file_name_base[len] = '\0'; + } - return file_name_base; + return file_name_base; } CHAR* LASreadOpener::get_file_name_base(U32 number) const { - CHAR* file_name_base = 0; + CHAR* file_name_base = 0; - if (get_file_name(number)) - { - file_name_base = LASCopyString(get_file_name(number)); - // remove extension - I32 len = (I32)strlen(file_name_base); - while ((len > 0) && (file_name_base[len] != '\\') && (file_name_base[len] != '/') && (file_name_base[len] != ':')) len--; - file_name_base[len] = '\0'; - } + if (get_file_name(number)) + { + file_name_base = LASCopyString(get_file_name(number)); + // remove extension + I32 len = (I32)strlen(file_name_base); + while ((len > 0) && (file_name_base[len] != '\\') && (file_name_base[len] != '/') && (file_name_base[len] != ':')) len--; + file_name_base[len] = '\0'; + } - return file_name_base; + return file_name_base; } void LASreadOpener::set_merged(const BOOL merged) { - this->merged = merged; + this->merged = merged; } void LASreadOpener::set_stored(const BOOL stored) { - this->stored = stored; + this->stored = stored; } void LASreadOpener::set_buffer_size(const F32 buffer_size) { - this->buffer_size = buffer_size; + this->buffer_size = buffer_size; } F32 LASreadOpener::get_buffer_size() const { - return buffer_size; + return buffer_size; } void LASreadOpener::set_filter(LASfilter* filter) { - this->filter = filter; + this->filter = filter; } void LASreadOpener::set_transform(LAStransform* transform) { - this->transform = transform; + this->transform = transform; } void LASreadOpener::set_auto_reoffset(const BOOL auto_reoffset) { - this->auto_reoffset = auto_reoffset; + this->auto_reoffset = auto_reoffset; } void LASreadOpener::set_files_are_flightlines(const I32 files_are_flightlines) { - this->files_are_flightlines = files_are_flightlines; - if (files_are_flightlines > (I32)(U16_MAX)) - { - REprintf( "WARNING: files_are_flightlines start value %d is too large\n", files_are_flightlines); - } - else if ((files_are_flightlines + files_are_flightlines_index) > (I32)(U16_MAX)) - { - REprintf( "WARNING: files_are_flightlines start value %d plus index %d is too large\n", files_are_flightlines, files_are_flightlines_index); - } + this->files_are_flightlines = files_are_flightlines; + if (files_are_flightlines > (I32)(U16_MAX)) + { + REprintf("WARNING: files_are_flightlines start value %d is too large\n", files_are_flightlines); + } + else if ((files_are_flightlines + files_are_flightlines_index) > (I32)(U16_MAX)) + { + REprintf("WARNING: files_are_flightlines start value %d plus index %d is too large\n", files_are_flightlines, files_are_flightlines_index); + } } void LASreadOpener::set_files_are_flightlines_index(const I32 files_are_flightlines_index) { - this->files_are_flightlines_index = files_are_flightlines_index-1; - if (files_are_flightlines_index > (I32)(U16_MAX)) - { - REprintf( "WARNING: files_are_flightlines_index index value %d is too large\n", files_are_flightlines_index); - } - else if ((files_are_flightlines + files_are_flightlines_index) > (I32)(U16_MAX)) - { - REprintf( "WARNING: files_are_flightlines start value %d plus index %d is too large\n", files_are_flightlines, files_are_flightlines_index); - } + this->files_are_flightlines_index = files_are_flightlines_index - 1; + if (files_are_flightlines_index > (I32)(U16_MAX)) + { + REprintf("WARNING: files_are_flightlines_index index value %d is too large\n", files_are_flightlines_index); + } + else if ((files_are_flightlines + files_are_flightlines_index) > (I32)(U16_MAX)) + { + REprintf("WARNING: files_are_flightlines start value %d plus index %d is too large\n", files_are_flightlines, files_are_flightlines_index); + } } void LASreadOpener::set_apply_file_source_ID(const BOOL apply_file_source_ID) { - this->apply_file_source_ID = apply_file_source_ID; + this->apply_file_source_ID = apply_file_source_ID; } void LASreadOpener::set_io_ibuffer_size(const U32 buffer_size) { - this->io_ibuffer_size = buffer_size; + this->io_ibuffer_size = buffer_size; } void LASreadOpener::set_file_name(const CHAR* file_name, BOOL unique) { - add_file_name(file_name, unique); + add_file_name(file_name, unique); } #ifdef _WIN32 #include BOOL LASreadOpener::add_file_name(const CHAR* file_name, BOOL unique) { - BOOL r = FALSE; - HANDLE h; - WIN32_FIND_DATA info; - h = FindFirstFile(file_name, &info); - if (h != INVALID_HANDLE_VALUE) - { - // find the path - I32 len = (I32)strlen(file_name); - while (len && (file_name[len] != '\\') && (file_name[len] != '/') && (file_name[len] != ':')) len--; - if (len) - { - len++; - CHAR full_file_name[512]; - strncpy(full_file_name, file_name, len); - do - { - snprintf(&full_file_name[len], 512, "%s", info.cFileName); - if (add_file_name_single(full_file_name, unique)) r = TRUE; - } while (FindNextFile(h, &info)); - } - else - { - do - { - if (add_file_name_single(info.cFileName, unique)) r = TRUE; - } while (FindNextFile(h, &info)); - } - FindClose(h); - } - return r; + BOOL r = FALSE; + HANDLE h; + WIN32_FIND_DATA info; + h = FindFirstFile(file_name, &info); + if (h != INVALID_HANDLE_VALUE) + { + // find the path + I32 len = (I32)strlen(file_name); + while (len && (file_name[len] != '\\') && (file_name[len] != '/') && (file_name[len] != ':')) len--; + if (len) + { + len++; + CHAR full_file_name[512]; + strncpy(full_file_name, file_name, len); + do + { + snprintf(&full_file_name[len], 512, "%s", info.cFileName); + if (add_file_name_single(full_file_name, unique)) r = TRUE; + } while (FindNextFile(h, &info)); + } + else + { + do + { + if (add_file_name_single(info.cFileName, unique)) r = TRUE; + } while (FindNextFile(h, &info)); + } + FindClose(h); + } + return r; } #endif @@ -2777,462 +2991,462 @@ BOOL LASreadOpener::add_file_name_single(const CHAR* file_name, BOOL unique) BOOL LASreadOpener::add_file_name(const CHAR* file_name, BOOL unique) #endif { - if (unique) - { - U32 i; - for (i = 0; i < file_name_number; i++) - { - if (strcmp(file_names[i], file_name) == 0) - { - return FALSE; - } - } - } - if (file_name_number == file_name_allocated) - { - if (file_names) - { - file_name_allocated *= 2; - file_names = (CHAR**)realloc(file_names, sizeof(CHAR*)*file_name_allocated); - } - else - { - file_name_allocated = 16; - file_names = (CHAR**)malloc(sizeof(CHAR*)*file_name_allocated); - } - if (file_names == 0) - { - REprintf( "ERROR: alloc for file_names pointer array failed at %d\n", file_name_allocated); - } - } - file_names[file_name_number] = LASCopyString(file_name); - file_name_number++; - return TRUE; + if (unique) + { + U32 i; + for (i = 0; i < file_name_number; i++) + { + if (strcmp(file_names[i], file_name) == 0) + { + return FALSE; + } + } + } + if (file_name_number == file_name_allocated) + { + if (file_names) + { + file_name_allocated *= 2; + file_names = (CHAR**)realloc(file_names, sizeof(CHAR*)*file_name_allocated); + } + else + { + file_name_allocated = 16; + file_names = (CHAR**)malloc(sizeof(CHAR*)*file_name_allocated); + } + if (file_names == 0) + { + REprintf("ERROR: alloc for file_names pointer array failed at %d\n", file_name_allocated); + } + } + file_names[file_name_number] = LASCopyString(file_name); + file_name_number++; + return TRUE; } BOOL LASreadOpener::add_file_name(const CHAR* file_name, U32 ID, BOOL unique) { - if (unique) - { - U32 i; - for (i = 0; i < file_name_number; i++) - { - if (strcmp(file_names[i], file_name) == 0) - { - return FALSE; - } - } - } - if (file_name_number == file_name_allocated) - { - if (file_names) - { - file_name_allocated *= 2; - file_names = (CHAR**)realloc(file_names, sizeof(CHAR*)*file_name_allocated); - file_names_ID = (U32*)realloc(file_names_ID, sizeof(U32)*file_name_allocated); - } - else - { - file_name_allocated = 16; - file_names = (CHAR**)malloc(sizeof(CHAR*)*file_name_allocated); - file_names_ID = (U32*)malloc(sizeof(U32)*file_name_allocated); - } - if (file_names == 0) - { - REprintf( "ERROR: alloc for file_names pointer array failed at %d\n", file_name_allocated); - return FALSE; - } - if (file_names_ID == 0) - { - REprintf( "ERROR: alloc for file_names_ID array failed at %d\n", file_name_allocated); - return FALSE; - } - } - file_names[file_name_number] = LASCopyString(file_name); - file_names_ID[file_name_number] = ID; - file_name_number++; - return TRUE; + if (unique) + { + U32 i; + for (i = 0; i < file_name_number; i++) + { + if (strcmp(file_names[i], file_name) == 0) + { + return FALSE; + } + } + } + if (file_name_number == file_name_allocated) + { + if (file_names) + { + file_name_allocated *= 2; + file_names = (CHAR**)realloc(file_names, sizeof(CHAR*)*file_name_allocated); + file_names_ID = (U32*)realloc(file_names_ID, sizeof(U32)*file_name_allocated); + } + else + { + file_name_allocated = 16; + file_names = (CHAR**)malloc(sizeof(CHAR*)*file_name_allocated); + file_names_ID = (U32*)malloc(sizeof(U32)*file_name_allocated); + } + if (file_names == 0) + { + REprintf("ERROR: alloc for file_names pointer array failed at %d\n", file_name_allocated); + return FALSE; + } + if (file_names_ID == 0) + { + REprintf("ERROR: alloc for file_names_ID array failed at %d\n", file_name_allocated); + return FALSE; + } + } + file_names[file_name_number] = LASCopyString(file_name); + file_names_ID[file_name_number] = ID; + file_name_number++; + return TRUE; } BOOL LASreadOpener::add_file_name(const CHAR* file_name, U32 ID, I64 npoints, F64 min_x, F64 min_y, F64 max_x, F64 max_y, BOOL unique) { - if (unique) - { - U32 i; - for (i = 0; i < file_name_number; i++) - { - if (strcmp(file_names[i], file_name) == 0) - { - return FALSE; - } - } - } - if (file_name_number == file_name_allocated) - { - if (file_names) - { - file_name_allocated *= 2; - file_names = (CHAR**)realloc(file_names, sizeof(CHAR*)*file_name_allocated); - file_names_ID = (U32*)realloc(file_names_ID, sizeof(U32)*file_name_allocated); - file_names_npoints = (I64*)realloc(file_names_npoints, sizeof(I64)*file_name_allocated); - file_names_min_x = (F64*)realloc(file_names_min_x, sizeof(F64)*file_name_allocated); - file_names_min_y = (F64*)realloc(file_names_min_y, sizeof(F64)*file_name_allocated); - file_names_max_x = (F64*)realloc(file_names_max_x, sizeof(F64)*file_name_allocated); - file_names_max_y = (F64*)realloc(file_names_max_y, sizeof(F64)*file_name_allocated); - } - else - { - file_name_allocated = 16; - file_names = (CHAR**)malloc(sizeof(CHAR*)*file_name_allocated); - file_names_ID = (U32*)malloc(sizeof(U32)*file_name_allocated); - file_names_npoints = (I64*)malloc(sizeof(I64)*file_name_allocated); - file_names_min_x = (F64*)malloc(sizeof(F64)*file_name_allocated); - file_names_min_y = (F64*)malloc(sizeof(F64)*file_name_allocated); - file_names_max_x = (F64*)malloc(sizeof(F64)*file_name_allocated); - file_names_max_y = (F64*)malloc(sizeof(F64)*file_name_allocated); - if (kdtree_rectangles == 0) - { - kdtree_rectangles = new LASkdtreeRectangles(); - if (kdtree_rectangles == 0) - { - REprintf( "ERROR: alloc for LASkdtreeRectangles failed\n"); - return FALSE; - } - } - kdtree_rectangles->init(); - } - if (file_names == 0) - { - REprintf( "ERROR: alloc for file_names pointer array failed at %d\n", file_name_allocated); - return FALSE; - } - if (file_names_ID == 0) - { - REprintf( "ERROR: alloc for file_names_ID array failed at %d\n", file_name_allocated); - return FALSE; - } - if (file_names_npoints == 0) - { - REprintf( "ERROR: alloc for file_names_npoints array failed at %d\n", file_name_allocated); - return FALSE; - } - if (file_names_min_x == 0) - { - REprintf( "ERROR: alloc for file_names_min_x array failed at %d\n", file_name_allocated); - return FALSE; - } - if (file_names_min_y == 0) - { - REprintf( "ERROR: alloc for file_names_min_y array failed at %d\n", file_name_allocated); - return FALSE; - } - if (file_names_max_x == 0) - { - REprintf( "ERROR: alloc for file_names_max_x array failed at %d\n", file_name_allocated); - return FALSE; - } - if (file_names_max_y == 0) - { - REprintf( "ERROR: alloc for file_names_max_y array failed at %d\n", file_name_allocated); - return FALSE; - } - } - file_names[file_name_number] = LASCopyString(file_name); - file_names_ID[file_name_number] = ID; - file_names_npoints[file_name_number] = npoints; - file_names_min_x[file_name_number] = min_x; - file_names_min_y[file_name_number] = min_y; - file_names_max_x[file_name_number] = max_x; - file_names_max_y[file_name_number] = max_y; - kdtree_rectangles->add(min_x, min_y, max_x, max_y); - file_name_number++; - return TRUE; + if (unique) + { + U32 i; + for (i = 0; i < file_name_number; i++) + { + if (strcmp(file_names[i], file_name) == 0) + { + return FALSE; + } + } + } + if (file_name_number == file_name_allocated) + { + if (file_names) + { + file_name_allocated *= 2; + file_names = (CHAR**)realloc(file_names, sizeof(CHAR*)*file_name_allocated); + file_names_ID = (U32*)realloc(file_names_ID, sizeof(U32)*file_name_allocated); + file_names_npoints = (I64*)realloc(file_names_npoints, sizeof(I64)*file_name_allocated); + file_names_min_x = (F64*)realloc(file_names_min_x, sizeof(F64)*file_name_allocated); + file_names_min_y = (F64*)realloc(file_names_min_y, sizeof(F64)*file_name_allocated); + file_names_max_x = (F64*)realloc(file_names_max_x, sizeof(F64)*file_name_allocated); + file_names_max_y = (F64*)realloc(file_names_max_y, sizeof(F64)*file_name_allocated); + } + else + { + file_name_allocated = 16; + file_names = (CHAR**)malloc(sizeof(CHAR*)*file_name_allocated); + file_names_ID = (U32*)malloc(sizeof(U32)*file_name_allocated); + file_names_npoints = (I64*)malloc(sizeof(I64)*file_name_allocated); + file_names_min_x = (F64*)malloc(sizeof(F64)*file_name_allocated); + file_names_min_y = (F64*)malloc(sizeof(F64)*file_name_allocated); + file_names_max_x = (F64*)malloc(sizeof(F64)*file_name_allocated); + file_names_max_y = (F64*)malloc(sizeof(F64)*file_name_allocated); + if (kdtree_rectangles == 0) + { + kdtree_rectangles = new LASkdtreeRectangles(); + if (kdtree_rectangles == 0) + { + REprintf("ERROR: alloc for LASkdtreeRectangles failed\n"); + return FALSE; + } + } + kdtree_rectangles->init(); + } + if (file_names == 0) + { + REprintf("ERROR: alloc for file_names pointer array failed at %d\n", file_name_allocated); + return FALSE; + } + if (file_names_ID == 0) + { + REprintf("ERROR: alloc for file_names_ID array failed at %d\n", file_name_allocated); + return FALSE; + } + if (file_names_npoints == 0) + { + REprintf("ERROR: alloc for file_names_npoints array failed at %d\n", file_name_allocated); + return FALSE; + } + if (file_names_min_x == 0) + { + REprintf("ERROR: alloc for file_names_min_x array failed at %d\n", file_name_allocated); + return FALSE; + } + if (file_names_min_y == 0) + { + REprintf("ERROR: alloc for file_names_min_y array failed at %d\n", file_name_allocated); + return FALSE; + } + if (file_names_max_x == 0) + { + REprintf("ERROR: alloc for file_names_max_x array failed at %d\n", file_name_allocated); + return FALSE; + } + if (file_names_max_y == 0) + { + REprintf("ERROR: alloc for file_names_max_y array failed at %d\n", file_name_allocated); + return FALSE; + } + } + file_names[file_name_number] = LASCopyString(file_name); + file_names_ID[file_name_number] = ID; + file_names_npoints[file_name_number] = npoints; + file_names_min_x[file_name_number] = min_x; + file_names_min_y[file_name_number] = min_y; + file_names_max_x[file_name_number] = max_x; + file_names_max_y[file_name_number] = max_y; + kdtree_rectangles->add(min_x, min_y, max_x, max_y); + file_name_number++; + return TRUE; } BOOL LASreadOpener::add_list_of_files(const CHAR* list_of_files, BOOL unique) { - FILE* file = fopen(list_of_files, "r"); - if (file == 0) - { - REprintf( "ERROR: cannot open '%s'\n", list_of_files); - return FALSE; - } - CHAR line[2048]; - CHAR name[2048]; - U32 ID; - I64 npoints; - F64 min_x; - F64 min_y; - F64 max_x; - F64 max_y; - int num; - while (fgets(line, 2048, file)) - { - // find end of line - I32 len = (I32)strlen(line) - 1; - // remove extra white spaces and line return at the end - while ((len > 0) && ((line[len] == '\n') || (line[len] == ' ') || (line[len] == '\t') || (line[len] == '\012'))) - { - line[len] = '\0'; - len--; - } - // try to parse number of points and xy bounds + FILE* file = fopen(list_of_files, "r"); + if (file == 0) + { + REprintf("ERROR: cannot open '%s'\n", list_of_files); + return FALSE; + } + CHAR line[2048]; + CHAR name[2048]; + U32 ID; + I64 npoints; + F64 min_x; + F64 min_y; + F64 max_x; + F64 max_y; + int num; + while (fgets(line, 2048, file)) + { + // find end of line + I32 len = (I32)strlen(line) - 1; + // remove extra white spaces and line return at the end + while ((len > 0) && ((line[len] == '\n') || (line[len] == ' ') || (line[len] == '\t') || (line[len] == '\012'))) + { + line[len] = '\0'; + len--; + } + // try to parse number of points and xy bounds #ifdef _WIN32 - num = sscanf(line, "%u,%" PRId64 ",%lf,%lf,%lf,%lf,", &ID, &npoints, &min_x, &min_y, &max_x, &max_y); + num = sscanf(line, "%u,%" PRId64 ",%lf,%lf,%lf,%lf,", &ID, &npoints, &min_x, &min_y, &max_x, &max_y); #else - num = sscanf(line, "%u,%" PRId64 ",%lf,%lf,%lf,%lf,", &ID, &npoints, &min_x, &min_y, &max_x, &max_y); + num = sscanf(line, "%u,%" PRId64 ",%lf,%lf,%lf,%lf,", &ID, &npoints, &min_x, &min_y, &max_x, &max_y); #endif - if (num == 6) - { - // skip ID, number of points, and xy bounds - num = 0; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - // remove extra white spaces at the beginning - while ((num < len) && ((line[num] == ' ') || (line[num] == '\t'))) num++; - add_file_name(&line[num], ID, npoints, min_x, min_y, max_x, max_y, unique); - } - else - { - // try to parse number and file name - num = sscanf(line, "%u,%s", &ID, name); - if (num == 2) - { - // skip ID - num = 0; - while ((num < len) && (line[num] != ',')) num++; - num++; - // remove extra white spaces at the beginning - while ((num < len) && ((line[num] == ' ') || (line[num] == '\t'))) num++; - add_file_name(&line[num], ID, unique); - } - else - { - add_file_name(line, unique); - } - } - } - fclose(file); - return TRUE; + if (num == 6) + { + // skip ID, number of points, and xy bounds + num = 0; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + // remove extra white spaces at the beginning + while ((num < len) && ((line[num] == ' ') || (line[num] == '\t'))) num++; + add_file_name(&line[num], ID, npoints, min_x, min_y, max_x, max_y, unique); + } + else + { + // try to parse number and file name + num = sscanf(line, "%u,%s", &ID, name); + if (num == 2) + { + // skip ID + num = 0; + while ((num < len) && (line[num] != ',')) num++; + num++; + // remove extra white spaces at the beginning + while ((num < len) && ((line[num] == ' ') || (line[num] == '\t'))) num++; + add_file_name(&line[num], ID, unique); + } + else + { + add_file_name(line, unique); + } + } + } + fclose(file); + return TRUE; } BOOL LASreadOpener::add_neighbor_file_name(const CHAR* neighbor_file_name, I64 npoints, F64 min_x, F64 min_y, F64 max_x, F64 max_y, BOOL unique) { - if (unique) - { - U32 i; - for (i = 0; i < neighbor_file_name_number; i++) - { - if (strcmp(neighbor_file_names[i], neighbor_file_name) == 0) - { - return FALSE; - } - } - } - if (neighbor_file_name_number == neighbor_file_name_allocated) - { - if (neighbor_file_names) - { - neighbor_file_name_allocated *= 2; - neighbor_file_names = (CHAR**)realloc(neighbor_file_names, sizeof(CHAR*)*neighbor_file_name_allocated); - neighbor_file_names_npoints = (I64*)realloc(neighbor_file_names_npoints, sizeof(I64)*neighbor_file_name_allocated); - neighbor_file_names_min_x = (F64*)realloc(neighbor_file_names_min_x, sizeof(F64)*neighbor_file_name_allocated); - neighbor_file_names_min_y = (F64*)realloc(neighbor_file_names_min_y, sizeof(F64)*neighbor_file_name_allocated); - neighbor_file_names_max_x = (F64*)realloc(neighbor_file_names_max_x, sizeof(F64)*neighbor_file_name_allocated); - neighbor_file_names_max_y = (F64*)realloc(neighbor_file_names_max_y, sizeof(F64)*neighbor_file_name_allocated); - } - else - { - neighbor_file_name_allocated = 16; - neighbor_file_names = (CHAR**)malloc(sizeof(CHAR*)*neighbor_file_name_allocated); - neighbor_file_names_npoints = (I64*)malloc(sizeof(I64)*neighbor_file_name_allocated); - neighbor_file_names_min_x = (F64*)malloc(sizeof(F64)*neighbor_file_name_allocated); - neighbor_file_names_min_y = (F64*)malloc(sizeof(F64)*neighbor_file_name_allocated); - neighbor_file_names_max_x = (F64*)malloc(sizeof(F64)*neighbor_file_name_allocated); - neighbor_file_names_max_y = (F64*)malloc(sizeof(F64)*neighbor_file_name_allocated); - if (neighbor_kdtree_rectangles == 0) - { - neighbor_kdtree_rectangles = new LASkdtreeRectangles(); - if (neighbor_kdtree_rectangles == 0) - { - REprintf( "ERROR: alloc for neighbor LASkdtreeRectangles failed\n"); - return FALSE; - } - } - kdtree_rectangles->init(); - } - if (neighbor_file_names == 0) - { - REprintf( "ERROR: alloc for neighbor_file_names pointer array failed at %d\n", neighbor_file_name_allocated); - return FALSE; - } - if (neighbor_file_names_min_x == 0) - { - REprintf( "ERROR: alloc for neighbor_file_names_min_x array failed at %d\n", neighbor_file_name_allocated); - return FALSE; - } - if (neighbor_file_names_min_y == 0) - { - REprintf( "ERROR: alloc for neighbor_file_names_min_y array failed at %d\n", neighbor_file_name_allocated); - return FALSE; - } - if (neighbor_file_names_max_x == 0) - { - REprintf( "ERROR: alloc for neighbor_file_names_max_x array failed at %d\n", neighbor_file_name_allocated); - return FALSE; - } - if (neighbor_file_names_max_y == 0) - { - REprintf( "ERROR: alloc for neighbor_file_names_max_y array failed at %d\n", neighbor_file_name_allocated); - return FALSE; - } - } - neighbor_file_names[neighbor_file_name_number] = LASCopyString(neighbor_file_name); - neighbor_file_names_npoints[neighbor_file_name_number] = npoints; - neighbor_file_names_min_x[neighbor_file_name_number] = min_x; - neighbor_file_names_min_y[neighbor_file_name_number] = min_y; - neighbor_file_names_max_x[neighbor_file_name_number] = max_x; - neighbor_file_names_max_y[neighbor_file_name_number] = max_y; - neighbor_kdtree_rectangles->add(min_x, min_y, max_x, max_y); - neighbor_file_name_number++; - return TRUE; + if (unique) + { + U32 i; + for (i = 0; i < neighbor_file_name_number; i++) + { + if (strcmp(neighbor_file_names[i], neighbor_file_name) == 0) + { + return FALSE; + } + } + } + if (neighbor_file_name_number == neighbor_file_name_allocated) + { + if (neighbor_file_names) + { + neighbor_file_name_allocated *= 2; + neighbor_file_names = (CHAR**)realloc(neighbor_file_names, sizeof(CHAR*)*neighbor_file_name_allocated); + neighbor_file_names_npoints = (I64*)realloc(neighbor_file_names_npoints, sizeof(I64)*neighbor_file_name_allocated); + neighbor_file_names_min_x = (F64*)realloc(neighbor_file_names_min_x, sizeof(F64)*neighbor_file_name_allocated); + neighbor_file_names_min_y = (F64*)realloc(neighbor_file_names_min_y, sizeof(F64)*neighbor_file_name_allocated); + neighbor_file_names_max_x = (F64*)realloc(neighbor_file_names_max_x, sizeof(F64)*neighbor_file_name_allocated); + neighbor_file_names_max_y = (F64*)realloc(neighbor_file_names_max_y, sizeof(F64)*neighbor_file_name_allocated); + } + else + { + neighbor_file_name_allocated = 16; + neighbor_file_names = (CHAR**)malloc(sizeof(CHAR*)*neighbor_file_name_allocated); + neighbor_file_names_npoints = (I64*)malloc(sizeof(I64)*neighbor_file_name_allocated); + neighbor_file_names_min_x = (F64*)malloc(sizeof(F64)*neighbor_file_name_allocated); + neighbor_file_names_min_y = (F64*)malloc(sizeof(F64)*neighbor_file_name_allocated); + neighbor_file_names_max_x = (F64*)malloc(sizeof(F64)*neighbor_file_name_allocated); + neighbor_file_names_max_y = (F64*)malloc(sizeof(F64)*neighbor_file_name_allocated); + if (neighbor_kdtree_rectangles == 0) + { + neighbor_kdtree_rectangles = new LASkdtreeRectangles(); + if (neighbor_kdtree_rectangles == 0) + { + REprintf("ERROR: alloc for neighbor LASkdtreeRectangles failed\n"); + return FALSE; + } + } + kdtree_rectangles->init(); + } + if (neighbor_file_names == 0) + { + REprintf("ERROR: alloc for neighbor_file_names pointer array failed at %d\n", neighbor_file_name_allocated); + return FALSE; + } + if (neighbor_file_names_min_x == 0) + { + REprintf("ERROR: alloc for neighbor_file_names_min_x array failed at %d\n", neighbor_file_name_allocated); + return FALSE; + } + if (neighbor_file_names_min_y == 0) + { + REprintf("ERROR: alloc for neighbor_file_names_min_y array failed at %d\n", neighbor_file_name_allocated); + return FALSE; + } + if (neighbor_file_names_max_x == 0) + { + REprintf("ERROR: alloc for neighbor_file_names_max_x array failed at %d\n", neighbor_file_name_allocated); + return FALSE; + } + if (neighbor_file_names_max_y == 0) + { + REprintf("ERROR: alloc for neighbor_file_names_max_y array failed at %d\n", neighbor_file_name_allocated); + return FALSE; + } + } + neighbor_file_names[neighbor_file_name_number] = LASCopyString(neighbor_file_name); + neighbor_file_names_npoints[neighbor_file_name_number] = npoints; + neighbor_file_names_min_x[neighbor_file_name_number] = min_x; + neighbor_file_names_min_y[neighbor_file_name_number] = min_y; + neighbor_file_names_max_x[neighbor_file_name_number] = max_x; + neighbor_file_names_max_y[neighbor_file_name_number] = max_y; + neighbor_kdtree_rectangles->add(min_x, min_y, max_x, max_y); + neighbor_file_name_number++; + return TRUE; } BOOL LASreadOpener::add_neighbor_list_of_files(const CHAR* neighbor_list_of_files, BOOL unique) { - FILE* file = fopen(neighbor_list_of_files, "r"); - if (file == 0) - { - REprintf( "ERROR: cannot open '%s'\n", neighbor_list_of_files); - return FALSE; - } - CHAR line[2048]; - U32 ID; - I64 npoints; - F64 min_x; - F64 min_y; - F64 max_x; - F64 max_y; - int num; - while (fgets(line, 2048, file)) - { - // find end of line - I32 len = (I32)strlen(line) - 1; - // remove extra white spaces and line return at the end - while ((len > 0) && ((line[len] == '\n') || (line[len] == ' ') || (line[len] == '\t') || (line[len] == '\012'))) - { - line[len] = '\0'; - len--; - } - // try to parse number of points and xy bounds + FILE* file = fopen(neighbor_list_of_files, "r"); + if (file == 0) + { + REprintf("ERROR: cannot open '%s'\n", neighbor_list_of_files); + return FALSE; + } + CHAR line[2048]; + U32 ID; + I64 npoints; + F64 min_x; + F64 min_y; + F64 max_x; + F64 max_y; + int num; + while (fgets(line, 2048, file)) + { + // find end of line + I32 len = (I32)strlen(line) - 1; + // remove extra white spaces and line return at the end + while ((len > 0) && ((line[len] == '\n') || (line[len] == ' ') || (line[len] == '\t') || (line[len] == '\012'))) + { + line[len] = '\0'; + len--; + } + // try to parse number of points and xy bounds #ifdef _WIN32 - num = sscanf(line, "%u,%" PRId64 ",%lf,%lf,%lf,%lf,", &ID, &npoints, &min_x, &min_y, &max_x, &max_y); + num = sscanf(line, "%u,%" PRId64 ",%lf,%lf,%lf,%lf,", &ID, &npoints, &min_x, &min_y, &max_x, &max_y); #else - num = sscanf(line, "%u,%" PRId64 ",%lf,%lf,%lf,%lf,", &ID, &npoints, &min_x, &min_y, &max_x, &max_y); + num = sscanf(line, "%u,%" PRId64 ",%lf,%lf,%lf,%lf,", &ID, &npoints, &min_x, &min_y, &max_x, &max_y); #endif - if (num == 6) - { - // skip number of points and xy bounds - num = 0; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - while ((num < len) && (line[num] != ',')) num++; - num++; - // remove extra white spaces at the beginning - while ((num < len) && ((line[num] == ' ') || (line[num] == '\t'))) num++; - add_neighbor_file_name(&line[num], npoints, min_x, min_y, max_x, max_y, unique); - } - else - { + if (num == 6) + { + // skip number of points and xy bounds + num = 0; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + while ((num < len) && (line[num] != ',')) num++; + num++; + // remove extra white spaces at the beginning + while ((num < len) && ((line[num] == ' ') || (line[num] == '\t'))) num++; + add_neighbor_file_name(&line[num], npoints, min_x, min_y, max_x, max_y, unique); + } + else + { #ifdef _WIN32 - add_neighbor_file_name_single(line); + add_neighbor_file_name_single(line); #else - add_neighbor_file_name(line); + add_neighbor_file_name(line); #endif - } - } - fclose(file); - return TRUE; + } + } + fclose(file); + return TRUE; } void LASreadOpener::delete_file_name(U32 file_name_id) { - if (file_name_id < file_name_number) - { - U32 i; - free(file_names[file_name_id]); - for (i = file_name_id+1; i < file_name_number; i++) - { - file_names[i-1] = file_names[i]; - } - } - file_name_number--; + if (file_name_id < file_name_number) + { + U32 i; + free(file_names[file_name_id]); + for (i = file_name_id + 1; i < file_name_number; i++) + { + file_names[i - 1] = file_names[i]; + } + } + file_name_number--; } BOOL LASreadOpener::set_file_name_current(U32 file_name_id) { - if (file_name_id < file_name_number) - { - file_name_current = file_name_id; - file_name = file_names[file_name_current]; - return TRUE; - } - return FALSE; + if (file_name_id < file_name_number) + { + file_name_current = file_name_id; + file_name = file_names[file_name_current]; + return TRUE; + } + return FALSE; } #ifdef _WIN32 #include BOOL LASreadOpener::add_neighbor_file_name(const CHAR* neighbor_file_name, BOOL unique) { - BOOL r = FALSE; - HANDLE h; - WIN32_FIND_DATA info; - h = FindFirstFile(neighbor_file_name, &info); - if (h != INVALID_HANDLE_VALUE) - { - // find the path - I32 len = (I32)strlen(neighbor_file_name); - while (len && (neighbor_file_name[len] != '\\') && (neighbor_file_name[len] != '/') && (neighbor_file_name[len] != ':')) len--; - if (len) - { - len++; - CHAR full_neighbor_file_name[512]; - strncpy(full_neighbor_file_name, neighbor_file_name, len); - do - { - snprintf(&full_neighbor_file_name[len], 512, "%s", info.cFileName); - if (add_neighbor_file_name_single(full_neighbor_file_name, unique)) r = TRUE; - } while (FindNextFile(h, &info)); - } - else - { - do - { - if (add_neighbor_file_name_single(info.cFileName, unique)) r = TRUE; - } while (FindNextFile(h, &info)); - } - FindClose(h); - } - return r; + BOOL r = FALSE; + HANDLE h; + WIN32_FIND_DATA info; + h = FindFirstFile(neighbor_file_name, &info); + if (h != INVALID_HANDLE_VALUE) + { + // find the path + I32 len = (I32)strlen(neighbor_file_name); + while (len && (neighbor_file_name[len] != '\\') && (neighbor_file_name[len] != '/') && (neighbor_file_name[len] != ':')) len--; + if (len) + { + len++; + CHAR full_neighbor_file_name[512]; + strncpy(full_neighbor_file_name, neighbor_file_name, len); + do + { + snprintf(&full_neighbor_file_name[len], 512, "%s", info.cFileName); + if (add_neighbor_file_name_single(full_neighbor_file_name, unique)) r = TRUE; + } while (FindNextFile(h, &info)); + } + else + { + do + { + if (add_neighbor_file_name_single(info.cFileName, unique)) r = TRUE; + } while (FindNextFile(h, &info)); + } + FindClose(h); + } + return r; } #endif @@ -3242,313 +3456,343 @@ BOOL LASreadOpener::add_neighbor_file_name_single(const CHAR* neighbor_file_name BOOL LASreadOpener::add_neighbor_file_name(const CHAR* neighbor_file_name, BOOL unique) #endif { - if (unique) - { - U32 i; - for (i = 0; i < neighbor_file_name_number; i++) - { - if (strcmp(neighbor_file_names[i], neighbor_file_name) == 0) - { - return FALSE; - } - } - } - if (neighbor_file_name_number == neighbor_file_name_allocated) - { - if (neighbor_file_names) - { - neighbor_file_name_allocated *= 2; - neighbor_file_names = (CHAR**)realloc(neighbor_file_names, sizeof(CHAR*)*neighbor_file_name_allocated); - } - else - { - neighbor_file_name_allocated = 16; - neighbor_file_names = (CHAR**)malloc(sizeof(CHAR*)*neighbor_file_name_allocated); - } - if (neighbor_file_names == 0) - { - REprintf( "ERROR: alloc for neighbor_file_names pointer array failed at %d\n", neighbor_file_name_allocated); - } - } - neighbor_file_names[neighbor_file_name_number] = LASCopyString(neighbor_file_name); - neighbor_file_name_number++; - return TRUE; + if (unique) + { + U32 i; + for (i = 0; i < neighbor_file_name_number; i++) + { + if (strcmp(neighbor_file_names[i], neighbor_file_name) == 0) + { + return FALSE; + } + } + } + if (neighbor_file_name_number == neighbor_file_name_allocated) + { + if (neighbor_file_names) + { + neighbor_file_name_allocated *= 2; + neighbor_file_names = (CHAR**)realloc(neighbor_file_names, sizeof(CHAR*)*neighbor_file_name_allocated); + } + else + { + neighbor_file_name_allocated = 16; + neighbor_file_names = (CHAR**)malloc(sizeof(CHAR*)*neighbor_file_name_allocated); + } + if (neighbor_file_names == 0) + { + REprintf("ERROR: alloc for neighbor_file_names pointer array failed at %d\n", neighbor_file_name_allocated); + } + } + neighbor_file_names[neighbor_file_name_number] = LASCopyString(neighbor_file_name); + neighbor_file_name_number++; + return TRUE; } BOOL LASreadOpener::set_point_type(U8 point_type) { - if (point_type > 10) - { - return FALSE; - } - this->point_type = point_type; - return TRUE; + if (point_type > 10) + { + return FALSE; + } + this->point_type = point_type; + return TRUE; } void LASreadOpener::set_parse_string(const CHAR* parse_string) { - if (this->parse_string) free(this->parse_string); - if (parse_string) - { - this->parse_string = LASCopyString(parse_string); - } - else - { - this->parse_string = 0; - } + if (this->parse_string) free(this->parse_string); + if (parse_string) + { + this->parse_string = LASCopyString(parse_string); + } + else + { + this->parse_string = 0; + } } const CHAR* LASreadOpener::get_parse_string() const { - return parse_string; + return parse_string; } void LASreadOpener::set_scale_factor(const F64* scale_factor) { - if (scale_factor) - { - if (this->scale_factor == 0) this->scale_factor = new F64[3]; - this->scale_factor[0] = scale_factor[0]; - this->scale_factor[1] = scale_factor[1]; - this->scale_factor[2] = scale_factor[2]; - } - else if (this->scale_factor) - { - delete [] this->scale_factor; - this->scale_factor = 0; - } + if (scale_factor) + { + if (this->scale_factor == 0) this->scale_factor = new F64[3]; + this->scale_factor[0] = scale_factor[0]; + this->scale_factor[1] = scale_factor[1]; + this->scale_factor[2] = scale_factor[2]; + } + else if (this->scale_factor) + { + delete[] this->scale_factor; + this->scale_factor = 0; + } } void LASreadOpener::set_offset(const F64* offset) { - if (offset) - { - if (this->offset == 0) this->offset = new F64[3]; - this->offset[0] = offset[0]; - this->offset[1] = offset[1]; - this->offset[2] = offset[2]; - } - else if (this->offset) - { - delete [] this->offset; - this->offset = 0; - } + if (offset) + { + if (this->offset == 0) this->offset = new F64[3]; + this->offset[0] = offset[0]; + this->offset[1] = offset[1]; + this->offset[2] = offset[2]; + } + else if (this->offset) + { + delete[] this->offset; + this->offset = 0; + } } void LASreadOpener::set_translate_intensity(const F32 translation) { - this->translate_intensity = translation; + this->translate_intensity = translation; } void LASreadOpener::set_scale_intensity(const F32 scale) { - this->scale_intensity = scale; + this->scale_intensity = scale; } void LASreadOpener::set_translate_scan_angle(const F32 translation) { - this->translate_scan_angle = translation; + this->translate_scan_angle = translation; } void LASreadOpener::set_scale_scan_angle(const F32 scale) { - this->scale_scan_angle = scale; + this->scale_scan_angle = scale; } void LASreadOpener::add_attribute(I32 data_type, const CHAR* name, const CHAR* description, F64 scale, F64 offset, F64 pre_scale, F64 pre_offset, F64 no_data) { - attribute_data_types[number_attributes] = data_type; - attribute_names[number_attributes] = (name ? LASCopyString(name) : 0); - attribute_descriptions[number_attributes] = (description ? LASCopyString(description) : 0); - attribute_scales[number_attributes] = scale; - attribute_offsets[number_attributes] = offset; - attribute_pre_scales[number_attributes] = pre_scale; - attribute_pre_offsets[number_attributes] = pre_offset; - attribute_no_datas[number_attributes] = no_data; - number_attributes++; + if ((data_type < 1) || (data_type > 10)) + { + REprintf("WARNING: attribute data type %d not supported. ignoring attribute '%s'.\n", data_type, name); + return; + } + attribute_data_types[number_attributes] = data_type; + attribute_names[number_attributes] = (name ? LASCopyString(name) : 0); + attribute_descriptions[number_attributes] = (description ? LASCopyString(description) : 0); + attribute_scales[number_attributes] = scale; + attribute_offsets[number_attributes] = offset; + attribute_pre_scales[number_attributes] = pre_scale; + attribute_pre_offsets[number_attributes] = pre_offset; + attribute_no_datas[number_attributes] = no_data; + number_attributes++; } void LASreadOpener::set_skip_lines(const U32 number_of_lines) { - this->skip_lines = number_of_lines; + this->skip_lines = number_of_lines; } void LASreadOpener::set_populate_header(BOOL populate_header) { - this->populate_header = populate_header; + this->populate_header = populate_header; } void LASreadOpener::set_keep_lastiling(BOOL keep_lastiling) { - this->keep_lastiling = keep_lastiling; + this->keep_lastiling = keep_lastiling; +} + +void LASreadOpener::set_keep_copc(BOOL keep_copc) +{ + this->keep_copc = keep_copc; } void LASreadOpener::set_pipe_on(BOOL pipe_on) { - this->pipe_on = pipe_on; + this->pipe_on = pipe_on; } void LASreadOpener::set_decompress_selective(U32 decompress_selective) { - this->decompress_selective = decompress_selective; - if (filter) - { - this->decompress_selective |= filter->get_decompress_selective(); - } - if (transform) - { - this->decompress_selective |= transform->get_decompress_selective(); - } - if (ignore) - { - this->decompress_selective |= ignore->get_decompress_selective(); - } + this->decompress_selective = decompress_selective; + if (filter) + { + this->decompress_selective |= filter->get_decompress_selective(); + } + if (transform) + { + this->decompress_selective |= transform->get_decompress_selective(); + } + if (ignore) + { + this->decompress_selective |= ignore->get_decompress_selective(); + } } void LASreadOpener::set_inside_tile(const F32 ll_x, const F32 ll_y, const F32 size) { - if (inside_tile == 0) inside_tile = new F32[3]; - inside_tile[0] = ll_x; - inside_tile[1] = ll_y; - inside_tile[2] = size; + if (inside_tile == 0) inside_tile = new F32[3]; + inside_tile[0] = ll_x; + inside_tile[1] = ll_y; + inside_tile[2] = size; } void LASreadOpener::set_inside_circle(const F64 center_x, const F64 center_y, const F64 radius) { - if (inside_circle == 0) inside_circle = new F64[3]; - inside_circle[0] = center_x; - inside_circle[1] = center_y; - inside_circle[2] = radius; + if (inside_circle == 0) inside_circle = new F64[3]; + inside_circle[0] = center_x; + inside_circle[1] = center_y; + inside_circle[2] = radius; } void LASreadOpener::set_inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y) { - if (inside_rectangle == 0) inside_rectangle = new F64[4]; - inside_rectangle[0] = min_x; - inside_rectangle[1] = min_y; - inside_rectangle[2] = max_x; - inside_rectangle[3] = max_y; + if (inside_rectangle == 0) inside_rectangle = new F64[4]; + inside_rectangle[0] = min_x; + inside_rectangle[1] = min_y; + inside_rectangle[2] = max_x; + inside_rectangle[3] = max_y; +} + +void LASreadOpener::set_max_depth(const I32 max_depth) +{ + inside_depth = 1; + copc_depth = max_depth; +} + +void LASreadOpener::set_resolution(const F32 resolution) +{ + inside_depth = 2; + copc_resolution = resolution; } BOOL LASreadOpener::active() const { - return ((file_name_current < file_name_number) || use_stdin); + return ((file_name_current < file_name_number) || use_stdin); } LASreadOpener::LASreadOpener() { - io_ibuffer_size = LAS_TOOLS_IO_IBUFFER_SIZE; - file_name = 0; - file_names = 0; - file_names_ID = 0; - file_names_npoints = 0; - file_names_min_x = 0; - file_names_min_y = 0; - file_names_max_x = 0; - file_names_max_y = 0; - kdtree_rectangles = 0; - neighbor_file_names = 0; - neighbor_file_names_npoints = 0; - neighbor_file_names_min_x = 0; - neighbor_file_names_min_y = 0; - neighbor_file_names_max_x = 0; - neighbor_file_names_max_y = 0; - neighbor_kdtree_rectangles = 0; - merged = FALSE; - stored = FALSE; - use_stdin = FALSE; - comma_not_point = FALSE; - scale_factor = 0; - offset = 0; - buffer_size = 0.0f; - auto_reoffset = FALSE; - files_are_flightlines = 0; - files_are_flightlines_index = -1; - apply_file_source_ID = FALSE; - itxt = FALSE; - ipts = FALSE; - iptx = FALSE; - translate_intensity = 0.0f; - scale_intensity = 1.0f; - translate_scan_angle = 0.0f; - scale_scan_angle = 1.0f; - number_attributes = 0; - for (I32 i = 0; i < 32; i++) - { - attribute_data_types[i] = 0; - attribute_names[i] = 0; - attribute_descriptions[i] = 0; - attribute_scales[i] = 1.0; - attribute_offsets[i] = 0.0; - attribute_pre_scales[i] = 1.0; - attribute_pre_offsets[i] = 0.0; - attribute_no_datas[i] = F64_MAX; - } - point_type = 0; - parse_string = 0; - skip_lines = 0; - populate_header = FALSE; - keep_lastiling = FALSE; - pipe_on = FALSE; - unique = FALSE; - file_name_number = 0; - file_name_allocated = 0; - file_name_current = 0; - neighbor_file_name_number = 0; - neighbor_file_name_allocated = 0; - decompress_selective = LASZIP_DECOMPRESS_SELECTIVE_ALL; - inside_tile = 0; - inside_circle = 0; - inside_rectangle = 0; - filter = 0; - transform = 0; - ignore = 0; - temp_file_base = 0; + io_ibuffer_size = LAS_TOOLS_IO_IBUFFER_SIZE; + file_name = 0; + file_names = 0; + file_names_ID = 0; + file_names_npoints = 0; + file_names_min_x = 0; + file_names_min_y = 0; + file_names_max_x = 0; + file_names_max_y = 0; + kdtree_rectangles = 0; + neighbor_file_names = 0; + neighbor_file_names_npoints = 0; + neighbor_file_names_min_x = 0; + neighbor_file_names_min_y = 0; + neighbor_file_names_max_x = 0; + neighbor_file_names_max_y = 0; + neighbor_kdtree_rectangles = 0; + merged = FALSE; + stored = FALSE; + use_stdin = FALSE; + comma_not_point = FALSE; + scale_factor = 0; + offset = 0; + buffer_size = 0.0f; + auto_reoffset = FALSE; + files_are_flightlines = 0; + files_are_flightlines_index = -1; + apply_file_source_ID = FALSE; + itxt = FALSE; + ipts = FALSE; + iptx = FALSE; + iptx_transform = FALSE; + translate_intensity = 0.0f; + scale_intensity = 1.0f; + translate_scan_angle = 0.0f; + scale_scan_angle = 1.0f; + number_attributes = 0; + for (I32 i = 0; i < 32; i++) + { + attribute_data_types[i] = 0; + attribute_names[i] = 0; + attribute_descriptions[i] = 0; + attribute_scales[i] = 1.0; + attribute_offsets[i] = 0.0; + attribute_pre_scales[i] = 1.0; + attribute_pre_offsets[i] = 0.0; + attribute_no_datas[i] = F64_MAX; + } + point_type = 0; + parse_string = 0; + skip_lines = 0; + populate_header = FALSE; + keep_lastiling = FALSE; + keep_copc = FALSE; + pipe_on = FALSE; + unique = FALSE; + file_name_number = 0; + file_name_allocated = 0; + file_name_current = 0; + neighbor_file_name_number = 0; + neighbor_file_name_allocated = 0; + decompress_selective = LASZIP_DECOMPRESS_SELECTIVE_ALL; + inside_tile = 0; + inside_circle = 0; + inside_rectangle = 0; + filter = 0; + transform = 0; + ignore = 0; + temp_file_base = 0; + + // COPC + inside_depth = 0; + copc_stream_order = 1; + copc_resolution = 0; + copc_depth = -1; } LASreadOpener::~LASreadOpener() { - if (file_names) - { - U32 i; - for (i = 0; i < file_name_number; i++) free(file_names[i]); - free(file_names); - if (file_names_ID) - { - free(file_names_ID); - if (file_names_npoints) - { - free(file_names_npoints); - free(file_names_min_x); - free(file_names_min_y); - free(file_names_max_x); - free(file_names_max_y); - } - } - } - if (kdtree_rectangles) delete kdtree_rectangles; - if (neighbor_file_names) - { - U32 i; - for (i = 0; i < neighbor_file_name_number; i++) free(neighbor_file_names[i]); - free(neighbor_file_names); - if (neighbor_file_names_npoints) - { - free(neighbor_file_names_npoints); - free(neighbor_file_names_min_x); - free(neighbor_file_names_min_y); - free(neighbor_file_names_max_x); - free(neighbor_file_names_max_y); - } - } - if (parse_string) free(parse_string); - if (scale_factor) delete [] scale_factor; - if (offset) delete [] offset; - if (inside_tile) delete [] inside_tile; - if (inside_circle) delete [] inside_circle; - if (inside_rectangle) delete [] inside_rectangle; - if (filter) delete filter; - if (transform) delete transform; - if (ignore) delete ignore; - if (temp_file_base) free(temp_file_base); + if (file_names) + { + U32 i; + for (i = 0; i < file_name_number; i++) free(file_names[i]); + free(file_names); + if (file_names_ID) + { + free(file_names_ID); + if (file_names_npoints) + { + free(file_names_npoints); + free(file_names_min_x); + free(file_names_min_y); + free(file_names_max_x); + free(file_names_max_y); + } + } + } + if (kdtree_rectangles) delete kdtree_rectangles; + if (neighbor_file_names) + { + U32 i; + for (i = 0; i < neighbor_file_name_number; i++) free(neighbor_file_names[i]); + free(neighbor_file_names); + if (neighbor_file_names_npoints) + { + free(neighbor_file_names_npoints); + free(neighbor_file_names_min_x); + free(neighbor_file_names_min_y); + free(neighbor_file_names_max_x); + free(neighbor_file_names_max_y); + } + } + if (parse_string) free(parse_string); + if (scale_factor) delete[] scale_factor; + if (offset) delete[] offset; + if (inside_tile) delete[] inside_tile; + if (inside_circle) delete[] inside_circle; + if (inside_rectangle) delete[] inside_rectangle; + if (filter) delete filter; + if (transform) delete transform; + if (ignore) delete ignore; + if (temp_file_base) free(temp_file_base); } diff --git a/src/LASlib/lasreader.hpp b/src/LASlib/lasreader.hpp index dc1b7a4..14a90d2 100644 --- a/src/LASlib/lasreader.hpp +++ b/src/LASlib/lasreader.hpp @@ -1,49 +1,51 @@ /* =============================================================================== - FILE: lasreader.hpp + FILE: lasreader.hpp - CONTENTS: + CONTENTS: - Interface to read LIDAR points from the LAS format versions 1.0 - 1.3 and - per on-the-fly conversion from simple ASCII files. + Interface to read LIDAR points from the LAS format versions 1.0 - 1.3 and + per on-the-fly conversion from simple ASCII files. - PROGRAMMERS: + PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de - COPYRIGHT: + COPYRIGHT: - (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2019, rapidlasso GmbH - fast tools to catch reality - This is free software; you can redistribute and/or modify it under the - terms of the GNU Lesser General Licence as published by the Free Software - Foundation. See the LICENSE.txt file for more information. + This is free software; you can redistribute and/or modify it under the + terms of the GNU Lesser General Licence as published by the Free Software + Foundation. See the LICENSE.txt file for more information. - This software is distributed WITHOUT ANY WARRANTY and without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + This software is distributed WITHOUT ANY WARRANTY and without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - CHANGE HISTORY: + CHANGE HISTORY: - 31 October 2019 -- adding kdtree of bounding boxes for large number of LAS/LAZ files - 19 August 2019 -- unify '-ignore_class 7', '-ignore_withheld', etc ... in LASignore - 7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro - 8 February 2018 -- new LASreaderStored via '-stored' option to allow piped operation - 15 December 2017 -- optional '-files_are_flightline 101' start number like '-faf 101' - 21 November 2017 -- allow adding up to 32 (from 10) additional extra bytes attributes - 5 August 2017 -- unless '-buffered 25' just created buffers always '-remain_buffered' - 5 August 2017 -- removed option '-unbuffered' because it makes too many assumptions - 7 February 2014 -- added option '-apply_file_source_ID' when reading LAS/LAZ - 22 August 2012 -- added the '-pipe_on' option for a multi-stage LAStools pipeline - 11 August 2012 -- added on-the-fly buffered reading of LiDAR files (efficient with LAX) - 5 September 2011 -- support for reading Terrasolid's BIN format - 11 June 2011 -- billion point support: p_count & npoints are 64 bit counters - 9 April 2011 -- added capability to read on-the-fly conversion from ASCII - 24 January 2011 -- introduced LASreadOpener - 21 January 2011 -- turned into abstract reader to support multiple files - 3 December 2010 -- updated to (somewhat) support LAS format 1.3 - 7 September 2008 -- updated to support LAS format 1.2 - 18 February 2007 -- created after repairing 2 vacuum cleaners in the garden + 18 April 2023 -- adding support of COPC spatial index standard + 10 March 2022 -- added '-iptx_transform' option + 31 October 2019 -- adding kdtree of bounding boxes for large number of LAS/LAZ files + 19 August 2019 -- unify '-ignore_class 7', '-ignore_withheld', etc ... in LASignore + 7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro + 8 February 2018 -- new LASreaderStored via '-stored' option to allow piped operation + 15 December 2017 -- optional '-files_are_flightline 101' start number like '-faf 101' + 21 November 2017 -- allow adding up to 32 (from 10) additional extra bytes attributes + 5 August 2017 -- unless '-buffered 25' just created buffers always '-remain_buffered' + 5 August 2017 -- removed option '-unbuffered' because it makes too many assumptions + 7 February 2014 -- added option '-apply_file_source_ID' when reading LAS/LAZ + 22 August 2012 -- added the '-pipe_on' option for a multi-stage LAStools pipeline + 11 August 2012 -- added on-the-fly buffered reading of LiDAR files (efficient with LAX) + 5 September 2011 -- support for reading Terrasolid's BIN format + 11 June 2011 -- billion point support: p_count & npoints are 64 bit counters + 9 April 2011 -- added capability to read on-the-fly conversion from ASCII + 24 January 2011 -- introduced LASreadOpener + 21 January 2011 -- turned into abstract reader to support multiple files + 3 December 2010 -- updated to (somewhat) support LAS format 1.3 + 7 September 2008 -- updated to support LAS format 1.2 + 18 February 2007 -- created after repairing 2 vacuum cleaners in the garden =============================================================================== */ @@ -52,8 +54,10 @@ #include "lasdefinitions.hpp" #include "lasignore.hpp" +#include "lastransform.hpp" class LASindex; +class COPCindex; class LASfilter; class LAStransform; class ByteStreamIn; @@ -62,104 +66,120 @@ class LASkdtreeRectangles; class LASLIB_DLL LASreader { public: - LASheader header; - LASpoint point; - - I64 npoints; - I64 p_count; - - virtual I32 get_format() const = 0; - virtual BOOL has_layers() const { return FALSE; }; - - void set_index(LASindex* index); - inline LASindex* get_index() const { return index; }; - virtual void set_filter(LASfilter* filter); - inline LASfilter* get_filter() const { return filter; }; - virtual void set_transform(LAStransform* transform); - inline LAStransform* get_transform() const { return transform; }; - void set_ignore(LASignore* ignore); - inline LASignore* get_ignore() const { return ignore; }; - - inline U32 get_inside() const { return inside; }; - virtual BOOL inside_none(); - virtual BOOL inside_tile(const F32 ll_x, const F32 ll_y, const F32 size); - inline F32 get_t_ll_x() const { return t_ll_x; }; - inline F32 get_t_ll_y() const { return t_ll_y; }; - inline F32 get_t_size() const { return t_size; }; - virtual BOOL inside_circle(const F64 center_x, const F64 center_y, const F64 radius); - inline F64 get_c_center_x() const { return c_center_x; }; - inline F64 get_c_center_y() const { return c_center_y; }; - inline F64 get_c_radius() const { return c_radius; }; - virtual BOOL inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y); - inline F64 get_r_min_x() const { return r_min_x; }; - inline F64 get_r_min_y() const { return r_min_y; }; - inline F64 get_r_max_x() const { return r_max_x; }; - inline F64 get_r_max_y() const { return r_max_y; }; - - virtual BOOL seek(const I64 p_index) = 0; - BOOL read_point() { return (this->*read_simple)(); }; - - inline BOOL ignore_point() { return (ignore ? ignore->ignore(&point) : FALSE); }; - - inline void compute_coordinates() { point.compute_coordinates(); }; - - inline F64 get_min_x() const { return header.min_x; }; - inline F64 get_min_y() const { return header.min_y; }; - inline F64 get_min_z() const { return header.min_z; }; - - inline F64 get_max_x() const { return header.max_x; }; - inline F64 get_max_y() const { return header.max_y; }; - inline F64 get_max_z() const { return header.max_z; }; - - inline F64 get_x() const { return get_x(point.get_X()); }; - inline F64 get_y() const { return get_y(point.get_Y()); }; - inline F64 get_z() const { return get_z(point.get_Z()); }; - - inline F64 get_x(const I32 x) const { return header.get_x(x); }; - inline F64 get_y(const I32 y) const { return header.get_y(y); }; - inline F64 get_z(const I32 z) const { return header.get_z(z); }; - - inline I64 get_X(const F64 x) const { return header.get_X(x); }; - inline I64 get_Y(const F64 y) const { return header.get_Y(y); }; - inline I64 get_Z(const F64 z) const { return header.get_Z(z); }; - - virtual ByteStreamIn* get_stream() const = 0; - virtual void close(BOOL close_stream=TRUE) = 0; - - LASreader(); - virtual ~LASreader(); - - void dealloc(); + LASheader header; + LASpoint point; + I64 npoints; + I64 p_count; + LASTransformMatrix transform_matrix; + + virtual I32 get_format() const = 0; + virtual BOOL has_layers() const { return FALSE; }; + + void set_index(LASindex* index); + inline LASindex* get_index() const { return index; }; + void set_copcindex(COPCindex* copc_index); + inline COPCindex* get_copcindex() const { return copc_index; }; + virtual void set_filter(LASfilter* filter); + inline LASfilter* get_filter() const { return filter; }; + virtual void set_transform(LAStransform* transform); + inline LAStransform* get_transform() const { return transform; }; + void set_ignore(LASignore* ignore); + inline LASignore* get_ignore() const { return ignore; }; + + inline U32 get_inside() const { return inside; }; + virtual BOOL inside_none(); + virtual BOOL inside_tile(const F32 ll_x, const F32 ll_y, const F32 size); + inline F32 get_t_ll_x() const { return t_ll_x; }; + inline F32 get_t_ll_y() const { return t_ll_y; }; + inline F32 get_t_size() const { return t_size; }; + virtual BOOL inside_circle(const F64 center_x, const F64 center_y, const F64 radius); + inline F64 get_c_center_x() const { return c_center_x; }; + inline F64 get_c_center_y() const { return c_center_y; }; + inline F64 get_c_radius() const { return c_radius; }; + virtual BOOL inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y); + inline F64 get_r_min_x() const { return r_min_x; }; + inline F64 get_r_min_y() const { return r_min_y; }; + inline F64 get_r_max_x() const { return r_max_x; }; + inline F64 get_r_max_y() const { return r_max_y; }; + virtual BOOL inside_copc_depth(const U8 mode, const I32 depth, const F32 resolution); + inline I32 get_copc_depth() const { return copc_depth; }; + inline F32 get_copc_resolution() const { return copc_resolution; }; + + virtual BOOL seek(const I64 p_index) = 0; + BOOL read_point() { return (this->*read_simple)(); }; + + inline BOOL ignore_point() { return (ignore ? ignore->ignore(&point) : FALSE); }; + + inline void compute_coordinates() { point.compute_coordinates(); }; + + inline F64 get_min_x() const { return header.min_x; }; + inline F64 get_min_y() const { return header.min_y; }; + inline F64 get_min_z() const { return header.min_z; }; + + inline F64 get_max_x() const { return header.max_x; }; + inline F64 get_max_y() const { return header.max_y; }; + inline F64 get_max_z() const { return header.max_z; }; + + inline F64 get_x() const { return get_x(point.get_X()); }; + inline F64 get_y() const { return get_y(point.get_Y()); }; + inline F64 get_z() const { return get_z(point.get_Z()); }; + + inline F64 get_x(const I32 x) const { return header.get_x(x); }; + inline F64 get_y(const I32 y) const { return header.get_y(y); }; + inline F64 get_z(const I32 z) const { return header.get_z(z); }; + + inline I64 get_X(const F64 x) const { return header.get_X(x); }; + inline I64 get_Y(const F64 y) const { return header.get_Y(y); }; + inline I64 get_Z(const F64 z) const { return header.get_Z(z); }; + + virtual ByteStreamIn* get_stream() const = 0; + virtual void close(BOOL close_stream = TRUE) = 0; + + LASreader(); + virtual ~LASreader(); + + void dealloc(); protected: - virtual BOOL read_point_default() = 0; + virtual BOOL read_point_default() = 0; - LASindex* index; - LASfilter* filter; - LAStransform* transform; - LASignore* ignore; + LASindex* index; + COPCindex* copc_index; + LASfilter* filter; + LAStransform* transform; + LASignore* ignore; - U32 inside; - F32 t_ll_x, t_ll_y, t_size, t_ur_x, t_ur_y; - F64 c_center_x, c_center_y, c_radius, c_radius_squared; - F64 r_min_x, r_min_y, r_max_x, r_max_y; - F64 orig_min_x, orig_min_y, orig_max_x, orig_max_y; + U32 inside; + F32 t_ll_x, t_ll_y, t_size, t_ur_x, t_ur_y; + F64 c_center_x, c_center_y, c_radius, c_radius_squared; + F64 r_min_x, r_min_y, r_max_x, r_max_y; + F64 orig_min_x, orig_min_y, orig_max_x, orig_max_y; + + // optional resolution-of-interest query (copc indexed) + U8 inside_depth; // 0 all, 1 max depth, 2 resolution + F32 copc_resolution; + I32 copc_depth; private: - BOOL (LASreader::*read_simple)(); - BOOL (LASreader::*read_complex)(); - - BOOL read_point_none(); - BOOL read_point_filtered(); - BOOL read_point_transformed(); - BOOL read_point_filtered_and_transformed(); - - BOOL read_point_inside_tile(); - BOOL read_point_inside_tile_indexed(); - BOOL read_point_inside_circle(); - BOOL read_point_inside_circle_indexed(); - BOOL read_point_inside_rectangle(); - BOOL read_point_inside_rectangle_indexed(); + BOOL(LASreader::*read_simple)(); + BOOL(LASreader::*read_complex)(); + + BOOL read_point_none(); + BOOL read_point_filtered(); + BOOL read_point_transformed(); + BOOL read_point_filtered_and_transformed(); + + BOOL read_point_inside_tile(); + BOOL read_point_inside_tile_indexed(); + BOOL read_point_inside_circle(); + BOOL read_point_inside_circle_indexed(); + BOOL read_point_inside_rectangle(); + BOOL read_point_inside_rectangle_indexed(); + + // COPC specialized readers + BOOL read_point_inside_circle_copc_indexed(); + BOOL read_point_inside_rectangle_copc_indexed(); + BOOL read_point_inside_depth_copc_indexed(); }; #include "laswaveform13reader.hpp" @@ -167,169 +187,182 @@ class LASLIB_DLL LASreader class LASLIB_DLL LASreadOpener { public: - void set_io_ibuffer_size(const U32 buffer_size); - inline U32 get_io_ibuffer_size() const { return io_ibuffer_size; }; - U32 get_file_name_number() const; - U32 get_file_name_current() const; - const CHAR* get_file_name() const; - const CHAR* get_file_name_only() const; - const CHAR* get_file_extension_only() const; - const CHAR* get_file_name(U32 number) const; - const CHAR* get_file_name_only(U32 number) const; - const CHAR* get_file_extension_only(U32 number) const; - CHAR* get_file_name_base() const; - CHAR* get_file_name_base(U32 number) const; - void set_file_name(const CHAR* file_name, BOOL unique=FALSE); - BOOL add_file_name(const CHAR* file_name, BOOL unique=FALSE); - BOOL add_list_of_files(const CHAR* list_of_files, BOOL unique=FALSE); - void delete_file_name(U32 file_name_id); - BOOL set_file_name_current(U32 file_name_id); - I32 get_file_format(U32 number) const; - void set_merged(const BOOL merged); - BOOL is_merged() const { return merged; }; - void set_stored(const BOOL stored); - BOOL is_stored() const { return stored; }; - void set_buffer_size(const F32 buffer_size); - F32 get_buffer_size() const; - void set_neighbor_file_name(const CHAR* neighbor_file_name, BOOL unique=FALSE); - BOOL add_neighbor_file_name(const CHAR* neighbor_file_name, BOOL unique=FALSE); - BOOL add_neighbor_file_name(const CHAR* file_name, I64 npoints, F64 min_x, F64 min_y, F64 max_x, F64 max_y, BOOL unique=FALSE); - BOOL add_neighbor_list_of_files(const CHAR* list_of_files, BOOL unique=FALSE); - void set_auto_reoffset(const BOOL auto_reoffset); - inline BOOL is_auto_reoffset() const { return auto_reoffset; }; - void set_files_are_flightlines(const I32 files_are_flightlines); - inline I32 are_files_flightlines() const { return files_are_flightlines; }; - void set_files_are_flightlines_index(const I32 files_are_flightlines_index); - inline I32 get_files_flight_index() const { return files_are_flightlines_index; }; - void set_apply_file_source_ID(const BOOL apply_file_source_ID); - inline BOOL applying_file_source_ID() const { return apply_file_source_ID; }; - void set_scale_factor(const F64* scale_factor); - inline const F64* get_scale_factor() const { return scale_factor; }; - void set_offset(const F64* offset); - inline const F64* get_offset() const { return offset; }; - void set_translate_intensity(const F32 translation); - void set_scale_intensity(const F32 scale); - void set_translate_scan_angle(const F32 translate_scan_angle); - void set_scale_scan_angle(const F32 scale_scan_angle); - void add_attribute(I32 data_type, const CHAR* name, const CHAR* description=0, F64 scale=1.0, F64 offset=0.0, F64 pre_scale=1.0, F64 pre_offset=0.0, F64 no_data=F64_MAX); - BOOL set_point_type(U8 point_type); - void set_parse_string(const CHAR* parse_string); - void set_skip_lines(const U32 number_of_lines); - void set_populate_header(BOOL populate_header); - void set_keep_lastiling(BOOL keep_lastiling); - void set_pipe_on(BOOL pipe_on); - const CHAR* get_parse_string() const; - void usage() const; - void set_decompress_selective(U32 decompress_selective); - void set_inside_tile(const F32 ll_x, const F32 ll_y, const F32 size); - void set_inside_circle(const F64 center_x, const F64 center_y, const F64 radius); - void set_inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y); - BOOL parse(int argc, char* argv[], BOOL parse_ignore=FALSE); - BOOL parse_str(CHAR* string); - BOOL is_piped() const; - BOOL is_buffered() const; - BOOL is_header_populated() const; - BOOL active() const; - BOOL is_inside() const; - I32 unparse(CHAR* string) const; - void set_filter(LASfilter* filter); - inline LASfilter* get_filter() { return filter; }; - void set_transform(LAStransform* transform); - inline LAStransform* get_transform() { return transform; }; - void set_ignore(LASignore* ignore); - inline LASignore* get_ignore() { return ignore; }; - void reset(); - const CHAR* get_temp_file_base() const { return temp_file_base; }; - LASreader* open(const CHAR* other_file_name=0, BOOL reset_after_other=TRUE); - BOOL reopen(LASreader* lasreader, BOOL remain_buffered=TRUE); - LASwaveform13reader* open_waveform13(const LASheader* lasheader); - I32 get_number_attributes() const { return number_attributes; }; - I32 get_attribute_data_type(U32 index) const { return attribute_data_types[index]; }; - const CHAR* get_attribute_name(U32 index) const { return attribute_names[index]; }; - const CHAR* get_attribute_description(U32 index) const { return attribute_descriptions[index]; }; - F64 get_attribute_scale(U32 index) const { return attribute_scales[index]; }; - F64 get_attribute_offset(U32 index) const { return attribute_offsets[index]; }; - F64 get_attribute_no_data(U32 index) const { return attribute_no_datas[index]; }; - LASreadOpener(); - ~LASreadOpener(); + void set_io_ibuffer_size(const U32 buffer_size); + inline U32 get_io_ibuffer_size() const { return io_ibuffer_size; }; + U32 get_file_name_number() const; + U32 get_file_name_current() const; + const CHAR* get_file_name() const; + const CHAR* get_file_name_only() const; + const CHAR* get_file_extension_only() const; + const CHAR* get_file_name(U32 number) const; + const CHAR* get_file_name_only(U32 number) const; + const CHAR* get_file_extension_only(U32 number) const; + CHAR* get_file_name_base() const; + CHAR* get_file_name_base(U32 number) const; + void set_file_name(const CHAR* file_name, BOOL unique = FALSE); + BOOL add_file_name(const CHAR* file_name, BOOL unique = FALSE); + BOOL add_list_of_files(const CHAR* list_of_files, BOOL unique = FALSE); + void delete_file_name(U32 file_name_id); + BOOL set_file_name_current(U32 file_name_id); + I32 get_file_format(U32 number) const; + void set_merged(const BOOL merged); + BOOL is_merged() const { return merged; }; + void set_stored(const BOOL stored); + BOOL is_stored() const { return stored; }; + void set_buffer_size(const F32 buffer_size); + F32 get_buffer_size() const; + BOOL add_neighbor_file_name(const CHAR* neighbor_file_name, BOOL unique = FALSE); + BOOL add_neighbor_file_name(const CHAR* file_name, I64 npoints, F64 min_x, F64 min_y, F64 max_x, F64 max_y, BOOL unique = FALSE); + BOOL add_neighbor_list_of_files(const CHAR* list_of_files, BOOL unique = FALSE); + void set_auto_reoffset(const BOOL auto_reoffset); + inline BOOL is_auto_reoffset() const { return auto_reoffset; }; + void set_files_are_flightlines(const I32 files_are_flightlines); + inline I32 are_files_flightlines() const { return files_are_flightlines; }; + void set_files_are_flightlines_index(const I32 files_are_flightlines_index); + inline I32 get_files_flight_index() const { return files_are_flightlines_index; }; + void set_apply_file_source_ID(const BOOL apply_file_source_ID); + inline BOOL applying_file_source_ID() const { return apply_file_source_ID; }; + void set_scale_factor(const F64* scale_factor); + inline const F64* get_scale_factor() const { return scale_factor; }; + void set_offset(const F64* offset); + inline const F64* get_offset() const { return offset; }; + void set_translate_intensity(const F32 translation); + void set_scale_intensity(const F32 scale); + void set_translate_scan_angle(const F32 translate_scan_angle); + void set_scale_scan_angle(const F32 scale_scan_angle); + void add_attribute(I32 data_type, const CHAR* name, const CHAR* description = 0, F64 scale = 1.0, F64 offset = 0.0, F64 pre_scale = 1.0, F64 pre_offset = 0.0, F64 no_data = F64_MAX); + BOOL set_point_type(U8 point_type); + void set_parse_string(const CHAR* parse_string); + void set_skip_lines(const U32 number_of_lines); + void set_populate_header(BOOL populate_header); + void set_keep_lastiling(BOOL keep_lastiling); + void set_keep_copc(BOOL keep_copc); + void set_pipe_on(BOOL pipe_on); + const CHAR* get_parse_string() const; + void usage() const; + void set_decompress_selective(U32 decompress_selective); + void set_inside_tile(const F32 ll_x, const F32 ll_y, const F32 size); + void set_inside_circle(const F64 center_x, const F64 center_y, const F64 radius); + void set_inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y); + void set_max_depth(const I32 max_depth); + void set_resolution(const F32 resolution); + BOOL parse(int argc, char* argv[], BOOL parse_ignore = FALSE); + BOOL parse_str(CHAR* string); + BOOL is_piped() const; + BOOL is_buffered() const; + BOOL is_header_populated() const; + BOOL active() const; + BOOL is_inside() const; + I32 unparse(CHAR* string) const; + void set_filter(LASfilter* filter); + inline LASfilter* get_filter() { return filter; }; + void set_transform(LAStransform* transform); + inline LAStransform* get_transform() { return transform; }; + void set_ignore(LASignore* ignore); + inline LASignore* get_ignore() { return ignore; }; + void reset(); + const CHAR* get_temp_file_base() const { return temp_file_base; }; + LASreader* open(const CHAR* other_file_name = 0, BOOL reset_after_other = TRUE); + BOOL reopen(LASreader* lasreader, BOOL remain_buffered = TRUE); + LASwaveform13reader* open_waveform13(const LASheader* lasheader); + I32 get_number_attributes() const { return number_attributes; }; + I32 get_attribute_data_type(U32 index) const { return attribute_data_types[index]; }; + const CHAR* get_attribute_name(U32 index) const { return attribute_names[index]; }; + const CHAR* get_attribute_description(U32 index) const { return attribute_descriptions[index]; }; + F64 get_attribute_scale(U32 index) const { return attribute_scales[index]; }; + F64 get_attribute_offset(U32 index) const { return attribute_offsets[index]; }; + F64 get_attribute_no_data(U32 index) const { return attribute_no_datas[index]; }; + void set_copc_stream_ordered_by_chunk() { copc_stream_order = 0; }; + void set_copc_stream_ordered_spatially() { copc_stream_order = 1; }; + void set_copc_stream_ordered_by_level() { copc_stream_order = 2; }; + LASreadOpener(); + ~LASreadOpener(); private: #ifdef _WIN32 - BOOL add_file_name_single(const CHAR* file_name, BOOL unique=FALSE); - BOOL add_neighbor_file_name_single(const CHAR* neighbor_file_name, BOOL unique=FALSE); + BOOL add_file_name_single(const CHAR* file_name, BOOL unique = FALSE); + BOOL add_neighbor_file_name_single(const CHAR* neighbor_file_name, BOOL unique = FALSE); #endif - BOOL add_file_name(const CHAR* file_name, U32 ID, BOOL unique); - BOOL add_file_name(const CHAR* file_name, U32 ID, I64 npoints, F64 min_x, F64 min_y, F64 max_x, F64 max_y, BOOL unique=FALSE); - U32 io_ibuffer_size; - const CHAR* file_name; - BOOL merged; - BOOL stored; - U32 file_name_current; - CHAR** file_names; - U32 file_name_number; - U32 file_name_allocated; - U32* file_names_ID; - I64* file_names_npoints; - F64* file_names_min_x; - F64* file_names_min_y; - F64* file_names_max_x; - F64* file_names_max_y; - LASkdtreeRectangles* kdtree_rectangles; - F32 buffer_size; - CHAR* temp_file_base; - CHAR** neighbor_file_names; - U32 neighbor_file_name_number; - U32 neighbor_file_name_allocated; - I64* neighbor_file_names_npoints; - F64* neighbor_file_names_min_x; - F64* neighbor_file_names_min_y; - F64* neighbor_file_names_max_x; - F64* neighbor_file_names_max_y; - LASkdtreeRectangles* neighbor_kdtree_rectangles; - BOOL comma_not_point; - F64* scale_factor; - F64* offset; - BOOL auto_reoffset; - I32 files_are_flightlines; - I32 files_are_flightlines_index; - BOOL apply_file_source_ID; - BOOL itxt; - BOOL ipts; - BOOL iptx; - F32 translate_intensity; - F32 scale_intensity; - F32 translate_scan_angle; - F32 scale_scan_angle; - I32 number_attributes; - I32 attribute_data_types[32]; - CHAR* attribute_names[32]; - CHAR* attribute_descriptions[32]; - F64 attribute_scales[32]; - F64 attribute_offsets[32]; - F64 attribute_pre_scales[32]; - F64 attribute_pre_offsets[32]; - F64 attribute_no_datas[32]; - U8 point_type; - CHAR* parse_string; - U32 skip_lines; - BOOL populate_header; - BOOL keep_lastiling; - BOOL pipe_on; - BOOL use_stdin; - BOOL unique; - - // optional extras - LASindex* index; - LASfilter* filter; - LAStransform* transform; - LASignore* ignore; - - // optional selective decompression (compressed new LAS 1.4 point types only) - U32 decompress_selective; - - // optional area-of-interest query (spatially indexed) - F32* inside_tile; - F64* inside_circle; - F64* inside_rectangle; + BOOL add_file_name(const CHAR* file_name, U32 ID, BOOL unique); + BOOL add_file_name(const CHAR* file_name, U32 ID, I64 npoints, F64 min_x, F64 min_y, F64 max_x, F64 max_y, BOOL unique = FALSE); + U32 io_ibuffer_size; + const CHAR* file_name; + BOOL merged; + BOOL stored; + U32 file_name_current; + CHAR** file_names; + U32 file_name_number; + U32 file_name_allocated; + U32* file_names_ID; + I64* file_names_npoints; + F64* file_names_min_x; + F64* file_names_min_y; + F64* file_names_max_x; + F64* file_names_max_y; + LASkdtreeRectangles* kdtree_rectangles; + F32 buffer_size; + CHAR* temp_file_base; + CHAR** neighbor_file_names; + U32 neighbor_file_name_number; + U32 neighbor_file_name_allocated; + I64* neighbor_file_names_npoints; + F64* neighbor_file_names_min_x; + F64* neighbor_file_names_min_y; + F64* neighbor_file_names_max_x; + F64* neighbor_file_names_max_y; + LASkdtreeRectangles* neighbor_kdtree_rectangles; + BOOL comma_not_point; + F64* scale_factor; + F64* offset; + BOOL auto_reoffset; + I32 files_are_flightlines; + I32 files_are_flightlines_index; + BOOL apply_file_source_ID; + BOOL itxt; + BOOL ipts; + BOOL iptx; + BOOL iptx_transform; + F32 translate_intensity; + F32 scale_intensity; + F32 translate_scan_angle; + F32 scale_scan_angle; + I32 number_attributes; + I32 attribute_data_types[32]; + CHAR* attribute_names[32]; + CHAR* attribute_descriptions[32]; + F64 attribute_scales[32]; + F64 attribute_offsets[32]; + F64 attribute_pre_scales[32]; + F64 attribute_pre_offsets[32]; + F64 attribute_no_datas[32]; + U8 point_type; + CHAR* parse_string; + U32 skip_lines; + BOOL populate_header; + BOOL keep_lastiling; + BOOL keep_copc; + BOOL pipe_on; + BOOL use_stdin; + BOOL unique; + + // optional extras + LASindex* index; + LASfilter* filter; + LAStransform* transform; + LASignore* ignore; + + // optional selective decompression (compressed new LAS 1.4 point types only) + U32 decompress_selective; + + // optional area-of-interest query (spatially indexed) + F32* inside_tile; + F64* inside_circle; + F64* inside_rectangle; + + // optional resolution-of-interest query (copc indexed) + U8 inside_depth; // 0 all, 1 max depth, 2 resolution + U8 copc_stream_order; // 0 normal, 1 spatially, 2 depth + F32 copc_resolution; + I32 copc_depth; }; #endif diff --git a/src/LASlib/lasreader_las.cpp b/src/LASlib/lasreader_las.cpp index a3f43fb..657f206 100644 --- a/src/LASlib/lasreader_las.cpp +++ b/src/LASlib/lasreader_las.cpp @@ -2,18 +2,18 @@ =============================================================================== FILE: lasreader_las.cpp - + CONTENTS: - + see corresponding header file - + PROGRAMMERS: - - martin.isenburg@rapidlasso.com - http://rapidlasso.com + + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2018, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2018, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -21,11 +21,11 @@ This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - + CHANGE HISTORY: - + see corresponding header file - + =============================================================================== */ #include "lasreader_las.hpp" @@ -35,6 +35,7 @@ #include "bytestreamin_istream.hpp" #include "lasreadpoint.hpp" #include "lasindex.hpp" +#include "lascopc.hpp" #ifdef _WIN32 #include @@ -53,17 +54,13 @@ BOOL LASreaderLAS::open(const char* file_name, I32 io_buffer_size, BOOL peek_onl } #ifdef _MSC_VER - file = fopen(file_name, "rb"); + wchar_t* utf16_file_name = UTF8toUTF16(file_name); + file = _wfopen(utf16_file_name, L"rb"); if (file == 0) { - wchar_t* utf16_file_name = UTF8toUTF16(file_name); - file = _wfopen(utf16_file_name, L"rb"); - if (file == 0) - { - REprintf( "ERROR: cannot open file '%ws' for read\n", utf16_file_name); - } - delete [] utf16_file_name; + REprintf( "ERROR: cannot open file '%ws' for read\n", utf16_file_name); } + delete [] utf16_file_name; #else file = fopen(file_name, "rb"); #endif @@ -404,7 +401,7 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel if (peek_only) { - // at least repair point type in incomplete header (no VLRs, no LASzip, no LAStiling) + // at least repair point type in incomplete header (no VLRs, no LASzip, no LAStiling) header.point_data_format &= 127; return TRUE; } @@ -412,11 +409,12 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel // read the variable length records into the header U32 vlrs_size = 0; + BOOL vlrs_corrupt = FALSE; if (header.number_of_variable_length_records) { - header.vlrs = (LASvlr*)malloc(sizeof(LASvlr)*header.number_of_variable_length_records); - + header.vlrs = (LASvlr*)calloc(header.number_of_variable_length_records, sizeof(LASvlr)); + for (i = 0; i < header.number_of_variable_length_records; i++) { // make sure there are enough bytes left to read a variable length record before the point block starts @@ -425,6 +423,7 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel { REprintf("WARNING: only %d bytes until point block after reading %d of %d vlrs. skipping remaining vlrs ...\n", (int)header.offset_to_point_data - vlrs_size - header.header_size, i, header.number_of_variable_length_records); header.number_of_variable_length_records = i; + vlrs_corrupt = TRUE; break; } @@ -487,12 +486,12 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel header.laszip = new LASzip(); // read this data following the header of the variable length record - // U16 compressor 2 bytes - // U32 coder 2 bytes - // U8 version_major 1 byte + // U16 compressor 2 bytes + // U32 coder 2 bytes + // U8 version_major 1 byte // U8 version_minor 1 byte // U16 version_revision 2 bytes - // U32 options 4 bytes + // U32 options 4 bytes // I32 chunk_size 4 bytes // I64 number_of_special_evlrs 8 bytes // I64 offset_to_special_evlrs 8 bytes @@ -582,13 +581,13 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel header.vlr_lastiling = new LASvlr_lastiling(); // read the payload of this VLR which contains 28 bytes - // U32 level 4 bytes - // U32 level_index 4 bytes - // U32 implicit_levels + buffer bit + reversible bit 4 bytes - // F32 min_x 4 bytes - // F32 max_x 4 bytes - // F32 min_y 4 bytes - // F32 max_y 4 bytes + // U32 level 4 bytes + // U32 level_index 4 bytes + // U32 implicit_levels + buffer bit + reversible bit 4 bytes + // F32 min_x 4 bytes + // F32 max_x 4 bytes + // F32 min_y 4 bytes + // F32 max_y 4 bytes if (header.vlrs[i].record_length_after_header == 28) { @@ -778,7 +777,7 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel else { REprintf("WARNING: unknown LASF_Projection VLR with record_id %d.\n", header.vlrs[i].record_id); - } + } } else { @@ -873,6 +872,43 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel i--; header.number_of_variable_length_records--; } + else if (strcmp(header.vlrs[i].user_id, "copc") == 0) + { + if (header.vlrs[i].data) + { + if (header.vlrs[i].record_id == 1) // COPC info + { + if (i != 0) + { + REprintf( "WARNING: COPC VLR info should be the first vlr (not specification-conform)\n"); + } + + if (header.version_major == 1 && header.version_minor == 4 && (header.point_data_format & 0x3F) >= 6 && (header.point_data_format & 0x3F) <= 8) + { + if (!header.vlr_copc_info) + { + // Unlike e.g. vlr_geo_ogc_wkt or vlr_classification, vlr_copc_info is not a pointer to the VLR payload (LASvlr_copc_info*)header.vlrs[i].data + // Instead we use a copy. This allows to remove the COPC VLR later and maintain the COPC index information for a COPC aware reader but writers + // will never receive any COPC data + header.vlr_copc_info = new LASvlr_copc_info; + memcpy(header.vlr_copc_info, header.vlrs[i].data, sizeof(LASvlr_copc_info)); + } + else + { + REprintf( "WARNING: variable length records contain more than one copc info\n"); + } + } + else + { + REprintf( "WARNING: COPC VLR info should belong in LAZ file 1.4 pdrf 6-8 not LAZ %u.%u pdrf %u (not specification-conform).\n", header.version_major, header.version_minor, header.point_data_format); + } + } + } + else + { + REprintf( "WARNING: no payload for copc (not specification-conform).\n"); + } + } } } @@ -904,8 +940,8 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel I64 here = stream->tell(); stream->seek(header.start_of_first_extended_variable_length_record); - header.evlrs = (LASevlr*)malloc(sizeof(LASevlr)*header.number_of_extended_variable_length_records); - + header.evlrs = (LASevlr*)calloc(header.number_of_extended_variable_length_records, sizeof(LASevlr)); + // read the extended variable length records into the header I64 evlrs_size = 0; @@ -962,12 +998,12 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel header.laszip = new LASzip(); // read this data following the header of the variable length record - // U16 compressor 2 bytes - // U32 coder 2 bytes - // U8 version_major 1 byte + // U16 compressor 2 bytes + // U32 coder 2 bytes + // U8 version_major 1 byte // U8 version_minor 1 byte // U16 version_revision 2 bytes - // U32 options 4 bytes + // U32 options 4 bytes // I32 chunk_size 4 bytes // I64 number_of_special_evlrs 8 bytes // I64 offset_to_special_evlrs 8 bytes @@ -1057,13 +1093,13 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel header.vlr_lastiling = new LASvlr_lastiling(); // read the payload of this VLR which contains 28 bytes - // U32 level 4 bytes - // U32 level_index 4 bytes - // U32 implicit_levels + buffer bit + reversible bit 4 bytes - // F32 min_x 4 bytes - // F32 max_x 4 bytes - // F32 min_y 4 bytes - // F32 max_y 4 bytes + // U32 level 4 bytes + // U32 level_index 4 bytes + // U32 implicit_levels + buffer bit + reversible bit 4 bytes + // F32 min_x 4 bytes + // F32 max_x 4 bytes + // F32 min_y 4 bytes + // F32 max_y 4 bytes if (header.evlrs[i].record_length_after_header == 28) { @@ -1237,12 +1273,57 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel i--; header.number_of_extended_variable_length_records--; } + else if (strcmp(header.evlrs[i].user_id, "copc") == 0) + { + if (header.evlrs[i].data) + { + if (header.evlrs[i].record_id == 1000) // COPC EPT hierarchy + { + if (header.vlr_copc_info) + { + // COPC offsets values are relative to the beginning of the file. We need to compute + // an extra offset relative to the beginning of this evlr payload + U64 offset_to_first_copc_entry = 60 + header.start_of_first_extended_variable_length_record; + for (j = 0; j < i; j++) { offset_to_first_copc_entry += 60 + header.evlrs[j].record_length_after_header; } + + if (!EPToctree::set_vlr_entries(header.evlrs[i].data, offset_to_first_copc_entry, header)) + { + REprintf( "WARNING: invalid COPC EPT hierarchy (not specification-conform).\n"); + delete header.vlr_copc_info; + header.vlr_copc_info = 0; + } + } + else + { + REprintf( "WARNING: no COPC VLR info before COPC EPT hierarchy EVLR (not specification-conform).\n"); + } + } + else + { + REprintf( "WARNING: unknown COPC EVLR (not specification-conform).\n"); + } + } + else + { + REprintf( "WARNING: no payload for COPC EVLR (not specification-conform).\n"); + } + } } stream->seek(here); } } } + // remove copc vlrs: the header contains two dynamically allocated pointers (vlr_copc_info and vlr_copc_entries) used to build a spatial index. + // COPC VLR and EVLR are removed and the header becomes the header of a regular LAZ file. + // This way the writers will never be able to produce and invalid the COPC file because we will never actually encounter a COPC header outside this method. + if (!keep_copc) + { + header.remove_vlr("copc", 1); // copc info + header.remove_vlr("copc", 10000); // copc extent (deprecated and no longer part of the specs) + header.remove_evlr("copc", 1000); // ept hierachy + } + // check the compressor state if (header.laszip) @@ -1251,19 +1332,27 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel { REprintf("ERROR: %s\n", header.laszip->get_error()); REprintf(" please upgrade to the latest release of LAStools (with LASzip)\n"); - REprintf(" or contact 'martin.isenburg@rapidlasso.com' for assistance.\n"); + REprintf(" or contact 'info@rapidlasso.de' for assistance.\n"); return FALSE; } } // remove extra bits in point data type - if ((header.point_data_format & 128) || (header.point_data_format & 64)) + if ((header.point_data_format & 128) || (header.point_data_format & 64)) { if (!header.laszip) { - REprintf("ERROR: this file was compressed with an experimental version of laszip\n"); - REprintf("ERROR: please contact 'martin.isenburg@rapidlasso.com' for assistance.\n"); + if (vlrs_corrupt) + { + REprintf("ERROR: your LAZ file has corruptions in the LAS header resulting in\n"); + REprintf("ERROR: the laszip VLR being lost. maybe your download failed?\n"); + } + else + { + REprintf("ERROR: this file was compressed with an experimental version of laszip\n"); + REprintf("ERROR: please contact 'info@rapidlasso.de' for assistance.\n"); + } return FALSE; } header.point_data_format &= 127; @@ -1299,7 +1388,7 @@ BOOL LASreaderLAS::open(ByteStreamIn* stream, BOOL peek_only, U32 decompress_sel for (count = 0; count < number; count++) { stream->seek(offset + 2); - CHAR user_id[16]; + CHAR user_id[16]; stream->getBytes((U8*)user_id, 16); U16 record_id; stream->get16bitsLE((U8*)&record_id); @@ -1390,7 +1479,7 @@ BOOL LASreaderLAS::read_point_default() if (point.have_wavepacket) { // distance in meters light travels in one nanoseconds divided by two divided by 1000 - F64 round_trip_distance_in_picoseconds = 0.299792458 / 2 / 1000; + F64 round_trip_distance_in_picoseconds = 0.299792458 / 2 / 1000; F64 x = -point.wavepacket.getXt(); F64 y = -point.wavepacket.getYt(); F64 z = -point.wavepacket.getZt(); @@ -1401,7 +1490,7 @@ BOOL LASreaderLAS::read_point_default() point.wavepacket.setXt((F32)x); point.wavepacket.setYt((F32)y); point.wavepacket.setZt((F32)z); -// alternative to converge on optical origin +// alternative to converge on optical origin // point.wavepacket.setXt(-point.wavepacket.getXt()/point.wavepacket.getLocation()); // point.wavepacket.setYt(-point.wavepacket.getYt()/point.wavepacket.getLocation()); // point.wavepacket.setZt(-point.wavepacket.getZt()/point.wavepacket.getLocation()); @@ -1436,7 +1525,7 @@ ByteStreamIn* LASreaderLAS::get_stream() const void LASreaderLAS::close(BOOL close_stream) { - if (reader) + if (reader) { reader->done(); delete reader; @@ -1472,6 +1561,7 @@ LASreaderLAS::LASreaderLAS() stream = 0; delete_stream = TRUE; reader = 0; + keep_copc = FALSE; } LASreaderLAS::~LASreaderLAS() diff --git a/src/LASlib/lasreader_las.hpp b/src/LASlib/lasreader_las.hpp index c4fe8ed..5831ba2 100644 --- a/src/LASlib/lasreader_las.hpp +++ b/src/LASlib/lasreader_las.hpp @@ -9,11 +9,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2018, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2018, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -24,6 +24,8 @@ CHANGE HISTORY: + 9 November 2022 -- support of COPC VLR and EVLR + 13 June 2022 -- support unicode filenames 10 July 2018 -- user must set seek-ability of istream (hard to determine) 19 April 2017 -- support for selective decompression for new LAS 1.4 points 1 February 2017 -- better support for OGC WKT strings in VLRs or EVLRs @@ -61,6 +63,7 @@ class LASreaderLAS : public LASreader public: void set_delete_stream(BOOL delete_stream=TRUE) { this->delete_stream = delete_stream; }; + void set_keep_copc(BOOL keep_copc) { this->keep_copc = keep_copc; }; BOOL open(const char* file_name, I32 io_buffer_size=LAS_TOOLS_IO_IBUFFER_SIZE, BOOL peek_only=FALSE, U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); BOOL open(FILE* file, BOOL peek_only=FALSE, U32 decompress_selective=LASZIP_DECOMPRESS_SELECTIVE_ALL); @@ -87,6 +90,7 @@ class LASreaderLAS : public LASreader BOOL delete_stream; LASreadPoint* reader; BOOL checked_end; + BOOL keep_copc; }; class LASreaderLASrescale : public virtual LASreaderLAS diff --git a/src/LASlib/lasreader_txt.cpp b/src/LASlib/lasreader_txt.cpp index 7e0e36b..7c8cabc 100644 --- a/src/LASlib/lasreader_txt.cpp +++ b/src/LASlib/lasreader_txt.cpp @@ -1,34 +1,35 @@ /* =============================================================================== - FILE: lasreader_txt.cpp + FILE: lasreader_txt.cpp - CONTENTS: + CONTENTS: - see corresponding header file + see corresponding header file - PROGRAMMERS: + PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de - COPYRIGHT: + COPYRIGHT: - (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2017, rapidlasso GmbH - fast tools to catch reality - This is free software; you can redistribute and/or modify it under the - terms of the GNU Lesser General Licence as published by the Free Software - Foundation. See the LICENSE.txt file for more information. + This is free software; you can redistribute and/or modify it under the + terms of the GNU Lesser General Licence as published by the Free Software + Foundation. See the LICENSE.txt file for more information. - This software is distributed WITHOUT ANY WARRANTY and without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + This software is distributed WITHOUT ANY WARRANTY and without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - CHANGE HISTORY: + CHANGE HISTORY: - see corresponding header file + see corresponding header file =============================================================================== */ #include "lasreader_txt.hpp" +#include "lastransform.hpp" #include #include @@ -41,2111 +42,2135 @@ extern "C" FILE* fopen_compressed(const char* filename, const char* mode, bool* BOOL LASreaderTXT::open(const CHAR* file_name, U8 point_type, const CHAR* parse_string, I32 skip_lines, BOOL populate_header) { - if (file_name == 0) - { - REprintf("ERROR: file name pointer is zero\n"); - return FALSE; - } - - FILE* file = fopen_compressed(file_name, "r", &piped); - if (file == 0) - { - REprintf( "ERROR: cannot open file '%s'\n", file_name); - return FALSE; - } - - if (setvbuf(file, NULL, _IOFBF, 10*LAS_TOOLS_IO_IBUFFER_SIZE) != 0) - { - REprintf( "WARNING: setvbuf() failed with buffer size %d\n", 10*LAS_TOOLS_IO_IBUFFER_SIZE); - } - - return open(file, file_name, point_type, parse_string, skip_lines, populate_header); + if (file_name == 0) + { + REprintf("ERROR: file name pointer is zero\n"); + return FALSE; + } + + FILE* file = fopen_compressed(file_name, "r", &piped); + if (file == 0) + { + REprintf("ERROR: cannot open file '%s'\n", file_name); + return FALSE; + } + + if (setvbuf(file, NULL, _IOFBF, 10 * LAS_TOOLS_IO_IBUFFER_SIZE) != 0) + { + REprintf("WARNING: setvbuf() failed with buffer size %d\n", 10 * LAS_TOOLS_IO_IBUFFER_SIZE); + } + + return open(file, file_name, point_type, parse_string, skip_lines, populate_header); } BOOL LASreaderTXT::open(FILE* file, const CHAR* file_name, U8 point_type, const CHAR* parse_string, I32 skip_lines, BOOL populate_header) { - int i; - - if (file == 0) - { - REprintf("ERROR: file pointer is zero\n"); - return FALSE; - } - - // clean the reader - - clean(); - - // clean the header - - header.clean(); - - // set the file pointer - - this->file = file; - - // add attributes in extra bytes - - if (number_attributes) - { - for (i = 0; i < number_attributes; i++) - { - I32 type = (attributes_data_types[i]-1)%10; - try { - LASattribute attribute(type, attribute_names[i], attribute_descriptions[i]); - if (attribute_scales[i] != 1.0 || attribute_offsets[i] != 0.0) - { - attribute.set_scale(attribute_scales[i]); - } - if (attribute_offsets[i] != 0.0) - { - attribute.set_offset(attribute_offsets[i]); - } - if (attribute_no_datas[i] != F64_MAX) - { - attribute.set_no_data(attribute_no_datas[i]); - } - header.add_attribute(attribute); - } - catch(...) { - REprintf("ERROR: initializing attribute %s\n", attribute_descriptions[i]); - return FALSE; - } - } - } - - if (parse_string && !check_parse_string(parse_string)) - { - return FALSE; - } - - // populate the header as much as it makes sense - - snprintf(header.system_identifier, 32, "LAStools (c) by rapidlasso GmbH"); - snprintf(header.generating_software, 32, "via LASreaderTXT (%d)", LAS_TOOLS_VERSION); - - // maybe set creation date + int i; + + if (file == 0) + { + REprintf("ERROR: file pointer is zero\n"); + return FALSE; + } + + // clean the reader + + clean(); + + // clean the header + + header.clean(); + + // set the file pointer + + this->file = file; + + // add attributes in extra bytes + + if (number_attributes) + { + for (i = 0; i < number_attributes; i++) + { + I32 type = (attributes_data_types[i] - 1) % 10; + try { + LASattribute attribute(type, attribute_names[i], attribute_descriptions[i]); + if (attribute_scales[i] != 1.0 || attribute_offsets[i] != 0.0) + { + attribute.set_scale(attribute_scales[i]); + } + if (attribute_offsets[i] != 0.0) + { + attribute.set_offset(attribute_offsets[i]); + } + if (attribute_no_datas[i] != F64_MAX) + { + attribute.set_no_data(attribute_no_datas[i]); + } + header.add_attribute(attribute); + } + catch (...) { + REprintf("ERROR: initializing attribute %s\n", attribute_descriptions[i]); + return FALSE; + } + } + } + + if (parse_string && !check_parse_string(parse_string)) + { + return FALSE; + } + + // populate the header as much as it makes sense + + snprintf(header.system_identifier, 32, "LAStools (c) by rapidlasso GmbH"); + snprintf(header.generating_software, 32, "via LASreaderTXT (%d)", LAS_TOOLS_VERSION); + + // maybe set creation date #ifdef _WIN32 - if (file_name) - { - WIN32_FILE_ATTRIBUTE_DATA attr; - SYSTEMTIME creation; - GetFileAttributesEx(file_name, GetFileExInfoStandard, &attr); - FileTimeToSystemTime(&attr.ftCreationTime, &creation); - int startday[13] = {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; - header.file_creation_day = startday[creation.wMonth] + creation.wDay; - header.file_creation_year = creation.wYear; - // leap year handling - if ((((creation.wYear)%4) == 0) && (creation.wMonth > 2)) header.file_creation_day++; - } - else - { - header.file_creation_day = 1; - header.file_creation_year = 2019; - } + if (file_name) + { + WIN32_FILE_ATTRIBUTE_DATA attr; + SYSTEMTIME creation; + GetFileAttributesEx(file_name, GetFileExInfoStandard, &attr); + FileTimeToSystemTime(&attr.ftCreationTime, &creation); + int startday[13] = { -1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + header.file_creation_day = startday[creation.wMonth] + creation.wDay; + header.file_creation_year = creation.wYear; + // leap year handling + if ((((creation.wYear) % 4) == 0) && (creation.wMonth > 2)) header.file_creation_day++; + } + else + { + header.file_creation_day = 1; + header.file_creation_year = 2019; + } #else - header.file_creation_day = 1; - header.file_creation_year = 2019; + header.file_creation_day = 1; + header.file_creation_year = 2019; #endif - if (point_type) - { - switch (point_type) - { - case 1: - header.point_data_record_length = 28; - break; - case 2: - header.point_data_record_length = 26; - break; - case 3: - header.point_data_record_length = 34; - break; - case 6: - header.point_data_record_length = 30; - break; - case 7: - header.point_data_record_length = 36; - break; - case 8: - header.point_data_record_length = 38; - break; - default: - return FALSE; - } - header.point_data_format = point_type; - } - else if (parse_string) - { - if (strstr(parse_string,"o") || strstr(parse_string,"l") || strstr(parse_string,"I")) - { - // new point types - if (strstr(parse_string,"I")) - { - header.point_data_format = 8; - header.point_data_record_length = 38; - } - else if (strstr(parse_string,"R") || strstr(parse_string,"G") || strstr(parse_string,"B") || strstr(parse_string,"H")) - { - header.point_data_format = 7; - header.point_data_record_length = 36; - } - else - { - header.point_data_format = 6; - header.point_data_record_length = 30; - } - } - else if (strstr(parse_string,"t")) - { - if (strstr(parse_string,"R") || strstr(parse_string,"G") || strstr(parse_string,"B") || strstr(parse_string,"H")) - { - header.point_data_format = 3; - header.point_data_record_length = 34; - } - else - { - header.point_data_format = 1; - header.point_data_record_length = 28; - } - } - else - { - if (strstr(parse_string,"R") || strstr(parse_string,"G") || strstr(parse_string,"B") || strstr(parse_string,"H")) - { - header.point_data_format = 2; - header.point_data_record_length = 26; - } - else - { - header.point_data_format = 0; - header.point_data_record_length = 20; - } - } - } - else - { - header.point_data_format = 0; - header.point_data_record_length = 20; - } - - this->point_type = header.point_data_format; - - // maybe update point size with extra bytes - - if (header.number_attributes) - { - header.point_data_record_length += header.get_attributes_size(); - } - - // initialize point - - point.init(&header, header.point_data_format, header.point_data_record_length, &header); - - // we do not know yet how many points to expect - - npoints = 0; - - // should we perform an extra pass to fully populate the header - - if (populate_header && file_name) - { - // create a cheaper parse string that only looks for 'x' 'y' 'z' 'r' and attributes in extra bytes - - char* parse_less; - if (parse_string == 0) - { - parse_less = LASCopyString("xyz"); - } - else - { - parse_less = LASCopyString(parse_string); - for (i = 0; i < (int)strlen(parse_string); i++) - { - if (parse_less[i] != 'x' && parse_less[i] != 'y' && parse_less[i] != 'z' && parse_less[i] != 'r' && (parse_less[i] < '0' || parse_less[i] > '0')) - { - parse_less[i] = 's'; - } - } - do - { - parse_less[i] = '\0'; - i--; - } while (parse_less[i] == 's'); - } - - // skip lines if we have to - - for (i = 0; i < skip_lines; i++) if (fgets(line, 512, file) == NULL) {} - - if (ipts) - { - if (fgets(line, 512, file)) - { -// temporarily comment this portion that is not useful in rlas. See #62 -/*#ifdef _WIN32 - if (sscanf(line, "%" PRId64 "", &npoints) != 1) + if (point_type) + { + switch (point_type) + { + case 1: + header.point_data_record_length = 28; + break; + case 2: + header.point_data_record_length = 26; + break; + case 3: + header.point_data_record_length = 34; + break; + case 6: + header.point_data_record_length = 30; + break; + case 7: + header.point_data_record_length = 36; + break; + case 8: + header.point_data_record_length = 38; + break; + default: + return FALSE; + } + header.point_data_format = point_type; + } + else if (parse_string) + { + if (strstr(parse_string, "o") || strstr(parse_string, "l") || strstr(parse_string, "I")) + { + // new point types + if (strstr(parse_string, "I")) + { + header.point_data_format = 8; + header.point_data_record_length = 38; + } + else if (strstr(parse_string, "R") || strstr(parse_string, "G") || strstr(parse_string, "B") || strstr(parse_string, "H")) + { + header.point_data_format = 7; + header.point_data_record_length = 36; + } + else + { + header.point_data_format = 6; + header.point_data_record_length = 30; + } + } + else if (strstr(parse_string, "t")) + { + if (strstr(parse_string, "R") || strstr(parse_string, "G") || strstr(parse_string, "B") || strstr(parse_string, "H")) + { + header.point_data_format = 3; + header.point_data_record_length = 34; + } + else + { + header.point_data_format = 1; + header.point_data_record_length = 28; + } + } + else + { + if (strstr(parse_string, "R") || strstr(parse_string, "G") || strstr(parse_string, "B") || strstr(parse_string, "H")) + { + header.point_data_format = 2; + header.point_data_record_length = 26; + } + else + { + header.point_data_format = 0; + header.point_data_record_length = 20; + } + } + } + else + { + header.point_data_format = 0; + header.point_data_record_length = 20; + } + + this->point_type = header.point_data_format; + + // maybe update point size with extra bytes + + if (header.number_attributes) + { + header.point_data_record_length += header.get_attributes_size(); + } + + // initialize point + + point.init(&header, header.point_data_format, header.point_data_record_length, &header); + + // we do not know yet how many points to expect + + npoints = 0; + + // should we perform an extra pass to fully populate the header + + if (populate_header && file_name) + { + // create a cheaper parse string that only looks for 'x' 'y' 'z' 'r' and attributes in extra bytes + + char* parse_less; + if (parse_string == 0) + { + parse_less = LASCopyString("xyz"); + } + else + { + parse_less = LASCopyString(parse_string); + for (i = 0; i < (int)strlen(parse_string); i++) + { + if (parse_less[i] != 'x' && parse_less[i] != 'y' && parse_less[i] != 'z' && parse_less[i] != 'r' && (parse_less[i] < '0' || parse_less[i] > '0')) + { + parse_less[i] = 's'; + } + } + do + { + parse_less[i] = '\0'; + i--; + } while (parse_less[i] == 's'); + } + + // skip lines if we have to + + for (i = 0; i < skip_lines; i++) if (fgets(line, 512, file) == NULL) {} + + if (ipts) + { + if (fgets(line, 512, file)) + { + // temporarily comment this portion that is not useful in rlas. See #62 + /*#ifdef _WIN32 + if (sscanf(line, "%" PRId64 "", &npoints) != 1) #else - if (sscanf(line, "%" PRId64 "", &npoints) != 1) + if (sscanf(line, "%" PRId64 "", &npoints) != 1) #endif*/ - { - REprintf( "ERROR: parsing number of points for '-itps'\n"); - return FALSE; - } + { + REprintf("ERROR: parsing number of points for '-itps'\n"); + return FALSE; + } #ifdef _WIN32 - REprintf( "PTS header states %" PRId64 " points. ignoring ...\n", npoints); + REprintf( "PTS header states %" PRId64 " points. ignoring ...\n", npoints); #else - REprintf( "PTS header states %" PRId64 " points. ignoring ...\n", npoints); + REprintf( "PTS header states %" PRId64 " points. ignoring ...\n", npoints); #endif - npoints = 0; - } - else - { - REprintf( "ERROR: reading PTS header for '-itps'\n"); - return FALSE; - } - } - else if (iptx) - { - I32 ncols; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%d", &ncols) != 1) - { - REprintf( "ERROR: parsing number of cols\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with number of cols\n"); - return FALSE; - } - I32 nrows; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%d", &nrows) != 1) - { - REprintf( "ERROR: parsing number of rows\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with number of rows\n"); - return FALSE; - } - npoints = (I64)ncols*(I64)nrows; + npoints = 0; + } + else + { + REprintf("ERROR: reading PTS header for '-itps'\n"); + return FALSE; + } + } + else if (iptx || iptx_transform) + { + I32 ncols; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%d", &ncols) != 1) + { + REprintf("ERROR: parsing number of cols\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with number of cols\n"); + return FALSE; + } + I32 nrows; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%d", &nrows) != 1) + { + REprintf("ERROR: parsing number of rows\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with number of rows\n"); + return FALSE; + } + npoints = (I64)ncols*(I64)nrows; #ifdef _WIN32 - REprintf( "PTX header states %d cols by %d rows aka %" PRId64 " points. ignoring ...\n", ncols, nrows, npoints); + REprintf( "PTX header states %d cols by %d rows aka %" PRId64 " points. ignoring ...\n", ncols, nrows, npoints); #else - REprintf( "PTX header states %d cols by %d rows aka %" PRId64 " points. ignoring ...\n", ncols, nrows, npoints); + REprintf( "PTX header states %d cols by %d rows aka %" PRId64 " points. ignoring ...\n", ncols, nrows, npoints); #endif - F64 translation[3]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf", &(translation[0]), &(translation[1]), &(translation[2])) != 3) - { - REprintf( "ERROR: parsing translation\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with translation\n"); - return FALSE; - } - F64 rotation_row_0[3]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf", &(rotation_row_0[0]), &(rotation_row_0[1]), &(rotation_row_0[2])) != 3) - { - REprintf( "ERROR: parsing rotation row 0\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with rotation row 0\n"); - return FALSE; - } - F64 rotation_row_1[3]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf", &(rotation_row_1[0]), &(rotation_row_1[1]), &(rotation_row_1[2])) != 3) - { - REprintf( "ERROR: parsing rotation row 1\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with rotation row 1\n"); - return FALSE; - } - F64 rotation_row_2[3]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf", &(rotation_row_2[0]), &(rotation_row_2[1]), &(rotation_row_2[2])) != 3) - { - REprintf( "ERROR: parsing rotation row 2\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with rotation row 2\n"); - return FALSE; - } - F64 transformation_row_0[4]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf %lf", &(transformation_row_0[0]), &(transformation_row_0[1]), &(transformation_row_0[2]), &(transformation_row_0[3])) != 4) - { - REprintf( "ERROR: parsing transformation row 0\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with transformation row 0\n"); - return FALSE; - } - F64 transformation_row_1[4]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf %lf", &(transformation_row_1[0]), &(transformation_row_1[1]), &(transformation_row_1[2]), &(transformation_row_1[3])) != 4) - { - REprintf( "ERROR: parsing transformation row 1\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with transformation row 1\n"); - return FALSE; - } - F64 transformation_row_2[4]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf %lf", &(transformation_row_2[0]), &(transformation_row_2[1]), &(transformation_row_2[2]), &(transformation_row_2[3])) != 4) - { - REprintf( "ERROR: parsing transformation row 2\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with transformation row 2\n"); - return FALSE; - } - F64 transformation_row_3[4]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf %lf", &(transformation_row_3[0]), &(transformation_row_3[1]), &(transformation_row_3[2]), &(transformation_row_3[3])) != 4) - { - REprintf( "ERROR: parsing transformation row 3\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with transformation row 3\n"); - return FALSE; - } - npoints = 0; - } - - // read the first line - - while (fgets(line, 512, file)) - { - if (parse(parse_less)) - { - // mark that we found the first point - npoints++; - // we can stop this loop - break; - } - else - { - line[strlen(line)-1] = '\0'; - REprintf( "WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, parse_less); - } - } - - // did we manage to parse a line - - if (npoints == 0) - { - REprintf( "ERROR: could not parse any lines with '%s'\n", parse_less); - fclose(file); - file = 0; - free(parse_less); - return FALSE; - } - - // init the bounding box - - header.min_x = header.max_x = point.coordinates[0]; - header.min_y = header.max_y = point.coordinates[1]; - header.min_z = header.max_z = point.coordinates[2]; - - // create return histogram - - if (point.extended_point_type) - { - if (point.extended_return_number >= 1 && point.extended_return_number <= 15) header.extended_number_of_points_by_return[point.extended_return_number-1]++; - } - else - { - if (point.return_number >= 1 && point.return_number <= 7) header.extended_number_of_points_by_return[point.return_number-1]++; - } - - // init the min and max of attributes in extra bytes - - if (number_attributes) - { - for (i = 0; i < number_attributes; i++) - { - header.attributes[i].set_min(point.extra_bytes + attribute_starts[i]); - header.attributes[i].set_max(point.extra_bytes + attribute_starts[i]); - } - } - - // loop over the remaining lines - - while (fgets(line, 512, file)) - { - if (parse(parse_less)) - { - // count points - npoints++; - // create return histogram - if (point.extended_point_type) - { - if (point.extended_return_number >= 1 && point.extended_return_number <= 15) header.extended_number_of_points_by_return[point.extended_return_number-1]++; - } - else - { - if (point.return_number >= 1 && point.return_number <= 7) header.extended_number_of_points_by_return[point.return_number-1]++; - } - // update bounding box - if (point.coordinates[0] < header.min_x) header.min_x = point.coordinates[0]; - else if (point.coordinates[0] > header.max_x) header.max_x = point.coordinates[0]; - if (point.coordinates[1] < header.min_y) header.min_y = point.coordinates[1]; - else if (point.coordinates[1] > header.max_y) header.max_y = point.coordinates[1]; - if (point.coordinates[2] < header.min_z) header.min_z = point.coordinates[2]; - else if (point.coordinates[2] > header.max_z) header.max_z = point.coordinates[2]; - // update the min and max of attributes in extra bytes - if (number_attributes) - { - for (i = 0; i < number_attributes; i++) - { - header.attributes[i].update_min(point.extra_bytes + attribute_starts[i]); - header.attributes[i].update_max(point.extra_bytes + attribute_starts[i]); - } - } - } - else - { - line[strlen(line)-1] = '\0'; - REprintf( "WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, parse_less); - } - } + F64 ptx_scan_pos[3]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf", &(ptx_scan_pos[0]), &(ptx_scan_pos[1]), &(ptx_scan_pos[2])) != 3) + { + REprintf("ERROR: parsing ptx_scan_pos\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with ptx_scan_pos\n"); + return FALSE; + } + F64 ptx_scan_axis_x[3]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf", &(ptx_scan_axis_x[0]), &(ptx_scan_axis_x[1]), &(ptx_scan_axis_x[2])) != 3) + { + REprintf("ERROR: parsing rotation row 0\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with rotation row 0\n"); + return FALSE; + } + F64 ptx_scan_axis_y[3]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf", &(ptx_scan_axis_y[0]), &(ptx_scan_axis_y[1]), &(ptx_scan_axis_y[2])) != 3) + { + REprintf("ERROR: parsing rotation row 1\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with rotation row 1\n"); + return FALSE; + } + F64 ptx_scan_axis_z[3]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf", &(ptx_scan_axis_z[0]), &(ptx_scan_axis_z[1]), &(ptx_scan_axis_z[2])) != 3) + { + REprintf("ERROR: parsing rotation row 2\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with rotation row 2\n"); + return FALSE; + } + F64 ptx_matrix_row_0[4]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf %lf", &(ptx_matrix_row_0[0]), &(ptx_matrix_row_0[1]), &(ptx_matrix_row_0[2]), &(ptx_matrix_row_0[3])) != 4) + { + REprintf("ERROR: parsing transformation row 0\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with transformation row 0\n"); + return FALSE; + } + F64 ptx_matrix_row_1[4]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf %lf", &(ptx_matrix_row_1[0]), &(ptx_matrix_row_1[1]), &(ptx_matrix_row_1[2]), &(ptx_matrix_row_1[3])) != 4) + { + REprintf("ERROR: parsing transformation row 1\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with transformation row 1\n"); + return FALSE; + } + F64 ptx_matrix_row_2[4]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf %lf", &(ptx_matrix_row_2[0]), &(ptx_matrix_row_2[1]), &(ptx_matrix_row_2[2]), &(ptx_matrix_row_2[3])) != 4) + { + REprintf("ERROR: parsing transformation row 2\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with transformation row 2\n"); + return FALSE; + } + F64 ptx_matrix_row_3[4]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf %lf", &(ptx_matrix_row_3[0]), &(ptx_matrix_row_3[1]), &(ptx_matrix_row_3[2]), &(ptx_matrix_row_3[3])) != 4) + { + REprintf("ERROR: parsing transformation row 3\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with transformation row 3\n"); + return FALSE; + } + npoints = 0; + } + + // read the first line + + while (fgets(line, 512, file)) + { + if (parse(parse_less)) + { + // mark that we found the first point + npoints++; + // we can stop this loop + break; + } + else + { + line[strlen(line) - 1] = '\0'; + REprintf("WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, parse_less); + } + } + + // did we manage to parse a line + + if (npoints == 0) + { + REprintf("ERROR: could not parse any lines with '%s'\n", parse_less); + fclose(file); + file = 0; + free(parse_less); + return FALSE; + } + + // init the bounding box + + header.min_x = header.max_x = point.coordinates[0]; + header.min_y = header.max_y = point.coordinates[1]; + header.min_z = header.max_z = point.coordinates[2]; + + // create return histogram + + if (point.extended_point_type) + { + if (point.extended_return_number >= 1 && point.extended_return_number <= 15) header.extended_number_of_points_by_return[point.extended_return_number - 1]++; + } + else + { + if (point.return_number >= 1 && point.return_number <= 7) header.extended_number_of_points_by_return[point.return_number - 1]++; + } + + // init the min and max of attributes in extra bytes + + if (number_attributes) + { + for (i = 0; i < number_attributes; i++) + { + header.attributes[i].set_min(point.extra_bytes + attribute_starts[i]); + header.attributes[i].set_max(point.extra_bytes + attribute_starts[i]); + } + } + + // loop over the remaining lines + + while (fgets(line, 512, file)) + { + if (parse(parse_less)) + { + // count points + npoints++; + // create return histogram + if (point.extended_point_type) + { + if (point.extended_return_number >= 1 && point.extended_return_number <= 15) header.extended_number_of_points_by_return[point.extended_return_number - 1]++; + } + else + { + if (point.return_number >= 1 && point.return_number <= 7) header.extended_number_of_points_by_return[point.return_number - 1]++; + } + // update bounding box + if (point.coordinates[0] < header.min_x) header.min_x = point.coordinates[0]; + else if (point.coordinates[0] > header.max_x) header.max_x = point.coordinates[0]; + if (point.coordinates[1] < header.min_y) header.min_y = point.coordinates[1]; + else if (point.coordinates[1] > header.max_y) header.max_y = point.coordinates[1]; + if (point.coordinates[2] < header.min_z) header.min_z = point.coordinates[2]; + else if (point.coordinates[2] > header.max_z) header.max_z = point.coordinates[2]; + // update the min and max of attributes in extra bytes + if (number_attributes) + { + for (i = 0; i < number_attributes; i++) + { + header.attributes[i].update_min(point.extra_bytes + attribute_starts[i]); + header.attributes[i].update_max(point.extra_bytes + attribute_starts[i]); + } + } + } + else + { + line[strlen(line) - 1] = '\0'; + REprintf("WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, parse_less); + } + } #ifdef _WIN32 - REprintf( "counted %" PRId64 " points in populate pass.\n", npoints); + REprintf( "counted %" PRId64 " points in populate pass.\n", npoints); #else - REprintf( "counted %" PRId64 " points in populate pass.\n", npoints); + REprintf( "counted %" PRId64 " points in populate pass.\n", npoints); #endif - if (point.extended_point_type || (npoints > U32_MAX) || header.extended_number_of_points_by_return[5] || header.extended_number_of_points_by_return[6] || header.extended_number_of_points_by_return[7] || header.extended_number_of_points_by_return[8] || header.extended_number_of_points_by_return[9] || header.extended_number_of_points_by_return[10] || header.extended_number_of_points_by_return[11] || header.extended_number_of_points_by_return[12] || header.extended_number_of_points_by_return[13] || header.extended_number_of_points_by_return[14]) - { - header.version_minor = 4; - header.header_size = 375; - header.offset_to_point_data = 375; - header.number_of_point_records = 0; - header.number_of_points_by_return[0] = 0; - header.number_of_points_by_return[1] = 0; - header.number_of_points_by_return[2] = 0; - header.number_of_points_by_return[3] = 0; - header.number_of_points_by_return[4] = 0; - header.extended_number_of_point_records = npoints; - } - else - { - header.version_minor = 2; - header.header_size = 227; - header.offset_to_point_data = 227; - header.number_of_point_records = (U32)npoints; - header.number_of_points_by_return[0] = (U32)header.extended_number_of_points_by_return[0]; - header.number_of_points_by_return[1] = (U32)header.extended_number_of_points_by_return[1]; - header.number_of_points_by_return[2] = (U32)header.extended_number_of_points_by_return[2]; - header.number_of_points_by_return[3] = (U32)header.extended_number_of_points_by_return[3]; - header.number_of_points_by_return[4] = (U32)header.extended_number_of_points_by_return[4]; - header.extended_number_of_point_records = 0; - header.extended_number_of_points_by_return[0] = 0; - header.extended_number_of_points_by_return[1] = 0; - header.extended_number_of_points_by_return[2] = 0; - header.extended_number_of_points_by_return[3] = 0; - header.extended_number_of_points_by_return[4] = 0; - } - - // free the parse less string - - free(parse_less); - - // close the input file - - fclose(file); - - // populate scale and offset - - populate_scale_and_offset(); - - // populate bounding box - - populate_bounding_box(); - - // mark that header is already populated - - populated_header = TRUE; - - // reopen input file for the second pass - - file = fopen_compressed(file_name, "r", &piped); - if (file == 0) - { - REprintf( "ERROR: could not open '%s' for second pass\n", file_name); - return FALSE; - } - - if (setvbuf(file, NULL, _IOFBF, 10*LAS_TOOLS_IO_IBUFFER_SIZE) != 0) - { - REprintf( "WARNING: setvbuf() failed with buffer size %d\n", 10*LAS_TOOLS_IO_IBUFFER_SIZE); - } - } - - if (parse_string == 0) - { - this->parse_string = LASCopyString("xyz"); - } - else - { - this->parse_string = LASCopyString(parse_string); - } - - // skip lines if we have to - - this->skip_lines = skip_lines; - if (skip_lines) - { - for (i = 0; i < skip_lines; i++) if (fgets(line, 512, file) == NULL) {} - } - else if (ipts) - { - if (fgets(line, 512, file)) - { - if (!populated_header) - { -// temporarily comment this portion that is not useful in rlas. See #62 -/*#ifdef _WIN32 - if (sscanf(line, "%" PRId64 "", &npoints) != 1) + if (point.extended_point_type || (npoints > U32_MAX) || header.extended_number_of_points_by_return[5] || header.extended_number_of_points_by_return[6] || header.extended_number_of_points_by_return[7] || header.extended_number_of_points_by_return[8] || header.extended_number_of_points_by_return[9] || header.extended_number_of_points_by_return[10] || header.extended_number_of_points_by_return[11] || header.extended_number_of_points_by_return[12] || header.extended_number_of_points_by_return[13] || header.extended_number_of_points_by_return[14]) + { + header.version_minor = 4; + header.header_size = 375; + header.offset_to_point_data = 375; + header.number_of_point_records = 0; + header.number_of_points_by_return[0] = 0; + header.number_of_points_by_return[1] = 0; + header.number_of_points_by_return[2] = 0; + header.number_of_points_by_return[3] = 0; + header.number_of_points_by_return[4] = 0; + header.extended_number_of_point_records = npoints; + } + else + { + header.version_minor = 2; + header.header_size = 227; + header.offset_to_point_data = 227; + header.number_of_point_records = (U32)npoints; + header.number_of_points_by_return[0] = (U32)header.extended_number_of_points_by_return[0]; + header.number_of_points_by_return[1] = (U32)header.extended_number_of_points_by_return[1]; + header.number_of_points_by_return[2] = (U32)header.extended_number_of_points_by_return[2]; + header.number_of_points_by_return[3] = (U32)header.extended_number_of_points_by_return[3]; + header.number_of_points_by_return[4] = (U32)header.extended_number_of_points_by_return[4]; + header.extended_number_of_point_records = 0; + header.extended_number_of_points_by_return[0] = 0; + header.extended_number_of_points_by_return[1] = 0; + header.extended_number_of_points_by_return[2] = 0; + header.extended_number_of_points_by_return[3] = 0; + header.extended_number_of_points_by_return[4] = 0; + } + + // free the parse less string + + free(parse_less); + + // close the input file + + fclose(file); + + // populate scale and offset + + populate_scale_and_offset(); + + // populate bounding box + + populate_bounding_box(); + + // mark that header is already populated + + populated_header = TRUE; + + // reopen input file for the second pass + + file = fopen_compressed(file_name, "r", &piped); + if (file == 0) + { + REprintf("ERROR: could not open '%s' for second pass\n", file_name); + return FALSE; + } + + if (setvbuf(file, NULL, _IOFBF, 10 * LAS_TOOLS_IO_IBUFFER_SIZE) != 0) + { + REprintf("WARNING: setvbuf() failed with buffer size %d\n", 10 * LAS_TOOLS_IO_IBUFFER_SIZE); + } + } + + if (parse_string == 0) + { + this->parse_string = LASCopyString("xyz"); + } + else + { + this->parse_string = LASCopyString(parse_string); + } + + // skip lines if we have to + + this->skip_lines = skip_lines; + if (skip_lines) + { + for (i = 0; i < skip_lines; i++) if (fgets(line, 512, file) == NULL) {} + } + else if (ipts) + { + if (fgets(line, 512, file)) + { + if (!populated_header) + { + // temporarily comment this portion that is not useful in rlas. See #62 + /*#ifdef _WIN32 + if (sscanf(line, "%" PRId64 "", &npoints) != 1) #else - if (sscanf(line, "%" PRId64 "", &npoints) != 1) + if (sscanf(line, "%" PRId64 "", &npoints) != 1) #endif*/ - { - REprintf( "ERROR: parsing number of points for '-itps'\n"); - return FALSE; - } - } - if (!populated_header) - { - if (npoints > U32_MAX) - { - header.version_minor = 4; - header.header_size = 375; - header.offset_to_point_data = 375; - header.number_of_point_records = 0; - header.number_of_points_by_return[0] = 0; - header.number_of_points_by_return[1] = 0; - header.number_of_points_by_return[2] = 0; - header.number_of_points_by_return[3] = 0; - header.number_of_points_by_return[4] = 0; - header.extended_number_of_point_records = npoints; - } - else - { - header.version_minor = 2; - header.header_size = 227; - header.offset_to_point_data = 227; - header.number_of_point_records = (U32)npoints; - header.extended_number_of_point_records = 0; - } - } - } - else - { - REprintf( "ERROR: reading PTS header for '-itps'\n"); - return FALSE; - } - - // add payload that informs about PTS - - U8* payload = new U8[32]; - memset(payload, 0, 32); - ((F32*)payload)[0] = translate_intensity; - ((F32*)payload)[1] = scale_intensity; - strcpy((char*)(payload + 16), (parse_string ? parse_string : "xyz")); - header.add_vlr("LAStools", 2000, 32, payload); - } - else if (iptx) - { - I32 ncols; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%d", &ncols) != 1) - { - REprintf( "ERROR: parsing number of cols\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with number of cols\n"); - return FALSE; - } - I32 nrows; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%d", &nrows) != 1) - { - REprintf( "ERROR: parsing number of rows\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with number of rows\n"); - return FALSE; - } - npoints = (I64)ncols*(I64)nrows; - if (!populated_header) - { - if (npoints > U32_MAX) - { - header.version_minor = 4; - header.header_size = 375; - header.offset_to_point_data = 375; - header.number_of_point_records = 0; - header.number_of_points_by_return[0] = 0; - header.number_of_points_by_return[1] = 0; - header.number_of_points_by_return[2] = 0; - header.number_of_points_by_return[3] = 0; - header.number_of_points_by_return[4] = 0; - header.extended_number_of_point_records = npoints; - } - else - { - header.version_minor = 2; - header.header_size = 227; - header.offset_to_point_data = 227; - header.number_of_point_records = (U32)npoints; - header.extended_number_of_point_records = 0; - } - } - F64 translation[3]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf", &(translation[0]), &(translation[1]), &(translation[2])) != 3) - { - REprintf( "ERROR: parsing translation\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with translation\n"); - return FALSE; - } - F64 rotation_row_0[3]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf", &(rotation_row_0[0]), &(rotation_row_0[1]), &(rotation_row_0[2])) != 3) - { - REprintf( "ERROR: parsing rotation row 0\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with rotation row 0\n"); - return FALSE; - } - F64 rotation_row_1[3]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf", &(rotation_row_1[0]), &(rotation_row_1[1]), &(rotation_row_1[2])) != 3) - { - REprintf( "ERROR: parsing rotation row 1\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with rotation row 1\n"); - return FALSE; - } - F64 rotation_row_2[3]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf", &(rotation_row_2[0]), &(rotation_row_2[1]), &(rotation_row_2[2])) != 3) - { - REprintf( "ERROR: parsing rotation row 2\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with rotation row 2\n"); - return FALSE; - } - F64 transformation_row_0[4]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf %lf", &(transformation_row_0[0]), &(transformation_row_0[1]), &(transformation_row_0[2]), &(transformation_row_0[3])) != 4) - { - REprintf( "ERROR: parsing transformation row 0\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with transformation row 0\n"); - return FALSE; - } - F64 transformation_row_1[4]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf %lf", &(transformation_row_1[0]), &(transformation_row_1[1]), &(transformation_row_1[2]), &(transformation_row_1[3])) != 4) - { - REprintf( "ERROR: parsing transformation row 1\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with transformation row 1\n"); - return FALSE; - } - F64 transformation_row_2[4]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf %lf", &(transformation_row_2[0]), &(transformation_row_2[1]), &(transformation_row_2[2]), &(transformation_row_2[3])) != 4) - { - REprintf( "ERROR: parsing transformation row 2\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with transformation row 2\n"); - return FALSE; - } - F64 transformation_row_3[4]; - if (fgets(line, 512, file)) - { - if (sscanf(line, "%lf %lf %lf %lf", &(transformation_row_3[0]), &(transformation_row_3[1]), &(transformation_row_3[2]), &(transformation_row_3[3])) != 4) - { - REprintf( "ERROR: parsing transformation row 3\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: reading line with transformation row 3\n"); - return FALSE; - } - - // add payload that informs about PTX - - U8* payload = new U8[32+240]; - memset(payload, 0, 32+240); - ((F32*)payload)[0] = translate_intensity; - ((F32*)payload)[1] = scale_intensity; - strcpy((char*)(payload + 16), (parse_string ? parse_string : "xyz")); - ((I64*)payload)[4] = (I64)ncols; - ((I64*)payload)[5] = (I64)nrows; - ((F64*)payload)[6] = translation[0]; - ((F64*)payload)[7] = translation[1]; - ((F64*)payload)[8] = translation[2]; - ((F64*)payload)[ 9] = rotation_row_0[0]; - ((F64*)payload)[10] = rotation_row_0[1]; - ((F64*)payload)[11] = rotation_row_0[2]; - ((F64*)payload)[12] = rotation_row_1[0]; - ((F64*)payload)[13] = rotation_row_1[1]; - ((F64*)payload)[14] = rotation_row_1[2]; - ((F64*)payload)[15] = rotation_row_2[0]; - ((F64*)payload)[16] = rotation_row_2[1]; - ((F64*)payload)[17] = rotation_row_2[2]; - ((F64*)payload)[18] = transformation_row_0[0]; - ((F64*)payload)[19] = transformation_row_0[1]; - ((F64*)payload)[20] = transformation_row_0[2]; - ((F64*)payload)[21] = transformation_row_0[3]; - ((F64*)payload)[22] = transformation_row_1[0]; - ((F64*)payload)[23] = transformation_row_1[1]; - ((F64*)payload)[24] = transformation_row_1[2]; - ((F64*)payload)[25] = transformation_row_1[3]; - ((F64*)payload)[26] = transformation_row_2[0]; - ((F64*)payload)[27] = transformation_row_2[1]; - ((F64*)payload)[28] = transformation_row_2[2]; - ((F64*)payload)[29] = transformation_row_2[3]; - ((F64*)payload)[30] = transformation_row_3[0]; - ((F64*)payload)[31] = transformation_row_3[1]; - ((F64*)payload)[32] = transformation_row_3[2]; - ((F64*)payload)[33] = transformation_row_3[3]; - header.add_vlr("LAStools", 2001, 32+240, payload); - } - else if (!populated_header) - { - if (this->point_type > 5) - { - header.version_minor = 4; - header.header_size = 375; - header.offset_to_point_data = 375; - } - else - { - header.version_minor = 2; - header.header_size = 227; - header.offset_to_point_data = 227; - } - } - - // maybe attributes in extra bytes - - if (header.number_attributes) - { - header.update_extra_bytes_vlr(); - } - - // read the first line with full parse_string - - i = 0; - while (fgets(line, 512, file)) - { - if (parse(this->parse_string)) - { - // mark that we found the first point - i = 1; - break; - } - else - { - line[strlen(line)-1] = '\0'; - REprintf( "WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, this->parse_string); - } - } - - // did we manage to parse a line - - if (i != 1) - { - REprintf( "ERROR: could not parse any lines with '%s'\n", this->parse_string); - fclose(this->file); - this->file = 0; - free(this->parse_string); - this->parse_string = 0; - return FALSE; - } - - if (!populated_header) - { - // init the bounding box that we will incrementally compute - - header.min_x = header.max_x = point.coordinates[0]; - header.min_y = header.max_y = point.coordinates[1]; - header.min_z = header.max_z = point.coordinates[2]; - - // init the min and max of attributes in extra bytes - - if (number_attributes) - { - for (i = 0; i < number_attributes; i++) - { - header.attributes[i].set_min(point.extra_bytes + attribute_starts[i]); - header.attributes[i].set_max(point.extra_bytes + attribute_starts[i]); - } - } - - // set scale and offset - - populate_scale_and_offset(); - } - - p_count = 0; - - return TRUE; + { + REprintf("ERROR: parsing number of points for '-itps'\n"); + return FALSE; + } + } + if (!populated_header) + { + if (npoints > U32_MAX) + { + header.version_minor = 4; + header.header_size = 375; + header.offset_to_point_data = 375; + header.number_of_point_records = 0; + header.number_of_points_by_return[0] = 0; + header.number_of_points_by_return[1] = 0; + header.number_of_points_by_return[2] = 0; + header.number_of_points_by_return[3] = 0; + header.number_of_points_by_return[4] = 0; + header.extended_number_of_point_records = npoints; + } + else + { + header.version_minor = 2; + header.header_size = 227; + header.offset_to_point_data = 227; + header.number_of_point_records = (U32)npoints; + header.extended_number_of_point_records = 0; + } + } + } + else + { + REprintf("ERROR: reading PTS header for '-itps'\n"); + return FALSE; + } + + // add payload that informs about PTS + + U8* payload = new U8[32]; + memset(payload, 0, 32); + ((F32*)payload)[0] = translate_intensity; + ((F32*)payload)[1] = scale_intensity; + strcpy((char*)(payload + 16), (parse_string ? parse_string : "xyz")); + header.add_vlr("LAStools", 2000, 32, payload); + } + else if (iptx || iptx_transform) + { + I32 ncols; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%d", &ncols) != 1) + { + REprintf("ERROR: parsing number of cols\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with number of cols\n"); + return FALSE; + } + I32 nrows; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%d", &nrows) != 1) + { + REprintf("ERROR: parsing number of rows\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with number of rows\n"); + return FALSE; + } + npoints = (I64)ncols*(I64)nrows; + if (!populated_header) + { + if (npoints > U32_MAX) + { + header.version_minor = 4; + header.header_size = 375; + header.offset_to_point_data = 375; + header.number_of_point_records = 0; + header.number_of_points_by_return[0] = 0; + header.number_of_points_by_return[1] = 0; + header.number_of_points_by_return[2] = 0; + header.number_of_points_by_return[3] = 0; + header.number_of_points_by_return[4] = 0; + header.extended_number_of_point_records = npoints; + } + else + { + header.version_minor = 2; + header.header_size = 227; + header.offset_to_point_data = 227; + header.number_of_point_records = (U32)npoints; + header.extended_number_of_point_records = 0; + } + } + F64 ptx_scan_pos[3]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf", &(ptx_scan_pos[0]), &(ptx_scan_pos[1]), &(ptx_scan_pos[2])) != 3) + { + REprintf("ERROR: parsing ptx_scan_pos\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with ptx_scan_pos\n"); + return FALSE; + } + F64 ptx_scan_axis_x[3]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf", &(ptx_scan_axis_x[0]), &(ptx_scan_axis_x[1]), &(ptx_scan_axis_x[2])) != 3) + { + REprintf("ERROR: parsing rotation row 0\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with rotation row 0\n"); + return FALSE; + } + F64 ptx_scan_axis_y[3]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf", &(ptx_scan_axis_y[0]), &(ptx_scan_axis_y[1]), &(ptx_scan_axis_y[2])) != 3) + { + REprintf("ERROR: parsing rotation row 1\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with rotation row 1\n"); + return FALSE; + } + F64 ptx_scan_axis_z[3]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf", &(ptx_scan_axis_z[0]), &(ptx_scan_axis_z[1]), &(ptx_scan_axis_z[2])) != 3) + { + REprintf("ERROR: parsing rotation row 2\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with rotation row 2\n"); + return FALSE; + } + F64 ptx_matrix_row_0[4]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf %lf", &(ptx_matrix_row_0[0]), &(ptx_matrix_row_0[1]), &(ptx_matrix_row_0[2]), &(ptx_matrix_row_0[3])) != 4) + { + REprintf("ERROR: parsing transformation row 0\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with transformation row 0\n"); + return FALSE; + } + F64 ptx_matrix_row_1[4]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf %lf", &(ptx_matrix_row_1[0]), &(ptx_matrix_row_1[1]), &(ptx_matrix_row_1[2]), &(ptx_matrix_row_1[3])) != 4) + { + REprintf("ERROR: parsing transformation row 1\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with transformation row 1\n"); + return FALSE; + } + F64 ptx_matrix_row_2[4]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf %lf", &(ptx_matrix_row_2[0]), &(ptx_matrix_row_2[1]), &(ptx_matrix_row_2[2]), &(ptx_matrix_row_2[3])) != 4) + { + REprintf("ERROR: parsing transformation row 2\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with transformation row 2\n"); + return FALSE; + } + F64 ptx_matrix_row_3[4]; + if (fgets(line, 512, file)) + { + if (sscanf(line, "%lf %lf %lf %lf", &(ptx_matrix_row_3[0]), &(ptx_matrix_row_3[1]), &(ptx_matrix_row_3[2]), &(ptx_matrix_row_3[3])) != 4) + { + REprintf("ERROR: parsing transformation row 3\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: reading line with transformation row 3\n"); + return FALSE; + } + + if (iptx) { + // add payload that informs about PTX + U8* payload = new U8[32 + 240]; + memset(payload, 0, 32 + 240); + ((F32*)payload)[0] = translate_intensity; + ((F32*)payload)[1] = scale_intensity; + strcpy((char*)(payload + 16), (parse_string ? parse_string : "xyz")); + ((I64*)payload)[4] = (I64)ncols; + ((I64*)payload)[5] = (I64)nrows; + ((F64*)payload)[6] = ptx_scan_pos[0]; + ((F64*)payload)[7] = ptx_scan_pos[1]; + ((F64*)payload)[8] = ptx_scan_pos[2]; + ((F64*)payload)[9] = ptx_scan_axis_x[0]; + ((F64*)payload)[10] = ptx_scan_axis_x[1]; + ((F64*)payload)[11] = ptx_scan_axis_x[2]; + ((F64*)payload)[12] = ptx_scan_axis_y[0]; + ((F64*)payload)[13] = ptx_scan_axis_y[1]; + ((F64*)payload)[14] = ptx_scan_axis_y[2]; + ((F64*)payload)[15] = ptx_scan_axis_z[0]; + ((F64*)payload)[16] = ptx_scan_axis_z[1]; + ((F64*)payload)[17] = ptx_scan_axis_z[2]; + ((F64*)payload)[18] = ptx_matrix_row_0[0]; + ((F64*)payload)[19] = ptx_matrix_row_0[1]; + ((F64*)payload)[20] = ptx_matrix_row_0[2]; + ((F64*)payload)[21] = ptx_matrix_row_0[3]; + ((F64*)payload)[22] = ptx_matrix_row_1[0]; + ((F64*)payload)[23] = ptx_matrix_row_1[1]; + ((F64*)payload)[24] = ptx_matrix_row_1[2]; + ((F64*)payload)[25] = ptx_matrix_row_1[3]; + ((F64*)payload)[26] = ptx_matrix_row_2[0]; + ((F64*)payload)[27] = ptx_matrix_row_2[1]; + ((F64*)payload)[28] = ptx_matrix_row_2[2]; + ((F64*)payload)[29] = ptx_matrix_row_2[3]; + ((F64*)payload)[30] = ptx_matrix_row_3[0]; + ((F64*)payload)[31] = ptx_matrix_row_3[1]; + ((F64*)payload)[32] = ptx_matrix_row_3[2]; + ((F64*)payload)[33] = ptx_matrix_row_3[3]; + header.add_vlr("LAStools", 2001, 32 + 240, payload); + } + if (iptx_transform) + { + transform_matrix.r11 = ptx_matrix_row_0[0]; + transform_matrix.r12 = ptx_matrix_row_1[0]; + transform_matrix.r13 = ptx_matrix_row_2[0]; + transform_matrix.r21 = ptx_matrix_row_0[1]; + transform_matrix.r22 = ptx_matrix_row_1[1]; + transform_matrix.r23 = ptx_matrix_row_2[1]; + transform_matrix.r31 = ptx_matrix_row_0[2]; + transform_matrix.r32 = ptx_matrix_row_1[2]; + transform_matrix.r33 = ptx_matrix_row_2[2]; + transform_matrix.tr1 = ptx_matrix_row_3[0]; + transform_matrix.tr2 = ptx_matrix_row_3[1]; + transform_matrix.tr3 = ptx_matrix_row_3[2]; + } + } + else if (!populated_header) + { + if (this->point_type > 5) + { + header.version_minor = 4; + header.header_size = 375; + header.offset_to_point_data = 375; + } + else + { + header.version_minor = 2; + header.header_size = 227; + header.offset_to_point_data = 227; + } + } + + // maybe attributes in extra bytes + + if (header.number_attributes) + { + header.update_extra_bytes_vlr(); + } + + // read the first line with full parse_string + + i = 0; + while (fgets(line, 512, file)) + { + if (parse(this->parse_string)) + { + // mark that we found the first point + i = 1; + break; + } + else + { + line[strlen(line) - 1] = '\0'; + REprintf("WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, this->parse_string); + } + } + + // did we manage to parse a line + + if (i != 1) + { + REprintf("ERROR: could not parse any lines with '%s'\n", this->parse_string); + fclose(this->file); + this->file = 0; + free(this->parse_string); + this->parse_string = 0; + return FALSE; + } + + if (!populated_header) + { + // init the bounding box that we will incrementally compute + + header.min_x = header.max_x = point.coordinates[0]; + header.min_y = header.max_y = point.coordinates[1]; + header.min_z = header.max_z = point.coordinates[2]; + + // init the min and max of attributes in extra bytes + + if (number_attributes) + { + for (i = 0; i < number_attributes; i++) + { + header.attributes[i].set_min(point.extra_bytes + attribute_starts[i]); + header.attributes[i].set_max(point.extra_bytes + attribute_starts[i]); + } + } + + // set scale and offset + + populate_scale_and_offset(); + } + + p_count = 0; + + return TRUE; } void LASreaderTXT::set_pts(BOOL pts) { - translate_intensity = 2048.0f; - scale_intensity = 1.0f; - this->ipts = pts; + translate_intensity = 2048.0f; + scale_intensity = 1.0f; + this->ipts = pts; } void LASreaderTXT::set_ptx(BOOL ptx) { - translate_intensity = 0.0f; - scale_intensity = 4095.0f; - this->iptx = ptx; + translate_intensity = 0.0f; + scale_intensity = 4095.0f; + this->iptx = ptx; +} + +void LASreaderTXT::set_ptx_transform(BOOL ptx_transform) +{ + translate_intensity = 0.0f; + scale_intensity = 4095.0f; + this->iptx_transform = ptx_transform; } void LASreaderTXT::set_translate_intensity(F32 translate_intensity) { - this->translate_intensity = translate_intensity; + this->translate_intensity = translate_intensity; } void LASreaderTXT::set_scale_intensity(F32 scale_intensity) { - this->scale_intensity = scale_intensity; + this->scale_intensity = scale_intensity; } void LASreaderTXT::set_translate_scan_angle(F32 translate_scan_angle) { - this->translate_scan_angle = translate_scan_angle; + this->translate_scan_angle = translate_scan_angle; } void LASreaderTXT::set_scale_scan_angle(F32 scale_scan_angle) { - this->scale_scan_angle = scale_scan_angle; + this->scale_scan_angle = scale_scan_angle; } void LASreaderTXT::set_scale_factor(const F64* scale_factor) { - if (scale_factor) - { - if (this->scale_factor == 0) this->scale_factor = new F64[3]; - this->scale_factor[0] = scale_factor[0]; - this->scale_factor[1] = scale_factor[1]; - this->scale_factor[2] = scale_factor[2]; - } - else if (this->scale_factor) - { - delete [] this->scale_factor; - this->scale_factor = 0; - } + if (scale_factor) + { + if (this->scale_factor == 0) this->scale_factor = new F64[3]; + this->scale_factor[0] = scale_factor[0]; + this->scale_factor[1] = scale_factor[1]; + this->scale_factor[2] = scale_factor[2]; + } + else if (this->scale_factor) + { + delete[] this->scale_factor; + this->scale_factor = 0; + } } void LASreaderTXT::set_offset(const F64* offset) { - if (offset) - { - if (this->offset == 0) this->offset = new F64[3]; - this->offset[0] = offset[0]; - this->offset[1] = offset[1]; - this->offset[2] = offset[2]; - } - else if (this->offset) - { - delete [] this->offset; - this->offset = 0; - } + if (offset) + { + if (this->offset == 0) this->offset = new F64[3]; + this->offset[0] = offset[0]; + this->offset[1] = offset[1]; + this->offset[2] = offset[2]; + } + else if (this->offset) + { + delete[] this->offset; + this->offset = 0; + } } void LASreaderTXT::add_attribute(I32 data_type, const char* name, const char* description, F64 scale, F64 offset, F64 pre_scale, F64 pre_offset, F64 no_data) { - attributes_data_types[number_attributes] = data_type; - if (name) - { - attribute_names[number_attributes] = LASCopyString(name); - } - else - { - char temp[32]; - snprintf(temp, 32, "attribute %d", number_attributes); - attribute_names[number_attributes] = LASCopyString(temp); - } - if (description) - { - attribute_descriptions[number_attributes] = LASCopyString(description); - } - else - { - attribute_descriptions[number_attributes] = 0; - } - attribute_scales[number_attributes] = scale; - attribute_offsets[number_attributes] = offset; - attribute_pre_scales[number_attributes] = pre_scale; - attribute_pre_offsets[number_attributes] = pre_offset; - attribute_no_datas[number_attributes] = no_data; - number_attributes++; + attributes_data_types[number_attributes] = data_type; + if (name) + { + attribute_names[number_attributes] = LASCopyString(name); + } + else + { + char temp[32]; + snprintf(temp, 32, "attribute %d", number_attributes); + attribute_names[number_attributes] = LASCopyString(temp); + } + if (description) + { + attribute_descriptions[number_attributes] = LASCopyString(description); + } + else + { + attribute_descriptions[number_attributes] = 0; + } + attribute_scales[number_attributes] = scale; + attribute_offsets[number_attributes] = offset; + attribute_pre_scales[number_attributes] = pre_scale; + attribute_pre_offsets[number_attributes] = pre_offset; + attribute_no_datas[number_attributes] = no_data; + number_attributes++; } BOOL LASreaderTXT::seek(const I64 p_index) { - U32 delta = 0; - if (p_index > p_count) - { - delta = (U32)(p_index - p_count); - } - else if (p_index < p_count) - { - if (piped) return FALSE; - fseek(file, 0, SEEK_SET); - // skip lines if we have to - int i; - for (i = 0; i < skip_lines; i++) if (fgets(line, 512, file) == NULL) {} - // read the first line with full parse_string - i = 0; - while (fgets(line, 512, file)) - { - if (parse(this->parse_string)) - { - // mark that we found the first point - i = 1; - break; - } - else - { - line[strlen(line)-1] = '\0'; - REprintf( "WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, this->parse_string); - } - } - // did we manage to parse a line - if (i != 1) - { - REprintf( "ERROR: could not parse any lines with '%s'\n", this->parse_string); - fclose(file); - file = 0; - free(this->parse_string); - this->parse_string = 0; - return FALSE; - } - delta = (U32)p_index; - } - while (delta) - { - read_point_default(); - delta--; - } - p_count = p_index; - return TRUE; + U32 delta = 0; + if (p_index > p_count) + { + delta = (U32)(p_index - p_count); + } + else if (p_index < p_count) + { + if (piped) return FALSE; + fseek(file, 0, SEEK_SET); + // skip lines if we have to + int i; + for (i = 0; i < skip_lines; i++) if (fgets(line, 512, file) == NULL) {} + // read the first line with full parse_string + i = 0; + while (fgets(line, 512, file)) + { + if (parse(this->parse_string)) + { + // mark that we found the first point + i = 1; + break; + } + else + { + line[strlen(line) - 1] = '\0'; + REprintf("WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, this->parse_string); + } + } + // did we manage to parse a line + if (i != 1) + { + REprintf("ERROR: could not parse any lines with '%s'\n", this->parse_string); + fclose(file); + file = 0; + free(this->parse_string); + this->parse_string = 0; + return FALSE; + } + delta = (U32)p_index; + } + while (delta) + { + read_point_default(); + delta--; + } + p_count = p_index; + return TRUE; } BOOL LASreaderTXT::read_point_default() { - if (p_count) - { - while (true) - { - if (fgets(line, 512, file)) - { - if (parse(parse_string)) - { - break; - } - else - { - line[strlen(line)-1] = '\0'; - REprintf( "WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, this->parse_string); - } - } - else - { - if (populated_header) - { - if (p_count != npoints) - { + if (p_count) + { + while (true) + { + if (fgets(line, 512, file)) + { + if (parse(parse_string)) + { + break; + } + else + { + line[strlen(line) - 1] = '\0'; + REprintf("WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, this->parse_string); + } + } + else + { + if (populated_header) + { + if (p_count != npoints) + { #ifdef _WIN32 - REprintf("WARNING: end-of-file after %" PRId64 " of %" PRId64 " points\n", p_count, npoints); + REprintf("WARNING: end-of-file after %" PRId64 " of %" PRId64 " points\n", p_count, npoints); #else - REprintf("WARNING: end-of-file after %" PRId64 " of %" PRId64 " points\n", p_count, npoints); + REprintf("WARNING: end-of-file after %" PRId64 " of %" PRId64 " points\n", p_count, npoints); #endif - } - } - else - { - if (npoints) - { - if (p_count != npoints) - { + } + } + else + { + if (npoints) + { + if (p_count != npoints) + { #ifdef _WIN32 - REprintf("WARNING: end-of-file after %" PRId64 " of %" PRId64 " points\n", p_count, npoints); + REprintf("WARNING: end-of-file after %" PRId64 " of %" PRId64 " points\n", p_count, npoints); #else - REprintf("WARNING: end-of-file after %" PRId64 " of %" PRId64 " points\n", p_count, npoints); + REprintf("WARNING: end-of-file after %" PRId64 " of %" PRId64 " points\n", p_count, npoints); #endif - } - } - npoints = p_count; - populate_bounding_box(); - } - return FALSE; - } - } - } - // compute the quantized x, y, and z values - point.set_X((I32)header.get_X(point.coordinates[0])); - point.set_Y((I32)header.get_Y(point.coordinates[1])); - point.set_Z((I32)header.get_Z(point.coordinates[2])); - p_count++; - if (!populated_header) - { - // update number of point records - // create return histogram - if (point.extended_point_type) - { - if (point.extended_return_number >= 1 && point.extended_return_number <= 15) header.extended_number_of_points_by_return[point.extended_return_number-1]++; - } - else if (header.version_minor == 4) - { - if (point.return_number >= 1 && point.return_number <= 7) header.extended_number_of_points_by_return[point.return_number-1]++; - } - else - { - if (point.return_number >= 1 && point.return_number <= 5) header.number_of_points_by_return[point.return_number-1]++; - } - // update bounding box - if (point.coordinates[0] < header.min_x) header.min_x = point.coordinates[0]; - else if (point.coordinates[0] > header.max_x) header.max_x = point.coordinates[0]; - if (point.coordinates[1] < header.min_y) header.min_y = point.coordinates[1]; - else if (point.coordinates[1] > header.max_y) header.max_y = point.coordinates[1]; - if (point.coordinates[2] < header.min_z) header.min_z = point.coordinates[2]; - else if (point.coordinates[2] > header.max_z) header.max_z = point.coordinates[2]; - // update the min and max of attributes in extra bytes - if (number_attributes) - { - for (I32 i = 0; i < number_attributes; i++) - { - header.attributes[i].update_min(point.extra_bytes + attribute_starts[i]); - header.attributes[i].update_max(point.extra_bytes + attribute_starts[i]); - } - } - } - return TRUE; + } + } + npoints = p_count; + populate_bounding_box(); + } + return FALSE; + } + } + } + // compute the quantized x, y, and z values + point.set_X((I32)header.get_X(point.coordinates[0])); + point.set_Y((I32)header.get_Y(point.coordinates[1])); + point.set_Z((I32)header.get_Z(point.coordinates[2])); + p_count++; + if (!populated_header) + { + // update number of point records + // create return histogram + if (point.extended_point_type) + { + if (point.extended_return_number >= 1 && point.extended_return_number <= 15) header.extended_number_of_points_by_return[point.extended_return_number - 1]++; + } + else if (header.version_minor == 4) + { + if (point.return_number >= 1 && point.return_number <= 7) header.extended_number_of_points_by_return[point.return_number - 1]++; + } + else + { + if (point.return_number >= 1 && point.return_number <= 5) header.number_of_points_by_return[point.return_number - 1]++; + } + // update bounding box + if (point.coordinates[0] < header.min_x) header.min_x = point.coordinates[0]; + else if (point.coordinates[0] > header.max_x) header.max_x = point.coordinates[0]; + if (point.coordinates[1] < header.min_y) header.min_y = point.coordinates[1]; + else if (point.coordinates[1] > header.max_y) header.max_y = point.coordinates[1]; + if (point.coordinates[2] < header.min_z) header.min_z = point.coordinates[2]; + else if (point.coordinates[2] > header.max_z) header.max_z = point.coordinates[2]; + // update the min and max of attributes in extra bytes + if (number_attributes) + { + for (I32 i = 0; i < number_attributes; i++) + { + header.attributes[i].update_min(point.extra_bytes + attribute_starts[i]); + header.attributes[i].update_max(point.extra_bytes + attribute_starts[i]); + } + } + } + return TRUE; } ByteStreamIn* LASreaderTXT::get_stream() const { - return 0; + return 0; } void LASreaderTXT::close(BOOL close_stream) { - if (file) - { - if (piped) while(fgets(line, 512, file)); - fclose(file); - file = 0; - } + if (file) + { + if (piped) while (fgets(line, 512, file)); + fclose(file); + file = 0; + } } BOOL LASreaderTXT::reopen(const char* file_name) { - int i; - - if (file_name == 0) - { - REprintf("ERROR: file name pointer is zero\n"); - return FALSE; - } - - file = fopen_compressed(file_name, "r", &piped); - if (file == 0) - { - REprintf( "ERROR: cannot reopen file '%s'\n", file_name); - return FALSE; - } - - if (setvbuf(file, NULL, _IOFBF, 10*LAS_TOOLS_IO_IBUFFER_SIZE) != 0) - { - REprintf( "WARNING: setvbuf() failed with buffer size %d\n", 10*LAS_TOOLS_IO_IBUFFER_SIZE); - } - - // skip lines if we have to - - for (i = 0; i < skip_lines; i++) if (fgets(line, 512, file) == NULL) {} - - // read the first line with full parse_string - - i = 0; - while (fgets(line, 512, file)) - { - if (parse(parse_string)) - { - // mark that we found the first point - i = 1; - break; - } - else - { - line[strlen(line)-1] = '\0'; - REprintf( "WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, parse_string); - } - } - - // did we manage to parse a line - - if (i != 1) - { - REprintf( "ERROR: could not parse any lines with '%s'\n", parse_string); - fclose(file); - file = 0; - return FALSE; - } - - p_count = 0; - - return TRUE; + int i; + + if (file_name == 0) + { + REprintf("ERROR: file name pointer is zero\n"); + return FALSE; + } + + file = fopen_compressed(file_name, "r", &piped); + if (file == 0) + { + REprintf("ERROR: cannot reopen file '%s'\n", file_name); + return FALSE; + } + + if (setvbuf(file, NULL, _IOFBF, 10 * LAS_TOOLS_IO_IBUFFER_SIZE) != 0) + { + REprintf("WARNING: setvbuf() failed with buffer size %d\n", 10 * LAS_TOOLS_IO_IBUFFER_SIZE); + } + + // skip lines if we have to + + for (i = 0; i < skip_lines; i++) if (fgets(line, 512, file) == NULL) {} + + // read the first line with full parse_string + + i = 0; + while (fgets(line, 512, file)) + { + if (parse(parse_string)) + { + // mark that we found the first point + i = 1; + break; + } + else + { + line[strlen(line) - 1] = '\0'; + REprintf("WARNING: cannot parse '%s' with '%s'. skipping ...\n", line, parse_string); + } + } + + // did we manage to parse a line + + if (i != 1) + { + REprintf("ERROR: could not parse any lines with '%s'\n", parse_string); + fclose(file); + file = 0; + return FALSE; + } + + p_count = 0; + + return TRUE; } void LASreaderTXT::clean() { - if (file) - { - fclose(file); - file = 0; - } - if (parse_string) - { - free(parse_string); - parse_string = 0; - } - skip_lines = 0; - populated_header = FALSE; + if (file) + { + fclose(file); + file = 0; + } + if (parse_string) + { + free(parse_string); + parse_string = 0; + } + skip_lines = 0; + populated_header = FALSE; } LASreaderTXT::LASreaderTXT() { - file = 0; - piped = false; - point_type = 0; - parse_string = 0; - scale_factor = 0; - offset = 0; - ipts = FALSE; - iptx = FALSE; - translate_intensity = 0.0f; - scale_intensity = 1.0f; - translate_scan_angle = 0.0f; - scale_scan_angle = 1.0f; - number_attributes = 0; - clean(); + file = 0; + piped = false; + point_type = 0; + parse_string = 0; + scale_factor = 0; + offset = 0; + ipts = FALSE; + iptx = FALSE; + iptx_transform = FALSE; + translate_intensity = 0.0f; + scale_intensity = 1.0f; + translate_scan_angle = 0.0f; + scale_scan_angle = 1.0f; + number_attributes = 0; + clean(); } LASreaderTXT::~LASreaderTXT() { - clean(); - if (scale_factor) - { - delete [] scale_factor; - scale_factor = 0; - } - if (offset) - { - delete [] offset; - offset = 0; - } + clean(); + if (scale_factor) + { + delete[] scale_factor; + scale_factor = 0; + } + if (offset) + { + delete[] offset; + offset = 0; + } } BOOL LASreaderTXT::parse_attribute(const char* l, I32 index) { - if (index >= header.number_attributes) - { - return FALSE; - } - F64 temp_d; - if (sscanf(l, "%lf", &temp_d) != 1) return FALSE; - if (attribute_pre_scales[index] != 1.0) - { - temp_d *= attribute_pre_scales[index]; - } - if (attribute_pre_offsets[index] != 0.0) - { - temp_d -= attribute_pre_offsets[index]; - } - if (header.attributes[index].data_type == 1) - { - I32 temp_i; - if (header.attributes[index].has_offset()) - { - temp_d -= header.attributes[index].offset[0]; - } - if (header.attributes[index].has_scale()) - { - temp_i = I32_QUANTIZE(temp_d/header.attributes[index].scale[0]); - } - else - { - temp_i = I32_QUANTIZE(temp_d); - } - if (temp_i < U8_MIN || temp_i > U8_MAX) - { - REprintf( "WARNING: attribute %d of type U8 is %d. clamped to [%d %d] range.\n", index, temp_i, U8_MIN, U8_MAX); - point.set_attribute(attribute_starts[index], U8_CLAMP(temp_i)); - } - else - { - point.set_attribute(attribute_starts[index], (U8)temp_i); - } - } - else if (header.attributes[index].data_type == 2) - { - I32 temp_i; - if (header.attributes[index].has_offset()) - { - temp_d -= header.attributes[index].offset[0]; - } - if (header.attributes[index].has_scale()) - { - temp_i = I32_QUANTIZE(temp_d/header.attributes[index].scale[0]); - } - else - { - temp_i = I32_QUANTIZE(temp_d); - } - if (temp_i < I8_MIN || temp_i > I8_MAX) - { - REprintf( "WARNING: attribute %d of type I8 is %d. clamped to [%d %d] range.\n", index, temp_i, I8_MIN, I8_MAX); - point.set_attribute(attribute_starts[index], I8_CLAMP(temp_i)); - } - else - { - point.set_attribute(attribute_starts[index], (I8)temp_i); - } - } - else if (header.attributes[index].data_type == 3) - { - I32 temp_i; - if (header.attributes[index].has_offset()) - { - temp_d -= header.attributes[index].offset[0]; - } - if (header.attributes[index].has_scale()) - { - temp_i = I32_QUANTIZE(temp_d/header.attributes[index].scale[0]); - } - else - { - temp_i = I32_QUANTIZE(temp_d); - } - if (temp_i < U16_MIN || temp_i > U16_MAX) - { - REprintf( "WARNING: attribute %d of type U16 is %d. clamped to [%d %d] range.\n", index, temp_i, U16_MIN, U16_MAX); - point.set_attribute(attribute_starts[index], U16_CLAMP(temp_i)); - } - else - { - point.set_attribute(attribute_starts[index], (U16)temp_i); - } - } - else if (header.attributes[index].data_type == 4) - { - I32 temp_i; - if (header.attributes[index].has_offset()) - { - temp_d -= header.attributes[index].offset[0]; - } - if (header.attributes[index].has_scale()) - { - temp_i = I32_QUANTIZE(temp_d/header.attributes[index].scale[0]); - } - else - { - temp_i = I32_QUANTIZE(temp_d); - } - if (temp_i < I16_MIN || temp_i > I16_MAX) - { - REprintf( "WARNING: attribute %d of type I16 is %d. clamped to [%d %d] range.\n", index, temp_i, I16_MIN, I16_MAX); - point.set_attribute(attribute_starts[index], I16_CLAMP(temp_i)); - } - else - { - point.set_attribute(attribute_starts[index], (I16)temp_i); - } - } - else if (header.attributes[index].data_type == 5) - { - U32 temp_u; - if (header.attributes[index].has_offset()) - { - temp_d -= header.attributes[index].offset[0]; - } - if (header.attributes[index].has_scale()) - { - temp_u = U32_QUANTIZE(temp_d/header.attributes[index].scale[0]); - } - else - { - temp_u = U32_QUANTIZE(temp_d); - } - point.set_attribute(attribute_starts[index], temp_u); - } - else if (header.attributes[index].data_type == 6) - { - I32 temp_i; - if (header.attributes[index].has_offset()) - { - temp_d -= header.attributes[index].offset[0]; - } - if (header.attributes[index].has_scale()) - { - temp_i = I32_QUANTIZE(temp_d/header.attributes[index].scale[0]); - } - else - { - temp_i = I32_QUANTIZE(temp_d); - } - point.set_attribute(attribute_starts[index], temp_i); - } - else if (header.attributes[index].data_type == 9) - { - F32 temp_f = (F32)temp_d; - point.set_attribute(attribute_starts[index], temp_f); - } - else if (header.attributes[index].data_type == 10) - { - point.set_attribute(attribute_starts[index], temp_d); - } - else - { - REprintf( "WARNING: attribute %d not (yet) implemented.\n", index); - return FALSE; - } - return TRUE; + if (index >= header.number_attributes) + { + return FALSE; + } + F64 temp_d; + if (sscanf(l, "%lf", &temp_d) != 1) return FALSE; + if (attribute_pre_scales[index] != 1.0) + { + temp_d *= attribute_pre_scales[index]; + } + if (attribute_pre_offsets[index] != 0.0) + { + temp_d -= attribute_pre_offsets[index]; + } + if (header.attributes[index].data_type == 1) + { + I32 temp_i; + if (header.attributes[index].has_offset()) + { + temp_d -= header.attributes[index].offset[0]; + } + if (header.attributes[index].has_scale()) + { + temp_i = I32_QUANTIZE(temp_d / header.attributes[index].scale[0]); + } + else + { + temp_i = I32_QUANTIZE(temp_d); + } + if (temp_i < U8_MIN || temp_i > U8_MAX) + { + REprintf("WARNING: attribute %d of type U8 is %d. clamped to [%d %d] range.\n", index, temp_i, U8_MIN, U8_MAX); + point.set_attribute(attribute_starts[index], U8_CLAMP(temp_i)); + } + else + { + point.set_attribute(attribute_starts[index], (U8)temp_i); + } + } + else if (header.attributes[index].data_type == 2) + { + I32 temp_i; + if (header.attributes[index].has_offset()) + { + temp_d -= header.attributes[index].offset[0]; + } + if (header.attributes[index].has_scale()) + { + temp_i = I32_QUANTIZE(temp_d / header.attributes[index].scale[0]); + } + else + { + temp_i = I32_QUANTIZE(temp_d); + } + if (temp_i < I8_MIN || temp_i > I8_MAX) + { + REprintf("WARNING: attribute %d of type I8 is %d. clamped to [%d %d] range.\n", index, temp_i, I8_MIN, I8_MAX); + point.set_attribute(attribute_starts[index], I8_CLAMP(temp_i)); + } + else + { + point.set_attribute(attribute_starts[index], (I8)temp_i); + } + } + else if (header.attributes[index].data_type == 3) + { + I32 temp_i; + if (header.attributes[index].has_offset()) + { + temp_d -= header.attributes[index].offset[0]; + } + if (header.attributes[index].has_scale()) + { + temp_i = I32_QUANTIZE(temp_d / header.attributes[index].scale[0]); + } + else + { + temp_i = I32_QUANTIZE(temp_d); + } + if (temp_i < U16_MIN || temp_i > U16_MAX) + { + REprintf("WARNING: attribute %d of type U16 is %d. clamped to [%d %d] range.\n", index, temp_i, U16_MIN, U16_MAX); + point.set_attribute(attribute_starts[index], U16_CLAMP(temp_i)); + } + else + { + point.set_attribute(attribute_starts[index], (U16)temp_i); + } + } + else if (header.attributes[index].data_type == 4) + { + I32 temp_i; + if (header.attributes[index].has_offset()) + { + temp_d -= header.attributes[index].offset[0]; + } + if (header.attributes[index].has_scale()) + { + temp_i = I32_QUANTIZE(temp_d / header.attributes[index].scale[0]); + } + else + { + temp_i = I32_QUANTIZE(temp_d); + } + if (temp_i < I16_MIN || temp_i > I16_MAX) + { + REprintf("WARNING: attribute %d of type I16 is %d. clamped to [%d %d] range.\n", index, temp_i, I16_MIN, I16_MAX); + point.set_attribute(attribute_starts[index], I16_CLAMP(temp_i)); + } + else + { + point.set_attribute(attribute_starts[index], (I16)temp_i); + } + } + else if (header.attributes[index].data_type == 5) + { + U32 temp_u; + if (header.attributes[index].has_offset()) + { + temp_d -= header.attributes[index].offset[0]; + } + if (header.attributes[index].has_scale()) + { + temp_u = U32_QUANTIZE(temp_d / header.attributes[index].scale[0]); + } + else + { + temp_u = U32_QUANTIZE(temp_d); + } + point.set_attribute(attribute_starts[index], temp_u); + } + else if (header.attributes[index].data_type == 6) + { + I32 temp_i; + if (header.attributes[index].has_offset()) + { + temp_d -= header.attributes[index].offset[0]; + } + if (header.attributes[index].has_scale()) + { + temp_i = I32_QUANTIZE(temp_d / header.attributes[index].scale[0]); + } + else + { + temp_i = I32_QUANTIZE(temp_d); + } + point.set_attribute(attribute_starts[index], temp_i); + } + else if (header.attributes[index].data_type == 9) + { + F32 temp_f = (F32)temp_d; + point.set_attribute(attribute_starts[index], temp_f); + } + else if (header.attributes[index].data_type == 10) + { + point.set_attribute(attribute_starts[index], temp_d); + } + else + { + REprintf("WARNING: attribute %d not (yet) implemented.\n", index); + return FALSE; + } + return TRUE; } BOOL LASreaderTXT::parse(const char* parse_string) { - I32 temp_i; - F32 temp_f; - const char* p = parse_string; - const char* l = line; - - while (p[0]) - { - if (p[0] == 'x') // we expect the x coordinate - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%lf", &(point.coordinates[0])) != 1) return FALSE; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'y') // we expect the y coordinate - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%lf", &(point.coordinates[1])) != 1) return FALSE; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'z') // we expect the x coordinate - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%lf", &(point.coordinates[2])) != 1) return FALSE; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 't') // we expect the gps time - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%lf", &(point.gps_time)) != 1) return FALSE; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'R') // we expect the red channel of the RGB field - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - point.rgb[0] = (short)temp_i; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'G') // we expect the green channel of the RGB field - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - point.rgb[1] = (short)temp_i; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'B') // we expect the blue channel of the RGB field - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - point.rgb[2] = (short)temp_i; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'I') // we expect the NIR channel of LAS 1.4 point type 8 - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - point.rgb[3] = (short)temp_i; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 's') // we expect a string or a number that we don't care about - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'i') // we expect the intensity - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%f", &temp_f) != 1) return FALSE; - if (translate_intensity != 0.0f) temp_f = temp_f+translate_intensity; - if (scale_intensity != 1.0f) temp_f = temp_f*scale_intensity; - if (temp_f < 0.0f || temp_f >= 65535.5f) REprintf( "WARNING: intensity %g is out of range of unsigned short\n", temp_f); - point.set_intensity(U16_QUANTIZE(temp_f)); - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'a') // we expect the scan angle - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%f", &temp_f) != 1) return FALSE; - if (translate_scan_angle != 0.0f) temp_f = temp_f+translate_scan_angle; - if (scale_scan_angle != 1.0f) temp_f = temp_f*scale_scan_angle; - if (temp_f < -128.0f || temp_f > 127.0f) REprintf( "WARNING: scan angle %g is out of range of char\n", temp_f); - point.set_scan_angle(temp_f); - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'n') // we expect the number of returns of given pulse - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (point_type > 5) - { - if (temp_i < 0 || temp_i > 15) REprintf( "WARNING: number of returns of given pulse %d is out of range of four bits\n", temp_i); - point.set_extended_number_of_returns(temp_i & 15); - } - else - { - if (temp_i < 0 || temp_i > 7) REprintf( "WARNING: number of returns of given pulse %d is out of range of three bits\n", temp_i); - point.set_number_of_returns(temp_i & 7); - } - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'r') // we expect the number of the return - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (point_type > 5) - { - if (temp_i < 0 || temp_i > 15) REprintf( "WARNING: return number %d is out of range of four bits\n", temp_i); - point.set_extended_return_number(temp_i & 15); - } - else - { - if (temp_i < 0 || temp_i > 7) REprintf( "WARNING: return number %d is out of range of three bits\n", temp_i); - point.set_return_number(temp_i & 7); - } - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'h') // we expect the witheld flag - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 1) REprintf( "WARNING: withheld flag %d is out of range of single bit\n", temp_i); - point.set_withheld_flag(temp_i ? 1 : 0); - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'k') // we expect the eypoint flag - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 1) REprintf( "WARNING: keypoint flag %d is out of range of single bit\n", temp_i); - point.set_keypoint_flag(temp_i ? 1 : 0); - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'g') // we expect the synthetic fla - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 1) REprintf( "WARNING: keypoint flag %d is out of range of single bit\n", temp_i); - point.set_synthetic_flag(temp_i ? 1 : 0); - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'o') // we expect the verlap flag - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 1) REprintf( "WARNING: overlap flag %d is out of range of single bit\n", temp_i); - point.set_extended_overlap_flag(temp_i ? 1 : 0); - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'l') // we expect the scanner channe - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 3) REprintf( "WARNING: scanner channel %d is out of range of two bits\n", temp_i); - point.extended_scanner_channel = temp_i & 3; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'E') // we expect a terrasolid echo encoding) - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 3) REprintf( "WARNING: terrasolid echo encoding %d is out of range of 0 to 3\n", temp_i); - if (temp_i == 0) // only echo - { - point.number_of_returns = 1; - point.return_number = 1; - } - else if (temp_i == 1) // first (of many) - { - point.number_of_returns = 2; - point.return_number = 1; - } - else if (temp_i == 3) // last (of many) - { - point.number_of_returns = 2; - point.return_number = 2; - } - else // intermediate - { - point.number_of_returns = 3; - point.return_number = 2; - } - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'c') // we expect the classification - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0) - { - REprintf( "WARNING: classification %d is negative. zeroing ...\n", temp_i); - point.set_classification(0); - point.set_extended_classification(0); - } - else if (point.extended_point_type) - { - if (temp_i > 255) - { - REprintf( "WARNING: extended classification %d is larger than 255. clamping ...\n", temp_i); - point.set_extended_classification(255); - } - else - { - point.set_extended_classification((U8)temp_i); - } - } - else - { - if (temp_i > 31) - { - REprintf( "WARNING: classification %d is larger than 31. clamping ...\n", temp_i); - point.set_classification(31); - } - else - { - point.set_classification((U8)temp_i); - } - } - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'u') // we expect the user data - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 255) - { - REprintf( "WARNING: user data %d is out of range of unsigned char\n", temp_i); - point.set_user_data(U8_CLAMP(temp_i)); - } - else - { - point.set_user_data((U8)temp_i); - } - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'p') // we expect the point source ID - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 65535) - { - REprintf( "WARNING: point source ID %d is out of range of unsigned short\n", temp_i); - point.set_point_source_ID(U16_CLAMP(temp_i)); - } - else - { - point.set_point_source_ID((U16)temp_i); - } - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'e') // we expect the edge of flight line flag - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 1) REprintf( "WARNING: edge of flight line flag %d is out of range of boolean flag\n", temp_i); - point.edge_of_flight_line = (temp_i ? 1 : 0); - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'd') // we expect the direction of scan flag - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - if (sscanf(l, "%d", &temp_i) != 1) return FALSE; - if (temp_i < 0 || temp_i > 1) REprintf( "WARNING: direction of scan flag %d is out of range of boolean flag\n", temp_i); - point.scan_direction_flag = (temp_i ? 1 : 0); - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if ((p[0] >= '0') && (p[0] <= '9')) // we expect attribute number 0 to 9 - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - I32 index = (I32)(p[0] - '0'); - if (!parse_attribute(l, index)) return FALSE; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == '(') // we expect attribute number 10 or higher - { - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces - if (l[0] == 0) return FALSE; - p++; - I32 index = 0; - while (p[0] >= '0' && p[0] <= '9') - { - index = 10*index + (I32)(p[0] - '0'); - p++; - } - if (!parse_attribute(l, index)) return FALSE; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'H') // we expect a hexadecimal coded RGB color - { - U32 hex_value; - char hex_string[3] = "__"; - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';' || l[0] == '\"')) l++; // first skip white spaces and quotes - if (l[0] == 0) return FALSE; - hex_string[0] = l[0]; hex_string[1] = l[1]; - sscanf(hex_string,"%x",&hex_value); - point.rgb[0] = hex_value; - hex_string[0] = l[2]; hex_string[1] = l[3]; - sscanf(hex_string,"%x",&hex_value); - point.rgb[1] = hex_value; - hex_string[0] = l[4]; hex_string[1] = l[5]; - sscanf(hex_string,"%x",&hex_value); - point.rgb[2] = hex_value; - l+=6; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else if (p[0] == 'J') // we expect a hexadecimal coded intensity - { - U32 hex_value; - while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';' || l[0] == '\"')) l++; // first skip white spaces and quotes - if (l[0] == 0) return FALSE; - sscanf(l,"%x",&hex_value); - point.intensity = U8_CLAMP(((F64)hex_value/(F64)0xFFFFFF)*255); - l+=6; - while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space - } - else - { - REprintf( "ERROR: unknown symbol '%c' in parse string\n", p[0]); - } - p++; - } - return TRUE; + I32 temp_i; + F32 temp_f; + const char* p = parse_string; + const char* l = line; + + while (p[0]) + { + if (p[0] == 'x') // we expect the x coordinate + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%lf", &(point.coordinates[0])) != 1) return FALSE; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'y') // we expect the y coordinate + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%lf", &(point.coordinates[1])) != 1) return FALSE; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'z') // we expect the x coordinate + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%lf", &(point.coordinates[2])) != 1) return FALSE; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 't') // we expect the gps time + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%lf", &(point.gps_time)) != 1) return FALSE; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'R') // we expect the red channel of the RGB field + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + point.rgb[0] = (short)temp_i; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'G') // we expect the green channel of the RGB field + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + point.rgb[1] = (short)temp_i; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'B') // we expect the blue channel of the RGB field + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + point.rgb[2] = (short)temp_i; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'I') // we expect the NIR channel of LAS 1.4 point type 8 + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + point.rgb[3] = (short)temp_i; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 's') // we expect a string or a number that we don't care about + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'i') // we expect the intensity + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%f", &temp_f) != 1) return FALSE; + if (translate_intensity != 0.0f) temp_f = temp_f + translate_intensity; + if (scale_intensity != 1.0f) temp_f = temp_f * scale_intensity; + if (temp_f < 0.0f || temp_f >= 65535.5f) REprintf("WARNING: intensity %g is out of range of unsigned short\n", temp_f); + point.set_intensity(U16_QUANTIZE(temp_f)); + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'a') // we expect the scan angle + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%f", &temp_f) != 1) return FALSE; + if (translate_scan_angle != 0.0f) temp_f = temp_f + translate_scan_angle; + if (scale_scan_angle != 1.0f) temp_f = temp_f * scale_scan_angle; + if (temp_f < -128.0f || temp_f > 127.0f) REprintf("WARNING: scan angle %g is out of range of char\n", temp_f); + point.set_scan_angle(temp_f); + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'n') // we expect the number of returns of given pulse + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (point_type > 5) + { + if (temp_i < 0 || temp_i > 15) REprintf("WARNING: number of returns of given pulse %d is out of range of four bits\n", temp_i); + point.set_extended_number_of_returns(temp_i & 15); + } + else + { + if (temp_i < 0 || temp_i > 7) REprintf("WARNING: number of returns of given pulse %d is out of range of three bits\n", temp_i); + point.set_number_of_returns(temp_i & 7); + } + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'r') // we expect the number of the return + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (point_type > 5) + { + if (temp_i < 0 || temp_i > 15) REprintf("WARNING: return number %d is out of range of four bits\n", temp_i); + point.set_extended_return_number(temp_i & 15); + } + else + { + if (temp_i < 0 || temp_i > 7) REprintf("WARNING: return number %d is out of range of three bits\n", temp_i); + point.set_return_number(temp_i & 7); + } + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'h') // we expect the witheld flag + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 1) REprintf("WARNING: withheld flag %d is out of range of single bit\n", temp_i); + point.set_withheld_flag(temp_i ? 1 : 0); + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'k') // we expect the eypoint flag + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 1) REprintf("WARNING: keypoint flag %d is out of range of single bit\n", temp_i); + point.set_keypoint_flag(temp_i ? 1 : 0); + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'g') // we expect the synthetic fla + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 1) REprintf("WARNING: keypoint flag %d is out of range of single bit\n", temp_i); + point.set_synthetic_flag(temp_i ? 1 : 0); + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'o') // we expect the verlap flag + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 1) REprintf("WARNING: overlap flag %d is out of range of single bit\n", temp_i); + point.set_extended_overlap_flag(temp_i ? 1 : 0); + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'l') // we expect the scanner channe + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 3) REprintf("WARNING: scanner channel %d is out of range of two bits\n", temp_i); + point.extended_scanner_channel = temp_i & 3; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'E') // we expect a terrasolid echo encoding) + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 3) REprintf("WARNING: terrasolid echo encoding %d is out of range of 0 to 3\n", temp_i); + if (temp_i == 0) // only echo + { + point.number_of_returns = 1; + point.return_number = 1; + } + else if (temp_i == 1) // first (of many) + { + point.number_of_returns = 2; + point.return_number = 1; + } + else if (temp_i == 3) // last (of many) + { + point.number_of_returns = 2; + point.return_number = 2; + } + else // intermediate + { + point.number_of_returns = 3; + point.return_number = 2; + } + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'c') // we expect the classification + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0) + { + REprintf("WARNING: classification %d is negative. zeroing ...\n", temp_i); + point.set_classification(0); + point.set_extended_classification(0); + } + else if (point.extended_point_type) + { + if (temp_i > 255) + { + REprintf("WARNING: extended classification %d is larger than 255. clamping ...\n", temp_i); + point.set_extended_classification(255); + } + else + { + point.set_extended_classification((U8)temp_i); + } + } + else + { + if (temp_i > 31) + { + REprintf("WARNING: classification %d is larger than 31. clamping ...\n", temp_i); + point.set_classification(31); + } + else + { + point.set_classification((U8)temp_i); + } + } + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'u') // we expect the user data + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 255) + { + REprintf("WARNING: user data %d is out of range of unsigned char\n", temp_i); + point.set_user_data(U8_CLAMP(temp_i)); + } + else + { + point.set_user_data((U8)temp_i); + } + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'p') // we expect the point source ID + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 65535) + { + REprintf("WARNING: point source ID %d is out of range of unsigned short\n", temp_i); + point.set_point_source_ID(U16_CLAMP(temp_i)); + } + else + { + point.set_point_source_ID((U16)temp_i); + } + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'e') // we expect the edge of flight line flag + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 1) REprintf("WARNING: edge of flight line flag %d is out of range of boolean flag\n", temp_i); + point.edge_of_flight_line = (temp_i ? 1 : 0); + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'd') // we expect the direction of scan flag + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + if (sscanf(l, "%d", &temp_i) != 1) return FALSE; + if (temp_i < 0 || temp_i > 1) REprintf("WARNING: direction of scan flag %d is out of range of boolean flag\n", temp_i); + point.scan_direction_flag = (temp_i ? 1 : 0); + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if ((p[0] >= '0') && (p[0] <= '9')) // we expect attribute number 0 to 9 + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + I32 index = (I32)(p[0] - '0'); + if (!parse_attribute(l, index)) return FALSE; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == '(') // we expect attribute number 10 or higher + { + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';')) l++; // first skip white spaces + if (l[0] == 0) return FALSE; + p++; + I32 index = 0; + while (p[0] >= '0' && p[0] <= '9') + { + index = 10 * index + (I32)(p[0] - '0'); + p++; + } + if (!parse_attribute(l, index)) return FALSE; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'H') // we expect a hexadecimal coded RGB color + { + I32 hex_value; + char hex_string[3] = "__"; + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';' || l[0] == '\"')) l++; // first skip white spaces and quotes + if (l[0] == 0) return FALSE; + hex_string[0] = l[0]; hex_string[1] = l[1]; + sscanf(hex_string, "%x", &hex_value); + point.rgb[0] = hex_value; + hex_string[0] = l[2]; hex_string[1] = l[3]; + sscanf(hex_string, "%x", &hex_value); + point.rgb[1] = hex_value; + hex_string[0] = l[4]; hex_string[1] = l[5]; + sscanf(hex_string, "%x", &hex_value); + point.rgb[2] = hex_value; + l += 6; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else if (p[0] == 'J') // we expect a hexadecimal coded intensity + { + I32 hex_value; + while (l[0] && (l[0] == ' ' || l[0] == ',' || l[0] == '\t' || l[0] == ';' || l[0] == '\"')) l++; // first skip white spaces and quotes + if (l[0] == 0) return FALSE; + sscanf(l, "%x", &hex_value); + point.intensity = U8_CLAMP(((F64)hex_value / (F64)0xFFFFFF) * 255); + l += 6; + while (l[0] && l[0] != ' ' && l[0] != ',' && l[0] != '\t' && l[0] != ';') l++; // then advance to next white space + } + else + { + REprintf("ERROR: unknown symbol '%c' in parse string\n", p[0]); + } + p++; + } + return TRUE; } BOOL LASreaderTXT::check_parse_string(const char* parse_string) { - const char* p = parse_string; - while (p[0]) - { - if ((p[0] != 'x') && // we expect the x coordinate - (p[0] != 'y') && // we expect the y coordinate - (p[0] != 'z') && // we expect the z coordinate - (p[0] != 't') && // we expect the gps time - (p[0] != 'R') && // we expect the red channel of the RGB field - (p[0] != 'G') && // we expect the green channel of the RGB field - (p[0] != 'B') && // we expect the blue channel of the RGB field - (p[0] != 'I') && // we expect the NIR channel - (p[0] != 's') && // we expect a string or a number that we don't care about - (p[0] != 'i') && // we expect the intensity - (p[0] != 'a') && // we expect the scan angle - (p[0] != 'n') && // we expect the number of returns of given pulse - (p[0] != 'r') && // we expect the number of the return - (p[0] != 'h') && // we expect the witheld flag - (p[0] != 'k') && // we expect the eypoint flag - (p[0] != 'g') && // we expect the synthetic fla - (p[0] != 'o') && // we expect the verlap flag - (p[0] != 'l') && // we expect the scanner channe - (p[0] != 'E') && // we expect terrasolid echo encoding - (p[0] != 'c') && // we expect the classification - (p[0] != 'u') && // we expect the user data - (p[0] != 'p') && // we expect the point source ID - (p[0] != 'e') && // we expect the edge of flight line flag - (p[0] != 'd') && // we expect the direction of scan flag - (p[0] != 'H') && // we expect hexadecimal coded RGB(I) colors - (p[0] != 'J')) // we expect a hexadecimal coded intensity - { - if ((p[0] >= '0') && (p[0] <= '9')) - { - I32 index = (I32)(p[0] - '0'); - if (index >= header.number_attributes) - { - REprintf( "ERROR: extra bytes attribute '%d' was not described.\n", index); - return FALSE; - } - attribute_starts[index] = header.get_attribute_start(index); - } - else if (p[0] == '(') - { - p++; - if ((p[0] >= '0') && (p[0] <= '9')) - { - I32 index = 0; - while ((p[0] >= '0') && (p[0] <= '9')) - { - index = 10*index + (I32)(p[0] - '0'); - p++; - } - if (index >= header.number_attributes) - { - REprintf( "ERROR: extra bytes attribute '%d' was not described.\n", index); - return FALSE; - } - if (p[0] != ')') - { - REprintf( "ERROR: extra bytes attribute '%d' misses closing bracket.\n", index); - return FALSE; - } - attribute_starts[index] = header.get_attribute_start(index); - } - else - { - REprintf( "ERROR: parse string opening bracket '(' misses extra bytes index.\n"); - return FALSE; - } - } - else - { - REprintf( "ERROR: unknown symbol '%c' in parse string. valid are\n", p[0]); - REprintf( " 'x' : the coordinate\n"); - REprintf( " 'y' : the coordinate\n"); - REprintf( " 'z' : the coordinate\n"); - REprintf( " 't' : the gps ime\n"); - REprintf( " 'R' : the ed channel of the RGB field\n"); - REprintf( " 'G' : the reen channel of the RGB field\n"); - REprintf( " 'B' : the lue channel of the RGB field\n"); - REprintf( " 'I' : the NR channel of LAS 1.4 point type 8\n"); - REprintf( " 's' : kip a string or a number that we don't care about\n"); - REprintf( " 'i' : the ntensity\n"); - REprintf( " 'a' : the scan ngle\n"); - REprintf( " 'n' : the umber of returns of that given pulse\n"); - REprintf( " 'r' : the number of the eturn\n"); - REprintf( " 'h' : the witheld flag\n"); - REprintf( " 'k' : the eypoint flag\n"); - REprintf( " 'g' : the synthetic fla\n"); - REprintf( " 'o' : the verlap flag of LAS 1.4 point types 6, 7, 8\n"); - REprintf( " 'l' : the scanner channe of LAS 1.4 point types 6, 7, 8\n"); - REprintf( " 'E' : terrasolid hco Encoding\n"); - REprintf( " 'c' : the lassification\n"); - REprintf( " 'u' : the ser data\n"); - REprintf( " 'p' : the

oint source ID\n"); - REprintf( " 'e' : the dge of flight line flag\n"); - REprintf( " 'd' : the irection of scan flag\n"); - REprintf( " '0'-'9' : additional attributes described as extra bytes (0 through 9)\n"); - REprintf( " '(13)' : additional attributes described as extra bytes (10 and up)\n"); - REprintf( " 'H' : a hexadecimal string encoding the RGB color\n"); - REprintf( " 'J' : a hexadecimal string encoding the intensity\n"); - return FALSE; - } - } - p++; - } - return TRUE; + const char* p = parse_string; + while (p[0]) + { + if ((p[0] != 'x') && // we expect the x coordinate + (p[0] != 'y') && // we expect the y coordinate + (p[0] != 'z') && // we expect the z coordinate + (p[0] != 't') && // we expect the gps time + (p[0] != 'R') && // we expect the red channel of the RGB field + (p[0] != 'G') && // we expect the green channel of the RGB field + (p[0] != 'B') && // we expect the blue channel of the RGB field + (p[0] != 'I') && // we expect the NIR channel + (p[0] != 's') && // we expect a string or a number that we don't care about + (p[0] != 'i') && // we expect the intensity + (p[0] != 'a') && // we expect the scan angle + (p[0] != 'n') && // we expect the number of returns of given pulse + (p[0] != 'r') && // we expect the number of the return + (p[0] != 'h') && // we expect the witheld flag + (p[0] != 'k') && // we expect the eypoint flag + (p[0] != 'g') && // we expect the synthetic fla + (p[0] != 'o') && // we expect the verlap flag + (p[0] != 'l') && // we expect the scanner channe + (p[0] != 'E') && // we expect terrasolid echo encoding + (p[0] != 'c') && // we expect the classification + (p[0] != 'u') && // we expect the user data + (p[0] != 'p') && // we expect the point source ID + (p[0] != 'e') && // we expect the edge of flight line flag + (p[0] != 'd') && // we expect the direction of scan flag + (p[0] != 'H') && // we expect hexadecimal coded RGB(I) colors + (p[0] != 'J')) // we expect a hexadecimal coded intensity + { + if ((p[0] >= '0') && (p[0] <= '9')) + { + I32 index = (I32)(p[0] - '0'); + if (index >= header.number_attributes) + { + REprintf("ERROR: extra bytes attribute '%d' was not described.\n", index); + return FALSE; + } + attribute_starts[index] = header.get_attribute_start(index); + } + else if (p[0] == '(') + { + p++; + if ((p[0] >= '0') && (p[0] <= '9')) + { + I32 index = 0; + while ((p[0] >= '0') && (p[0] <= '9')) + { + index = 10 * index + (I32)(p[0] - '0'); + p++; + } + if (index >= header.number_attributes) + { + REprintf("ERROR: extra bytes attribute '%d' was not described.\n", index); + return FALSE; + } + if (p[0] != ')') + { + REprintf("ERROR: extra bytes attribute '%d' misses closing bracket.\n", index); + return FALSE; + } + attribute_starts[index] = header.get_attribute_start(index); + } + else + { + REprintf("ERROR: parse string opening bracket '(' misses extra bytes index.\n"); + return FALSE; + } + } + else + { + REprintf("ERROR: unknown symbol '%c' in parse string. valid are\n", p[0]); + REprintf(" 'x' : the coordinate\n"); + REprintf(" 'y' : the coordinate\n"); + REprintf(" 'z' : the coordinate\n"); + REprintf(" 't' : the gps ime\n"); + REprintf(" 'R' : the ed channel of the RGB field\n"); + REprintf(" 'G' : the reen channel of the RGB field\n"); + REprintf(" 'B' : the lue channel of the RGB field\n"); + REprintf(" 'I' : the NR channel of LAS 1.4 point type 8\n"); + REprintf(" 's' : kip a string or a number that we don't care about\n"); + REprintf(" 'i' : the ntensity\n"); + REprintf(" 'a' : the scan ngle\n"); + REprintf(" 'n' : the umber of returns of that given pulse\n"); + REprintf(" 'r' : the number of the eturn\n"); + REprintf(" 'h' : the witheld flag\n"); + REprintf(" 'k' : the eypoint flag\n"); + REprintf(" 'g' : the synthetic fla\n"); + REprintf(" 'o' : the verlap flag of LAS 1.4 point types 6, 7, 8\n"); + REprintf(" 'l' : the scanner channe of LAS 1.4 point types 6, 7, 8\n"); + REprintf(" 'E' : terrasolid hco Encoding\n"); + REprintf(" 'c' : the lassification\n"); + REprintf(" 'u' : the ser data\n"); + REprintf(" 'p' : the

oint source ID\n"); + REprintf(" 'e' : the dge of flight line flag\n"); + REprintf(" 'd' : the irection of scan flag\n"); + REprintf(" '0'-'9' : additional attributes described as extra bytes (0 through 9)\n"); + REprintf(" '(13)' : additional attributes described as extra bytes (10 and up)\n"); + REprintf(" 'H' : a hexadecimal string encoding the RGB color\n"); + REprintf(" 'J' : a hexadecimal string encoding the intensity\n"); + return FALSE; + } + } + p++; + } + return TRUE; } void LASreaderTXT::populate_scale_and_offset() { - // if not specified in the command line, set a reasonable scale_factor - if (scale_factor) - { - header.x_scale_factor = scale_factor[0]; - header.y_scale_factor = scale_factor[1]; - header.z_scale_factor = scale_factor[2]; - } - else - { - if (-360 < header.min_x && -360 < header.min_y && header.max_x < 360 && header.max_y < 360) // do we have longitude / latitude coordinates - { - header.x_scale_factor = 1e-7; - header.y_scale_factor = 1e-7; - } - else // then we assume utm or mercator / lambertian projections - { - header.x_scale_factor = 0.01; - header.y_scale_factor = 0.01; - } - header.z_scale_factor = 0.01; - } - - // if not specified in the command line, set a reasonable offset - if (offset) - { - header.x_offset = offset[0]; - header.y_offset = offset[1]; - header.z_offset = offset[2]; - } - else - { - if (F64_IS_FINITE(header.min_x) && F64_IS_FINITE(header.max_x)) - header.x_offset = ((I64)((header.min_x + header.max_x)/header.x_scale_factor/20000000))*10000000*header.x_scale_factor; - else - header.x_offset = 0; - - if (F64_IS_FINITE(header.min_y) && F64_IS_FINITE(header.max_y)) - header.y_offset = ((I64)((header.min_y + header.max_y)/header.y_scale_factor/20000000))*10000000*header.y_scale_factor; - else - header.y_offset = 0; - - if (F64_IS_FINITE(header.min_z) && F64_IS_FINITE(header.max_z)) - header.z_offset = ((I64)((header.min_z + header.max_z)/header.z_scale_factor/20000000))*10000000*header.z_scale_factor; - else - header.z_offset = 0; - } + // if not specified in the command line, set a reasonable scale_factor + if (scale_factor) + { + header.x_scale_factor = scale_factor[0]; + header.y_scale_factor = scale_factor[1]; + header.z_scale_factor = scale_factor[2]; + } + else + { + if (-360 < header.min_x && -360 < header.min_y && header.max_x < 360 && header.max_y < 360) // do we have longitude / latitude coordinates + { + header.x_scale_factor = 1e-7; + header.y_scale_factor = 1e-7; + } + else // then we assume utm or mercator / lambertian projections + { + header.x_scale_factor = 0.01; + header.y_scale_factor = 0.01; + } + header.z_scale_factor = 0.01; + } + + // if not specified in the command line, set a reasonable offset + if (offset) + { + header.x_offset = offset[0]; + header.y_offset = offset[1]; + header.z_offset = offset[2]; + } + else + { + if (F64_IS_FINITE(header.min_x) && F64_IS_FINITE(header.max_x)) + header.x_offset = ((I64)((header.min_x + header.max_x) / header.x_scale_factor / 20000000)) * 10000000 * header.x_scale_factor; + else + header.x_offset = 0; + + if (F64_IS_FINITE(header.min_y) && F64_IS_FINITE(header.max_y)) + header.y_offset = ((I64)((header.min_y + header.max_y) / header.y_scale_factor / 20000000)) * 10000000 * header.y_scale_factor; + else + header.y_offset = 0; + + if (F64_IS_FINITE(header.min_z) && F64_IS_FINITE(header.max_z)) + header.z_offset = ((I64)((header.min_z + header.max_z) / header.z_scale_factor / 20000000)) * 10000000 * header.z_scale_factor; + else + header.z_offset = 0; + } } void LASreaderTXT::populate_bounding_box() { - // compute quantized and then unquantized bounding box - - F64 dequant_min_x = header.get_x((I32)(header.get_X(header.min_x))); - F64 dequant_max_x = header.get_x((I32)(header.get_X(header.max_x))); - F64 dequant_min_y = header.get_y((I32)(header.get_Y(header.min_y))); - F64 dequant_max_y = header.get_y((I32)(header.get_Y(header.max_y))); - F64 dequant_min_z = header.get_z((I32)(header.get_Z(header.min_z))); - F64 dequant_max_z = header.get_z((I32)(header.get_Z(header.max_z))); - - // make sure there is not sign flip - - if ((header.min_x > 0) != (dequant_min_x > 0)) - { - REprintf( "WARNING: quantization sign flip for min_x from %g to %g.\n", header.min_x, dequant_min_x); - REprintf( " set scale factor for x coarser than %g with '-rescale'\n", header.x_scale_factor); - } - else - { - header.min_x = dequant_min_x; - } - if ((header.max_x > 0) != (dequant_max_x > 0)) - { - REprintf( "WARNING: quantization sign flip for max_x from %g to %g.\n", header.max_x, dequant_max_x); - REprintf( " set scale factor for x coarser than %g with '-rescale'\n", header.x_scale_factor); - } - else - { - header.max_x = dequant_max_x; - } - if ((header.min_y > 0) != (dequant_min_y > 0)) - { - REprintf( "WARNING: quantization sign flip for min_y from %g to %g.\n", header.min_y, dequant_min_y); - REprintf( " set scale factor for y coarser than %g with '-rescale'\n", header.y_scale_factor); - } - else - { - header.min_y = dequant_min_y; - } - if ((header.max_y > 0) != (dequant_max_y > 0)) - { - REprintf( "WARNING: quantization sign flip for max_y from %g to %g.\n", header.max_y, dequant_max_y); - REprintf( " set scale factor for y coarser than %g with '-rescale'\n", header.y_scale_factor); - } - else - { - header.max_y = dequant_max_y; - } - if ((header.min_z > 0) != (dequant_min_z > 0)) - { - REprintf( "WARNING: quantization sign flip for min_z from %g to %g.\n", header.min_z, dequant_min_z); - REprintf( " set scale factor for z coarser than %g with '-rescale'\n", header.z_scale_factor); - } - else - { - header.min_z = dequant_min_z; - } - if ((header.max_z > 0) != (dequant_max_z > 0)) - { - REprintf( "WARNING: quantization sign flip for max_z from %g to %g.\n", header.max_z, dequant_max_z); - REprintf( " set scale factor for z coarser than %g with '-rescale'\n", header.z_scale_factor); - } - else - { - header.max_z = dequant_max_z; - } + // compute quantized and then unquantized bounding box + + F64 dequant_min_x = header.get_x((I32)(header.get_X(header.min_x))); + F64 dequant_max_x = header.get_x((I32)(header.get_X(header.max_x))); + F64 dequant_min_y = header.get_y((I32)(header.get_Y(header.min_y))); + F64 dequant_max_y = header.get_y((I32)(header.get_Y(header.max_y))); + F64 dequant_min_z = header.get_z((I32)(header.get_Z(header.min_z))); + F64 dequant_max_z = header.get_z((I32)(header.get_Z(header.max_z))); + + // make sure there is not sign flip + + if ((header.min_x > 0) != (dequant_min_x > 0)) + { + REprintf("WARNING: quantization sign flip for min_x from %g to %g.\n", header.min_x, dequant_min_x); + REprintf(" set scale factor for x coarser than %g with '-rescale'\n", header.x_scale_factor); + } + else + { + header.min_x = dequant_min_x; + } + if ((header.max_x > 0) != (dequant_max_x > 0)) + { + REprintf("WARNING: quantization sign flip for max_x from %g to %g.\n", header.max_x, dequant_max_x); + REprintf(" set scale factor for x coarser than %g with '-rescale'\n", header.x_scale_factor); + } + else + { + header.max_x = dequant_max_x; + } + if ((header.min_y > 0) != (dequant_min_y > 0)) + { + REprintf("WARNING: quantization sign flip for min_y from %g to %g.\n", header.min_y, dequant_min_y); + REprintf(" set scale factor for y coarser than %g with '-rescale'\n", header.y_scale_factor); + } + else + { + header.min_y = dequant_min_y; + } + if ((header.max_y > 0) != (dequant_max_y > 0)) + { + REprintf("WARNING: quantization sign flip for max_y from %g to %g.\n", header.max_y, dequant_max_y); + REprintf(" set scale factor for y coarser than %g with '-rescale'\n", header.y_scale_factor); + } + else + { + header.max_y = dequant_max_y; + } + if ((header.min_z > 0) != (dequant_min_z > 0)) + { + REprintf("WARNING: quantization sign flip for min_z from %g to %g.\n", header.min_z, dequant_min_z); + REprintf(" set scale factor for z coarser than %g with '-rescale'\n", header.z_scale_factor); + } + else + { + header.min_z = dequant_min_z; + } + if ((header.max_z > 0) != (dequant_max_z > 0)) + { + REprintf("WARNING: quantization sign flip for max_z from %g to %g.\n", header.max_z, dequant_max_z); + REprintf(" set scale factor for z coarser than %g with '-rescale'\n", header.z_scale_factor); + } + else + { + header.max_z = dequant_max_z; + } } LASreaderTXTrescale::LASreaderTXTrescale(F64 x_scale_factor, F64 y_scale_factor, F64 z_scale_factor) : LASreaderTXT() { - scale_factor[0] = x_scale_factor; - scale_factor[1] = y_scale_factor; - scale_factor[2] = z_scale_factor; + scale_factor[0] = x_scale_factor; + scale_factor[1] = y_scale_factor; + scale_factor[2] = z_scale_factor; } BOOL LASreaderTXTrescale::open(const CHAR* file_name, U8 point_type, const CHAR* parse_string, I32 skip_lines, BOOL populate_header) { - if (!LASreaderTXT::open(file_name, point_type, parse_string, skip_lines, populate_header)) return FALSE; - // do we need to change anything - if (scale_factor[0] && (header.x_scale_factor != scale_factor[0])) - { - header.x_scale_factor = scale_factor[0]; - } - if (scale_factor[1] && (header.y_scale_factor != scale_factor[1])) - { - header.y_scale_factor = scale_factor[1]; - } - if (scale_factor[2] && (header.z_scale_factor != scale_factor[2])) - { - header.z_scale_factor = scale_factor[2]; - } - return TRUE; + if (!LASreaderTXT::open(file_name, point_type, parse_string, skip_lines, populate_header)) return FALSE; + // do we need to change anything + if (scale_factor[0] && (header.x_scale_factor != scale_factor[0])) + { + header.x_scale_factor = scale_factor[0]; + } + if (scale_factor[1] && (header.y_scale_factor != scale_factor[1])) + { + header.y_scale_factor = scale_factor[1]; + } + if (scale_factor[2] && (header.z_scale_factor != scale_factor[2])) + { + header.z_scale_factor = scale_factor[2]; + } + return TRUE; } LASreaderTXTreoffset::LASreaderTXTreoffset(F64 x_offset, F64 y_offset, F64 z_offset) : LASreaderTXT() { - this->offset[0] = x_offset; - this->offset[1] = y_offset; - this->offset[2] = z_offset; + this->offset[0] = x_offset; + this->offset[1] = y_offset; + this->offset[2] = z_offset; } BOOL LASreaderTXTreoffset::open(const CHAR* file_name, U8 point_type, const CHAR* parse_string, I32 skip_lines, BOOL populate_header) { - if (!LASreaderTXT::open(file_name, point_type, parse_string, skip_lines, populate_header)) return FALSE; - // do we need to change anything - if (header.x_offset != offset[0]) - { - header.x_offset = offset[0]; - } - if (header.y_offset != offset[1]) - { - header.y_offset = offset[1]; - } - if (header.z_offset != offset[2]) - { - header.z_offset = offset[2]; - } - return TRUE; + if (!LASreaderTXT::open(file_name, point_type, parse_string, skip_lines, populate_header)) return FALSE; + // do we need to change anything + if (header.x_offset != offset[0]) + { + header.x_offset = offset[0]; + } + if (header.y_offset != offset[1]) + { + header.y_offset = offset[1]; + } + if (header.z_offset != offset[2]) + { + header.z_offset = offset[2]; + } + return TRUE; } LASreaderTXTrescalereoffset::LASreaderTXTrescalereoffset(F64 x_scale_factor, F64 y_scale_factor, F64 z_scale_factor, F64 x_offset, F64 y_offset, F64 z_offset) : LASreaderTXTrescale(x_scale_factor, y_scale_factor, z_scale_factor), LASreaderTXTreoffset(x_offset, y_offset, z_offset) @@ -2154,31 +2179,31 @@ LASreaderTXTrescalereoffset::LASreaderTXTrescalereoffset(F64 x_scale_factor, F64 BOOL LASreaderTXTrescalereoffset::open(const CHAR* file_name, U8 point_type, const CHAR* parse_string, I32 skip_lines, BOOL populate_header) { - if (!LASreaderTXT::open(file_name, point_type, parse_string, skip_lines, populate_header)) return FALSE; - // do we need to change anything - if (scale_factor[0] && (header.x_scale_factor != scale_factor[0])) - { - header.x_scale_factor = scale_factor[0]; - } - if (scale_factor[1] && (header.y_scale_factor != scale_factor[1])) - { - header.y_scale_factor = scale_factor[1]; - } - if (scale_factor[2] && (header.z_scale_factor != scale_factor[2])) - { - header.z_scale_factor = scale_factor[2]; - } - if (header.x_offset != offset[0]) - { - header.x_offset = offset[0]; - } - if (header.y_offset != offset[1]) - { - header.y_offset = offset[1]; - } - if (header.z_offset != offset[2]) - { - header.z_offset = offset[2]; - } - return TRUE; + if (!LASreaderTXT::open(file_name, point_type, parse_string, skip_lines, populate_header)) return FALSE; + // do we need to change anything + if (scale_factor[0] && (header.x_scale_factor != scale_factor[0])) + { + header.x_scale_factor = scale_factor[0]; + } + if (scale_factor[1] && (header.y_scale_factor != scale_factor[1])) + { + header.y_scale_factor = scale_factor[1]; + } + if (scale_factor[2] && (header.z_scale_factor != scale_factor[2])) + { + header.z_scale_factor = scale_factor[2]; + } + if (header.x_offset != offset[0]) + { + header.x_offset = offset[0]; + } + if (header.y_offset != offset[1]) + { + header.y_offset = offset[1]; + } + if (header.z_offset != offset[2]) + { + header.z_offset = offset[2]; + } + return TRUE; } diff --git a/src/LASlib/lasreader_txt.hpp b/src/LASlib/lasreader_txt.hpp index 316e945..17838d4 100644 --- a/src/LASlib/lasreader_txt.hpp +++ b/src/LASlib/lasreader_txt.hpp @@ -1,36 +1,37 @@ /* =============================================================================== - FILE: lasreader_txt.hpp + FILE: lasreader_txt.hpp - CONTENTS: + CONTENTS: - Reads LIDAR points in LAS format through on-the-fly conversion from ASCII. + Reads LIDAR points in LAS format through on-the-fly conversion from ASCII. - PROGRAMMERS: + PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de - COPYRIGHT: + COPYRIGHT: - (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2017, rapidlasso GmbH - fast tools to catch reality - This is free software; you can redistribute and/or modify it under the - terms of the GNU Lesser General Licence as published by the Free Software - Foundation. See the LICENSE.txt file for more information. + This is free software; you can redistribute and/or modify it under the + terms of the GNU Lesser General Licence as published by the Free Software + Foundation. See the LICENSE.txt file for more information. - This software is distributed WITHOUT ANY WARRANTY and without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + This software is distributed WITHOUT ANY WARRANTY and without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - CHANGE HISTORY: + CHANGE HISTORY: - 7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro - 22 July 2018 -- bug fix for parsing classfication to point type 6 (or higher) - 11 January 2017 -- added witheld and scanner channe for the parse string - 11 January 2017 -- added 'k'eypoint and 'o'verlap flags for the parse string - 17 January 2016 -- pre-scaling and pre-offsetting of "extra bytes" attributes - 9 July 2014 -- allowing input from stdin after the 7:1 in the World Cup - 8 April 2011 -- created after starting a google group for LAStools users + 10 March 2022 -- added '-iptx_transform' option + 7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro + 22 July 2018 -- bug fix for parsing classfication to point type 6 (or higher) + 11 January 2017 -- added witheld and scanner channe for the parse string + 11 January 2017 -- added 'k'eypoint and 'o'verlap flags for the parse string + 17 January 2016 -- pre-scaling and pre-offsetting of "extra bytes" attributes + 9 July 2014 -- allowing input from stdin after the 7:1 in the World Cup + 8 April 2011 -- created after starting a google group for LAStools users =============================================================================== */ @@ -44,92 +45,93 @@ class LASreaderTXT : public LASreader { public: + BOOL iptx_transform; + void set_pts(BOOL pts); + void set_ptx(BOOL ptx); + void set_ptx_transform(BOOL ptx); - void set_pts(BOOL pts); - void set_ptx(BOOL ptx); + void set_translate_intensity(F32 translate_intensity); + void set_scale_intensity(F32 scale_intensity); + void set_translate_scan_angle(F32 translate_scan_angle); + void set_scale_scan_angle(F32 scale_scan_angle); + void set_scale_factor(const F64* scale_factor); + void set_offset(const F64* offset); + void add_attribute(I32 data_type, const CHAR* name, const CHAR* description = 0, F64 scale = 1.0, F64 offset = 0.0, F64 pre_scale = 1.0, F64 pre_offset = 0.0, F64 no_data = F64_MAX); + virtual BOOL open(const CHAR* file_name, U8 point_type = 0, const CHAR* parse_string = 0, I32 skip_lines = 0, BOOL populate_header = FALSE); + virtual BOOL open(FILE* file, const CHAR* file_name = 0, U8 point_type = 0, const CHAR* parse_string = 0, I32 skip_lines = 0, BOOL populate_header = FALSE); - void set_translate_intensity(F32 translate_intensity); - void set_scale_intensity(F32 scale_intensity); - void set_translate_scan_angle(F32 translate_scan_angle); - void set_scale_scan_angle(F32 scale_scan_angle); - void set_scale_factor(const F64* scale_factor); - void set_offset(const F64* offset); - void add_attribute(I32 data_type, const CHAR* name, const CHAR* description=0, F64 scale=1.0, F64 offset=0.0, F64 pre_scale=1.0, F64 pre_offset=0.0, F64 no_data=F64_MAX); - virtual BOOL open(const CHAR* file_name, U8 point_type=0, const CHAR* parse_string=0, I32 skip_lines=0, BOOL populate_header=FALSE); - virtual BOOL open(FILE* file, const CHAR* file_name=0, U8 point_type=0, const CHAR* parse_string=0, I32 skip_lines=0, BOOL populate_header=FALSE); + I32 get_format() const { return LAS_TOOLS_FORMAT_TXT; }; - I32 get_format() const { return LAS_TOOLS_FORMAT_TXT; }; + BOOL seek(const I64 p_index); - BOOL seek(const I64 p_index); + ByteStreamIn* get_stream() const; + void close(BOOL close_stream = TRUE); + BOOL reopen(const CHAR* file_name); - ByteStreamIn* get_stream() const; - void close(BOOL close_stream=TRUE); - BOOL reopen(const CHAR* file_name); - - LASreaderTXT(); - virtual ~LASreaderTXT(); + LASreaderTXT(); + virtual ~LASreaderTXT(); protected: - BOOL read_point_default(); + BOOL read_point_default(); private: - U8 point_type; - CHAR* parse_string; - F32 translate_intensity; - F32 scale_intensity; - F32 translate_scan_angle; - F32 scale_scan_angle; - F64* scale_factor; - F64* offset; - I32 skip_lines; - BOOL populated_header; - BOOL ipts; - BOOL iptx; - FILE* file; - bool piped; - CHAR line[512]; - I32 number_attributes; - I32 attributes_data_types[32]; - const CHAR* attribute_names[32]; - const CHAR* attribute_descriptions[32]; - F64 attribute_scales[32]; - F64 attribute_offsets[32]; - F64 attribute_pre_scales[32]; - F64 attribute_pre_offsets[32]; - F64 attribute_no_datas[32]; - I32 attribute_starts[32]; - BOOL parse_attribute(const CHAR* l, I32 index); - BOOL parse(const CHAR* parse_string); - BOOL check_parse_string(const CHAR* parse_string); - void populate_scale_and_offset(); - void populate_bounding_box(); - void clean(); + U8 point_type; + CHAR* parse_string; + F32 translate_intensity; + F32 scale_intensity; + F32 translate_scan_angle; + F32 scale_scan_angle; + F64* scale_factor; + F64* offset; + I32 skip_lines; + BOOL populated_header; + BOOL ipts; + BOOL iptx; + FILE* file; + bool piped; + CHAR line[512]; + I32 number_attributes; + I32 attributes_data_types[32]; + const CHAR* attribute_names[32]; + const CHAR* attribute_descriptions[32]; + F64 attribute_scales[32]; + F64 attribute_offsets[32]; + F64 attribute_pre_scales[32]; + F64 attribute_pre_offsets[32]; + F64 attribute_no_datas[32]; + I32 attribute_starts[32]; + BOOL parse_attribute(const CHAR* l, I32 index); + BOOL parse(const CHAR* parse_string); + BOOL check_parse_string(const CHAR* parse_string); + void populate_scale_and_offset(); + void populate_bounding_box(); + void clean(); }; class LASreaderTXTrescale : public virtual LASreaderTXT { public: - virtual BOOL open(const CHAR* file_name, U8 point_type=0, const CHAR* parse_string=0, I32 skip_lines=0, BOOL populate_header=FALSE); - LASreaderTXTrescale(F64 x_scale_factor, F64 y_scale_factor, F64 z_scale_factor); + virtual BOOL open(const CHAR* file_name, U8 point_type = 0, const CHAR* parse_string = 0, I32 skip_lines = 0, BOOL populate_header = FALSE); + LASreaderTXTrescale(F64 x_scale_factor, F64 y_scale_factor, F64 z_scale_factor); protected: - F64 scale_factor[3]; + F64 scale_factor[3]; }; class LASreaderTXTreoffset : public virtual LASreaderTXT { public: - virtual BOOL open(const CHAR* file_name, U8 point_type=0, const CHAR* parse_string=0, I32 skip_lines=0, BOOL populate_header=FALSE); - LASreaderTXTreoffset(F64 x_offset, F64 y_offset, F64 z_offset); + virtual BOOL open(const CHAR* file_name, U8 point_type = 0, const CHAR* parse_string = 0, I32 skip_lines = 0, BOOL populate_header = FALSE); + LASreaderTXTreoffset(F64 x_offset, F64 y_offset, F64 z_offset); protected: - F64 offset[3]; + F64 offset[3]; }; class LASreaderTXTrescalereoffset : public LASreaderTXTrescale, LASreaderTXTreoffset { public: - BOOL open(const CHAR* file_name, U8 point_type=0, const CHAR* parse_string=0, I32 skip_lines=0, BOOL populate_header=FALSE); - LASreaderTXTrescalereoffset(F64 x_scale_factor, F64 y_scale_factor, F64 z_scale_factor, F64 x_offset, F64 y_offset, F64 z_offset); + BOOL open(const CHAR* file_name, U8 point_type = 0, const CHAR* parse_string = 0, I32 skip_lines = 0, BOOL populate_header = FALSE); + LASreaderTXTrescalereoffset(F64 x_scale_factor, F64 y_scale_factor, F64 z_scale_factor, F64 x_offset, F64 y_offset, F64 z_offset); }; #endif diff --git a/src/LASlib/lasreaderbuffered.cpp b/src/LASlib/lasreaderbuffered.cpp index 71ac57f..2f862ce 100644 --- a/src/LASlib/lasreaderbuffered.cpp +++ b/src/LASlib/lasreaderbuffered.cpp @@ -2,18 +2,18 @@ =============================================================================== FILE: lasreaderbuffered.cpp - + CONTENTS: - + see corresponding header file - + PROGRAMMERS: - - martin.isenburg@rapidlasso.com - http://rapidlasso.com - + + info@rapidlasso.de - https://rapidlasso.de + COPYRIGHT: - - (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality + + (c) 2007-2012, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -21,11 +21,11 @@ This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - + CHANGE HISTORY: - + see corresponding header file - + =============================================================================== */ #include "lasreaderbuffered.hpp" @@ -301,7 +301,7 @@ BOOL LASreaderBuffered::open() reoffset = TRUE; } } - + // check y if ((((header.max_y - header.y_offset) / header.y_scale_factor) > I32_MAX) || (((header.min_y - header.y_offset) / header.y_scale_factor) < I32_MIN)) @@ -327,7 +327,7 @@ BOOL LASreaderBuffered::open() reoffset = TRUE; } } - + // check z if ((((header.max_z - header.z_offset) / header.z_scale_factor) > I32_MAX) || (((header.min_z - header.z_offset) / header.z_scale_factor) < I32_MIN)) @@ -443,6 +443,17 @@ BOOL LASreaderBuffered::inside_rectangle(const F64 min_x, const F64 min_y, const return TRUE; } +BOOL LASreaderBuffered::inside_copc_depth(const U8 mode, const I32 depth, const F32 resolution) +{ + if (!header.vlr_copc_info) + return FALSE; + + inside_depth = mode; + copc_depth = depth; + copc_resolution = resolution; + return TRUE; +} + I32 LASreaderBuffered::get_format() const { return lasreader->get_format(); @@ -472,7 +483,7 @@ BOOL LASreaderBuffered::read_point_default() void LASreaderBuffered::close(BOOL close_stream) { - if (lasreader) + if (lasreader) { lasreader->close(close_stream); } @@ -482,7 +493,7 @@ void LASreaderBuffered::close(BOOL close_stream) void LASreaderBuffered::clean() { /* - if (lasreader) + if (lasreader) { delete lasreader; lasreader = 0; diff --git a/src/LASlib/lasreaderbuffered.hpp b/src/LASlib/lasreaderbuffered.hpp index 60fa065..64321c2 100644 --- a/src/LASlib/lasreaderbuffered.hpp +++ b/src/LASlib/lasreaderbuffered.hpp @@ -15,11 +15,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2012, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -30,6 +30,7 @@ CHANGE HISTORY: + 2 May 2023 -- adding support of COPC spatial index standard 17 July 2012 -- created after converting the LASzip paper from LaTeX to Word =============================================================================== @@ -68,6 +69,7 @@ class LASreaderBuffered : public LASreader BOOL inside_tile(const F32 ll_x, const F32 ll_y, const F32 size); BOOL inside_circle(const F64 center_x, const F64 center_y, const F64 radius); BOOL inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y); + BOOL inside_copc_depth(const U8 mode, const I32 depth, const F32 resolution); I32 get_format() const; diff --git a/src/LASlib/lasreadermerged.cpp b/src/LASlib/lasreadermerged.cpp index f895e36..acefc8b 100644 --- a/src/LASlib/lasreadermerged.cpp +++ b/src/LASlib/lasreadermerged.cpp @@ -2,18 +2,18 @@ =============================================================================== FILE: lasreadermerged.cpp - + CONTENTS: - + see corresponding header file - + PROGRAMMERS: - - martin.isenburg@rapidlasso.com - http://rapidlasso.com - + + info@rapidlasso.de - https://rapidlasso.de + COPYRIGHT: - - (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality + + (c) 2007-2019, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -21,16 +21,17 @@ This software is distributed WITHOUT ANY WARRANTY and without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - + CHANGE HISTORY: - + see corresponding header file - + =============================================================================== */ #include "lasreadermerged.hpp" #include "lasindex.hpp" +#include "lascopc.hpp" #include "lasfilter.hpp" #include "lastransform.hpp" @@ -815,7 +816,7 @@ BOOL LASreaderMerged::open() // have there not been any points before if (npoints == lasreader->npoints) { - // use the counters + // use the counters header.number_of_point_records = lasreader->header.number_of_point_records; for (j = 0; j < 5; j++) { @@ -851,7 +852,7 @@ BOOL LASreaderMerged::open() } else { - // increment point counters + // increment point counters header.number_of_point_records += lasreader->header.number_of_point_records; for (j = 0; j < 5; j++) { @@ -1036,7 +1037,7 @@ BOOL LASreaderMerged::open() reoffset = TRUE; } } - + // check y if ((((header.max_y - header.y_offset) / header.y_scale_factor) > I32_MAX) || (((header.min_y - header.y_offset) / header.y_scale_factor) < I32_MIN)) @@ -1062,7 +1063,7 @@ BOOL LASreaderMerged::open() reoffset = TRUE; } } - + // check z if ((((header.max_z - header.z_offset) / header.z_scale_factor) > I32_MAX) || (((header.min_z - header.z_offset) / header.z_scale_factor) < I32_MIN)) @@ -1269,6 +1270,17 @@ BOOL LASreaderMerged::inside_rectangle(const F64 min_x, const F64 min_y, const F return TRUE; } +BOOL LASreaderMerged::inside_copc_depth(const U8 mode, const I32 depth, const F32 resolution) +{ + if (!header.vlr_copc_info) + return FALSE; + + inside_depth = mode; + copc_depth = depth; + copc_resolution = resolution; + return TRUE; +} + I32 LASreaderMerged::get_format() const { return lasreader->get_format(); @@ -1330,7 +1342,7 @@ BOOL LASreaderMerged::read_point_default() void LASreaderMerged::close(BOOL close_stream) { - if (lasreader) + if (lasreader) { lasreader->close(close_stream); } @@ -1347,7 +1359,7 @@ BOOL LASreaderMerged::reopen() void LASreaderMerged::clean() { - if (lasreader) + if (lasreader) { delete lasreader; lasreader = 0; @@ -1497,11 +1509,28 @@ BOOL LASreaderMerged::open_next_file() REprintf( "ERROR: could not open lasreaderlas for file '%s'\n", file_names[file_name_current]); return FALSE; } - LASindex* index = new LASindex; + LASindex *index = new LASindex; if (index->read(file_names[file_name_current])) lasreaderlas->set_index(index); else + { delete index; + index = 0; + } + + // Creation of the COPC index + if (lasreaderlas->header.vlr_copc_entries) + { + if (index) + { + REprintf( "WARNING: both LAX file and COPC spatial indexing registered. COPC has the precedence.\n"); + delete index; + index = 0; + } + + COPCindex *copc_index = new COPCindex(lasreaderlas->header); + lasreaderlas->set_copcindex(copc_index); + } } else if (lasreaderbin) { @@ -1616,6 +1645,7 @@ BOOL LASreaderMerged::open_next_file() else if (inside == 1) lasreader->inside_tile(t_ll_x, t_ll_y, t_size); else lasreader->inside_circle(c_center_x, c_center_y, c_radius); } + if (inside_depth) lasreader->inside_copc_depth(inside_depth, copc_depth, copc_resolution); return TRUE; } return FALSE; diff --git a/src/LASlib/lasreadermerged.hpp b/src/LASlib/lasreadermerged.hpp index 96aba37..1949379 100644 --- a/src/LASlib/lasreadermerged.hpp +++ b/src/LASlib/lasreadermerged.hpp @@ -9,11 +9,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2019, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2019, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -24,6 +24,7 @@ CHANGE HISTORY: + 2 May 2023 -- adding support of COPC spatial index standard 4 November 2019 -- add ID to files for subsets of merged '-faf' files 5 September 2018 -- support for reading points from the PLY format 1 December 2017 -- support extra bytes during '-merged' operations @@ -74,6 +75,7 @@ class LASreaderMerged : public LASreader BOOL inside_tile(const F32 ll_x, const F32 ll_y, const F32 size); BOOL inside_circle(const F64 center_x, const F64 center_y, const F64 radius); BOOL inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y); + BOOL inside_copc_depth(const U8 mode, const I32 depth, const F32 resolution); I32 get_format() const; diff --git a/src/LASlib/lasreaderpipeon.cpp b/src/LASlib/lasreaderpipeon.cpp index 7f01788..246b4fa 100644 --- a/src/LASlib/lasreaderpipeon.cpp +++ b/src/LASlib/lasreaderpipeon.cpp @@ -9,11 +9,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2012, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -31,6 +31,7 @@ #include "lasreaderpipeon.hpp" #include "lasindex.hpp" +#include "lascopc.hpp" #include "lasfilter.hpp" #include "lastransform.hpp" @@ -43,7 +44,7 @@ BOOL LASreaderPipeOn::open(LASreader* lasreader) { if (lasreader == 0) { - REprintf( "ERROR: no lasreader\n"); + REprintf("ERROR: no lasreader\n"); return FALSE; } @@ -89,14 +90,14 @@ BOOL LASreaderPipeOn::open(LASreader* lasreader) if (laswriterlas == 0) { - REprintf( "ERROR: allocating laswriterlas\n"); + REprintf("ERROR: allocating laswriterlas\n"); return FALSE; } /*if (!laswriterlas->open(stdout, &header)) { delete laswriterlas; - REprintf( "ERROR: opening laswriterlas to stdout\n"); + REprintf("ERROR: opening laswriterlas to stdout\n"); return FALSE; }*/ @@ -118,6 +119,16 @@ LASindex* LASreaderPipeOn::get_index() const return (lasreader ? lasreader->get_index() : 0); } +void LASreaderPipeOn::set_copcindex(COPCindex* copcindex) +{ + if (lasreader) lasreader->set_copcindex(copcindex); +} + +COPCindex* LASreaderPipeOn::get_copcindex() const +{ + return (lasreader ? lasreader->get_copcindex() : 0); +} + void LASreaderPipeOn::set_filter(LASfilter* filter) { if (lasreader) lasreader->set_filter(filter); @@ -143,6 +154,11 @@ BOOL LASreaderPipeOn::inside_rectangle(const F64 min_x, const F64 min_y, const F return (lasreader ? lasreader->inside_rectangle(min_x, min_y, max_x, max_y) : FALSE); } +BOOL LASreaderPipeOn::inside_copc_depth(const U8 mode, const I32 depth, const F32 resolution) +{ + return (lasreader ? lasreader->inside_copc_depth(mode, depth, resolution) : FALSE); +} + I32 LASreaderPipeOn::get_format() const { return (lasreader ? lasreader->get_format() : LAS_TOOLS_FORMAT_DEFAULT); diff --git a/src/LASlib/lasreaderpipeon.hpp b/src/LASlib/lasreaderpipeon.hpp index f745da5..ff45eb9 100644 --- a/src/LASlib/lasreaderpipeon.hpp +++ b/src/LASlib/lasreaderpipeon.hpp @@ -10,11 +10,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2012, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2012, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -25,6 +25,7 @@ CHANGE HISTORY: + 2 May 2023 -- adding support of COPC spatial index standard 21 August 2012 -- created after swimming in the Main river 3 days in a row =============================================================================== @@ -46,12 +47,15 @@ class LASreaderPipeOn : public LASreader void set_index(LASindex* index); LASindex* get_index() const; + void set_copcindex(COPCindex* copcindex); + COPCindex* get_copcindex() const; void set_filter(LASfilter* filter); void set_transform(LAStransform* transform); BOOL inside_tile(const F32 ll_x, const F32 ll_y, const F32 size); BOOL inside_circle(const F64 center_x, const F64 center_y, const F64 radius); BOOL inside_rectangle(const F64 min_x, const F64 min_y, const F64 max_x, const F64 max_y); + BOOL inside_copc_depth(const U8 mode, const I32 depth, const F32 resolution); BOOL seek(const I64 p_index){ return FALSE; }; diff --git a/src/LASlib/lastransform.hpp b/src/LASlib/lastransform.hpp index f761506..397bef2 100644 --- a/src/LASlib/lastransform.hpp +++ b/src/LASlib/lastransform.hpp @@ -1,40 +1,43 @@ /* =============================================================================== - FILE: lastransform.hpp - - CONTENTS: - - Transforms LIDAR points with a number of different operations. - - PROGRAMMERS: - - martin.isenburg@rapidlasso.com - http://rapidlasso.com - - COPYRIGHT: - - (c) 2007-2018, martin isenburg, rapidlasso - fast tools to catch reality - - This is free software; you can redistribute and/or modify it under the - terms of the GNU Lesser General Licence as published by the Free Software - Foundation. See the LICENSE.txt file for more information. - - This software is distributed WITHOUT ANY WARRANTY and without even the - implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - CHANGE HISTORY: - - 10 May 2019 -- checking for overflows in X, Y, Z 32 bit integers of fixed-point LAS - 6 March 2018 -- changed '%g' to '%lf' for all sprintf() of F64 values - 28 February 2017 -- now '-set_RGB_of_class' also works for classifications > 31 - 1 February 2017 -- new '-copy_intensity_into_z' for use in lasgrid or lascanopy - 9 May 2016 -- new '-translate_raw_xy_at_random 2 2' for random pertubation - 20 April 2016 -- new '-switch_R_G', '-switch_R_B' and '-set_RGB 32768 16384 0' - 25 January 2016 -- brand-new opportunity to do a '-filtered_transform' - 18 December 2011 -- added '-flip_waveform_direction' to deal with Riegl's data - 20 March 2011 -- added -translate_raw_xyz after the fullest of full moons - 21 January 2011 -- re-created after matt told me about the optech dashmap bug - + FILE: lastransform.hpp + + CONTENTS: + + Transforms LIDAR points with a number of different operations. + + PROGRAMMERS: + + info@rapidlasso.de - https://rapidlasso.de + + COPYRIGHT: + + (c) 2007-2021, rapidlasso GmbH - fast tools to catch reality + + This is free software; you can redistribute and/or modify it under the + terms of the GNU Lesser General Licence as published by the Free Software + Foundation. See the LICENSE.txt file for more information. + + This software is distributed WITHOUT ANY WARRANTY and without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + CHANGE HISTORY: + + 10 March 2022 -- added TransformMatrix operation + 18 November 2021 -- new '-forceRGB' to use RGB values also in non-RGB point versions + 15 June 2021 -- new '-clamp_RGB_to_8bit' transform useful to avoid 8 bit overflow + 10 May 2019 -- checking for overflows in X, Y, Z 32 bit integers of fixed-point LAS + 6 March 2018 -- changed '%g' to '%lf' for all sprintf() of F64 values + 28 February 2017 -- now '-set_RGB_of_class' also works for classifications > 31 + 1 February 2017 -- new '-copy_intensity_into_z' for use in lasgrid or lascanopy + 9 May 2016 -- new '-translate_raw_xy_at_random 2 2' for random pertubation + 20 April 2016 -- new '-switch_R_G', '-switch_R_B' and '-set_RGB 32768 16384 0' + 25 January 2016 -- brand-new opportunity to do a '-filtered_transform' + 18 December 2011 -- added '-flip_waveform_direction' to deal with Riegl's data + 20 March 2011 -- added -translate_raw_xyz after the fullest of full moons + 21 January 2011 -- re-created after matt told me about the optech dashmap bug + =============================================================================== */ #ifndef LAS_TRANSFORM_HPP @@ -45,20 +48,80 @@ class LASfilter; +struct LASTransformMatrix { + F64 r11; + F64 r12; + F64 r13; + F64 r21; + F64 r22; + F64 r23; + F64 r31; + F64 r32; + F64 r33; + F64 tr1; + F64 tr2; + F64 tr3; +}; + class LASoperation { public: - virtual const CHAR * name() const = 0; - virtual I32 get_command(CHAR* string) const = 0; - virtual U32 get_decompress_selective() const { return LASZIP_DECOMPRESS_SELECTIVE_CHANNEL_RETURNS_XY; }; - inline I64 get_overflow() const { return overflow; }; - inline void zero_overflow() { overflow = 0; }; - virtual void transform(LASpoint* point) = 0; - virtual void reset(){ overflow = 0; }; - inline LASoperation(){ overflow = 0; }; - virtual ~LASoperation(){}; + virtual const CHAR * name() const = 0; + virtual I32 get_command(CHAR* string) const = 0; + virtual U32 get_decompress_selective() const { return LASZIP_DECOMPRESS_SELECTIVE_CHANNEL_RETURNS_XY; }; + inline I64 get_overflow() const { return overflow; }; + inline void zero_overflow() { overflow = 0; }; + virtual void transform(LASpoint* point) = 0; + virtual void reset() { overflow = 0; }; + inline LASoperation() { overflow = 0; }; + virtual ~LASoperation() {}; protected: - I64 overflow; + I64 overflow; +}; + +// this operation is public cause used out of reader in ptx header +class LASoperationTransformMatrix : public LASoperation +{ +public: + inline const CHAR* name() const { return "transform_matrix"; }; + inline I32 get_command(CHAR* string) const { return snprintf(string, 512, "-%s %lf,%lf,%lf %lf,%lf,%lf %lf,%lf,%lf %lf,%lf,%lf", name(), r11, r12, r13, r21, r22, r23, r31, r32, r33, tr1, tr2, tr3); }; + inline U32 get_decompress_selective() const { return LASZIP_DECOMPRESS_SELECTIVE_CHANNEL_RETURNS_XY | LASZIP_DECOMPRESS_SELECTIVE_Z; }; + inline void transform(LASpoint* point) { + F64 x = point->get_x(); + F64 y = point->get_y(); + F64 z = point->get_z(); + F64 xr = x * r11 + y * r12 + z * r13 + tr1; + F64 yr = x * r21 + y * r22 + z * r23 + tr2; + F64 zr = x * r31 + y * r32 + z * r33 + tr3; + if (!point->set_x(xr)) + { + overflow++; + } + if (!point->set_y(yr)) + { + overflow++; + } + if (!point->set_z(zr)) + { + overflow++; + } + }; + LASoperationTransformMatrix(F64 r11, F64 r12, F64 r13, F64 r21, F64 r22, F64 r23, F64 r31, F64 r32, F64 r33, F64 tr1, F64 tr2, F64 tr3) + { + this->r11 = r11; this->r12 = r12; this->r13 = r13; + this->r21 = r21; this->r22 = r22; this->r23 = r23; + this->r31 = r31; this->r32 = r32; this->r33 = r33; + this->tr1 = tr1; this->tr2 = tr2; this->tr3 = tr3; + }; + LASoperationTransformMatrix(LASTransformMatrix tm) + { + this->r11 = tm.r11; this->r12 = tm.r12; this->r13 = tm.r13; + this->r21 = tm.r21; this->r22 = tm.r22; this->r23 = tm.r23; + this->r31 = tm.r31; this->r32 = tm.r32; this->r33 = tm.r33; + this->tr1 = tm.tr1; this->tr2 = tm.tr2; this->tr3 = tm.tr3; + }; +private: + F64 r11, r12, r13, r21, r22, r23, r31, r32, r33, tr1, tr2, tr3; }; #define LASTRANSFORM_X_COORDINATE 0x00000001 @@ -74,42 +137,41 @@ class LASoperation class LAStransform { public: + U32 transformed_fields; + F64 registers[16]; - U32 transformed_fields; - F64 registers[16]; - - void usage() const; - void clean(); - BOOL parse(int argc, char* argv[]); - BOOL parse(CHAR* string); - I32 unparse(CHAR* string) const; - inline BOOL active() const { return (num_operations != 0); }; - U32 get_decompress_selective() const; - inline BOOL filtered() const { return is_filtered; }; + void usage() const; + void clean(); + BOOL parse(int argc, char* argv[]); + BOOL parse(CHAR* string); + I32 unparse(CHAR* string) const; + inline BOOL active() const { return (num_operations != 0); }; + U32 get_decompress_selective() const; + inline BOOL filtered() const { return is_filtered; }; - void setFilter(LASfilter* filter); + void setFilter(LASfilter* filter); - void setPointSource(U16 value); - void unsetPointSource(); + void setPointSource(U16 value); + void unsetPointSource(); - void transform(LASpoint* point); + void transform(LASpoint* point); - void check_for_overflow() const; + void check_for_overflow() const; - void reset(); + void reset(); + void add_operation(LASoperation* operation); - LAStransform(); - ~LAStransform(); + LAStransform(); + ~LAStransform(); private: - void add_operation(LASoperation* operation); - void delete_operation(const CHAR* name); - U32 num_operations; - U32 alloc_operations; - LASoperation** operations; - BOOL is_filtered; - LASfilter* filter; + void delete_operation(const CHAR* name); + U32 num_operations; + U32 alloc_operations; + LASoperation** operations; + BOOL is_filtered; + LASfilter* filter; }; #endif diff --git a/src/LASlib/laswriter.hpp b/src/LASlib/laswriter.hpp index 5e7a2de..d7c9515 100644 --- a/src/LASlib/laswriter.hpp +++ b/src/LASlib/laswriter.hpp @@ -10,11 +10,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2015, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2015, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -25,6 +25,7 @@ CHANGE HISTORY: + 14 June 2023 -- add tell() to the writers to be able to write copc files 7 September 2018 -- replaced calls to _strdup with calls to the LASCopyString macro 17 August 2017 -- switch on "native LAS 1.4 extension". turns off with '-no_native'. 29 March 2017 -- enable "native LAS 1.4 extension" for LASzip via '-native' @@ -62,6 +63,7 @@ class LASLIB_DLL LASwriter virtual BOOL update_header(const LASheader* header, BOOL use_inventory=FALSE, BOOL update_extra_bytes=FALSE) = 0; virtual I64 close(BOOL update_npoints=TRUE) = 0; + virtual I64 tell() { return 0; }; void dealloc(); diff --git a/src/LASlib/laswriter_las.cpp b/src/LASlib/laswriter_las.cpp index b9cc62f..cf3542b 100644 --- a/src/LASlib/laswriter_las.cpp +++ b/src/LASlib/laswriter_las.cpp @@ -9,11 +9,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2017, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -65,30 +65,26 @@ BOOL LASwriterLAS::open(const char* file_name, const LASheader* header, U32 comp } #ifdef _MSC_VER - file = fopen(file_name, "wb"); + wchar_t* utf16_file_name = UTF8toUTF16(file_name); + file = _wfopen(utf16_file_name, L"wb"); if (file == 0) { - wchar_t* utf16_file_name = UTF8toUTF16(file_name); - file = _wfopen(utf16_file_name, L"wb"); - if (file == 0) - { - REprintf( "ERROR: cannot open file '%ws' for write\n", utf16_file_name); - } - delete [] utf16_file_name; + REprintf("ERROR: cannot open file '%ws' for write\n", utf16_file_name); } + delete[] utf16_file_name; #else file = fopen(file_name, "wb"); #endif if (file == 0) { - REprintf( "ERROR: cannot open file '%s' for write\n", file_name); + REprintf("ERROR: cannot open file '%s' for write\n", file_name); return FALSE; } if (setvbuf(file, NULL, _IOFBF, io_buffer_size) != 0) { - REprintf( "WARNING: setvbuf() failed with buffer size %d\n", io_buffer_size); + REprintf("WARNING: setvbuf() failed with buffer size %d\n", io_buffer_size); } ByteStreamOut* out; @@ -113,7 +109,7 @@ BOOL LASwriterLAS::open(FILE* file, const LASheader* header, U32 compressor, I32 { if(_setmode( _fileno( stdout ), _O_BINARY ) == -1 ) { - REprintf( "ERROR: cannot set stdout to binary (untranslated) mode\n"); + REprintf("ERROR: cannot set stdout to binary (untranslated) mode\n"); } } #endif @@ -1216,6 +1212,19 @@ BOOL LASwriterLAS::update_header(const LASheader* header, BOOL use_inventory, BO } stream->seekEnd(); } + + // COPC EPT hierarchy EVLR is computed and added to the header after the last point is written. + // Therefore, it cannot be added when opening the writer. We use update_header to propagate the EVLR + // just before closing the writer. EVLRs are written when closing. This trick allows us to be COPC + // compatible with minimal changes to the code. + for (i = 0; i < header->number_of_extended_variable_length_records; i++) + { + if ((strcmp(header->evlrs[i].user_id, "copc") == 0) && header->evlrs[i].record_id == 1000) + { + evlrs = header->evlrs; + } + } + return TRUE; } @@ -1247,9 +1256,13 @@ I64 LASwriterLAS::close(BOOL update_npoints) I64 real_start_of_first_extended_variable_length_record = stream->tell(); // write extended variable length records variable after variable (to avoid alignment issues) - + U64 copc_root_hier_size = 0; + U64 copc_root_hier_offset = 0; for (U32 i = 0; i < number_of_extended_variable_length_records; i++) { + if ((strcmp(evlrs[i].user_id, "copc") == 0) && evlrs[i].record_id == 1000) + copc_root_hier_offset = stream->tell() + 60; + // check variable length records contents if (evlrs[i].reserved != 0xAABB) @@ -1303,6 +1316,15 @@ I64 LASwriterLAS::close(BOOL update_npoints) return FALSE; } } + + if ((strcmp(evlrs[i].user_id, "copc") == 0) && evlrs[i].record_id == 1000) + { + copc_root_hier_size = evlrs[i].record_length_after_header; + stream->seek(375 + 54 + 40); + stream->put64bitsLE((U8*)&copc_root_hier_offset); + stream->put64bitsLE((U8*)&copc_root_hier_size); + stream->seekEnd(); + } } if (real_start_of_first_extended_variable_length_record != start_of_first_extended_variable_length_record) @@ -1377,6 +1399,11 @@ I64 LASwriterLAS::close(BOOL update_npoints) return bytes; } +I64 LASwriterLAS::tell() +{ + return stream->tell(); +} + LASwriterLAS::LASwriterLAS() { file = 0; diff --git a/src/LASlib/laswriter_las.hpp b/src/LASlib/laswriter_las.hpp index 8c6ae8a..13ada2a 100644 --- a/src/LASlib/laswriter_las.hpp +++ b/src/LASlib/laswriter_las.hpp @@ -9,11 +9,11 @@ PROGRAMMERS: - martin.isenburg@rapidlasso.com - http://rapidlasso.com + info@rapidlasso.de - https://rapidlasso.de COPYRIGHT: - (c) 2007-2017, martin isenburg, rapidlasso - fast tools to catch reality + (c) 2007-2017, rapidlasso GmbH - fast tools to catch reality This is free software; you can redistribute and/or modify it under the terms of the GNU Lesser General Licence as published by the Free Software @@ -74,6 +74,7 @@ class LASwriterLAS : public LASwriter BOOL update_header(const LASheader* header, BOOL use_inventory=FALSE, BOOL update_extra_bytes=FALSE); I64 close(BOOL update_npoints=TRUE); + I64 tell(); LASwriterLAS(); ~LASwriterLAS(); diff --git a/src/LASzip/lascopc.cpp b/src/LASzip/lascopc.cpp new file mode 100644 index 0000000..9d8e207 --- /dev/null +++ b/src/LASzip/lascopc.cpp @@ -0,0 +1,530 @@ +/* + =============================================================================== + + FILE: lascopc.cpp + + CONTENTS: + + see corresponding header file + + PROGRAMMERS: + + Jean-Romain Roussel + + COPYRIGHT: + + (c) 2023 rapidlasso - fast tools to catch reality + + This is free software; you can redistribute and/or modify it under the + terms of the GNU Lesser General Licence as published by the Free Software + Foundation. See the LICENSE.txt file for more information. + + This software is distributed WITHOUT ANY WARRANTY and without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + CHANGE HISTORY: + + see corresponding header file + + =============================================================================== + */ +#include "lascopc.hpp" + +#ifdef LASZIPDLL_EXPORTS +#include "lasreadpoint.hpp" +#else +#include "lasreader.hpp" +#endif + +#include +#include +#include + +#define MAX(a, b, c) ((a) <= (b)? (b) <= (c)? (c) : (b) : (a) <= (c)? (c) : (a)) // MSVC does not like std::max({a, b, c}) + +EPTkey::EPTkey(I32 d, I32 x, I32 y, I32 z) : d(d), x(x), y(y), z(z) {} +EPTkey::EPTkey() : EPTkey(-1, -1, -1, -1) {} + +std::array EPTkey::get_children() const +{ + std::array children; + for (U8 direction = 0 ; direction < 8 ; direction++) + { + EPTkey key(*this); + + key.d++; + key.x *= 2; + key.y *= 2; + key.z *= 2; + + if (direction & (((U8)1) << 0)) key.x++; + if (direction & (((U8)1) << 1)) key.y++; + if (direction & (((U8)1) << 2)) key.z++; + + children[direction] = key; + } + + return children; +} + +EPTkey EPTkey::get_parent() const +{ + if (!is_valid()) return EPTkey(); + if (d == 0) return EPTkey(); + return EPTkey(d - 1, x >> 1, y >> 1, z >> 1); +} + +EPToctant::EPToctant() +{ + offset.start = 0; + offset.end = 0; + position.start = 0; + position.end = 0; + xmin = 0; + ymin = 0; + zmin = 0; + xmax = 0; + ymax = 0; + zmax = 0; +} + +EPToctant::EPToctant(const LASvlr_copc_entry entry, const F64 xmin, const F64 ymin, const F64 zmin, const F64 xmax, const F64 ymax, const F64 zmax, const U64 start, const U64 end) +{ + d = entry.key.depth; + x = entry.key.x; + y = entry.key.y; + z = entry.key.z; + + // The address range in the file + offset.start = entry.offset; + offset.end = entry.offset + entry.byte_size; + + // The point range in the file + position.start = start; + position.end = end; + + // Step size accounts for depth level + F64 size = MAX(xmax - xmin, ymax - ymin, zmax - zmin); + F64 res = size / std::pow(2, d); + + // Bounding box + this->xmin = res * x + xmin; + this->ymin = res * y + ymin; + this->zmin = res * z + zmin; + this->xmax = this->xmin + res; + this->ymax = this->ymin + res; + this->zmax = this->zmin + res; +} + +EPToctree::EPToctree(const LASheader& header) +{ + if (header.vlr_copc_info) + { + xmin = header.vlr_copc_info->center_x - header.vlr_copc_info->halfsize; + ymin = header.vlr_copc_info->center_y - header.vlr_copc_info->halfsize; + zmin = header.vlr_copc_info->center_z - header.vlr_copc_info->halfsize; + xmax = header.vlr_copc_info->center_x + header.vlr_copc_info->halfsize; + ymax = header.vlr_copc_info->center_y + header.vlr_copc_info->halfsize; + zmax = header.vlr_copc_info->center_z + header.vlr_copc_info->halfsize; + point_spacing = header.vlr_copc_info->spacing; + max_depth = 0; + } + else + { + F64 center_x = (header.min_x + header.max_x)/2; + F64 center_y = (header.min_y + header.max_y)/2; + F64 center_z = (header.min_z + header.max_z)/2; + F64 halfsize = MAX(header.max_x - header.min_x, header.max_y - header.min_y, header.max_z - header.min_z)/2; + + xmin = center_x - halfsize; + ymin = center_y - halfsize; + zmin = center_z - halfsize; + xmax = center_x + halfsize; + ymax = center_y + halfsize; + zmax = center_z + halfsize; + point_spacing = 0; + max_depth = 0; + } + + if (header.vlr_copc_info && header.vlr_copc_entries) + { + registry.reserve(header.number_of_copc_entries); + + U64 ni = 0; + U64 nf = 0; + for (U32 i = 0 ; i < header.number_of_copc_entries ; i++) + { + if (header.vlr_copc_entries[i].point_count > 0) + { + ni = nf; + nf = ni + header.vlr_copc_entries[i].point_count-1; + EPToctant octant(header.vlr_copc_entries[i], xmin, ymin, zmin, xmax, ymax, zmax, ni, nf); + registry[(EPTkey)octant] = octant; + if (octant.d > max_depth) max_depth = octant.d; + nf++; + } + else + { + // Octants with 0 point must be added to be able to reccurse the octree + EPToctant octant(header.vlr_copc_entries[i], xmin, ymin, zmin, xmax, ymax, zmax, 0, 0); + registry[(EPTkey)octant] = octant; + } + } + } +} + +// Static function used to parse and assigned data to the LASheader in LASreaderLAS. The reasons of this function are: +// 1. Keep the copc logic code here, adding minimal modifications in the legacy LASlib/LASzip core code. +// 2. Make sure that the legacy code style (name convention, usage raw pointer and so on) stay unchanged. +// (the LASvlr_copc_entry pointer allocated on heap is deleted by the LASheader) +BOOL EPToctree::set_vlr_entries(const U8* data, const U64 offset_to_first_copc_entry, LASheader& header) +{ + if (!data) return FALSE; + + std::vector page; + std::vector entries; + std::deque child_entries; + LASvlr_copc_entry* payload = (LASvlr_copc_entry*)data; + + // Read the root page + U64 n_root_entries = header.vlr_copc_info->root_hier_size/sizeof(LASvlr_copc_entry); + U64 root_offset = header.vlr_copc_info->root_hier_offset - offset_to_first_copc_entry; + U64 n_entries_before_root = root_offset/sizeof(LASvlr_copc_entry); + page = std::vector(payload + n_entries_before_root, payload + n_entries_before_root + n_root_entries); + + for (size_t j = 0; j < page.size(); j++) + { + if (page[j].point_count >= 0) entries.push_back(page[j]); + else if (page[j].point_count == -1) child_entries.push_back(page[j]); + } + + // Recurse the tree of entries + while (child_entries.size()) + { + LASvlr_copc_entry e = child_entries.front(); + child_entries.pop_front(); + + U64 page_size = e.byte_size; + U64 n_entry = page_size/sizeof(LASvlr_copc_entry); + U64 page_offset = e.offset - offset_to_first_copc_entry; + U64 n_entries_before_page = page_offset/sizeof(LASvlr_copc_entry); + page = std::vector(payload + n_entries_before_page, payload + n_entries_before_page + n_entry); + + for (size_t j = 0; j < page.size(); j++) + { + if (page[j].point_count >= 0) entries.push_back(page[j]); + else if (page[j].point_count == -1) child_entries.push_back(page[j]); + } + } + + std::sort(entries.begin(), entries.end(), [](const LASvlr_copc_entry& e1, const LASvlr_copc_entry& e2) { return e1.offset < e2.offset; }); + + U64 sum = 0; + for (size_t j = 0; j < entries.size(); j++) + sum += entries[j].point_count; + + if (sum != header.extended_number_of_point_records) + { + REprintf("WARNING: COPC EPT hierarchy EVLR number of point does not match with the header.\n"); + return FALSE; + } + + header.number_of_copc_entries = (U32)entries.size(); + header.vlr_copc_entries = new LASvlr_copc_entry[header.number_of_copc_entries]; + for (size_t j = 0; j < header.number_of_copc_entries; j++) + header.vlr_copc_entries[j] = entries[j]; + + return TRUE; +} + +I32 EPToctree::compute_max_depth(const LASheader& header, U64 max_points_per_octant) +{ + // strategy to regulate the maximum depth of the octree + F64 xsize = header.max_x - header.min_x; + F64 ysize = header.max_y - header.min_y; + F64 zsize = header.max_z - header.min_z; + F64 size = MAX(xsize, ysize, zsize); + U64 npts = MAX((U64)header.number_of_point_records, header.extended_number_of_point_records, 0); + I32 max_depth = 0; + + while (npts > max_points_per_octant) + { + if (xsize >= size) { npts /= 2; } + if (ysize >= size) { npts /= 2; } + if (zsize >= size) { npts /= 2; } + size /= 2; + max_depth++; + } + + return max_depth; +} + +EPTkey EPToctree::get_key(const LASpoint* p, const I32 depth) const +{ + I32 grid_size = (I32)std::pow(2, depth); + F64 grid_resolution = (xmax - xmin) / grid_size; + + I32 xi = I32_FLOOR((p->get_x() - xmin) / grid_resolution); + I32 yi = I32_FLOOR((p->get_y() - ymin) / grid_resolution); + I32 zi = I32_FLOOR((p->get_z() - zmin) / grid_resolution); + + if (xi < 0) xi = 0; + if (yi < 0) yi = 0; + if (zi < 0) zi = 0; + if (xi >= grid_size) xi = grid_size - 1; + if (yi >= grid_size) yi = grid_size - 1; + if (zi >= grid_size) zi = grid_size - 1; + + return EPTkey(depth, xi, yi, zi); +} + +I32 EPToctree::get_cell(const LASpoint*p, const EPTkey& key) const +{ + F64 size = get_halfsize()*2; + F64 res = size / (1 << key.d); + + // Bounding box of the octant + F64 minx = res * key.x + (get_center_x() - get_halfsize()); + F64 miny = res * key.y + (get_center_y() - get_halfsize()); + F64 minz = res * key.z + (get_center_z() - get_halfsize()); + F64 maxx = minx + res; + //F64 maxy = miny + res; + //F64 maxz = minz + res; + + // Get cell id in this octant + F64 grid_resolution = (maxx - minx) / grid_size; + I32 xi = (I32)std::floor((p->get_x() - minx) / grid_resolution); + I32 yi = (I32)std::floor((p->get_y() - miny) / grid_resolution); + I32 zi = (I32)std::floor((p->get_z() - minz) / grid_resolution); + xi = (std::min)((std::max)(0, xi), grid_size - 1); + yi = (std::min)((std::max)(0, yi), grid_size - 1); + zi = (std::min)((std::max)(0, zi), grid_size - 1); + + return zi * grid_size * grid_size + yi * grid_size + xi; +} + +COPCindex::COPCindex(const LASheader& header) : EPToctree(header) +{ + start = 0; + end = 0; + current_interval = 0; + have_interval = false; + + r_min_x = F64_MIN; + r_min_y = F64_MIN; + r_min_z = F64_MIN; + r_max_x = F64_MAX; + r_max_y = F64_MAX; + r_max_z = F64_MAX; + q_depth = max_depth; + + sort_octants = &spatial_order; +} + +void COPCindex::set_depth_limit(const I32 depth) +{ + q_depth = (depth < 0) ? max_depth : depth; + query_intervals(); +} + +void COPCindex::set_resolution(const F64 resolution) +{ + q_depth = max_depth; + + if (resolution <= 0.0) + return; + + F64 current_resolution = point_spacing; + for (I32 i = 0; i <= max_depth; i++) + { + if (current_resolution <= resolution) + { + q_depth = i; + break; + } + current_resolution /= 2.0; + } + + query_intervals(); +} + +void COPCindex::intersect_rectangle(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y) +{ + this->r_min_x = r_min_x; + this->r_min_y = r_min_y; + this->r_max_x = r_max_x; + this->r_max_y = r_max_y; + query_intervals(); +} + +void COPCindex::intersect_cuboid(const F64 r_min_x, const F64 r_min_y, const F64 r_min_z, const F64 r_max_x, const F64 r_max_y, const F64 r_max_z) +{ + this->r_min_z = r_min_z; + this->r_max_z = r_max_z; + intersect_rectangle(r_min_x, r_min_y, r_max_x, r_max_y); +} + +void COPCindex::intersect_circle(const F64 center_x, const F64 center_y, const F64 radius) +{ + F64 r_min_x = center_x - radius; + F64 r_min_y = center_y - radius; + F64 r_max_x = center_x + radius; + F64 r_max_y = center_y + radius; + intersect_rectangle(r_min_x, r_min_y, r_max_x, r_max_y); +} + +void COPCindex::intersect_sphere(const F64 center_x, const F64 center_y, const F64 center_z, const F64 radius) +{ + F64 r_min_x = center_x - radius; + F64 r_min_y = center_y - radius; + F64 r_min_z = center_z - radius; + F64 r_max_x = center_x + radius; + F64 r_max_y = center_y + radius; + F64 r_max_z = center_z + radius; + intersect_cuboid(r_min_x, r_min_y, r_min_z, r_max_x, r_max_y, r_max_z); +} + +bool COPCindex::query_intervals() +{ + clear_intervals(); + query_intervals(EPTkey::root()); + std::sort(query.begin(), query.end(), sort_octants); + + for (const EPToctant& oct : query) + { + points_intervals.push_back(oct.position); + offsets_intervals.push_back(oct.offset); + } + merge_intervals(); + return query.size() > 0; +} + +void COPCindex::query_intervals(const EPTkey& key) +{ + auto it = registry.find(key); + if (it != registry.end()) + { + EPToctant const &oct = it->second; + bool inside = !(oct.xmin > r_max_x || oct.xmax < r_min_x || oct.ymin > r_max_y || oct.ymax < r_min_y || oct.zmin > r_max_z || oct.zmax < r_min_z); + bool indepth = oct.d <= q_depth; + if (indepth && inside) + { + if (oct.offset.start > 0) query.push_back(oct); // if start == 0 it is an octant with 0 points + for (EPTkey const &k : key.get_children()) query_intervals(k); // octants with 0 points may have childs with non 0 points + } + } +} + +void COPCindex::merge_intervals() +{ + merge_intervals(points_intervals); + merge_intervals(offsets_intervals); +} + +void COPCindex::merge_intervals(std::vector& x) +{ + if (x.size() < 2) return; + + std::vector ans; + ans.reserve(x.size()/2); + Range prev = x[0]; + + for (U32 i = 1 ; i < x.size() ; i++) + { + Range current = x[i]; + if ((current.start-prev.end) <= 1) + { + prev.end = current.end; + } + else + { + ans.push_back(prev); + prev = current; + } + } + + ans.push_back(prev); + x.swap(ans); +} + +void COPCindex::clear_intervals() +{ + start = 0; + end = 0; + current_interval = 0; + points_intervals.clear(); + offsets_intervals.clear(); + query.clear(); +} + +bool COPCindex::has_intervals() +{ + if (current_interval < points_intervals.size()) + { + start = points_intervals[current_interval].start; + end = points_intervals[current_interval].end; + current_interval++; + have_interval = true; + return true; + } + else + { + have_interval = false; + return false; + } +} + +std::vector COPCindex::get_points_intervals() +{ + if (query.empty()) query_intervals(); + return points_intervals; +} + +std::vector COPCindex::get_offsets_intervals() +{ + if (query.empty()) query_intervals(); + return offsets_intervals; +} + +U64 COPCindex::get_number_of_points() +{ + if (query.empty()) query_intervals(); + + U64 sum = 0; + for (const Range& r : points_intervals) + sum += r.end-r.start+1; + + return sum; +} + +#ifdef LASZIPDLL_EXPORTS +BOOL COPCindex::seek_next(LASreadPoint* reader, I64 &p_count) +{ + if (!have_interval) + { + if (!has_intervals()) return FALSE; + reader->seek((U32)p_count, start); + p_count = start; + } + if (p_count == (I64)end) + { + have_interval = FALSE; + } + return TRUE; +} +#else +BOOL COPCindex::seek_next(LASreader* reader) +{ + if (!have_interval) + { + if (!has_intervals()) return FALSE; + reader->seek(start); + } + if (reader->p_count == (I64)end) + { + have_interval = FALSE; + } + return TRUE; +} +#endif + diff --git a/src/LASzip/lascopc.hpp b/src/LASzip/lascopc.hpp new file mode 100644 index 0000000..26f9196 --- /dev/null +++ b/src/LASzip/lascopc.hpp @@ -0,0 +1,247 @@ +/* + =============================================================================== + + FILE: lascopc.hpp + + CONTENTS: + + Interface to support COPC standard https://copc.io/ + + PROGRAMMERS: + + Jean-Romain Roussel + + COPYRIGHT: + + (c) 2023 rapidlasso - fast tools to catch reality + + This is free software; you can redistribute and/or modify it under the + terms of the GNU Lesser General Licence as published by the Free Software + Foundation. See the LICENSE.txt file for more information. + + This software is distributed WITHOUT ANY WARRANTY and without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + CHANGE HISTORY: + + 17 April 2023 -- created to support copc standard + + =============================================================================== + */ + +#ifndef LAS_COPC_HPP +#define LAS_COPC_HPP + +#include +#include +#include + +#include "lasdefinitions.hpp" +#include "mydefs.hpp" + +#ifdef LASZIPDLL_EXPORTS +class LASreadPoint; +#else +class LASreader; +#endif + +struct Range +{ + U64 start; + U64 end; +}; + +inline bool operator<(const Range& a, const Range& b) { return a.start < b.start; } + +struct EPTkey +{ + EPTkey(); + EPTkey(I32 d, I32 x, I32 y, I32 z); + static EPTkey root() { return EPTkey(0, 0, 0, 0); } + bool is_valid() const { return d >= 0 && x >= 0 && y >= 0 && z >= 0; } + std::array get_children() const; + EPTkey get_parent() const; + + I32 d; + I32 x; + I32 y; + I32 z; +}; + +struct EPTKeyHasher +{ + // PDAL hash method copied + std::size_t operator()(const EPTkey &k) const + { + std::hash h; + U64 k1 = ((U64)k.d << 32) | k.x; + U64 k2 = ((U64)k.y << 32) | k.z; + return h(k1) ^ (h(k2) << 1); + } +}; + +inline bool operator==(const EPTkey& a, const EPTkey& b) { return a.d == b.d && a.x == b.x && a.y == b.y && a.z == b.z; } +inline bool operator!=(const EPTkey& a, const EPTkey& b) { return !(a == b); } +inline bool operator<(const EPTkey& a, const EPTkey& b) +{ + if (a.x < b.x) return true; + if (a.x > b.x) return false; + if (a.y < b.y) return true; + if (a.y > b.y) return false; + if (a.z < b.z) return true; + if (a.z > b.z) return false; + if (a.d < b.d) return true; + if (a.d > b.d) return false; + return false; +} + +struct EPToctant : public EPTkey +{ + EPToctant(); + EPToctant(const LASvlr_copc_entry entry, const F64 xmin, const F64 ymin, const F64 zmin, const F64 xmax, const F64 ymax, const F64 zmax, const U64 start, const U64 end); + + Range offset; // Address in file + Range position; // Point position in file + + // Bounding box of the entry + F64 xmin; + F64 ymin; + F64 zmin; + F64 xmax; + F64 ymax; + F64 zmax; +}; + +inline bool spatial_order(const EPToctant& a, const EPToctant& b) +{ + // 2D spatial order + F64 dx_a = (F64)a.x/(1 << a.d); + F64 dx_b = (F64)b.x/(1 << b.d); + if (dx_a < dx_b) return true; + if (dx_a > dx_b) return false; + + F64 dy_a = (F64)a.y/(1 << a.d); + F64 dy_b = (F64)b.y/(1 << b.d); + if (dy_a < dy_b) return true; + if (dy_a > dy_b) return false; + + if (a.d < b.d) return true; + if (a.d > b.d) return false; + + F64 dz_a = (F64)a.z/(1 << a.d); + F64 dz_b = (F64)b.z/(1 << b.d); + if (dz_a < dz_b) return true; + if (dz_a > dz_b) return false; + + return false; +} + +inline bool depth_order(const EPToctant& a, const EPToctant& b) +{ + if (a.d < b.d) return true; + if (a.d > b.d) return false; + if (a.x < b.x) return true; + if (a.x > b.x) return false; + if (a.y < b.y) return true; + if (a.y > b.y) return false; + if (a.z < b.z) return true; + if (a.z > b.z) return false; + return false; +} + +inline bool file_order(const EPToctant& a, const EPToctant& b) +{ + if (a.offset.start < b.offset.start) return true; + return false; +} + +class EPToctree +{ +public: + EPToctree(const LASheader& header); + static BOOL set_vlr_entries(const U8* data, const U64 offset_to_first_copc_entry, LASheader& header); + static I32 compute_max_depth(const LASheader& header, const U64 max_points_per_octant); + EPTkey get_key(const LASpoint* p, const I32 depth) const; + I32 get_cell(const LASpoint*p, const EPTkey& key) const; + inline I32 get_max_depth() const { return max_depth; }; + inline F64 get_center_x() const { return (xmin+xmax)/2; }; + inline F64 get_center_y() const { return (ymin+ymax)/2; }; + inline F64 get_center_z() const { return (zmin+zmax)/2; }; + inline F64 get_halfsize() const { return (xmax-xmin)/2; }; + inline F64 get_size() const { return xmax-xmin; }; + inline F64 get_xmin() const { return xmin; }; + inline F64 get_ymin() const { return ymin; }; + inline F64 get_zmin() const { return zmin; }; + inline F64 get_xmax() const { return xmax; }; + inline F64 get_ymax() const { return ymax; }; + inline F64 get_zmax() const { return zmax; }; + inline I32 get_gridsize() const { return grid_size; }; + inline void set_gridsize(I32 size) { if (size > 2) grid_size = size; }; + +protected: + F64 xmin; + F64 ymin; + F64 zmin; + F64 xmax; + F64 ymax; + F64 zmax; + F64 point_spacing; + I32 max_depth; + I32 grid_size; + std::unordered_map registry; +}; + +class COPCindex : private EPToctree +{ +public: + COPCindex(const LASheader& header); + void set_depth_limit(const I32 depth); + void set_resolution(const F64 resolution); + void set_stream_ordered_by_chunk() { sort_octants = &file_order; }; + void set_stream_ordered_spatially() { sort_octants = &spatial_order; }; + void set_stream_ordered_by_depth() { sort_octants = &depth_order; }; + void intersect_rectangle(const F64 r_min_x, const F64 r_min_y, const F64 r_max_x, const F64 r_max_y); + void intersect_cuboid(const F64 r_min_x, const F64 r_min_y, const F64 r_min_z, const F64 r_max_x, const F64 r_max_y, const F64 r_max_z); + void intersect_circle(const F64 center_x, const F64 center_y, const F64 radius); + void intersect_sphere(const F64 center_x, const F64 center_y, const F64 center_z, const F64 radius); + std::vector get_points_intervals(); + std::vector get_offsets_intervals(); + U64 get_number_of_points(); + + // seek to next interval +#ifdef LASZIPDLL_EXPORTS + BOOL seek_next(LASreadPoint* reader, I64 &p_count); +#else + BOOL seek_next(LASreader* lasreader); +#endif + +private: + void query_intervals(const EPTkey& key); + void merge_intervals(); + void merge_intervals(std::vector& x); + void clear_intervals(); + bool query_intervals(); + bool has_intervals(); + bool (*sort_octants)(const EPToctant& a, const EPToctant& b); + +private: + F64 r_min_x; + F64 r_min_y; + F64 r_min_z; + F64 r_max_x; + F64 r_max_y; + F64 r_max_z; + I32 q_depth; + + bool have_interval; + I64 start; + I64 end; + U32 current_interval; + std::vector points_intervals; + std::vector offsets_intervals; + std::vector query; +}; + +#endif + + diff --git a/src/Makevars b/src/Makevars index f0ffa1f..72a29e2 100644 --- a/src/Makevars +++ b/src/Makevars @@ -47,6 +47,7 @@ SOURCES = LASlib/lasreader_txt.cpp \ LASzip/lasreadpoint.cpp \ LASzip/integercompressor.cpp \ LASzip/lasinterval.cpp \ + LASzip/lascopc.cpp \ ./altrep_compact_replication.cpp \ ./rlasstreamer.cpp \ ./rlasextrabytesattributes.cpp \ diff --git a/src/Makevars.win b/src/Makevars.win index f0ffa1f..72a29e2 100644 --- a/src/Makevars.win +++ b/src/Makevars.win @@ -47,6 +47,7 @@ SOURCES = LASlib/lasreader_txt.cpp \ LASzip/lasreadpoint.cpp \ LASzip/integercompressor.cpp \ LASzip/lasinterval.cpp \ + LASzip/lascopc.cpp \ ./altrep_compact_replication.cpp \ ./rlasstreamer.cpp \ ./rlasextrabytesattributes.cpp \