25#include "lazperf/readers.hpp"
33 if ( mVersion.first == 1 && mVersion.second == 4 )
35 if ( mVersion.first == 1 && mVersion.second == 3 )
37 if ( mVersion.first == 1 && mVersion.second <= 2 )
45 if ( std::string( data, 4 ) !=
"LASF" )
47 mError = QStringLiteral(
"Supplied header is not from a LAZ file" );
51 std::istringstream file( std::string( data, length ) );
52 lazperf::header14
header = lazperf::header14::create( file );
60 uint64_t currentOffset = 0;
61 for ( uint64_t i = 0; i < ( uint64_t )mVlrCount && currentOffset < length; ++i )
63 lazperf::vlr_header vlrHeader;
64 vlrHeader.fill( data + currentOffset, 54 );
67 vlr.
userId = QString::fromStdString( vlrHeader.user_id );
69 vlr.
data = QByteArray( data + currentOffset + 54, vlrHeader.data_length );
70 mVlrVector.push_back( vlr );
71 currentOffset += 54 + vlrHeader.data_length;
75 parseExtrabyteAttributes();
79void QgsLazInfo::parseHeader( lazperf::header14 &header )
85 mCreationYearDay = QPair<uint16_t, uint16_t>(
header.creation.year,
header.creation.day );
86 mVersion = QPair<uint8_t, uint8_t>(
header.version.major,
header.version.minor );
87 mPointFormat =
header.pointFormat();
89 mProjectId = QString( QByteArray(
header.guid, 16 ).toHex() );
90 mSystemId = QString::fromLocal8Bit(
header.system_identifier, 32 );
91 while ( !mSystemId.isEmpty() && mSystemId.back() ==
'\0' )
93 mSystemId.remove( mSystemId.size() - 1, 1 );
95 mSoftwareId = QString::fromLocal8Bit(
header.generating_software, 32 ).trimmed();
96 while ( !mSoftwareId.isEmpty() && mSoftwareId.back() ==
'\0' )
98 mSoftwareId.remove( mSoftwareId.size() - 1, 1 );
104 mVlrCount =
header.vlr_count;
106 parseLazAttributes();
110void QgsLazInfo::parseCrs()
113 for ( LazVlr &vlr : mVlrVector )
115 if ( vlr.userId.trimmed() == QLatin1String(
"LASF_Projection" ) && vlr.recordId == 2112 )
125 QVariantMap metadata;
126 metadata[ QStringLiteral(
"creation_year" ) ] = mHeader.creation.year;
127 metadata[ QStringLiteral(
"creation_day" ) ] = mHeader.creation.day;
128 metadata[ QStringLiteral(
"major_version" ) ] = mHeader.version.major;
129 metadata[ QStringLiteral(
"minor_version" ) ] = mHeader.version.minor;
130 metadata[ QStringLiteral(
"dataformat_id" ) ] = mHeader.pointFormat();
131 metadata[ QStringLiteral(
"scale_x" ) ] = mScale.
x();
132 metadata[ QStringLiteral(
"scale_y" ) ] = mScale.
y();
133 metadata[ QStringLiteral(
"scale_z" ) ] = mScale.
z();
134 metadata[ QStringLiteral(
"offset_x" ) ] = mOffset.
x();
135 metadata[ QStringLiteral(
"offset_y" ) ] = mOffset.
y();
136 metadata[ QStringLiteral(
"offset_z" ) ] = mOffset.
z();
137 metadata[ QStringLiteral(
"project_id" ) ] = QString( QByteArray( mHeader.guid, 16 ).toHex() );
138 metadata[ QStringLiteral(
"system_id" ) ] = QString::fromLocal8Bit( mHeader.system_identifier, 32 );
139 metadata[ QStringLiteral(
"software_id" ) ] = QString::fromLocal8Bit( mHeader.generating_software, 32 );
145 for (
LazVlr vlr : mVlrVector )
147 if ( vlr.userId == userId && vlr.recordId == recordId )
155void QgsLazInfo::parseLazAttributes()
157 if ( mPointFormat < 0 || mPointFormat > 10 )
159 QgsDebugMsgLevel( QStringLiteral(
"Invalid point record format %1" ).arg( mPointFormat ), 2 );
179 if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
183 if ( mPointFormat != 0 && mPointFormat != 2 )
187 if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
193 if ( mPointFormat == 8 || mPointFormat == 10 )
200void QgsLazInfo::parseExtrabyteAttributes()
202 QByteArray ebVlrRaw =
vlrData(
"LASF_Spec", 4 );
213 QVector<QgsLazInfo::ExtraBytesAttributeDetails> extrabyteAttributes;
214 lazperf::eb_vlr ebVlr;
215 ebVlr.fill( rawData, length );
216 for ( std::vector<lazperf::eb_vlr::ebfield>::reverse_iterator it = ebVlr.items.rbegin(); it != ebVlr.items.rend(); ++it )
218 lazperf::eb_vlr::ebfield &field = *it;
220 ebAtrr.
attribute = QString::fromStdString( field.name );
221 switch ( field.data_type )
225 ebAtrr.
size = field.options;
269 ebAtrr.
size = field.options;
272 int accOffset = ( extrabyteAttributes.empty() ?
pointRecordLength : extrabyteAttributes.back().offset ) - ebAtrr.
size;
273 ebAtrr.
offset = accOffset;
274 extrabyteAttributes.push_back( ebAtrr );
276 return extrabyteAttributes;
283 char headerRawData[ 375 ];
285 file.read( headerRawData, 375 );
289 std::unique_ptr<char[]> vlrEntriesRawData(
new char[ vlrDataSize ] );
291 file.read( vlrEntriesRawData.get(), vlrDataSize );
303 QNetworkRequest nr( url );
305 nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
306 nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
false );
307 nr.setRawHeader(
"Range",
"bytes=0-374" );
312 QgsDebugError( QStringLiteral(
"Request failed: " ) + url.toString() );
314 if ( req.
reply().
attribute( QNetworkRequest::HttpStatusCodeAttribute ).toInt() == 200 )
320 lazInfo.mError = QStringLiteral(
"Range query 0-374 to \"%1\" failed: \"%2\"" ).arg( url.toString() ).arg( req.
errorMessage() );
327 QByteArray lazHeaderData = reply.
content();
329 lazInfo.
parseRawHeader( lazHeaderData.data(), lazHeaderData.size() );
334 QNetworkRequest nr( url );
336 nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
337 nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute,
false );
339 QByteArray vlrRequestRange = QStringLiteral(
"bytes=%1-%2" ).arg( firstVlrOffset ).arg( lazInfo.
firstPointRecordOffset() - 1 ).toLocal8Bit();
340 nr.setRawHeader(
"Range", vlrRequestRange );
345 QgsDebugError( QStringLiteral(
"Request failed: " ) + url.toString() );
347 lazInfo.mError = QStringLiteral(
"Range query %1-%2 to \"%3\" failed: \"%4\"" ).arg( firstVlrOffset ).arg( lazInfo.
firstPointRecordOffset() - 1 )
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr, RequestFlags requestFlags=QgsBlockingNetworkRequest::RequestFlags())
Performs a "get" operation on the specified request.
@ NoError
No error was encountered.
QgsNetworkReplyContent reply() const
Returns the content of the network reply, after a get(), post(), head() or put() request has been mad...
static QgsCoordinateReferenceSystem fromWkt(const QString &wkt)
Creates a CRS from a WKT spatial ref sys definition string.
Class for extracting information contained in LAZ file such as the public header block and variable l...
uint32_t firstVariableLengthRecord() const
Returns the absolute offset to the first variable length record in the LAZ file.
QByteArray vlrData(QString userId, int recordId)
Returns the binary data of the variable length record with the user identifier userId and record iden...
uint32_t firstPointRecordOffset() const
Returns the absolute offset to the first point record in the LAZ file.
static QgsLazInfo fromUrl(QUrl &url)
Static function to create a QgsLazInfo class from a file over network.
lazperf::header14 header() const
Returns the LAZPERF header object.
void parseRawVlrEntries(char *data, uint64_t length)
Parses the variable length records found in the array data of length length.
QVariantMap toMetadata() const
Returns a map containing various metadata extracted from the LAZ file.
void parseRawHeader(char *data, uint64_t length)
Parses the raw header data loaded from a LAZ file.
static QgsLazInfo fromFile(std::ifstream &file)
Static function to create a QgsLazInfo class from a file.
QgsLazInfo()
Constructor for an empty laz info parser.
int pointRecordLength() const
Returns the length of each point record in bytes.
static QVector< ExtraBytesAttributeDetails > parseExtrabytes(char *rawData, int length, int pointRecordLength)
Static function to parse the raw extrabytes VLR into a list of recognizable extrabyte attributes.
Encapsulates a network reply within a container which is inexpensive to copy and safe to pass between...
QVariant attribute(QNetworkRequest::Attribute code) const
Returns the attribute associated with the code.
QByteArray content() const
Returns the reply content.
void push_back(const QgsPointCloudAttribute &attribute)
Adds extra attribute.
Attribute for point cloud data pair of name and size in bytes.
@ UShort
Unsigned short int 2 bytes.
@ Short
Short int 2 bytes.
@ UChar
Unsigned char 1 byte.
@ UInt32
Unsigned int32 4 bytes.
@ UInt64
Unsigned int64 8 bytes.
Class for storage of 3D vectors similar to QVector3D, with the difference that it uses double precisi...
double y() const
Returns Y coordinate.
double z() const
Returns Z coordinate.
double x() const
Returns X coordinate.
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
#define QgsSetRequestInitiatorClass(request, _class)