ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
LasMetadata.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 "LasMetadata.h"
9 
10 #include "LasDetails.h"
11 
12 #include <ecvPointCloud.h>
13 
14 namespace LasMetadata
15 {
16  static constexpr size_t SYSTEM_IDENTIFIER_SIZE = 32;
17 
19  static const char ProjectionVLR[] = "LASF_Projection";
20 
22  static QString ProjectionVLRToString(const laszip_vlr_struct& vlr)
23  {
24  if (QString(vlr.user_id) != ProjectionVLR)
25  {
26  CVLog::Warning("[LAS] Invalid Projection VLR");
27  return {};
28  }
29 
30  if (vlr.record_length_after_header < 2)
31  {
32  // too short
33  return {};
34  }
35 
36  QString wkt;
37  if (vlr.record_id == 2111)
38  {
39  wkt = "Math Transform WKT: ";
40  }
41  else if (vlr.record_id == 2112)
42  {
43  wkt = "Coordinate System WKT: ";
44  }
45  else
46  {
47  // unhandled but silent, as this will happen a lot (for IDs 34735 to 34737 for instance)
48  return {};
49  }
50 
51  wkt += QByteArray(reinterpret_cast<const char*>(vlr.data), vlr.record_length_after_header).trimmed();
52 
53  return wkt;
54  }
55 
56  void SaveMetadataInto(const laszip_header& header,
57  ccPointCloud& pointCloud,
58  const std::vector<LasExtraScalarField>& extraScalarFields)
59  {
60  pointCloud.setMetaData(LasMetadata::X_SCALE, header.x_scale_factor);
61  pointCloud.setMetaData(LasMetadata::Y_SCALE, header.y_scale_factor);
62  pointCloud.setMetaData(LasMetadata::Z_SCALE, header.z_scale_factor);
63 
64  pointCloud.setMetaData(LasMetadata::X_OFFSET, header.x_offset);
65  pointCloud.setMetaData(LasMetadata::Y_OFFSET, header.y_offset);
66  pointCloud.setMetaData(LasMetadata::Z_OFFSET, header.z_offset);
67 
68  pointCloud.setMetaData(LasMetadata::VERSION_MAJOR, header.version_major);
69  pointCloud.setMetaData(LasMetadata::VERSION_MINOR, header.version_minor);
70  pointCloud.setMetaData(LasMetadata::POINT_FORMAT, header.point_data_format);
71  pointCloud.setMetaData(LasMetadata::GLOBAL_ENCODING, header.global_encoding);
72 
73  QByteArray projectUUID;
74  projectUUID.reserve(16);
75  projectUUID.append(reinterpret_cast<const char*>(&header.project_ID_GUID_data_1), 4);
76  projectUUID.append(reinterpret_cast<const char*>(&header.project_ID_GUID_data_2), 2);
77  projectUUID.append(reinterpret_cast<const char*>(&header.project_ID_GUID_data_3), 2);
78  projectUUID.append(reinterpret_cast<const char*>(&header.project_ID_GUID_data_4), 8);
79  assert(projectUUID.size() == 16);
80  pointCloud.setMetaData(LasMetadata::PROJECT_UUID, std::move(projectUUID));
81 
82  if (header.system_identifier[0] != 0)
83  {
84  pointCloud.setMetaData(LasMetadata::SYSTEM_IDENTIFIER, QString::fromLatin1(header.system_identifier, SYSTEM_IDENTIFIER_SIZE));
85  }
86 
87  if (header.number_of_variable_length_records > 0)
88  {
89  LasVlr vlrs(header);
90  vlrs.extraScalarFields = std::move(extraScalarFields);
91  pointCloud.setMetaData(LasMetadata::VLRS, QVariant::fromValue(vlrs));
92 
93  // specific case: save the LASF_Projection VLR has a human readable string (if possible)
94  for (const laszip_vlr_struct& vlr : vlrs.vlrs)
95  {
96  if (QString(vlr.user_id) == ProjectionVLR)
97  {
98  QString proj = ProjectionVLRToString(vlr);
99  if (!proj.isEmpty())
100  {
101  pointCloud.setMetaData("LAS.projection", proj);
102  }
103  break;
104  }
105  }
106  }
107  }
108 
109  bool LoadProjectUUID(const ccPointCloud& pointCloud, laszip_header& header)
110  {
111  if (pointCloud.hasMetaData(LasMetadata::PROJECT_UUID))
112  {
113  QVariant value = pointCloud.getMetaData(LasMetadata::PROJECT_UUID);
114  QByteArray byteArray = value.toByteArray();
115  if (byteArray.size() != 16)
116  {
117  CVLog::Warning("[LAS] Invalid project UUID meta data");
118  return false;
119  }
120 
121  const char* bufferData = byteArray.data();
122 
123  // 1st block (32 bits)
124  header.project_ID_GUID_data_1 = *(const laszip_U32*)bufferData;
125  bufferData += 4;
126  // 2nd block (16 bits)
127  header.project_ID_GUID_data_2 = *(const laszip_U16*)bufferData;
128  bufferData += 2;
129  // 3rd block (16 bits)
130  header.project_ID_GUID_data_3 = *(const laszip_U16*)bufferData;
131  bufferData += 2;
132  // 4th block (8 * 8 bits)
133  memcpy(header.project_ID_GUID_data_4, bufferData, 8);
134 
135  return true;
136  }
137 
138  return false;
139  }
140 
141  bool LoadVlrs(const ccPointCloud& pointCloud, LasVlr& vlr)
142  {
143  if (pointCloud.hasMetaData(LasMetadata::VLRS))
144  {
145  QVariant value = pointCloud.getMetaData(LasMetadata::VLRS);
146  if (value.canConvert<LasVlr>())
147  {
148  vlr = value.value<LasVlr>();
149  return true;
150  }
151  }
152 
153  return false;
154  }
155 
156  bool LoadScaleFrom(const ccPointCloud& pointCloud, CCVector3d& scale)
157  {
158  bool hasScaleMetaData = false;
159  scale.x = pointCloud.getMetaData(LasMetadata::X_SCALE).toDouble(&hasScaleMetaData);
160  if (hasScaleMetaData)
161  {
162  scale.y = pointCloud.getMetaData(LasMetadata::Y_SCALE).toDouble(&hasScaleMetaData);
163  if (hasScaleMetaData)
164  {
165  scale.z = pointCloud.getMetaData(LasMetadata::Z_SCALE).toDouble(&hasScaleMetaData);
166  }
167  }
168  return hasScaleMetaData;
169  }
170 
171  bool LoadOffsetFrom(const ccPointCloud& pointCloud, CCVector3d& offset)
172  {
173  bool hasOffsetMetaData = false;
174  offset.x = pointCloud.getMetaData(LasMetadata::X_OFFSET).toDouble(&hasOffsetMetaData);
175  if (hasOffsetMetaData)
176  {
177  offset.y = pointCloud.getMetaData(LasMetadata::Y_OFFSET).toDouble(&hasOffsetMetaData);
178  if (hasOffsetMetaData)
179  {
180  offset.z = pointCloud.getMetaData(LasMetadata::Z_OFFSET).toDouble(&hasOffsetMetaData);
181  }
182  }
183  return hasOffsetMetaData;
184  }
185 
187  {
188  bool ok = false;
189  int pointFormatId = pointCloud.getMetaData(LasMetadata::POINT_FORMAT).toInt(&ok);
190  if (!ok)
191  {
192  return false;
193  }
194 
195  int versionMajor = pointCloud.getMetaData(LasMetadata::VERSION_MAJOR).toInt(&ok);
196  if (!ok)
197  {
198  return false;
199  }
200 
201  int versionMinor = pointCloud.getMetaData(LasMetadata::VERSION_MINOR).toInt(&ok);
202  if (!ok)
203  {
204  return false;
205  }
206  // TODO
207  // version.majorVersion = versionMajor;
208  version.minorVersion = versionMinor;
209  version.pointFormat = pointFormatId;
210  return true;
211  }
212 
213  bool LoadGlobalEncoding(const ccPointCloud& pointCloud, uint16_t& outGlobalEncoding)
214  {
215  outGlobalEncoding = 0;
216 
217  bool ok = false;
218  uint globalEncoding = pointCloud.getMetaData(LasMetadata::GLOBAL_ENCODING).toUInt(&ok);
219  if (!ok)
220  {
221  return false;
222  }
223  if (globalEncoding > 65535)
224  {
225  CVLog::Warning("[LAS] Invalid global encoding value: " + QString::number(globalEncoding));
226  }
227  outGlobalEncoding = static_cast<uint16_t>(globalEncoding);
228  return true;
229  }
230 
231 } // namespace LasMetadata
std::string version
int offset
laszip_vlr laszip_vlr_struct
Definition: LasDetails.h:46
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
Definition: CVLog.cpp:133
Type y
Definition: CVGeom.h:137
Type x
Definition: CVGeom.h:137
Type z
Definition: CVGeom.h:137
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.)
unsigned int uint
Definition: cutil_math.h:28
constexpr const char Y_OFFSET[]
Definition: LasMetadata.h:45
static constexpr size_t SYSTEM_IDENTIFIER_SIZE
Definition: LasMetadata.cpp:16
bool LoadOffsetFrom(const ccPointCloud &pointCloud, CCVector3d &offset)
constexpr const char X_SCALE[]
Definition: LasMetadata.h:41
void SaveMetadataInto(const laszip_header &header, ccPointCloud &pointCloud, const std::vector< LasExtraScalarField > &extraScalarFields)
Definition: LasMetadata.cpp:56
constexpr const char Z_OFFSET[]
Definition: LasMetadata.h:46
bool LoadGlobalEncoding(const ccPointCloud &pointCloud, uint16_t &outGlobalEncoding)
constexpr const char VERSION_MINOR[]
Definition: LasMetadata.h:48
constexpr const char GLOBAL_ENCODING[]
Definition: LasMetadata.h:50
static QString ProjectionVLRToString(const laszip_vlr_struct &vlr)
Converts a vlr to a QByteArray.
Definition: LasMetadata.cpp:22
bool LoadScaleFrom(const ccPointCloud &pointCloud, CCVector3d &scale)
bool LoadProjectUUID(const ccPointCloud &pointCloud, laszip_header &header)
constexpr const char SYSTEM_IDENTIFIER[]
Definition: LasMetadata.h:52
constexpr const char Y_SCALE[]
Definition: LasMetadata.h:42
static const char ProjectionVLR[]
Projection VLR.
Definition: LasMetadata.cpp:19
constexpr const char VLRS[]
Definition: LasMetadata.h:53
constexpr const char PROJECT_UUID[]
Definition: LasMetadata.h:51
constexpr const char POINT_FORMAT[]
Definition: LasMetadata.h:49
constexpr const char VERSION_MAJOR[]
Definition: LasMetadata.h:47
bool LoadVlrs(const ccPointCloud &pointCloud, LasVlr &vlr)
bool LoadLasVersionFrom(const ccPointCloud &pointCloud, LasDetails::LasVersion &version)
constexpr const char Z_SCALE[]
Definition: LasMetadata.h:43
constexpr const char X_OFFSET[]
Definition: LasMetadata.h:44
See SelectBestVersion
Definition: LasDetails.h:178
Definition: LasVlr.h:38
std::vector< laszip_vlr_struct > vlrs
Definition: LasVlr.h:120
std::vector< LasExtraScalarField > extraScalarFields
Definition: LasVlr.h:121