24#include "qgspointcloudexpression.h" 
   28#include <QElapsedTimer> 
   29#include <QTemporaryFile> 
   37#include "lazperf/las.hpp" 
   38#include "lazperf/readers.hpp" 
   57      const char val = char( value );
 
   63      const unsigned char val = ( 
unsigned char )( value );
 
   70      short val = short( value );
 
   71      memcpy( s + position, 
reinterpret_cast<char * 
>( &val ), 
sizeof( 
short ) );
 
   76      unsigned short val = 
static_cast< unsigned short>( value );
 
   77      memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( 
unsigned short ) );
 
   83      qint32 val = qint32( value );
 
   84      memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( qint32 ) );
 
   89      quint32 val = quint32( value );
 
   90      memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( quint32 ) );
 
   96      qint64 val = qint64( value );
 
   97      memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( qint64 ) );
 
  102      quint64 val = quint64( value );
 
  103      memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( quint64 ) );
 
  109      float val = float( value );
 
  110      memcpy( s + position, 
reinterpret_cast< char * 
>( &val ),  
sizeof( 
float ) );
 
  115      double val = double( value );
 
  116      memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( 
double ) );
 
  127  if ( outputType == inputType )
 
  129    memcpy( data + outputPosition, input + inputPosition, inputSize );
 
  137      const char val = *( input + inputPosition );
 
  138      return lazStoreToStream_<char>( data, outputPosition, outputType, val );
 
  142      const unsigned char val = *( input + inputPosition );
 
  143      return lazStoreToStream_<unsigned char>( data, outputPosition, outputType, val );
 
  147      const short val = *
reinterpret_cast< const short * 
>( input + inputPosition );
 
  148      return lazStoreToStream_<short>( data, outputPosition, outputType, val );
 
  152      const unsigned short val = *
reinterpret_cast< const unsigned short * 
>( input + inputPosition );
 
  153      return lazStoreToStream_<unsigned short>( data, outputPosition, outputType, val );
 
  157      const qint32 val = *
reinterpret_cast<const qint32 * 
>( input + inputPosition );
 
  158      return lazStoreToStream_<qint32>( data, outputPosition, outputType, val );
 
  162      const quint32 val = *
reinterpret_cast<const quint32 * 
>( input + inputPosition );
 
  163      return lazStoreToStream_<quint32>( data, outputPosition, outputType, val );
 
  167      const qint64 val = *
reinterpret_cast<const qint64 * 
>( input + inputPosition );
 
  168      return lazStoreToStream_<qint64>( data, outputPosition, outputType, val );
 
  172      const quint64 val = *
reinterpret_cast<const quint64 * 
>( input + inputPosition );
 
  173      return lazStoreToStream_<quint64>( data, outputPosition, outputType, val );
 
  177      const float val = *
reinterpret_cast< const float * 
>( input + inputPosition );
 
  178      return lazStoreToStream_<float>( data, outputPosition, outputType, val );
 
  182      const double val = *
reinterpret_cast< const double * 
>( input + inputPosition );
 
  183      return lazStoreToStream_<double>( data, outputPosition, outputType, val );
 
  191std::vector< QgsLazDecoder::RequestedAttributeDetails > prepareRequestedAttributeDetails_( 
const QgsPointCloudAttributeCollection &requestedAttributes, QVector<QgsLazInfo::ExtraBytesAttributeDetails> &extrabytesAttr )
 
  193  const QVector<QgsPointCloudAttribute> requestedAttributesVector = requestedAttributes.
