ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
LasDetails.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 "LasDetails.h"
9 
10 #include "LasScalarField.h"
11 
12 // LASzip
13 #include <laszip/laszip_api.h>
14 
15 // CORE
16 #include <CVLog.h>
17 
18 // DB
19 #include <ecvPointCloud.h>
20 #include <ecvScalarField.h>
21 
22 // Qt
23 #include <QDataStream>
24 // System
25 #include <cstring>
26 #include <stdexcept>
27 
28 static const std::vector<unsigned> PointFormatForV1_2 = {0, 1, 2, 3};
29 static const std::vector<unsigned> PointFormatForV1_3 = {0, 1, 2, 3, 4, 5};
30 static const std::vector<unsigned> PointFormatForV1_4 = {6, 7, 8, 9, 10};
31 static const std::array<const char*, 3> VersionsArray = {"1.2", "1.3", "1.4"};
32 
33 namespace LasDetails
34 {
36  {
37  return recordID == 65'535 && strncmp(userID, "LASF_Spec", EvlrHeader::USER_ID_SIZE) == 0;
38  }
39 
41  {
42  EvlrHeader self;
43  self.recordID = 65'535;
44  strncpy(self.userID, "LASF_Spec", EvlrHeader::USER_ID_SIZE);
45  strncpy(self.description, "Waveform Data Packets", EvlrHeader::DESCRIPTION_SIZE);
46  self.recordLength = 0;
47  return self;
48  }
49 
50  QDataStream& operator>>(QDataStream& stream, EvlrHeader& hdr)
51  {
52  stream.setByteOrder(QDataStream::ByteOrder::LittleEndian);
53 
54  uint16_t reserved;
55  stream >> reserved;
56  stream.readRawData(hdr.userID, EvlrHeader::USER_ID_SIZE);
57  stream >> hdr.recordID;
58  quint64 recordLength_;
59  stream >> recordLength_;
60  hdr.recordLength = recordLength_;
61  stream.readRawData(hdr.description, EvlrHeader::DESCRIPTION_SIZE);
62 
63  return stream;
64  };
65 
66  QDataStream& operator<<(QDataStream& stream, const EvlrHeader& hdr)
67  {
68  uint16_t reserved{0};
69  stream.setByteOrder(QDataStream::ByteOrder::LittleEndian);
70 
71  stream << reserved;
72  stream.writeRawData(hdr.userID, EvlrHeader::USER_ID_SIZE);
73  stream << hdr.recordID;
74  stream << (quint64)hdr.recordLength;
75  stream.writeRawData(hdr.description, EvlrHeader::DESCRIPTION_SIZE);
76 
77  return stream;
78  }
79 
80  uint16_t PointFormatSize(unsigned pointFormat)
81  {
82  switch (pointFormat)
83  {
84  case 0:
85  return 20;
86  case 1:
87  return 28;
88  case 2:
89  return 26;
90  case 3:
91  return 34;
92  case 4:
93  return 28 + 29;
94  case 5:
95  return 34 + 29;
96  case 6:
97  return 30;
98  case 7:
99  return 36;
100  case 8:
101  return 38;
102  case 9:
103  return 30 + 29;
104  case 10:
105  return 38 + 29;
106  default:
107  assert(false);
108  return 0;
109  }
110  }
111 
112  uint16_t HeaderSize(unsigned versionMinor)
113  {
114  switch (versionMinor)
115  {
116  case 2:
117  return 227;
118  case 3:
119  return 227 + 8;
120  case 4:
121  return 375;
122  default:
123  return 227;
124  }
125  }
126 
128  {
129  if (strcmp(vlr.user_id, "Laszip encoded") == 0 && vlr.record_id == 22204)
130  {
131  return true;
132  }
133  return false;
134  }
135 
137  {
138  if (strcmp(vlr.user_id, "LASF_Spec") == 0 && vlr.record_id == 4)
139  {
140  return true;
141  }
142  return false;
143  }
144 
145  unsigned SizeOfVlrs(const laszip_vlr_struct* vlrs, unsigned numVlrs)
146  {
147  constexpr laszip_U32 header_size = static_cast<laszip_U32>(LAS_VLR_HEADER_SIZE);
148  return std::accumulate(vlrs,
149  vlrs + numVlrs,
150  0,
151  [=](laszip_U32 size, const laszip_vlr_struct& vlr)
152  { return vlr.record_length_after_header + header_size + size; });
153  }
154 
155  const std::vector<unsigned>* PointFormatsAvailableForVersion(QString version)
156  {
157  if (version.size() == 3 && version.startsWith("1."))
158  {
159  if (version[2] == '2')
160  {
161  return &PointFormatForV1_2;
162  }
163  if (version[2] == '3')
164  {
165  return &PointFormatForV1_3;
166  }
167  if (version[2] == '4')
168  {
169  return &PointFormatForV1_4;
170  }
171  }
172 
173  CVLog::Warning("Unknown LAS version: " + version);
174  return nullptr;
175  }
176 
177  const std::array<const char*, 3>& AvailableVersions()
178  {
179  return VersionsArray;
180  }
181 
183  {
184  // These are exclusive to 'extended' point formats (>= 6)
185  bool hasOverlapFlag = cloud.getScalarFieldIndexByName(LasNames::OverlapFlag) != -1;
186  bool hasNIR = cloud.getScalarFieldIndexByName(LasNames::NearInfrared) != -1;
187  bool hasScannerChannel = cloud.getScalarFieldIndexByName(LasNames::ScannerChannel) != -1;
188  bool hasScanAngle = cloud.getScalarFieldIndexByName(LasNames::ScanAngle) != -1;
189 
190  bool isExtendedRequired = hasOverlapFlag || hasNIR || hasScannerChannel || hasScanAngle;
191 
192  if (!isExtendedRequired)
193  {
194  // We may need extended point format because some fields need to store more value
195  // than what is possible on non-extended point format.
196  int classificationIdx = cloud.getScalarFieldIndexByName(LasNames::Classification);
197  if (classificationIdx != -1)
198  {
199  const cloudViewer::ScalarField* classification = cloud.getScalarField(classificationIdx);
201  {
202  isExtendedRequired = true;
203  }
204  }
205 
206  int returnNumberIdx = cloud.getScalarFieldIndexByName(LasNames::ReturnNumber);
207  if (returnNumberIdx != -1)
208  {
209  const cloudViewer::ScalarField* returnNumber = cloud.getScalarField(returnNumberIdx);
211  {
212  isExtendedRequired = true;
213  }
214  }
215 
216  int numReturnsIdx = cloud.getScalarFieldIndexByName(LasNames::NumberOfReturns);
217  if (numReturnsIdx != -1)
218  {
219  const cloudViewer::ScalarField* numReturns = cloud.getScalarField(numReturnsIdx);
221  {
222  isExtendedRequired = true;
223  }
224  }
225  }
226 
227  bool hasRGB = cloud.hasColors();
228  bool hasWaveform = cloud.hasFWF();
229 
230  if (isExtendedRequired)
231  {
232  int pointFormat = 6;
233  if (hasWaveform)
234  {
235  if (hasRGB)
236  {
237  pointFormat = 10;
238  }
239  else
240  {
241  pointFormat = 9;
242  }
243  }
244  else
245  {
246  if (hasRGB && hasNIR)
247  {
248  pointFormat = 8;
249  }
250  else if (hasRGB && !hasNIR)
251  {
252  pointFormat = 7;
253  }
254  }
255  return {pointFormat, 4};
256  }
257  else
258  {
259  bool hasGpsTime = cloud.getScalarFieldIndexByName(LasNames::GpsTime) != -1;
260  int pointFormat = 0;
261  int minorVersion = 2;
262  if (hasWaveform)
263  {
264  minorVersion = 3;
265  if (hasGpsTime)
266  pointFormat = 4;
267  else if (hasRGB)
268  pointFormat = 5;
269  }
270  else
271  {
272  if (hasGpsTime)
273  {
274  pointFormat += 1;
275  }
276  if (hasRGB)
277  {
278  pointFormat += 2;
279  }
280  }
281  return {pointFormat, minorVersion};
282  }
283  }
284 
286  {
287  dst = src;
288  dst.data = new laszip_U8[src.record_length_after_header];
289  std::copy(src.data, src.data + src.record_length_after_header, dst.data);
290  }
291 
292 } // namespace LasDetails
int size
std::string version
static const std::array< const char *, 3 > VersionsArray
Definition: LasDetails.cpp:31
static const std::vector< unsigned > PointFormatForV1_3
Definition: LasDetails.cpp:29
static const std::vector< unsigned > PointFormatForV1_4
Definition: LasDetails.cpp:30
static const std::vector< unsigned > PointFormatForV1_2
Definition: LasDetails.cpp:28
constexpr size_t LAS_VLR_HEADER_SIZE
Definition: LasDetails.h:49
laszip_vlr laszip_vlr_struct
Definition: LasDetails.h:46
bool copy
Definition: VtkUtils.cpp:74
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool hasFWF() const
Returns whether the cloud has associated Full WaveForm data.
bool hasColors() const override
Returns whether colors are enabled or not.
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.
A simple scalar field (to be associated to a point cloud)
Definition: ScalarField.h:25
ScalarType getMax() const
Returns the maximum value.
Definition: ScalarField.h:74
const std::array< const char *, 3 > & AvailableVersions()
Definition: LasDetails.cpp:177
bool IsLaszipVlr(const laszip_vlr_struct &)
Returns whether the vlr is the vlr for/of LASzip compression.
Definition: LasDetails.cpp:127
uint16_t PointFormatSize(unsigned pointFormat)
Definition: LasDetails.cpp:80
LasVersion SelectBestVersion(const ccPointCloud &cloud)
Definition: LasDetails.cpp:182
bool IsExtraBytesVlr(const laszip_vlr_struct &)
Returns whether the vlr describes extra bytes.
Definition: LasDetails.cpp:136
QDataStream & operator<<(QDataStream &stream, const EvlrHeader &hdr)
Definition: LasDetails.cpp:66
uint16_t HeaderSize(unsigned versionMinor)
Returns the header size for the given minor version of the standard used.
Definition: LasDetails.cpp:112
void CloneVlrInto(const laszip_vlr_struct &src, laszip_vlr_struct &dst)
Clones the content of the src vlr into the dst vlr.
Definition: LasDetails.cpp:285
unsigned SizeOfVlrs(const laszip_vlr_struct *vlrs, unsigned numVlrs)
Definition: LasDetails.cpp:145
QDataStream & operator>>(QDataStream &stream, EvlrHeader &hdr)
Definition: LasDetails.cpp:50
const std::vector< unsigned > * PointFormatsAvailableForVersion(QString version)
Definition: LasDetails.cpp:155
constexpr const char * ScanAngle
Definition: LasDetails.h:74
constexpr const char * NumberOfReturns
Definition: LasDetails.h:61
constexpr const char * OverlapFlag
Definition: LasDetails.h:76
constexpr const char * Classification
Definition: LasDetails.h:64
constexpr const char * ScannerChannel
Definition: LasDetails.h:75
constexpr const char * ReturnNumber
Definition: LasDetails.h:60
constexpr const char * NearInfrared
Definition: LasDetails.h:77
constexpr const char * GpsTime
Definition: LasDetails.h:71
static constexpr size_t DESCRIPTION_SIZE
Definition: LasDetails.h:96
static constexpr size_t USER_ID_SIZE
Definition: LasDetails.h:95
char description[DESCRIPTION_SIZE]
Definition: LasDetails.h:101
char userID[USER_ID_SIZE]
Definition: LasDetails.h:98
bool isWaveFormDataPackets() const
Definition: LasDetails.cpp:35
static EvlrHeader Waveform()
Definition: LasDetails.cpp:40
See SelectBestVersion
Definition: LasDetails.h:178
static LasScalarField::Range ValueRange(LasScalarField::Id id)
Returns the range of value the given field (ID) supports.