24#include "lazperf/readers.hpp" 
   32  if ( mVersion.first == 1 && mVersion.second == 4 )
 
   34  if ( mVersion.first == 1 && mVersion.second == 3 )
 
   36  if ( mVersion.first == 1 && mVersion.second <= 2 )
 
   44  if ( std::string( data, 4 ) != 
"LASF" )
 
   46    mError = QStringLiteral( 
"Supplied header is not from a LAZ file" );
 
   50  std::istringstream file( std::string( data, length ) );
 
   51  lazperf::header14 
header = lazperf::header14::create( file );
 
   59  uint64_t currentOffset = 0;
 
   60  for ( uint64_t i = 0; i < ( uint64_t )mVlrCount && currentOffset < length; ++i )
 
   62    lazperf::vlr_header vlrHeader;
 
   63    vlrHeader.fill( data + currentOffset, 54 );
 
   66    vlr.
userId = QString::fromStdString( vlrHeader.user_id );
 
   68    vlr.
data = QByteArray( data + currentOffset + 54, vlrHeader.data_length );
 
   69    mVlrVector.push_back( vlr );
 
   70    currentOffset += 54 + vlrHeader.data_length;
 
   74  parseExtrabyteAttributes();
 
   78void QgsLazInfo::parseHeader( lazperf::header14 &header )
 
   84  mCreationYearDay = QPair<uint16_t, uint16_t>( 
header.creation.year, 
header.creation.day );
 
   85  mVersion = QPair<uint8_t, uint8_t>( 
header.version.major, 
header.version.minor );
 
   86  mPointFormat = 
header.pointFormat();
 
   88  mProjectId = QString( QByteArray( 
header.guid, 16 ).toHex() );
 
   89  mSystemId = QString::fromLocal8Bit( 
header.system_identifier, 32 );
 
   90  while ( !mSystemId.isEmpty() && mSystemId.back() == 
'\0' )
 
   92    mSystemId.remove( mSystemId.size() - 1, 1 );
 
   94  mSoftwareId = QString::fromLocal8Bit( 
header.generating_software, 32 ).trimmed();
 
   95  while ( !mSoftwareId.isEmpty() && mSoftwareId.back() == 
'\0' )
 
   97    mSoftwareId.remove( mSoftwareId.size() - 1, 1 );
 
  103  mVlrCount = 
header.vlr_count;
 
  105  parseLazAttributes();
 
  109void QgsLazInfo::parseCrs()
 
  112  for ( LazVlr &vlr : mVlrVector )
 
  114    if ( vlr.userId.trimmed() == QLatin1String( 
"LASF_Projection" ) && vlr.recordId == 2112 )
 
  124  QVariantMap metadata;
 
  125  metadata[ QStringLiteral( 
"creation_year" ) ] = mHeader.creation.year;
 
  126  metadata[ QStringLiteral( 
"creation_day" ) ] = mHeader.creation.day;
 
  127  metadata[ QStringLiteral( 
"major_version" ) ] = mHeader.version.major;
 
  128  metadata[ QStringLiteral( 
"minor_version" ) ] = mHeader.version.minor;
 
  129  metadata[ QStringLiteral( 
"dataformat_id" ) ] = mHeader.pointFormat();
 
  130  metadata[ QStringLiteral( 
"scale_x" ) ] = mScale.
x();
 
  131  metadata[ QStringLiteral( 
"scale_y" ) ] = mScale.
y();
 
  132  metadata[ QStringLiteral( 
"scale_z" ) ] = mScale.
z();
 
  133  metadata[ QStringLiteral( 
"offset_x" ) ] = mOffset.
x();
 
  134  metadata[ QStringLiteral( 
"offset_y" ) ] = mOffset.
y();
 
  135  metadata[ QStringLiteral( 
"offset_z" ) ] = mOffset.
z();
 
  136  metadata[ QStringLiteral( 
"project_id" ) ] = QString( QByteArray( mHeader.guid, 16 ).toHex() );
 
  137  metadata[ QStringLiteral( 
"system_id" ) ] = QString::fromLocal8Bit( mHeader.system_identifier, 32 );
 
  138  metadata[ QStringLiteral( 
"software_id" ) ] = QString::fromLocal8Bit( mHeader.generating_software, 32 );
 
  144  for ( 
LazVlr vlr : mVlrVector )
 
  146    if ( vlr.userId == userId && vlr.recordId == recordId )
 
  154void QgsLazInfo::parseLazAttributes()
 
  156  if ( mPointFormat < 0 || mPointFormat > 10 )
 
  158    QgsDebugMsgLevel( QStringLiteral( 
"Invalid point record format %1" ).arg( mPointFormat ), 2 );
 
  174  if ( mPointFormat == 6 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 9 || mPointFormat == 10 )
 
  179  if ( mPointFormat != 0 && mPointFormat != 2 )
 
  183  if ( mPointFormat == 2 || mPointFormat == 3 || mPointFormat == 5 || mPointFormat == 7 || mPointFormat == 8 || mPointFormat == 10 )
 
  189  if ( mPointFormat == 8 || mPointFormat == 10 )
 
  196void QgsLazInfo::parseExtrabyteAttributes()
 
  198  QByteArray ebVlrRaw = 
