ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
LasIOFilter.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "LasIOFilter.h"
9 
10 #include "LasMetadata.h"
11 #include "LasOpenDialog.h"
12 #include "LasSaveDialog.h"
13 #include "LasSaver.h"
14 #include "LasScalarFieldLoader.h"
15 #include "LasScalarFieldSaver.h"
16 #include "LasVlr.h"
17 #include "LasWaveformLoader.h"
18 #include "LasWaveformSaver.h"
19 
20 // CC
22 #include <ecvColorScalesManager.h>
23 #include <ecvPointCloud.h>
24 #include <ecvProgressDialog.h>
25 #include <ecvScalarField.h>
26 
27 // Qt
28 #include <QDate>
29 #include <QElapsedTimer>
30 #include <QFileInfo>
31 
32 // LASzip
33 #include <laszip/laszip_api.h>
34 
35 // System
36 #include <memory>
37 #include <numeric>
38 #include <utility>
39 
41  bool& preserveCoordinateShift,
42  const CCVector3d& lasOffset,
43  const CCVector3d& firstPoint)
44 {
45  ecvGlobalShiftManager::Mode csModeBackup = parameters.shiftHandlingMode;
46  CCVector3d shift;
47  bool useLasOffset = false;
48 
49  // set the lasOffset as default if none was provided
50  if (lasOffset.norm2() != 0 && (!parameters.coordinatesShiftEnabled || !(*parameters.coordinatesShiftEnabled)))
51  {
52  if (csModeBackup != ecvGlobalShiftManager::NO_DIALOG) // No dialog, practically means
53  // that we don't want any shift!
54  {
55  useLasOffset = true;
56  shift = -lasOffset;
58  {
60  }
61  }
62  }
63 
64  if (!FileIOFilter::HandleGlobalShift(firstPoint,
65  shift,
66  preserveCoordinateShift,
67  parameters,
68  useLasOffset))
69  {
70  preserveCoordinateShift = false;
71  shift = CCVector3d(0.0, 0.0, 0.0);
72  }
73 
74  // restore previous parameters
75  parameters.shiftHandlingMode = csModeBackup;
76  return shift;
77 }
78 
80  : FileIOFilter({"LAS IO Filter",
81  3.0f, // priority (same as the old PDAL-based plugin)
82  QStringList{"las", "laz"},
83  "las",
84  QStringList{"LAS file (*.las *.laz)"},
85  QStringList{"LAS file (*.las *.laz)"},
86  Import | Export})
87 {
88  m_openDialog.resetShouldSkipDialog();
89 }
90 
91 CC_FILE_ERROR LasIOFilter::loadFile(const QString& fileName,
92  ccHObject& container,
93  LoadParameters& parameters)
94 {
95  laszip_POINTER laszipReader;
96  laszip_header* laszipHeader{nullptr};
97  laszip_BOOL isCompressed{false};
98  laszip_CHAR* errorMsg{nullptr};
99 
100  if (laszip_create(&laszipReader))
101  {
102  CVLog::Warning("[LAS] Failed to create reader");
104  }
105 
106  if (laszip_open_reader(laszipReader, qPrintable(fileName), &isCompressed))
107  {
108  laszip_get_error(laszipHeader, &errorMsg);
109  CVLog::Warning("[LAS] laszip error: '%s'", errorMsg);
110  laszip_clean(laszipReader);
111  laszip_destroy(laszipReader);
113  }
114 
115  if (laszip_get_header_pointer(laszipReader, &laszipHeader))
116  {
117  laszip_get_error(laszipHeader, &errorMsg);
118  CVLog::Warning("[LAS] laszip error: '%s'", errorMsg);
119  laszip_close_reader(laszipReader);
120  laszip_clean(laszipReader);
121  laszip_destroy(laszipReader);
123  }
124 
125  laszip_U64 pointCount;
126  if (laszipHeader->version_minor == 4)
127  {
128  pointCount = laszipHeader->extended_number_of_point_records;
129  }
130  else
131  {
132  pointCount = laszipHeader->number_of_point_records;
133  }
134 
135  if (pointCount >= std::numeric_limits<unsigned>::max())
136  {
137  // TODO
138  CVLog::Error("Files with more that %lu points are not supported", pointCount);
140  }
141 
142  std::vector<LasScalarField> availableScalarFields = LasScalarField::ForPointFormat(laszipHeader->point_data_format);
143 
144  std::vector<LasExtraScalarField> availableEXtraScalarFields = LasExtraScalarField::ParseExtraScalarFields(*laszipHeader);
145 
146  std::unique_ptr<FileInfo> infoOfCurrentFile = std::make_unique<FileInfo>();
147  infoOfCurrentFile->version.minorVersion = laszipHeader->version_minor;
148  infoOfCurrentFile->version.pointFormat = laszipHeader->point_data_format;
149  infoOfCurrentFile->extraScalarFields = availableEXtraScalarFields;
150 
151  bool fileContentIsDifferentFromPrevious = (m_infoOfLastOpened && (*m_infoOfLastOpened != *infoOfCurrentFile));
152 
153  m_openDialog.setInfo(laszipHeader->version_minor, laszipHeader->point_data_format, pointCount);
154  m_openDialog.setAvailableScalarFields(availableScalarFields, availableEXtraScalarFields);
155  m_infoOfLastOpened = std::move(infoOfCurrentFile);
156 
157  // The idea is that when Loading a file (as opposed to tiling one)
158  // we want to show the dialog when the file structure is different from the previous
159  // (not same scalar fields, etc) even if the user asked to skip dialogs
160  // as we can't choose for him.
161  //
162  // For tiling even if the file is different from the previous,
163  // since we copy points without loading into CC we don't have to force the
164  // dialog to be re-shown.
165  if (m_openDialog.shouldSkipDialog() && m_openDialog.action() == LasOpenDialog::Action::Load && fileContentIsDifferentFromPrevious)
166  {
167  m_openDialog.resetShouldSkipDialog();
168  }
169 
170  if (parameters.sessionStart)
171  {
172  // we do this AFTER restoring the previous context because it may still
173  // be good that the previous configuration is restored even though the
174  // user needs to confirm it
175  m_openDialog.resetShouldSkipDialog();
176  }
177 
178  if (parameters.alwaysDisplayLoadDialog && !m_openDialog.shouldSkipDialog())
179  {
180  m_openDialog.exec();
181  if (m_openDialog.result() == QDialog::Rejected)
182  {
183  laszip_close_reader(laszipReader);
184  laszip_clean(laszipReader);
185  laszip_destroy(laszipReader);
187  }
188  }
189 
190  if (m_openDialog.action() == LasOpenDialog::Action::Tile)
191  {
192  return TileLasReader(laszipReader, fileName, m_openDialog.tilingOptions());
193  }
194 
195  auto pointCloud = std::make_unique<ccPointCloud>(QFileInfo(fileName).fileName());
196  if (!pointCloud->reserve(pointCount))
197  {
198  laszip_close_reader(laszipReader);
199  laszip_clean(laszipReader);
200  laszip_destroy(laszipReader);
202  }
203 
204  m_openDialog.filterOutNotChecked(availableScalarFields, availableEXtraScalarFields);
205 
206  laszip_F64 laszipCoordinates[3] = {0};
207  laszip_point* laszipPoint{nullptr};
208  CCVector3 currentPoint{};
209  bool preserveGlobalShift{true};
210 
211  if (laszip_get_point_pointer(laszipReader, &laszipPoint))
212  {
213  laszip_get_error(laszipHeader, &errorMsg);
214  CVLog::Warning("[LAS] laszip error: '%s'", errorMsg);
215  laszip_close_reader(laszipReader);
216  laszip_clean(laszipReader);
217  laszip_destroy(laszipReader);
219  }
220 
221  LasScalarFieldLoader loader(availableScalarFields,
222  availableEXtraScalarFields,
223  *pointCloud);
224 
226  loader.setForce8bitRgbMode(m_openDialog.shouldForce8bitColors());
227  loader.setManualTimeShift(m_openDialog.timeShiftValue());
228  std::unique_ptr<LasWaveformLoader> waveformLoader{nullptr};
229  if (LasDetails::HasWaveform(laszipHeader->point_data_format))
230  {
231  waveformLoader = std::make_unique<LasWaveformLoader>(*laszipHeader,
232  fileName,
233  *pointCloud);
234  }
235 
236  QElapsedTimer timer;
237  timer.start();
238 
239  ecvProgressDialog progressDialog(true, parameters.parentWidget);
240  progressDialog.setMethodTitle("Loading LAS points");
241  progressDialog.setInfo("Loading points");
242  cloudViewer::NormalizedProgress normProgress(&progressDialog, pointCount);
243  progressDialog.start();
244 
246  CCVector3d globalShift(0, 0, 0);
247  for (unsigned i = 0; i < pointCount; ++i)
248  {
249  if (progressDialog.isCancelRequested())
250  {
252  break;
253  }
254 
255  if (laszip_read_point(laszipReader))
256  {
257  error = CC_FERR_THIRD_PARTY_LIB_FAILURE; // error will be logged later
258  break;
259  }
260 
261  if (laszip_get_coordinates(laszipReader, laszipCoordinates))
262  {
263  error = CC_FERR_THIRD_PARTY_LIB_FAILURE; // error will be logged later
264  break;
265  }
266 
267  if (i == 0)
268  {
269  CCVector3d firstPoint(laszipCoordinates);
270 
271  CCVector3d lasOffset(laszipHeader->x_offset,
272  laszipHeader->y_offset,
273  0.0 /*laszipHeader->z_offset*/); // it's never a good idea to shift along Z
274 
275  globalShift = GetGlobalShift(parameters,
276  preserveGlobalShift,
277  lasOffset,
278  firstPoint);
279 
280  if (preserveGlobalShift)
281  {
282  pointCloud->setGlobalShift(globalShift);
283  }
284 
285  if (globalShift.norm2() != 0.0)
286  {
287  CVLog::Warning("[LAS] Cloud has been re-centered! Translation: "
288  "(%.2f ; %.2f ; %.2f)",
289  globalShift.x,
290  globalShift.y,
291  globalShift.z);
292  }
293  }
294 
295  currentPoint.x = static_cast<PointCoordinateType>(laszipCoordinates[0] + globalShift.x);
296  currentPoint.y = static_cast<PointCoordinateType>(laszipCoordinates[1] + globalShift.y);
297  currentPoint.z = static_cast<PointCoordinateType>(laszipCoordinates[2] + globalShift.z);
298 
299  pointCloud->addPoint(currentPoint);
300 
301  error = loader.handleScalarFields(*pointCloud, *laszipPoint);
302  if (error != CC_FERR_NO_ERROR)
303  {
304  break;
305  }
306 
307  error = loader.handleExtraScalarFields(*pointCloud, *laszipPoint);
308  if (error != CC_FERR_NO_ERROR)
309  {
310  break;
311  }
312 
313  if (LasDetails::HasRGB(laszipHeader->point_data_format))
314  {
315  error = loader.handleRGBValue(*pointCloud, *laszipPoint);
316  if (error != CC_FERR_NO_ERROR)
317  {
318  break;
319  }
320  }
321 
322  if (waveformLoader)
323  {
324  waveformLoader->loadWaveform(*pointCloud, *laszipPoint);
325  }
326 
327  normProgress.oneStep();
328  }
329 
330  for (const LasScalarField& field : loader.standardFields())
331  {
332  if (field.sf == nullptr)
333  {
334  // It may be null if all values were the same
335  continue;
336  }
337  field.sf->computeMinAndMax();
338  field.sf->setSaturationStart(field.sf->getMin());
339  field.sf->setSaturationStop(field.sf->getMax());
340  field.sf->setMinDisplayed(field.sf->getMin());
341  field.sf->setMaxDisplayed(field.sf->getMax());
342 
343  switch (field.id)
344  {
364  {
365  auto cMin = static_cast<int64_t>(field.sf->getMin());
366  auto cMax = static_cast<int64_t>(field.sf->getMax());
367  int64_t steps = std::min<int64_t>(cMax - cMin + 1, 256);
368  field.sf->setColorRampSteps(steps);
369  break;
370  }
373  break;
376  break;
377  }
378 
379  pointCloud->addScalarField(field.sf);
380  }
381 
382  for (const LasExtraScalarField& field : loader.extraFields())
383  {
384  for (size_t i = 0; i < field.numElements(); ++i)
385  {
386  assert(field.scalarFields[i] != nullptr);
387  field.scalarFields[i]->computeMinAndMax();
388  field.scalarFields[i]->setSaturationStart(field.scalarFields[i]->getMin());
389  field.scalarFields[i]->setSaturationStop(field.scalarFields[i]->getMax());
390  field.scalarFields[i]->setMinDisplayed(field.scalarFields[i]->getMin());
391  field.scalarFields[i]->setMaxDisplayed(field.scalarFields[i]->getMax());
392  pointCloud->addScalarField(field.scalarFields[i]);
393  }
394  }
395 
396  int idx = pointCloud->getScalarFieldIndexByName(LasNames::Intensity);
397  if (idx != -1)
398  {
399  pointCloud->setCurrentDisplayedScalarField(idx);
400  }
401  else if (pointCloud->getNumberOfScalarFields() > 0)
402  {
403  pointCloud->setCurrentDisplayedScalarField(0);
404  }
405  pointCloud->showColors(pointCloud->hasColors());
406  pointCloud->showSF(!pointCloud->hasColors() && pointCloud->hasDisplayedScalarField());
407 
408  for (LasExtraScalarField& extraField : availableEXtraScalarFields)
409  {
410  extraField.resetScalarFieldsPointers();
411  }
412 
413  LasMetadata::SaveMetadataInto(*laszipHeader, *pointCloud, availableEXtraScalarFields);
414 
415  container.addChild(pointCloud.release());
416 
418  {
419  laszip_get_error(laszipHeader, &errorMsg);
420  CVLog::Warning("[LAS] laszip error: '%s'", errorMsg);
421  }
422 
423  laszip_close_reader(laszipReader);
424  laszip_clean(laszipReader);
425  laszip_destroy(laszipReader);
426 
427  timer.elapsed();
428  qint64 elapsed = timer.elapsed();
429  int32_t minutes = timer.elapsed() / (1000 * 60);
430  elapsed -= minutes * (1000 * 60);
431  int32_t seconds = elapsed / 1000;
432  elapsed -= seconds * 1000;
433  CVLog::Print(QString("[LAS] File loaded in %1m%2s%3ms").arg(minutes).arg(seconds).arg(elapsed));
434  return error;
435 }
436 
437 bool LasIOFilter::canSave(CV_CLASS_ENUM type, bool& multiple, bool& exclusive) const
438 {
439  multiple = false;
440  exclusive = true;
441  return type == CV_TYPES::POINT_CLOUD;
442 }
443 
445 {
446  if (!entity || filename.isEmpty())
447  {
448  return CC_FERR_BAD_ARGUMENT;
449  }
450 
451  if (!entity->isA(CV_TYPES::POINT_CLOUD))
452  {
454  }
455  auto* pointCloud = static_cast<ccPointCloud*>(entity);
456 
457  LasSaveDialog saveDialog(pointCloud, parameters.parentWidget);
458 
459  CCVector3d bbMax, bbMin;
460  if (!pointCloud->getOwnGlobalBB(bbMin, bbMax))
461  {
462  if (pointCloud->size() != 0)
463  {
464  // it can only be acceptable if the cloud is empty
465  //(yes, some people expect to save empty clouds!)
466  return CC_FERR_NO_SAVE;
467  }
468  else
469  {
470  bbMax = bbMin = CCVector3d(0.0, 0.0, 0.0);
471  }
472  }
473 
474  // Determine the best LAS offset (required for determing the best LAS scale)
475  CCVector3d lasOffset;
476  bool hasLASOffset = LasMetadata::LoadOffsetFrom(*pointCloud, lasOffset);
477  bool lasOffsetCanBeUsed = hasLASOffset && !ecvGlobalShiftManager::NeedShift(bbMax - lasOffset);
478 
479  CCVector3d globaShift = pointCloud->getGlobalShift();
480  bool hasGlobalShift = pointCloud->isShifted();
481  bool globalShiftCanBeUsed = hasGlobalShift && !ecvGlobalShiftManager::NeedShift(bbMax + globaShift); //'global shift' is the opposite of LAS offset ;)
482 
483  bool minBBCornerCanBeUsed = !ecvGlobalShiftManager::NeedShift(bbMax - bbMin);
484 
485  if (!lasOffsetCanBeUsed)
486  {
487  if (hasLASOffset)
488  {
489  CVLog::Warning(QString("[LAS] The former LAS offset (%1 ; %2 ; %3) doesn't seem to be optimal").arg(lasOffset.x).arg(lasOffset.y).arg(lasOffset.z));
490  }
491 
492  if (hasGlobalShift && (globalShiftCanBeUsed || !minBBCornerCanBeUsed))
493  {
494  CVLog::Warning("[LAS] Will use the entity Global Shift as LAS offset");
495  lasOffset = -globaShift; //'global shift' is the opposite of LAS offset ;)
496  }
497  else if (minBBCornerCanBeUsed)
498  {
499  CVLog::Warning("[LAS] Will use the minimum bounding-box corner (X, Y) as LAS offset");
500  lasOffset.x = bbMin.x;
501  lasOffset.y = bbMin.y;
502  lasOffset.z = 0;
503  }
504  }
505 
506  // Maximum cloud 'extents' relatively to the 'offset' point
507  CCVector3d diagPos = bbMax - lasOffset;
508  CCVector3d diagNeg = lasOffset - bbMin;
509  CCVector3d diag(std::max(diagPos.x, diagNeg.x),
510  std::max(diagPos.y, diagNeg.y),
511  std::max(diagPos.z, diagNeg.z));
512 
513  // Optimal scale (for accuracy) --> 1e-9 because the maximum integer is roughly +/-2e+9
514  CCVector3d optimalScale(1.0e-9 * std::max<double>(diag.x, 1.0),
515  1.0e-9 * std::max<double>(diag.y, 1.0),
516  1.0e-9 * std::max<double>(diag.z, 1.0));
517 
518  // See if we have a scale from an origin las file
519  CCVector3d originalScale;
520  bool canUseOriginalScale = false;
521  bool hasScaleMetaData = LasMetadata::LoadScaleFrom(*pointCloud, originalScale);
522  if (hasScaleMetaData)
523  {
524  // We may not be able to use the previous LAS scale
525  canUseOriginalScale = (originalScale.x >= optimalScale.x
526  && originalScale.y >= optimalScale.y
527  && originalScale.z >= optimalScale.z);
528  }
529 
530  // Uniformize the optimal scale to make it less disturbing to some lastools users ;)
531  {
532  double maxScale = std::max(optimalScale.x, std::max(optimalScale.y, optimalScale.z));
533  double n = ceil(log10(maxScale)); // ceil because n should be negative
534  maxScale = pow(10.0, n);
535  optimalScale.x = optimalScale.y = optimalScale.z = maxScale;
536  }
537  saveDialog.setOptimalScale(optimalScale);
538 
539  if (hasScaleMetaData)
540  {
541  // If we can use the original scale, it will be come the default scale
542  saveDialog.setOriginalScale(originalScale, canUseOriginalScale, true);
543  }
544 
545  // Find the best version for the file or try to use the one from original file
546  LasDetails::LasVersion bestVersion = LasDetails::SelectBestVersion(*pointCloud);
547  LasDetails::LasVersion savedVersion;
548  if (LasMetadata::LoadLasVersionFrom(*pointCloud, savedVersion))
549  {
550  // We do have a version we saved from the original file,
551  // however we don't want to downgrade it.
552  if (bestVersion.minorVersion < savedVersion.minorVersion && bestVersion.pointFormat < savedVersion.pointFormat)
553  {
554  bestVersion = savedVersion;
555  }
556  }
557 
558  saveDialog.setVersionAndPointFormat(bestVersion);
559 
560  // Try to pre-fill in the UI any saved extra scalar fields
561  LasVlr vlr;
562  if (LasMetadata::LoadVlrs(*pointCloud, vlr))
563  {
565  }
566 
567  saveDialog.setExtraScalarFields(vlr.extraScalarFields);
568 
569  if (parameters.alwaysDisplaySaveDialog)
570  {
571  saveDialog.exec();
572  if (saveDialog.result() == QDialog::Rejected)
573  {
575  }
576  }
577 
579  {
580  params.standardFields = saveDialog.fieldsToSave();
581  params.extraFields = saveDialog.extraFieldsToSave();
582  params.shouldSaveRGB = saveDialog.shouldSaveRGB();
583  params.shouldSaveWaveform = saveDialog.shouldSaveWaveform();
584 
585  saveDialog.selectedVersion(params.versionMajor, params.versionMinor);
586  params.pointFormat = saveDialog.selectedPointFormat();
587 
588  params.lasScale = saveDialog.chosenScale();
589  params.lasOffset = lasOffset;
590  }
591 
592  // In case of command line call, add automatically all remaining scalar fiels as extra scalar fields
593  if (!parameters.alwaysDisplaySaveDialog)
594  {
595  uint sfCount = pointCloud->getNumberOfScalarFields();
596  for (uint index = 0; index < sfCount; index++)
597  {
598  ccScalarField* sf = static_cast<ccScalarField*>(pointCloud->getScalarField(index));
599  const char* sfName = sf->getName();
600  bool found = false;
601  for (auto& el : params.standardFields)
602  if (strcmp(sfName, el.name()) == 0)
603  {
604  found = true;
605  break;
606  }
607  if (!found)
608  for (auto& el : params.extraFields)
609  if (strcmp(sfName, el.scalarFields[0]->getName()) == 0)
610  {
611  found = true;
612  break;
613  }
614  if (!found)
615  {
616  CVLog::Print("[LAS] scalar field " + QString(sfName) + " will be saved automatically in the extra fields of the output file");
617  LasExtraScalarField field;
618  const std::string stdName = sfName;
619  strncpy(field.name, stdName.c_str(), LasExtraScalarField::MAX_NAME_SIZE);
620 
621  if (stdName.size() > LasExtraScalarField::MAX_NAME_SIZE)
622  {
623  CVLog::Warning("[LAS] Extra Scalar field name '%s' is too long and will be truncated",
624  stdName.c_str());
625  }
626 
627  field.type = LasExtraScalarField::DataType::f32;
628  field.scalarFields[0] = sf;
629 
630  params.extraFields.push_back(field);
631  }
632  }
633  }
634 
635  LasSaver saver(*pointCloud, params);
636  CC_FILE_ERROR error = saver.open(filename);
637  if (error != CC_FERR_NO_ERROR)
638  {
639  return error;
640  }
641 
642  ecvProgressDialog progressDialog(true, parameters.parentWidget);
643  progressDialog.setMethodTitle("Saving LAS points");
644  progressDialog.setInfo("Saving points");
645  QScopedPointer<cloudViewer::NormalizedProgress> normProgress;
646  if (parameters.parentWidget)
647  {
648  normProgress.reset(new cloudViewer::NormalizedProgress(&progressDialog, pointCloud->size()));
649  progressDialog.start();
650  }
651 
652  for (unsigned i = 0; i < pointCloud->size(); ++i)
653  {
654  error = saver.saveNextPoint();
655  if (error != CC_FERR_NO_ERROR)
656  {
657  break;
658  }
659 
660  if (normProgress && !normProgress->oneStep())
661  {
663  break;
664  }
665  }
666 
668  {
669  CVLog::Warning(QString("[LAS] laszip error :'%1'").arg(saver.getLastError()));
670  return error;
671  }
672 
673  if (saver.savesWaveforms())
674  {
675  const ccPointCloud::SharedFWFDataContainer& fwfData = pointCloud->fwfData();
676  QFileInfo info(filename);
677  QString wdpFilename = QString("%1/%2.wdp").arg(info.path(), info.baseName());
678  QFile fwfFile(wdpFilename);
679 
680  if (!fwfFile.open(QIODevice::WriteOnly))
681  {
682  CVLog::Error("[LAS] Failed to write waveform data");
684  }
685  else
686  {
687  {
689  QDataStream stream(&fwfFile);
690  stream << header;
691  }
692  fwfFile.write(reinterpret_cast<const char*>(fwfData->data()), fwfData->size());
693  CVLog::Print(QString("[LAS] Successfully saved FWF in external file '%1'").arg(wdpFilename));
694  }
695  }
696 
697  return error;
698 }
Vector3Tpl< double > CCVector3d
Double 3D Vector.
Definition: CVGeom.h:804
float PointCoordinateType
Type of the coordinates of a (N-D) point.
Definition: CVTypes.h:16
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
Definition: CVTypes.h:97
std::string filename
char type
CC_FILE_ERROR
Typical I/O filter errors.
Definition: FileIOFilter.h:20
@ CC_FERR_CANCELED_BY_USER
Definition: FileIOFilter.h:30
@ CC_FERR_THIRD_PARTY_LIB_FAILURE
Definition: FileIOFilter.h:36
@ CC_FERR_WRITING
Definition: FileIOFilter.h:25
@ CC_FERR_BAD_ARGUMENT
Definition: FileIOFilter.h:22
@ CC_FERR_NO_SAVE
Definition: FileIOFilter.h:27
@ CC_FERR_NO_ERROR
Definition: FileIOFilter.h:21
@ CC_FERR_NOT_IMPLEMENTED
Definition: FileIOFilter.h:38
@ CC_FERR_BAD_ENTITY_TYPE
Definition: FileIOFilter.h:29
@ CC_FERR_NOT_ENOUGH_MEMORY
Definition: FileIOFilter.h:31
static CCVector3d GetGlobalShift(FileIOFilter::LoadParameters &parameters, bool &preserveCoordinateShift, const CCVector3d &lasOffset, const CCVector3d &firstPoint)
Definition: LasIOFilter.cpp:40
CC_FILE_ERROR TileLasReader(laszip_POINTER laszipReader, const QString &originName, const LasTilingOptions &options)
Definition: LasTiler.cpp:14
cmdLineReadable * params[]
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
static bool Print(const char *format,...)
Prints out a formatted message in console.
Definition: CVLog.cpp:113
static bool Error(const char *format,...)
Display an error dialog with formatted message.
Definition: CVLog.cpp:143
Generic file I/O filter.
Definition: FileIOFilter.h:46
static bool HandleGlobalShift(const CCVector3d &P, CCVector3d &Pshift, bool &preserveCoordinateShift, LoadParameters &loadParameters, bool useInputCoordinatesShiftIfPossible=false)
Shortcut to the ecvGlobalShiftManager mechanism specific for files.
This serves the same purpose as LasScalarField but for extra bytes.
static constexpr unsigned MAX_NAME_SIZE
char name[MAX_NAME_SIZE]
static void MatchExtraBytesToScalarFields(std::vector< LasExtraScalarField > &extraScalarFields, const ccPointCloud &pointCloud)
ccScalarField * scalarFields[MAX_DIM_SIZE]
static std::vector< LasExtraScalarField > ParseExtraScalarFields(const laszip_header &laszipHeader)
CC_FILE_ERROR loadFile(const QString &fileName, ccHObject &container, LoadParameters &parameters) override
Loads one or more entities from a file.
Definition: LasIOFilter.cpp:91
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.
CC_FILE_ERROR saveToFile(ccHObject *entity, const QString &filename, const SaveParameters &parameters) override
Saves an entity (or a group of) to a file.
LasTilingOptions tilingOptions() const
bool shouldSkipDialog() const
void setAvailableScalarFields(const std::vector< LasScalarField > &scalarFields, const std::vector< LasExtraScalarField > &extraScalarFields)
double timeShiftValue() const
Action action() const
@ Tile
The user wants to tile the file into multiple smaller ones.
@ Load
The user wants to load the file in ACloudViewer.
bool shouldForce8bitColors() const
void setInfo(int versionMinor, int pointFormatId, qulonglong numPoints)
void filterOutNotChecked(std::vector< LasScalarField > &scalarFields, std::vector< LasExtraScalarField > &extraScalarFields)
bool shouldIgnoreFieldsWithDefaultValues() const
void resetShouldSkipDialog()
void setExtraScalarFields(const std::vector< LasExtraScalarField > &extraScalarFields)
Set the extra LAS scalar fields saved from the original file.
void setOriginalScale(const CCVector3d &scale, bool canUseScale, bool autoCheck=true)
bool shouldSaveWaveform() const
Returns whether the user wants to save the Waveforms.
void selectedVersion(uint8_t &versionMajor, uint8_t &versionMinor) const
Returns the version currently selected.
bool shouldSaveRGB() const
Returns whether the user wants to save RGB.
std::vector< LasScalarField > fieldsToSave() const
uint8_t selectedPointFormat() const
Returns the point format currently selected.
CCVector3d chosenScale() const
Returns the currently selected scale.
std::vector< LasExtraScalarField > extraFieldsToSave() const
void setVersionAndPointFormat(const LasDetails::LasVersion versionAndFmt)
void setOptimalScale(const CCVector3d &scale, bool autoCheck=false)
Set scale that would offer the user the best precision.
CC_FILE_ERROR open(const QString filePath)
Definition: LasSaver.cpp:118
bool savesWaveforms() const
Definition: LasSaver.cpp:222
QString getLastError() const
Definition: LasSaver.cpp:227
CC_FILE_ERROR saveNextPoint()
Definition: LasSaver.cpp:150
CC_FILE_ERROR handleRGBValue(ccPointCloud &pointCloud, const laszip_point &currentPoint)
const std::vector< LasExtraScalarField > & extraFields() const
CC_FILE_ERROR handleScalarFields(ccPointCloud &pointCloud, const laszip_point &currentPoint)
CC_FILE_ERROR handleExtraScalarFields(ccPointCloud &pointCloud, const laszip_point &currentPoint)
void setManualTimeShift(double timeShift)
void setForce8bitRgbMode(bool state)
void setIgnoreFieldsWithDefaultValues(bool state)
const std::vector< LasScalarField > & standardFields() const
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
Type norm2() const
Returns vector square norm.
Definition: CVGeom.h:417
static ccColorScale::Shared GetDefaultScale(DEFAULT_SCALES scale=BGYR)
Returns a pre-defined color scale (static shortcut)
Hierarchical CLOUDVIEWER Object.
Definition: ecvHObject.h:25
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
bool isA(CV_CLASS_ENUM type) const
Definition: ecvObject.h:131
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
QSharedPointer< const FWFDataContainer > SharedFWFDataContainer
A scalar field associated to display-related parameters.
bool oneStep()
Increments total progress value of a single unit.
const char * getName() const
Returns scalar field name.
Definition: ScalarField.h:43
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)
virtual void start() override
virtual void setInfo(const char *infoStr) override
Notifies some information about the ongoing process.
virtual bool isCancelRequested() override
Checks if the process should be canceled.
virtual void setMethodTitle(const char *methodTitle) override
Notifies the algorithm title.
unsigned int uint
Definition: cutil_math.h:28
int max(int a, int b)
Definition: cutil_math.h:48
static void error(char *msg)
Definition: lsd.c:159
@ POINT_CLOUD
Definition: CVTypes.h:104
bool HasRGB(unsigned pointFormatId)
Returns whether the point format supports RGB.
Definition: LasDetails.h:132
LasVersion SelectBestVersion(const ccPointCloud &cloud)
Definition: LasDetails.cpp:182
bool HasWaveform(unsigned pointFormatId)
Returns whether the point format supports Waveforms.
Definition: LasDetails.h:143
bool LoadOffsetFrom(const ccPointCloud &pointCloud, CCVector3d &offset)
void SaveMetadataInto(const laszip_header &header, ccPointCloud &pointCloud, const std::vector< LasExtraScalarField > &extraScalarFields)
Definition: LasMetadata.cpp:56
bool LoadScaleFrom(const ccPointCloud &pointCloud, CCVector3d &scale)
bool LoadVlrs(const ccPointCloud &pointCloud, LasVlr &vlr)
bool LoadLasVersionFrom(const ccPointCloud &pointCloud, LasDetails::LasVersion &version)
constexpr const char * Intensity
Definition: LasDetails.h:59
MiniVec< float, N > ceil(const MiniVec< float, N > &a)
Definition: MiniVec.h:89
#define seconds
Definition: rename.h:375
Generic loading parameters.
Definition: FileIOFilter.h:51
ecvGlobalShiftManager::Mode shiftHandlingMode
How to handle big coordinates.
Definition: FileIOFilter.h:64
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:78
bool sessionStart
Session start (whether the load action is the first of a session)
Definition: FileIOFilter.h:80
bool * coordinatesShiftEnabled
Whether shift on load has been applied after loading (optional)
Definition: FileIOFilter.h:69
Generic saving parameters.
Definition: FileIOFilter.h:84
QWidget * parentWidget
Parent widget (if any)
Definition: FileIOFilter.h:93
static EvlrHeader Waveform()
Definition: LasDetails.cpp:40
See SelectBestVersion
Definition: LasDetails.h:178
static std::vector< LasScalarField > ForPointFormat(unsigned pointFormatId)
Definition: LasVlr.h:38
std::vector< LasExtraScalarField > extraScalarFields
Definition: LasVlr.h:121
double timer
Definition: struct.h:215