attributes();
 
  195  std::vector< QgsLazDecoder::RequestedAttributeDetails > requestedAttributeDetails;
 
  196  requestedAttributeDetails.reserve( requestedAttributesVector.size() );
 
  200    if ( requestedAttribute.name().compare( QLatin1String( 
"X" ), Qt::CaseInsensitive ) == 0 )
 
  202      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::X, requestedAttribute.type(), requestedAttribute.size() ) );
 
  204    else if ( requestedAttribute.name().compare( QLatin1String( 
"Y" ), Qt::CaseInsensitive ) == 0 )
 
  206      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Y, requestedAttribute.type(), requestedAttribute.size() ) );
 
  208    else if ( requestedAttribute.name().compare( QLatin1String( 
"Z" ), Qt::CaseInsensitive ) == 0 )
 
  210      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Z, requestedAttribute.type(), requestedAttribute.size() ) );
 
  212    else if ( requestedAttribute.name().compare( QLatin1String( 
"Classification" ), Qt::CaseInsensitive ) == 0 )
 
  214      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Classification, requestedAttribute.type(), requestedAttribute.size() ) );
 
  216    else if ( requestedAttribute.name().compare( QLatin1String( 
"Intensity" ), Qt::CaseInsensitive ) == 0 )
 
  218      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Intensity, requestedAttribute.type(), requestedAttribute.size() ) );
 
  220    else if ( requestedAttribute.name().compare( QLatin1String( 
"ReturnNumber" ), Qt::CaseInsensitive ) == 0 )
 
  222      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ReturnNumber, requestedAttribute.type(), requestedAttribute.size() ) );
 
  224    else if ( requestedAttribute.name().compare( QLatin1String( 
"NumberOfReturns" ), Qt::CaseInsensitive ) == 0 )
 
  226      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::NumberOfReturns, requestedAttribute.type(), requestedAttribute.size() ) );
 
  228    else if ( requestedAttribute.name().compare( QLatin1String( 
"ScanDirectionFlag" ), Qt::CaseInsensitive ) == 0 )
 
  230      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ScanDirectionFlag, requestedAttribute.type(), requestedAttribute.size() ) );
 
  232    else if ( requestedAttribute.name().compare( QLatin1String( 
"EdgeOfFlightLine" ), Qt::CaseInsensitive ) == 0 )
 
  234      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::EdgeOfFlightLine, requestedAttribute.type(), requestedAttribute.size() ) );
 
  236    else if ( requestedAttribute.name().compare( QLatin1String( 
"ScanAngleRank" ), Qt::CaseInsensitive ) == 0 )
 
  238      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ScanAngleRank, requestedAttribute.type(), requestedAttribute.size() ) );
 
  240    else if ( requestedAttribute.name().compare( QLatin1String( 
"UserData" ), Qt::CaseInsensitive ) == 0 )
 
  242      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::UserData, requestedAttribute.type(), requestedAttribute.size() ) );
 
  244    else if ( requestedAttribute.name().compare( QLatin1String( 
"PointSourceId" ), Qt::CaseInsensitive ) == 0 )
 
  246      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::PointSourceId, requestedAttribute.type(), requestedAttribute.size() ) );
 
  248    else if ( requestedAttribute.name().compare( QLatin1String( 
"GpsTime" ), Qt::CaseInsensitive ) == 0 )
 
  250      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::GpsTime, requestedAttribute.type(), requestedAttribute.size() ) );
 
  252    else if ( requestedAttribute.name().compare( QLatin1String( 
"Red" ), Qt::CaseInsensitive ) == 0 )
 
  254      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Red, requestedAttribute.type(), requestedAttribute.size() ) );
 
  256    else if ( requestedAttribute.name().compare( QLatin1String( 
"Green" ), Qt::CaseInsensitive ) == 0 )
 
  258      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Green, requestedAttribute.type(), requestedAttribute.size() ) );
 
  260    else if ( requestedAttribute.name().compare( QLatin1String( 
"Blue" ), Qt::CaseInsensitive ) == 0 )
 
  262      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Blue, requestedAttribute.type(), requestedAttribute.size() ) );
 
  264    else if ( requestedAttribute.name().compare( QLatin1String( 
"ScannerChannel" ), Qt::CaseInsensitive ) == 0 )
 
  266      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ScannerChannel, requestedAttribute.type(), requestedAttribute.size() ) );
 
  268    else if ( requestedAttribute.name().compare( QLatin1String( 
"Synthetic" ), Qt::CaseInsensitive ) == 0 )
 
  270      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Synthetic, requestedAttribute.type(), requestedAttribute.size() ) );
 
  272    else if ( requestedAttribute.name().compare( QLatin1String( 
"KeyPoint" ), Qt::CaseInsensitive ) == 0 )
 
  274      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::KeyPoint, requestedAttribute.type(), requestedAttribute.size() ) );
 
  276    else if ( requestedAttribute.name().compare( QLatin1String( 
"Withheld" ), Qt::CaseInsensitive ) == 0 )
 
  278      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Withheld, requestedAttribute.type(), requestedAttribute.size() ) );
 
  280    else if ( requestedAttribute.name().compare( QLatin1String( 
"Overlap" ), Qt::CaseInsensitive ) == 0 )
 
  282      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Overlap, requestedAttribute.type(), requestedAttribute.size() ) );
 
  284    else if ( requestedAttribute.name().compare( QLatin1String( 
"Infrared" ), Qt::CaseInsensitive ) == 0 )
 
  286      requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::NIR, requestedAttribute.type(), requestedAttribute.size() ) );
 
  290      bool foundAttr = 
