diff --git a/src/readheader.cpp b/src/readheader.cpp index 64be0c1..ec58752 100644 --- a/src/readheader.cpp +++ b/src/readheader.cpp @@ -267,146 +267,153 @@ List vlrsreader(LASheader* lasheader) } else if ((strcmp(vlr.user_id, "LASF_Spec") == 0) && (vlr.data != 0)) { - if (vlr.record_id == 4) // ExtraBytes - { - lvlrsnames.push_back("Extra_Bytes"); - lvlrnames.push_back("Extra Bytes Description"); + if (vlr.record_id == 3) // TextArea + { + CHAR* text_area_description = (CHAR*) vlr.data; + lvlr.push_back(std::string(text_area_description, vlr.record_length_after_header)); + lvlrnames.push_back("Text Area Description"); + lvlrsnames.push_back("TextArea"); + } + else if (vlr.record_id == 4) // ExtraBytes + { + lvlrsnames.push_back("Extra_Bytes"); + lvlrnames.push_back("Extra Bytes Description"); + + List ExtraBytes(0); + List ExtraBytesnames(0); - List ExtraBytes(0); - List ExtraBytesnames(0); + for (int j = 0; j < lasheader->number_attributes; j++) + { + LASattribute attemp(lasheader->attributes[j]); - for (int j = 0; j < lasheader->number_attributes; j++) + if (attemp.data_type) { - LASattribute attemp(lasheader->attributes[j]); + int data_type = ((I32)(attemp.data_type)-1)%10; + //int dim = ((I32)(attemp.data_type)-1)/10+1; + + List ExtraByte(0); + List ExtraBytenames(0); + ExtraByte.push_back(((I16*)(attemp.reserved))[0]); + ExtraBytenames.push_back("reserved"); + ExtraByte.push_back((I32)(attemp.data_type)); + ExtraBytenames.push_back("data_type"); + ExtraByte.push_back((I32)(attemp.options)); + ExtraBytenames.push_back("options"); + ExtraByte.push_back(attemp.name); + ExtraBytenames.push_back("name"); + + // 2 and 3 dimensional arrays are deprecated in LASlib + // (see https://github.com/LAStools/LAStools/blob/master/LASlib/example/lasexample_write_only_with_extra_bytes.cpp) + double scale = 1.0; + if(attemp.has_scale()) + { + scale = attemp.scale[0]; + ExtraByte.push_back(scale); + ExtraBytenames.push_back("scale"); + } + + double offset = 0.0; + if(attemp.has_offset()) + { + offset = attemp.offset[0]; + ExtraByte.push_back(offset); + ExtraBytenames.push_back("offset"); + } - if (attemp.data_type) + if (data_type < 8) { - int data_type = ((I32)(attemp.data_type)-1)%10; - //int dim = ((I32)(attemp.data_type)-1)/10+1; - - List ExtraByte(0); - List ExtraBytenames(0); - ExtraByte.push_back(((I16*)(attemp.reserved))[0]); - ExtraBytenames.push_back("reserved"); - ExtraByte.push_back((I32)(attemp.data_type)); - ExtraBytenames.push_back("data_type"); - ExtraByte.push_back((I32)(attemp.options)); - ExtraBytenames.push_back("options"); - ExtraByte.push_back(attemp.name); - ExtraBytenames.push_back("name"); - - // 2 and 3 dimensional arrays are deprecated in LASlib - // (see https://github.com/LAStools/LAStools/blob/master/LASlib/example/lasexample_write_only_with_extra_bytes.cpp) - double scale = 1.0; - if(attemp.has_scale()) + I64* temp; // as R does not support long long int it is converted to double + + if (attemp.has_no_data()) + { + temp = ((I64*)(attemp.no_data)); + ExtraByte.push_back(*temp); + ExtraBytenames.push_back("no_data"); + } + + if (attemp.has_min()) + { + temp = ((I64*)(attemp.min)); + ExtraByte.push_back(*temp*scale+offset); + ExtraBytenames.push_back("min"); + } + + if (attemp.has_max()) { - scale = attemp.scale[0]; - ExtraByte.push_back(scale); - ExtraBytenames.push_back("scale"); + temp = ((I64*)(attemp.max)); + ExtraByte.push_back(*temp*scale+offset); + ExtraBytenames.push_back("max"); } + } + else + { + F64* temp; - double offset = 0.0; - if(attemp.has_offset()) + if (attemp.has_no_data()) { - offset = attemp.offset[0]; - ExtraByte.push_back(offset); - ExtraBytenames.push_back("offset"); + temp = ((F64*)(attemp.no_data)); + ExtraByte.push_back(*temp*scale+offset); + ExtraBytenames.push_back("no_data"); } - if (data_type < 8) + if (attemp.has_min()) { - I64* temp; // as R does not support long long int it is converted to double - - if (attemp.has_no_data()) - { - temp = ((I64*)(attemp.no_data)); - ExtraByte.push_back(*temp); - ExtraBytenames.push_back("no_data"); - } - - if (attemp.has_min()) - { - temp = ((I64*)(attemp.min)); - ExtraByte.push_back(*temp*scale+offset); - ExtraBytenames.push_back("min"); - } - - if (attemp.has_max()) - { - temp = ((I64*)(attemp.max)); - ExtraByte.push_back(*temp*scale+offset); - ExtraBytenames.push_back("max"); - } + temp = ((F64*)(attemp.min)); + ExtraByte.push_back(*temp*scale+offset); + ExtraBytenames.push_back("min"); } - else + + if (attemp.has_max()) { - F64* temp; - - if (attemp.has_no_data()) - { - temp = ((F64*)(attemp.no_data)); - ExtraByte.push_back(*temp*scale+offset); - ExtraBytenames.push_back("no_data"); - } - - if (attemp.has_min()) - { - temp = ((F64*)(attemp.min)); - ExtraByte.push_back(*temp*scale+offset); - ExtraBytenames.push_back("min"); - } - - if (attemp.has_max()) - { - temp = ((F64*)(attemp.max)); - ExtraByte.push_back(*temp*scale+offset); - ExtraBytenames.push_back("max"); - } + temp = ((F64*)(attemp.max)); + ExtraByte.push_back(*temp*scale+offset); + ExtraBytenames.push_back("max"); } + } - // Fix #53 - int len = 0 ; while(len < 32 && attemp.description[len] != '\0') len++; - std::string desc; - desc.resize(len); - memcpy(&desc[0], &attemp.description, len); + // Fix #53 + int len = 0 ; while(len < 32 && attemp.description[len] != '\0') len++; + std::string desc; + desc.resize(len); + memcpy(&desc[0], &attemp.description, len); - ExtraByte.push_back(desc); - ExtraBytenames.push_back("description"); + ExtraByte.push_back(desc); + ExtraBytenames.push_back("description"); - ExtraByte.names() = ExtraBytenames; - ExtraBytes.push_back(ExtraByte); - ExtraBytesnames.push_back(attemp.name); - } - else - { - Rcout << "extra byte " << j << " undocumented: dropped" << std::endl; - } + ExtraByte.names() = ExtraBytenames; + ExtraBytes.push_back(ExtraByte); + ExtraBytesnames.push_back(attemp.name); + } + else + { + Rcout << "extra byte " << j << " undocumented: dropped" << std::endl; } - - ExtraBytes.names() = ExtraBytesnames; - lvlr.push_back(ExtraBytes); - } - else if (vlr.record_id >= 100 && vlr.record_id < 355) // FWF - { - LASvlr_wave_packet_descr* vlr_wave_packet_descr = (LASvlr_wave_packet_descr*) vlr.data; - - List FWF = List::create( - Named("Bits per sample") = (U32)(vlr_wave_packet_descr->getBitsPerSample()), - Named("Waveform compression type") = (U32)(vlr_wave_packet_descr->getCompressionType()), - Named("Number of sample") = vlr_wave_packet_descr->getNumberOfSamples(), - Named("Temporal Spacing") = vlr_wave_packet_descr->getTemporalSpacing(), - Named("Digitizer Gain") = vlr_wave_packet_descr->getDigitizerGain(), - Named("Digitizer Offset") = vlr_wave_packet_descr->getDigitizerOffset()); - - lvlrsnames.push_back("Full WaveForm Description"); - lvlrnames.push_back("Full WaveForm"); - lvlr.push_back(FWF); - } - else - { - // not supported yet - lvlrsnames.push_back(vlr.user_id); } + + ExtraBytes.names() = ExtraBytesnames; + lvlr.push_back(ExtraBytes); + } + else if (vlr.record_id >= 100 && vlr.record_id < 355) // FWF + { + LASvlr_wave_packet_descr* vlr_wave_packet_descr = (LASvlr_wave_packet_descr*) vlr.data; + + List FWF = List::create( + Named("Bits per sample") = (U32)(vlr_wave_packet_descr->getBitsPerSample()), + Named("Waveform compression type") = (U32)(vlr_wave_packet_descr->getCompressionType()), + Named("Number of sample") = vlr_wave_packet_descr->getNumberOfSamples(), + Named("Temporal Spacing") = vlr_wave_packet_descr->getTemporalSpacing(), + Named("Digitizer Gain") = vlr_wave_packet_descr->getDigitizerGain(), + Named("Digitizer Offset") = vlr_wave_packet_descr->getDigitizerOffset()); + + lvlrsnames.push_back("Full WaveForm Description"); + lvlrnames.push_back("Full WaveForm"); + lvlr.push_back(FWF); + } + else + { + // not supported yet + lvlrsnames.push_back(vlr.user_id); + } } else { @@ -490,7 +497,14 @@ List evlrsreader(LASheader* lasheader) } else if ((strcmp(vlr.user_id, "LASF_Spec") == 0) && (vlr.data != 0)) { - if (vlr.record_id == 4) // ExtraBytes + if (vlr.record_id == 3) // TextArea + { + CHAR* text_area_description = (CHAR*) vlr.data; + lvlr.push_back(std::string(text_area_description, vlr.record_length_after_header)); + lvlrnames.push_back("Text Area Description"); + lvlrsnames.push_back("TextArea"); + } + else if (vlr.record_id == 4) // ExtraBytes { lvlrsnames.push_back("Extra_Bytes"); lvlrnames.push_back("Extra Bytes Description"); diff --git a/src/writeLAS.cpp b/src/writeLAS.cpp index 3e8ae2f..8f2e3f3 100644 --- a/src/writeLAS.cpp +++ b/src/writeLAS.cpp @@ -172,6 +172,41 @@ void C_writer(CharacterVector file, List LASheader, List data) ExtraByte.start = header.get_attribute_start(ExtraByte.id); } } + else if (names[i] == "TextArea") + { + if (vlr.containsElementNamed("Text Area Description")) + { + CharacterVector TEXT = vlr["Text Area Description"]; + std::string stext = as(TEXT); + CharacterVector desc = vlr["description"]; + std::string sdesc = as(desc); + I32 stext_size = stext.size(); + + // truncate strings larger than U16_MAX, and ensure it is null terminated + if ((sizeof(CHAR)*stext_size) >= U16_MAX) + { + stext_size = U16_MAX; + stext[stext_size-1]='\0'; + } + + // ensure that any text area description is null terminated. + I32 null_terminator = 0; + CHAR* vlr_text_area_desc; + if (stext[stext_size-1] == '\0') + { + vlr_text_area_desc = new CHAR[stext_size]; + } + else + { + null_terminator = 1; + vlr_text_area_desc = new CHAR[stext_size+1]; + vlr_text_area_desc[stext_size] = '\0'; + } + memcpy(vlr_text_area_desc, stext.c_str(), sizeof(CHAR)*stext_size); + + header.add_vlr("LASF_Spec", 3, (U16)(sizeof(CHAR)*(stext_size+null_terminator)), (U8*)vlr_text_area_desc, FALSE, sdesc.c_str()); + } + } else { }