vlrData( 
"LASF_Spec", 4 );
 
  209  QVector<QgsLazInfo::ExtraBytesAttributeDetails> extrabyteAttributes;
 
  210  lazperf::eb_vlr ebVlr;
 
  211  ebVlr.fill( rawData, length );
 
  212  for ( std::vector<lazperf::eb_vlr::ebfield>::reverse_iterator it = ebVlr.items.rbegin(); it != ebVlr.items.rend(); ++it )
 
  214    lazperf::eb_vlr::ebfield &
field = *it;
 
  217    switch ( 
field.data_type )
 
  268    int accOffset = ( extrabyteAttributes.empty() ? 
pointRecordLength : extrabyteAttributes.back().offset ) - ebAtrr.
size;
 
  269    ebAtrr.
offset = accOffset;
 
  270    extrabyteAttributes.push_back( ebAtrr );
 
  272  return extrabyteAttributes;
 
  279  char headerRawData[ 375 ];
 
  281  file.read( headerRawData, 375 );
 
  285  std::unique_ptr<char[]> vlrEntriesRawData( 
new char[ vlrDataSize ] );
 
  287  file.read( vlrEntriesRawData.get(), vlrDataSize );
 
  299    lazInfo.mError = QStringLiteral( 
"The server of submitted URL doesn't support range queries" );
 
  305    QNetworkRequest nr( url );
 
  307    nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
 
  308    nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute, 
false );
 
  309    nr.setRawHeader( 
"Range", 
"bytes=0-374" );
 
  314      QgsDebugError( QStringLiteral( 
"Request failed: " ) + url.toString() );
 
  315      lazInfo.mError = QStringLiteral( 
"Range query 0-374 to \"%1\" failed: \"%2\"" ).arg( url.toString() ).arg( req.
errorMessage() );
 
  320    QByteArray lazHeaderData = reply.
content();
 
  322    lazInfo.
parseRawHeader( lazHeaderData.data(), lazHeaderData.size() );
 
  327    QNetworkRequest nr( url );
 
  329    nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
 
  330    nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute, 
false );
 
  332    QByteArray vlrRequestRange = QStringLiteral( 
"bytes=%1-%2" ).arg( firstVlrOffset ).arg( lazInfo.
firstPointRecordOffset() - 1 ).toLocal8Bit();
 
  333    nr.setRawHeader( 
"Range", vlrRequestRange );
 
  338      QgsDebugError( QStringLiteral( 
"Request failed: " ) + url.toString() );
 
  340      lazInfo.mError = QStringLiteral( 
"Range query %1-%2 to \"%3\" failed: \"%4\"" ).arg( firstVlrOffset ).arg( lazInfo.
firstPointRecordOffset() - 1 )
 
  354  QNetworkRequest nr( url );
 
  356  nr.setAttribute( QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::AlwaysNetwork );
 
  357  nr.setAttribute( QNetworkRequest::CacheSaveControlAttribute, 
false );
 
  358  nr.setRawHeader( 
"Range", 
"bytes=0-0" );
 
  364  const QString acceptRangesHeader = reply.
rawHeader( QStringLiteral( 
"Accept-Ranges" ).toLocal8Bit() );
 
  365  return acceptRangesHeader.compare( QStringLiteral( 
"bytes" ), Qt::CaseSensitivity::CaseInsensitive ) == 0;
 
A thread safe class for performing blocking (sync) network requests, with full support for QGIS proxy...
 
ErrorCode get(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "get" operation on the specified request.
 
ErrorCode head(QNetworkRequest &request, bool forceRefresh=false, QgsFeedback *feedback=nullptr)
Performs a "head" operation on the specified request.
 
QString errorMessage() const
Returns the error message string, after a get(), post(), head() or put() request has been made.
 
@ 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.
 
static bool supportsRangeQueries(QUrl &url)
Static function to check whether the server of URL url supports range queries.
 
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...
 
QByteArray content() const
Returns the reply content.
 
QByteArray rawHeader(const QByteArray &headerName) const
Returns the content of the header with the specified headerName, or an empty QByteArray if the specif...
 
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.
 
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)