false;
 
  293        if ( requestedAttribute.name().compare( eba.attribute.trimmed() ) == 0 )
 
  295          requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ExtraBytes, eba.type, eba.size, eba.offset ) );
 
  303        requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::MissingOrUnknown, requestedAttribute.type(), requestedAttribute.size() ) );
 
  307  return requestedAttributeDetails;
 
  310bool decodePoint( 
char *buf, 
int lasPointFormat, 
char *dataBuffer, std::size_t &outputOffset, std::vector< QgsLazDecoder::RequestedAttributeDetails > &requestedAttributeDetails )
 
  312  lazperf::las::point10 p10;
 
  313  lazperf::las::gpstime gps;
 
  314  lazperf::las::rgb rgb;
 
  315  lazperf::las::nir14 nir;
 
  316  lazperf::las::point14 p14;
 
  320  const bool isLas14 = ( lasPointFormat == 6 || lasPointFormat == 7 || lasPointFormat == 8 || lasPointFormat == 9 || lasPointFormat == 10 );
 
  322  switch ( lasPointFormat )
 
  330      gps.unpack( buf + 
sizeof( lazperf::las::point10 ) );
 
  334      rgb.unpack( buf + 
sizeof( lazperf::las::point10 ) );
 
  338      gps.unpack( buf + 
sizeof( lazperf::las::point10 ) );
 
  339      rgb.unpack( buf + 
sizeof( lazperf::las::point10 ) + 
sizeof( lazperf::las::gpstime ) );
 
  348      rgb.unpack( buf + 
sizeof( lazperf::las::point14 ) );
 
  352      rgb.unpack( buf + 
sizeof( lazperf::las::point14 ) );
 
  353      nir.unpack( buf + 
sizeof( lazperf::las::point14 ) + 
sizeof( lazperf::las::rgb ) );
 
  361  for ( 
const QgsLazDecoder::RequestedAttributeDetails &requestedAttribute : requestedAttributeDetails )
 
  363    switch ( requestedAttribute.attribute )
 
  365      case QgsLazDecoder::LazAttribute::X:
 
  366        lazStoreToStream_<qint32>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.x() : p10.x );
 
  368      case QgsLazDecoder::LazAttribute::Y:
 
  369        lazStoreToStream_<qint32>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.y() : p10.y );
 
  371      case QgsLazDecoder::LazAttribute::Z:
 
  372        lazStoreToStream_<qint32>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.z() : p10.z );
 
  374      case QgsLazDecoder::LazAttribute::Classification:
 
  378          lazStoreToStream_<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p14.classification() );
 
  383          lazStoreToStream_<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, ( p10.classification & 0x1F ) == 12 ? 0 : p10.classification & 0x1F );
 
  387      case QgsLazDecoder::LazAttribute::Intensity:
 
  388        lazStoreToStream_<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.intensity() : p10.intensity );
 
  390      case QgsLazDecoder::LazAttribute::ReturnNumber:
 
  391        lazStoreToStream_<unsigned char>( dataBuffer,  outputOffset, requestedAttribute.type, isLas14 ? p14.returnNum() : p10.return_number );
 
  393      case QgsLazDecoder::LazAttribute::NumberOfReturns:
 
  394        lazStoreToStream_<unsigned char>( dataBuffer,  outputOffset, requestedAttribute.type, isLas14 ? p14.numReturns() : p10.number_of_returns_of_given_pulse );
 
  396      case QgsLazDecoder::LazAttribute::ScanDirectionFlag:
 
  397        lazStoreToStream_<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.scanDirFlag() : p10.scan_direction_flag );
 
  399      case QgsLazDecoder::LazAttribute::EdgeOfFlightLine:
 
  400        lazStoreToStream_<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.eofFlag() : p10.edge_of_flight_line );
 
  402      case QgsLazDecoder::LazAttribute::ScanAngleRank:
 
  403        lazStoreToStream_<float>( dataBuffer, outputOffset, requestedAttribute.type,
 
  406                                  ? p14.scanAngle() * 0.006f
 
  408                                  : p10.scan_angle_rank );
 
  410      case QgsLazDecoder::LazAttribute::UserData:
 
  411        lazStoreToStream_<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.userData() : p10.user_data );
 
  413      case QgsLazDecoder::LazAttribute::PointSourceId:
 
  414        lazStoreToStream_<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.pointSourceID() : p10.point_source_ID );
 
  416      case QgsLazDecoder::LazAttribute::GpsTime:
 
  418        lazStoreToStream_<double>( dataBuffer, outputOffset, requestedAttribute.type,
 
  419                                   isLas14 ? p14.gpsTime() : *reinterpret_cast<const double *>( reinterpret_cast<const void *>( &gps.value ) ) );
 
  421      case QgsLazDecoder::LazAttribute::Red:
 
  422        lazStoreToStream_<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.r );
 
  424      case QgsLazDecoder::LazAttribute::Green:
 
  425        lazStoreToStream_<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.g );
 
  427      case QgsLazDecoder::LazAttribute::Blue:
 
  428        lazStoreToStream_<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.b );
 
  430      case QgsLazDecoder::LazAttribute::ScannerChannel:
 
  431        lazStoreToStream_<char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? 
