26 #include <QCoreApplication>
32 #include <laspoint.hpp>
33 #include <lasreader_las.hpp>
34 #include <laswriter_las.hpp>
37 #include <ui_saveLASFileDlg.h>
53 CVLog::Warning(QString(
"Extra field '%1' renamed '%2' to comply to "
63 typedef QSharedPointer<ExtraLasField>
Shared;
78 static_cast<uint16_t
>(2 + 16 + 2 + 2 + 32);
83 buffer.resize(bufferSize);
84 if (buffer.size() == bufferSize) {
85 char* bufferData = buffer.data();
87 *(uint16_t*)bufferData = vlr.reserved;
90 for (
int j = 0; j < 16; ++j, ++bufferData) *bufferData = vlr.user_id[j];
92 *(uint16_t*)bufferData = vlr.record_id;
95 *(uint16_t*)bufferData = vlr.record_length_after_header;
98 for (
int j = 0; j < 32; ++j, ++bufferData)
99 *bufferData = vlr.description[j];
102 vlr.record_length_after_header);
116 const char* bufferData = buffer.data();
118 vlr.reserved = *(
const uint16_t*)bufferData;
121 for (
int j = 0; j < 16; ++j, ++bufferData) vlr.user_id[j] = *bufferData;
123 vlr.record_id = *(
const uint16_t*)bufferData;
126 vlr.record_length_after_header = *(
const uint16_t*)bufferData;
130 if (vlr.record_length_after_header != buffer.size() -
VLR_HEADER_SIZE) {
136 for (
int j = 0; j < 32; ++j, ++bufferData) vlr.description[j] = *bufferData;
139 vlr.data =
new U8[vlr.record_length_after_header];
145 memcpy_s(vlr.data, vlr.record_length_after_header,
151 class LASSaveDlg :
public QDialog,
public Ui::SaveLASFileDialog {
154 : QDialog(parent),
Ui::SaveLASFileDialog() {
159 evlrListWidget->clear();
160 extraFieldGroupBox->setEnabled(
false);
161 extraFieldGroupBox->setChecked(
false);
165 QListWidgetItem* item =
new QListWidgetItem(description);
166 evlrListWidget->addItem(item);
168 item->setSelected(
true);
170 extraFieldGroupBox->setEnabled(
true);
171 extraFieldGroupBox->setChecked(
false);
175 if (!extraFieldGroupBox->isChecked())
return false;
177 QListWidgetItem* item = evlrListWidget->item(
static_cast<int>(index));
178 return item && item->isSelected();
185 QStringList{
"las",
"laz"},
"las",
191 bool& exclusive)
const {
204 if (!entity ||
filename.isEmpty()) {
211 "[LAS_FWF] This filter can only save one cloud at a time!");
216 bool hasFWF = cloud->
hasFWF();
230 fi.absolutePath() +
"/" + fi.completeBaseName() +
".wdp";
231 QFile fwfFile(fwFilename);
232 if (fwfFile.open(QFile::WriteOnly)) {
234 uint16_t reserved = 0;
235 fwfFile.write((
const char*)&reserved, 2);
237 char userID[16] = {0};
238 strcpy(userID,
"LASF_Spec");
239 fwfFile.write(userID, 16);
241 uint16_t recordID = 65535;
242 fwfFile.write((
const char*)&recordID, 2);
247 uint64_t recordLength = data->size();
248 fwfFile.write((
const char*)&recordLength, 8);
250 char description[32] = {0};
251 strcpy(description,
"WAVEFORM DATA PACKETS");
252 fwfFile.write(description, 32);
255 fwfFile.write((
const char*)data->data(), data->size());
258 if (fwfFile.error() != QFile::NoError) {
260 "writing the FWF data file!\n(%1)")
264 CVLog::Print(QString(
"[LAS_FWF] FWF data file written: %1")
270 std::vector<LasField> fieldsToSave;
271 uint8_t minPointFormat = 0;
275 std::vector<ExtraLasField> extraFieldsToSave;
282 bool standardField =
false;
283 for (
const LasField& lf : fieldsToSave) {
285 standardField =
true;
290 if (!standardField) {
292 extraFieldsToSave.emplace_back(
308 bool hasScaleMetaData =
false;
311 .toDouble(&hasScaleMetaData);
312 if (hasScaleMetaData) {
314 .toDouble(&hasScaleMetaData);
315 if (hasScaleMetaData) {
317 .toDouble(&hasScaleMetaData);
321 bool hasOffsetMetaData =
false;
324 .toDouble(&hasOffsetMetaData);
325 if (hasOffsetMetaData) {
327 .toDouble(&hasOffsetMetaData);
328 if (hasOffsetMetaData) {
330 .toDouble(&hasOffsetMetaData);
335 if (!hasOffsetMetaData && isShifted) {
339 hasOffsetMetaData =
true;
349 lasheader.x_offset = lasOffset.
x;
350 lasheader.y_offset = lasOffset.
y;
351 lasheader.z_offset = lasOffset.
z;
361 CCVector3d optimalScale(1.0e-9 * std::max<double>(diag.
x, 1.0),
362 1.0e-9 * std::max<double>(diag.
y, 1.0),
363 1.0e-9 * std::max<double>(diag.
z, 1.0));
365 bool canUseOriginalScale =
false;
366 if (hasScaleMetaData) {
368 canUseOriginalScale = (lasScale.
x >= optimalScale.
x &&
369 lasScale.
y >= optimalScale.
y &&
370 lasScale.
z >= optimalScale.
z);
381 maxScale = pow(10.0, n);
382 optimalScale.
x = optimalScale.
y = optimalScale.
z = maxScale;
387 static QSharedPointer<LASSaveDlg>
s_saveDlg(
nullptr);
391 QString(
"(%1, %2, %3)")
394 .arg(optimalScale.
z));
396 if (hasScaleMetaData) {
397 QString text = QString(
"(%1, %2, %3)")
401 if (!canUseOriginalScale) {
402 text +=
"[too small]";
404 s_saveDlg->origAccuracyLabel->setText(text);
406 s_saveDlg->origAccuracyLabel->setText(
"none");
409 if (!canUseOriginalScale) {
410 if (
s_saveDlg->origRadioButton->isChecked())
411 s_saveDlg->bestRadioButton->setChecked(
true);
412 s_saveDlg->origRadioButton->setEnabled(
false);
422 if (
s_saveDlg->bestRadioButton->isChecked()) {
423 lasScale = optimalScale;
424 }
else if (
s_saveDlg->customRadioButton->isChecked()) {
425 double s =
s_saveDlg->customScaleDoubleSpinBox->value();
433 size_t evlrIndex = 0;
434 for (
size_t i = 0; i < extraFieldsToSave.size(); ++i) {
438 extraFieldsToSave[evlrIndex] =
439 extraFieldsToSave[i];
443 extraFieldsToSave.resize(
445 }
else if (!hasScaleMetaData) {
446 lasScale = optimalScale;
449 lasheader.x_scale_factor = lasScale.
x;
450 lasheader.y_scale_factor = lasScale.
y;
451 lasheader.z_scale_factor = lasScale.
z;
454 minPointFormat, hasColors, hasFWF,
457 lasheader.point_data_format = minPointFormat;
458 lasheader.version_minor =
460 if (lasheader.version_minor == 4) {
463 lasheader.header_size += 148;
464 lasheader.offset_to_point_data += 148;
466 lasheader.point_data_record_length =
468 lasheader.point_data_format);
473 lasheader.start_of_waveform_data_packet_record = 0;
474 lasheader.global_encoding |= ((
U16)4);
486 for (ccPointCloud::FWFDescriptorSet::const_iterator it =
489 LASvlr_wave_packet_descr* d =
new LASvlr_wave_packet_descr;
492 static_cast<U8
>(it.value().bitsPerSample));
493 d->setCompressionType(
static_cast<U8
>(0));
495 static_cast<F64
>(it.value().digitizerGain));
496 d->setDigitizerOffset(
497 static_cast<F64
>(it.value().digitizerOffset));
498 d->setNumberOfSamples(
499 static_cast<F64
>(it.value().numberOfSamples));
500 d->setTemporalSpacing(
501 static_cast<U32>(it.value().samplingRate_ps));
505 lasheader.add_vlr(
"LASF_Spec",
506 99 +
static_cast<U16>(it.key()), 26,
507 (U8*)d,
FALSE,
"Waveform descriptor");
515 if (!buffer.isEmpty()) {
519 vlr.record_length_after_header,
520 vlr.data,
FALSE, vlr.description);
526 "[LAS_FWF] Invalid projection VLR meta-data. Can't "
527 "restore Coordinate Reference System.");
536 LASattribute attribute(
537 f.isShifted ||
sizeof(ScalarType) == 8
540 qPrintable(f.sanitizedName),
541 "additional attributes");
542 lasheader.point_data_record_length +=
543 (attribute.data_type == LAS_ATTRIBUTE_F32 + 1
547 I32 attributeIndex = lasheader.add_attribute(attribute);
549 lasheader.get_attribute_start(attributeIndex);
565 if (!extraFieldsToSave.empty()) {
566 lasheader.update_extra_bytes_vlr(
TRUE);
573 if (!laspoint.init(&lasheader, lasheader.point_data_format,
574 lasheader.point_data_record_length, 0)) {
579 LASwriterLAS laswriter;
580 bool useLAZ = QFileInfo(
filename).suffix().toUpper().endsWith(
'Z');
581 if (!laswriter.open(qUtf8Printable(
filename), &lasheader,
582 useLAZ ? LASZIP_COMPRESSOR_LAYERED_CHUNKED
583 : LASZIP_COMPRESSOR_NONE)) {
588 QScopedPointer<ecvProgressDialog> progressDialog(0);
590 progressDialog.reset(
592 progressDialog->setWindowTitle(QObject::tr(
"Export LAS file"));
593 progressDialog->setLabelText(
594 QObject::tr(
"Points: %1").arg(cloud->
size()));
595 progressDialog->show();
596 QCoreApplication::processEvents();
601 bool hasReturnNumberField =
false;
602 bool hasPlainClassificationField =
false;
603 for (
const LasField& f : fieldsToSave) {
605 hasReturnNumberField =
true;
607 hasPlainClassificationField =
true;
611 for (
unsigned i = 0; i < cloud->
size(); ++i) {
619 static_cast<U32>(P->
x / lasheader.x_scale_factor));
621 static_cast<U32>(P->
y / lasheader.y_scale_factor));
623 static_cast<U32>(P->
z / lasheader.z_scale_factor));
627 static_cast<U32>((Pglobal.
x - lasheader.x_offset) /
628 lasheader.x_scale_factor));
630 static_cast<U32>((Pglobal.
y - lasheader.y_offset) /
631 lasheader.y_scale_factor));
633 static_cast<U32>((Pglobal.
z - lasheader.z_offset) /
634 lasheader.z_scale_factor));
638 U8 classification = 0;
639 bool compositeClassif =
false;
640 for (std::vector<LasField>::const_iterator it =
641 fieldsToSave.begin();
642 it != fieldsToSave.end(); ++it) {
651 laspoint.set_intensity(
652 static_cast<U16>(it->sf->getValue(i)));
655 laspoint.set_return_number(
656 static_cast<U8
>(it->sf->getValue(i)));
659 laspoint.set_number_of_returns(
660 static_cast<U8
>(it->sf->getValue(i)));
663 laspoint.set_scan_direction_flag(
664 static_cast<U8
>(it->sf->getValue(i)));
667 laspoint.set_edge_of_flight_line(
668 static_cast<U8
>(it->sf->getValue(i)));
671 laspoint.set_classification(
672 static_cast<U8
>(it->sf->getValue(i)));
675 laspoint.set_scan_angle_rank(
676 static_cast<U8
>(it->sf->getValue(i)));
679 laspoint.set_user_data(
680 static_cast<U8
>(it->sf->getValue(i)));
683 laspoint.set_point_source_ID(
684 static_cast<U16>(it->sf->getValue(i)));
692 laspoint.set_gps_time(
693 static_cast<F64
>(it->sf->getValue(i)) +
694 it->sf->getGlobalShift());
698 (
static_cast<U8
>(it->sf->getValue(i)) &
700 compositeClassif =
true;
704 (
static_cast<U8
>(it->sf->getValue(i)) &
706 compositeClassif =
true;
710 (
static_cast<U8
>(it->sf->getValue(i)) &
712 compositeClassif =
true;
716 (
static_cast<U8
>(it->sf->getValue(i)) &
718 compositeClassif =
true;
727 if (compositeClassif && !hasPlainClassificationField) {
728 laspoint.set_classification(classification);
734 laspoint.set_R(
static_cast<U16>(rgb.
r) << 8);
735 laspoint.set_G(
static_cast<U16>(rgb.
g) << 8);
736 laspoint.set_B(
static_cast<U16>(rgb.
b) << 8);
743 laspoint.wavepacket.setIndex(
745 laspoint.wavepacket.setLocation(
747 laspoint.wavepacket.setOffset(
750 laspoint.wavepacket.setSize(
752 laspoint.wavepacket.setXt(
static_cast<F32
>(w.
beamDir().
x));
753 laspoint.wavepacket.setYt(
static_cast<F32
>(w.
beamDir().
y));
754 laspoint.wavepacket.setZt(
static_cast<F32
>(w.
beamDir().
z));
756 if (!hasReturnNumberField) {
758 laspoint.set_return_number(
762 if (!hasReturnNumberField) {
763 laspoint.set_return_number(0);
770 ScalarType s = f.sf->getValue(i);
772 double sd = s + f.sf->getGlobalShift();
773 laspoint.set_attribute(f.startIndex, sd);
775 laspoint.set_attribute(f.startIndex, s);
780 laswriter.write_point(&laspoint);
783 laswriter.update_inventory(&laspoint);
798 }
catch (
const std::bad_alloc&) {
810 unsigned currentCount,
811 ScalarType defaultValue = 0) {
824 qPrintable(
static_cast<ExtraLasField*
>(lasField)->fieldName));
831 CVLog::Warning(QString(
"[LAS] Not enough memory to load a field: '%1'")
840 for (
unsigned i = 0; i < currentCount; ++i) {
854 bool ignoreDefaultFields =
true;
857 LASreaderLAS lasreader;
858 if (!lasreader.open(qUtf8Printable(
filename))) {
863 unsigned pointCount =
static_cast<unsigned>(lasreader.npoints);
865 QObject::tr(
"Reading %1 points").arg(pointCount)));
868 QScopedPointer<ecvProgressDialog> progressDialog(0);
870 progressDialog.reset(
872 progressDialog->setWindowTitle(QObject::tr(
"Import LAS file"));
873 progressDialog->setLabelText(
874 QObject::tr(
"Points: %1").arg(pointCount));
875 progressDialog->setRange(
882 progressDialog->show();
883 QCoreApplication::processEvents();
889 unsigned pointsRead = 0;
894 if (!cloud->
reserve(pointCount)) {
901 bool ignoreColors =
false;
902 bool hasColors =
false;
903 bool hasColorsAboveZero =
false;
905 uint64_t fwfDataOffset = 0;
909 std::vector<LasField::Shared> fieldsToLoad;
949 for (I32 i = 0; i < lasreader.header.number_attributes; ++i) {
950 const LASattribute& attribute = lasreader.header.attributes[i];
953 field->
isShifted = (attribute.data_type == 10);
957 bool hasFWF = (lasreader.header.vlr_wave_packet_descr != 0);
958 for (
int fakeIteration = 0; hasFWF && fakeIteration < 1;
962 }
catch (
const std::bad_alloc&) {
964 "Not enough memory to import the waveform data"));
971 uint64_t fwfDataCount = 0;
972 if (lasreader.header.start_of_waveform_data_packet_record != 0) {
974 assert(lasreader.header.global_encoding & 2);
976 fwfDataSource.setFileName(
filename);
977 if (!fwfDataSource.open(QFile::ReadOnly)) {
979 QString(
"Failed to read the associated waveform "
985 if (!fwfDataSource.seek(
987 .start_of_waveform_data_packet_record)) {
989 QString(
"Failed to find the associated waveform "
990 "data packets header"));
994 QByteArray evlrHeader = fwfDataSource.read(60);
995 if (evlrHeader.size() < 60) {
997 QString(
"Failed to read the associated waveform "
1004 unsigned short reserved =
1005 *
reinterpret_cast<const unsigned short*
>(
1006 evlrHeader.constData() + 0);
1009 unsigned short recordID =
1010 *
reinterpret_cast<const unsigned short*
>(
1011 evlrHeader.constData() + 18);
1012 assert(recordID == 65535);
1013 fwfDataCount = *
reinterpret_cast<const uint64_t*
>(
1014 evlrHeader.constData() +
1016 if (fwfDataCount == 0) {
1018 "Invalid waveform data packet size (0). We'll load "
1019 "all the remaining part of the file!"));
1020 fwfDataCount = fwfDataSource.size() - fwfDataSource.pos();
1027 wdpFilename.replace(QFileInfo(
filename).suffix(),
"wdp");
1028 fwfDataSource.setFileName(wdpFilename);
1029 if (!fwfDataSource.open(QFile::ReadOnly)) {
1031 QString(
"Failed to read the associated waveform "
1032 "data packets file (looking for '%1')")
1039 fwfDataCount = fwfDataSource.size();
1041 if (fwfDataCount > 60) {
1042 QByteArray evlrHeader = fwfDataSource.read(60);
1043 const char* userID =
reinterpret_cast<const char*
>(
1044 evlrHeader.constData() +
1046 if (strncmp(userID,
"LASF_Spec", 9) == 0) {
1049 fwfDataOffset += 60;
1052 fwfDataSource.seek(0);
1058 if (fwfDataSource.isOpen() && fwfDataCount != 0) {
1062 container->resize(fwfDataCount);
1063 }
catch (
const std::bad_alloc&) {
1065 "Not enough memory to import the waveform data"));
1072 fwfDataSource.read((
char*)container->data(), fwfDataCount);
1073 fwfDataSource.close();
1081 lasreader.header.y_scale_factor,
1082 lasreader.header.z_scale_factor);
1084 lasreader.header.y_offset,
1085 lasreader.header.z_offset);
1094 for (
size_t pointIndex = 0; lasreader.read_point(); ++pointIndex) {
1095 const LASpoint&
point = lasreader.point;
1102 if (hasFWF &&
point.have_wavepacket) {
1105 U8 packetIndex =
point.wavepacket.getIndex();
1107 LASvlr_wave_packet_descr* descriptor =
1109 .vlr_wave_packet_descr[packetIndex];
1113 descriptor->getNumberOfSamples();
1121 descriptor->getDigitizerOffset();
1123 descriptor->getTemporalSpacing();
1131 point.wavepacket.getOffset() - fwfDataOffset,
1132 point.wavepacket.getSize());
1134 point.wavepacket.getYt(),
1135 point.wavepacket.getZt()));
1141 if (cloud->
size() == 0)
1146 bool useLasShift =
false;
1148 if (lasShift.
norm2() != 0 &&
1160 bool preserveCoordinateShift =
true;
1162 parameters, useLasShift)) {
1163 if (preserveCoordinateShift) {
1167 "[LAS] Cloud has been recentered! Translation: "
1168 "(%.2f ; %.2f ; %.2f)",
1169 Pshift.
x, Pshift.
y, Pshift.
z);
1177 if (!ignoreColors) {
1179 U16 mergedColorComp =
1181 if (mergedColorComp != 0) {
1186 "[LAS] Not enough memory to load RGB "
1188 ignoreColors =
true;
1190 for (
unsigned i = 0; i < cloud->
size(); ++i) {
1199 if (colorBitDec == 0) {
1200 U16 mergedColorComp =
1202 if (mergedColorComp > 255) {
1210 for (
unsigned i = 0; i < cloud->
size(); ++i) {
1218 static_cast<unsigned char>(
1219 (
point.rgb[0] >> colorBitDec) & 255),
1220 static_cast<unsigned char>(
1221 (
point.rgb[1] >> colorBitDec) & 255),
1222 static_cast<unsigned char>(
1223 (
point.rgb[2] >> colorBitDec) & 255));
1232 switch (field->type) {
1234 value =
static_cast<double>(
point.get_intensity());
1237 value =
static_cast<double>(
point.get_return_number());
1240 value =
static_cast<double>(
1241 point.get_number_of_returns());
1244 value =
static_cast<double>(
1245 point.get_scan_direction_flag());
1248 value =
static_cast<double>(
1249 point.get_edge_of_flight_line());
1252 value =
static_cast<double>(
point.get_classification());
1255 value =
static_cast<double>(
1256 point.get_scan_angle_rank());
1259 value =
static_cast<double>(
point.get_user_data());
1262 value =
static_cast<double>(
1263 point.get_point_source_ID());
1266 value =
point.get_gps_time();
1270 value -= field->sf->getGlobalShift();
1274 value =
static_cast<double>(
point.get_classification() &
1278 value =
static_cast<double>(
point.get_classification() &
1282 value =
static_cast<double>(
point.get_classification() &
1286 value =
static_cast<double>(
point.get_classification() &
1290 value =
point.get_attribute_as_float(
1300 ScalarType s =
static_cast<ScalarType
>(value);
1301 field->sf->addElement(s);
1304 if (cloud->
size() == 0) {
1305 field->firstValue = value;
1308 if (!ignoreDefaultFields || value != field->firstValue ||
1309 (field->firstValue != field->defaultValue &&
1310 field->firstValue >= field->minValue)) {
1312 cloud->
size(), field->firstValue)) {
1319 field->sf->setGlobalShift(field->firstValue);
1320 value -= field->firstValue;
1322 "[LAS] Time SF has been shifted to "
1323 "prevent a loss of accuracy (%.2f)",
1325 field->firstValue = 0;
1328 ScalarType s =
static_cast<ScalarType
>(value);
1329 field->sf->addElement(s);
1332 QString(
"[LAS] Not enough memory: '%1' "
1333 "field will be ignored!")
1335 field->sf->release();
1350 for (uint32_t i = 0;
1351 i < lasreader.header.number_of_variable_length_records; ++i) {
1352 const LASvlr& vlr = lasreader.header.vlrs[i];
1356 if (buffer.size() != 0) {
1360 "[LAS] Failed to save projection information (not "
1375 if (cloud->
size() == 0) {
1381 field->sf->release();
1392 field->sf->computeMinAndMax();
1401 int cMin =
static_cast<int>(field->sf->getMin());
1402 int cMax =
static_cast<int>(field->sf->getMax());
1403 field->sf->setColorRampSteps(
1404 std::min<int>(cMax - cMin + 1, 256));
1408 field->sf->setColorScale(
1420 field->sf->release();
1424 QString(
"[LAS] All '%1' values were the same (%2)! "
1425 "We ignored them...")
1430 .arg(field->firstValue));
1440 }
catch (
const std::bad_alloc&) {
Vector3Tpl< float > CCVector3f
Float 3D Vector.
Vector3Tpl< double > CCVector3d
Double 3D Vector.
float PointCoordinateType
Type of the coordinates of a (N-D) point.
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
CC_FILE_ERROR
Typical I/O filter errors.
@ CC_FERR_CANCELED_BY_USER
@ CC_FERR_THIRD_PARTY_LIB_FAILURE
@ CC_FERR_BAD_ENTITY_TYPE
@ CC_FERR_NOT_ENOUGH_MEMORY
static QByteArray ToQByteArray(const LASvlr &vlr)
bool PrepareLASField(ccScalarField *&sf, LasField *lasField, unsigned totalCount, unsigned currentCount, ScalarType defaultValue=0)
static const uint16_t VLR_HEADER_SIZE
VLR buffer header size (in bytes)
static bool FromQByteArray(const QByteArray &buffer, LASvlr &vlr)
static const char ProjectionVLR[]
Projection VLR.
static const char LAS_OFFSET_X_META_DATA[]
static const char LAS_SCALE_X_META_DATA[]
const char LAS_FIELD_NAMES[][28]
static const char LAS_OFFSET_Y_META_DATA[]
static const char LAS_SCALE_Z_META_DATA[]
static const char LAS_SCALE_Y_META_DATA[]
static const char LAS_OFFSET_Z_META_DATA[]
QSharedPointer< LASSaveDlg > s_saveDlg(nullptr)
Semi persistent save dialog.
virtual void link()
Increase counter.
virtual void release()
Decrease counter and deletes object when 0.
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool HandleGlobalShift(const CCVector3d &P, CCVector3d &Pshift, bool &preserveCoordinateShift, LoadParameters &loadParameters, bool useInputCoordinatesShiftIfPossible=false)
Shortcut to the ecvGlobalShiftManager mechanism specific for files.
virtual CC_FILE_ERROR saveToFile(ccHObject *entity, const QString &filename, const SaveParameters ¶meters) override
Saves an entity (or a group of) to a file.
virtual CC_FILE_ERROR loadFile(const QString &filename, ccHObject &container, LoadParameters ¶meters) override
Loads one or more entities from a file.
static QString GetFileFilter()
virtual bool canSave(CV_CLASS_ENUM type, bool &multiple, bool &exclusive) const override
Returns whether this I/O filter can save the specified type of entity.
void addEVLR(const QString &description)
bool doSaveEVLR(size_t index) const
LASSaveDlg(QWidget *parent=0)
Type norm2() const
Returns vector square norm.
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
static ccColorScale::Shared GetDefaultScale(DEFAULT_SCALES scale=BGYR)
Returns a pre-defined color scale (static shortcut)
virtual void showColors(bool state)
Sets colors visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
Hierarchical CLOUDVIEWER Object.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
void setMetaData(const QString &key, const QVariant &data)
Sets a meta-data element.
QVariant getMetaData(const QString &key) const
Returns a given associated meta data.
bool hasMetaData(const QString &key) const
Returns whether a meta-data element with the given key exists or not.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void setCurrentDisplayedScalarField(int index)
Sets the currently displayed scalar field.
QMap< uint8_t, WaveformDescriptor > FWFDescriptorSet
Waveform descriptors set.
FWFDescriptorSet & fwfDescriptors()
Gives access to the FWF descriptors.
std::vector< ccWaveform > & waveforms()
Gives access to the associated FWF data.
QSharedPointer< const FWFDataContainer > SharedFWFDataContainer
ccWaveformProxy waveformProxy(unsigned index) const
Returns a proxy on a given waveform.
int addScalarField(const char *uniqueName) override
Creates a new scalar field and registers it.
bool reserve(unsigned numberOfPoints) override
Reserves memory for all the active features.
bool hasFWF() const
Returns whether the cloud has associated Full WaveForm data.
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
bool compressFWFData()
Compresses the associated FWF data container.
bool hasColors() const override
Returns whether colors are enabled or not.
std::vector< uint8_t > FWFDataContainer
Waveform data container.
void setPointColor(size_t pointIndex, const ecvColor::Rgb &col)
Sets a particular point color.
SharedFWFDataContainer & fwfData()
Gives access to the associated FWF data container.
const ecvColor::Rgb & getPointColor(unsigned pointIndex) const override
Returns color corresponding to a given point.
void addRGBColor(const ecvColor::Rgb &C)
Pushes an RGB color on stack.
A scalar field associated to display-related parameters.
double getGlobalShift() const
Returns the global shift (if any)
bool getOwnGlobalBB(CCVector3d &minCorner, CCVector3d &maxCorner) override
CCVector3d toGlobal3d(const Vector3Tpl< T > &Plocal) const
Returns the point back-projected into the original coordinates system.
bool isShifted() const
Returns whether the cloud is shifted or not.
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
bool oneStep()
Increments total progress value of a single unit.
int getScalarFieldIndexByName(const char *name) const
Returns the index of a scalar field represented by its name.
ScalarField * getScalarField(int index) const
Returns a pointer to a specific scalar field.
unsigned getNumberOfScalarFields() const
Returns the number of associated (and active) scalar fields.
void addPoint(const CCVector3 &P)
Adds a 3D point to the database.
unsigned size() const override
const CCVector3 * getPoint(unsigned index) const override
void addElement(ScalarType value)
const char * getName() const
Returns scalar field name.
bool reserveSafe(std::size_t count)
Reserves memory (no exception thrown)
static bool NeedShift(const CCVector3d &P)
Returns whether a particular point (coordinates) is too big or not.
Mode
Strategy to handle coordinates shift/scale.
Graphical progress indicator (thread-safe)
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
constexpr Rgb black(0, 0, 0)
Generic loading parameters.
ecvGlobalShiftManager::Mode shiftHandlingMode
How to handle big coordinates.
QWidget * parentWidget
Parent widget (if any)
bool * coordinatesShiftEnabled
Whether shift on load has been applied after loading (optional)
Generic saving parameters.
QWidget * parentWidget
Parent widget (if any)
bool alwaysDisplaySaveDialog
static bool GetLASFields(ccPointCloud *cloud, std::vector< LasField > &fieldsToSave, uint8_t &minPointFormat)
Returns the (compliant) LAS fields in a point cloud.
static uint8_t UpdateMinPointFormat(uint8_t minPointFormat, bool withRGB, bool withFWF, bool allowLegacyFormats=true)
QSharedPointer< LasField > Shared
Shared type.
static unsigned GetFormatRecordLength(uint8_t pointFormat)
static QString SanitizeString(const QString &str)
static uint8_t VersionMinorForPointFormat(uint8_t pointFormat)