char( p14.scannerChannel() ) : 0 );
 
  433      case QgsLazDecoder::LazAttribute::Synthetic:
 
  434        lazStoreToStream_<char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? 
char( ( p14.classFlags() >> 0 ) & 0x01 ) : char( ( p10.classification >> 5 ) & 0x01 ) );
 
  436      case QgsLazDecoder::LazAttribute::KeyPoint:
 
  437        lazStoreToStream_<char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? 
char( ( p14.classFlags() >> 1 ) & 0x01 ) : char( ( p10.classification >> 6 ) & 0x01 ) );
 
  439      case QgsLazDecoder::LazAttribute::Withheld:
 
  440        lazStoreToStream_<char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? 
char( ( p14.classFlags() >> 2 ) & 0x01 ) : char( ( p10.classification >> 7 ) & 0x01 ) );
 
  442      case QgsLazDecoder::LazAttribute::Overlap:
 
  446          lazStoreToStream_<char>( dataBuffer, outputOffset, requestedAttribute.type, 
char( ( p14.classFlags() >> 3 ) & 0x01 ) );
 
  451          lazStoreToStream_<char>( dataBuffer, outputOffset, requestedAttribute.type, ( p10.classification & 0x1F ) == 12 ? 1 : 0 );
 
  455      case QgsLazDecoder::LazAttribute::NIR:
 
  457        if ( lasPointFormat == 8 || lasPointFormat == 10 )
 
  459          lazStoreToStream_<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, nir.val );
 
  464          lazStoreToStream_<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, 0 );
 
  469      case QgsLazDecoder::LazAttribute::ExtraBytes:
 
  471        switch ( requestedAttribute.type )
 
  474            lazStoreToStream_<char>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<char * 
>( &buf[requestedAttribute.offset] ) );
 
  477            lazStoreToStream_<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<unsigned char * 
>( &buf[requestedAttribute.offset] ) );
 
  480            lazStoreToStream_<qint16>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint16 * 
>( &buf[requestedAttribute.offset] ) );
 
  483            lazStoreToStream_<quint16>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint16 * 
>( &buf[requestedAttribute.offset] ) );
 
  486            lazStoreToStream_<qint32>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint32 * 
>( &buf[requestedAttribute.offset] ) );
 
  489            lazStoreToStream_<quint32>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint32 * 
>( &buf[requestedAttribute.offset] ) );
 
  492            lazStoreToStream_<qint64>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint64 * 
>( &buf[requestedAttribute.offset] ) );
 
  495            lazStoreToStream_<quint64>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint64 * 
>( &buf[requestedAttribute.offset] ) );
 
  498            lazStoreToStream_<float>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<float * 
>( &buf[requestedAttribute.offset] ) );
 
  501            lazStoreToStream_<double>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<double * 
>( &buf[requestedAttribute.offset] ) );
 
  506      case QgsLazDecoder::LazAttribute::MissingOrUnknown:
 
  508        lazStoreToStream_<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, 0 );
 
  512    outputOffset += requestedAttribute.size;
 
  517template<
typename FileType>
 
  531    lazperf::reader::generic_file f( file );
 
  538    int lasPointFormat = f.header().pointFormat();
 
  539    if ( lasPointFormat != 0 && lasPointFormat != 1 && lasPointFormat != 2 && lasPointFormat != 3 &&
 
  540         lasPointFormat != 6 && lasPointFormat != 7 && lasPointFormat != 8 )
 
  542      QgsDebugError( QStringLiteral( 
"Unexpected point format record (%1) - only 0, 1, 2, 3, 6, 7, 8 are supported" ).arg( lasPointFormat ) );
 
  546    const size_t count = f.header().point_count;
 
  547    const QgsVector3D scale( f.header().scale.x, f.header().scale.y, f.header().scale.z );
 
  548    const QgsVector3D offset( f.header().offset.x, f.header().offset.y, f.header().offset.z );
 
  550    QByteArray bufArray( f.header().point_record_length, 0 );
 
  551    char *buf = bufArray.data();
 
  553    const size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
 
  555    data.resize( requestedPointRecordSize * count );
 
  556    char *dataBuffer = data.data();
 
  558    std::size_t outputOffset = 0;
 
  560    auto block = std::make_unique< QgsPointCloudBlock >(
 
  566    int skippedPoints = 0;
 
  567    const bool filterIsValid = filterExpression.isValid();
 
  568    if ( !filterExpression.prepare( block.get() ) && filterIsValid )
 
  571      block->setPointCount( 0 );
 
  575    int xAttributeOffset, yAttributeOffset;
 
  578    const bool hasFilterRect = !filterRect.
isEmpty();
 
  581      attributeX = requestedAttributes.
find( QLatin1String( 
"X" ), xAttributeOffset );
 
  582      attributeY = requestedAttributes.
find( QLatin1String( 
"Y" ), yAttributeOffset );
 
  589    std::vector<char> rawExtrabytes = f.vlrData( 
"LASF_Spec", 4 );
 
  590    QVector<QgsLazInfo::ExtraBytesAttributeDetails> extrabyteAttributesDetails = 
QgsLazInfo::parseExtrabytes( rawExtrabytes.data(), rawExtrabytes.size(), f.header().point_record_length );
 
  591    std::vector< QgsLazDecoder::RequestedAttributeDetails > requestedAttributeDetails = prepareRequestedAttributeDetails_( requestedAttributes, extrabyteAttributesDetails );
 
  593    for ( 
size_t i = 0 ; i < count ; i ++ )
 
  597      bool skipThisPoint = !decodePoint( buf, lasPointFormat, dataBuffer, outputOffset, requestedAttributeDetails );
 
  600      if ( !skipThisPoint && hasFilterRect && attributeX && attributeY )
 
  602        const double x = attributeX->
convertValueToDouble( dataBuffer + outputOffset - requestedPointRecordSize + xAttributeOffset );
 
  603        const double y = attributeY->
convertValueToDouble( dataBuffer + outputOffset - requestedPointRecordSize + yAttributeOffset );
 
  605          skipThisPoint = 
true;
 
  607      if ( !skipThisPoint && filterIsValid )
 
  610        double eval = filterExpression.evaluate( i - skippedPoints );
 
  611        if ( !eval || std::isnan( eval ) )
 
  612          skipThisPoint = 
true;
 
  617        outputOffset -= requestedPointRecordSize;
 
  623    QgsDebugMsgLevel( QStringLiteral( 
"LAZ-PERF Read through the points in %1 seconds." ).arg( t.elapsed() / 1000. ), 2 );
 
  625    block->setPointCount( count - skippedPoints );
 
  628  catch ( std::exception &e )
 
  630    QgsDebugError( 
"Error decompressing laz file: " + QString::fromLatin1( e.what() ) );
 
  635std::unique_ptr<QgsPointCloudBlock> QgsLazDecoder::decompressLaz( 
const QString &filename,
 
  637    QgsPointCloudExpression &filterExpression, 
QgsRectangle &filterRect )
 
  639  std::ifstream file( toNativePath( filename ), std::ios::binary );
 
  641  return decompressLaz_<std::ifstream>( file, requestedAttributes, filterExpression, filterRect );
 
  644std::unique_ptr<QgsPointCloudBlock> QgsLazDecoder::decompressLaz( 
const QByteArray &byteArrayData,
 
  646    QgsPointCloudExpression &filterExpression, 
QgsRectangle &filterRect )
 
  648  std::istringstream file( byteArrayData.toStdString() );
 
  649  return decompressLaz_<std::istringstream>( file, requestedAttributes, filterExpression, filterRect );
 
  656  if ( lasPointFormat != 6 && lasPointFormat != 7 && lasPointFormat != 8 )
 
  658    QgsDebugError( QStringLiteral( 
"Unexpected point format record (%1) - only 6, 7, 8 are supported for COPC format" ).arg( lasPointFormat ) );
 
  664  lazperf::reader::chunk_decompressor decompressor( lasPointFormat, lazInfo.
extrabytesCount(), data.data() );
 
  666  const size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
 
  667  QByteArray blockData;
 
  668  blockData.resize( requestedPointRecordSize * pointCount );
 
  669  char *dataBuffer = blockData.data();
 
  671  std::size_t outputOffset = 0;
 
  673  QVector<QgsLazInfo::ExtraBytesAttributeDetails> extrabyteAttributesDetails = lazInfo.
extrabytes();
 
  674  std::vector< RequestedAttributeDetails > requestedAttributeDetails = prepareRequestedAttributeDetails_( requestedAttributes, extrabyteAttributesDetails );
 
  675  auto block = std::make_unique< QgsPointCloudBlock >(
 
  676                 pointCount, requestedAttributes,
 
  680  int skippedPoints = 0;
 
  681  const bool filterIsValid = filterExpression.isValid();
 
  682  if ( !filterExpression.prepare( block.get() ) && filterIsValid )
 
  685    block->setPointCount( 0 );
 
  689  int xAttributeOffset, yAttributeOffset;
 
  692  const bool hasFilterRect = !filterRect.
isEmpty();
 
  695    attributeX = requestedAttributes.
find( QLatin1String( 
"X" ), xAttributeOffset );
 
  696    attributeY = requestedAttributes.
find( QLatin1String( 
"Y" ), yAttributeOffset );
 
  702  for ( 
int i = 0 ; i < pointCount; ++i )
 
  704    decompressor.decompress( decodedData.get() );
 
  705    char *buf = decodedData.get();
 
  707    bool skipThisPoint = !decodePoint( buf, lasPointFormat, dataBuffer, outputOffset, requestedAttributeDetails );
 
  710    if ( !skipThisPoint && hasFilterRect && attributeX && attributeY )
 
  712      const double x = attributeX->
convertValueToDouble( dataBuffer + outputOffset - requestedPointRecordSize + xAttributeOffset );
 
  713      const double y = attributeY->
convertValueToDouble( dataBuffer + outputOffset - requestedPointRecordSize + yAttributeOffset );
 
  715        skipThisPoint = 
true;
 
  717    if ( !skipThisPoint && filterIsValid )
 
  720      double eval = filterExpression.evaluate( i - skippedPoints );
 
  721      if ( !eval || std::isnan( eval ) )
 
  722        skipThisPoint = 
true;
 
  727      outputOffset -= requestedPointRecordSize;
 
  732  block->setPointCount( pointCount - skippedPoints );
 
  737std::wstring QgsLazDecoder::toNativePath( 
const QString &filename )
 
  739  std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > converter;
 
  740  return converter.from_bytes( filename.toStdString() );
 
  743std::string QgsLazDecoder::toNativePath( 
const QString &filename )
 
  745  return filename.toStdString();
 
Extracts information contained in a LAZ file, such as the public header block and variable length rec...
 
int extrabytesCount() const
Returns the number of extrabytes contained in the LAZ dataset.
 
QgsVector3D scale() const
Returns the scale of the points coordinates.
 
int pointFormat() const
Returns the point format of the point records contained in the LAZ file.
 
QVector< ExtraBytesAttributeDetails > extrabytes() const
Returns the list of extrabytes contained in the LAZ file.
 
QgsVector3D offset() const
Returns the offset of the points coordinates.
 
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.
 
A collection of point cloud attributes.
 
int pointRecordSize() const
Returns total size of record.
 
const QgsPointCloudAttribute * find(const QString &attributeName, int &offset) const
Finds the attribute with the name.
 
QVector< QgsPointCloudAttribute > attributes() const
Returns all attributes.
 
Attribute for point cloud data pair of name and size in bytes.
 
DataType
Systems of unit measurement.
 
@ 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 convertValueToDouble(const char *ptr) const
Returns the attribute's value as a double for data pointed to by ptr.
 
A rectangle specified with double values.
 
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
 
void setYMinimum(double y)
Set the minimum y value.
 
void setXMinimum(double x)
Set the minimum x value.
 
void setYMaximum(double y)
Set the maximum y value.
 
void setXMaximum(double x)
Set the maximum x value.
 
A 3D vector (similar to QVector3D) with the difference that it uses double precision instead of singl...
 
double y() const
Returns Y coordinate.
 
double x() const
Returns X coordinate.
 
#define QgsDebugMsgLevel(str, level)
 
#define QgsDebugError(str)