22 #include "qgsconfig.h" 
   31 #include <QElapsedTimer> 
   32 #include <QTemporaryFile> 
   37 #include "lazperf/las.hpp" 
   38 #include <lazperf/lazperf.hpp> 
   55       const char val = char( value );
 
   61       const unsigned char val = ( 
unsigned char )( value );
 
   68       short val = short( value );
 
   69       memcpy( s + position, 
reinterpret_cast<char * 
>( &val ), 
sizeof( 
short ) );
 
   74       unsigned short val = 
static_cast< unsigned short>( value );
 
   75       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( 
unsigned short ) );
 
   81       qint32 val = qint32( value );
 
   82       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( qint32 ) );
 
   87       quint32 val = quint32( value );
 
   88       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( quint32 ) );
 
   94       qint64 val = qint64( value );
 
   95       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( qint64 ) );
 
  100       quint64 val = quint64( value );
 
  101       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( quint64 ) );
 
  107       float val = float( value );
 
  108       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ),  
sizeof( 
float ) );
 
  113       double val = double( value );
 
  114       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( 
double ) );
 
  125   if ( outputType == inputType )
 
  127     memcpy( data + outputPosition, input + inputPosition, inputSize );
 
  135       const char val = *( input + inputPosition );
 
  136       return _lazStoreToStream<char>( data, outputPosition, outputType, val );
 
  140       const unsigned char val = *( input + inputPosition );
 
  141       return _lazStoreToStream<unsigned char>( data, outputPosition, outputType, val );
 
  145       const short val = *
reinterpret_cast< const short * 
>( input + inputPosition );
 
  146       return _lazStoreToStream<short>( data, outputPosition, outputType, val );
 
  150       const unsigned short val = *
reinterpret_cast< const unsigned short * 
>( input + inputPosition );
 
  151       return _lazStoreToStream<unsigned short>( data, outputPosition, outputType, val );
 
  155       const qint32 val = *
reinterpret_cast<const qint32 * 
>( input + inputPosition );
 
  156       return _lazStoreToStream<qint32>( data, outputPosition, outputType, val );
 
  160       const quint32 val = *
reinterpret_cast<const quint32 * 
>( input + inputPosition );
 
  161       return _lazStoreToStream<quint32>( data, outputPosition, outputType, val );
 
  165       const qint64 val = *
reinterpret_cast<const qint64 * 
>( input + inputPosition );
 
  166       return _lazStoreToStream<qint64>( data, outputPosition, outputType, val );
 
  170       const quint64 val = *
reinterpret_cast<const quint64 * 
>( input + inputPosition );
 
  171       return _lazStoreToStream<quint64>( data, outputPosition, outputType, val );
 
  175       const float val = *
reinterpret_cast< const float * 
>( input + inputPosition );
 
  176       return _lazStoreToStream<float>( data, outputPosition, outputType, val );
 
  180       const double val = *
reinterpret_cast< const double * 
>( input + inputPosition );
 
  181       return _lazStoreToStream<double>( data, outputPosition, outputType, val );
 
  189 std::vector< QgsLazDecoder::RequestedAttributeDetails > __prepareRequestedAttributeDetails( 
const QgsPointCloudAttributeCollection &requestedAttributes, QVector<QgsLazInfo::ExtraBytesAttributeDetails> &extrabytesAttr )
 
  191   const QVector<QgsPointCloudAttribute> requestedAttributesVector = requestedAttributes.
attributes();
 
  193   std::vector< QgsLazDecoder::RequestedAttributeDetails > requestedAttributeDetails;
 
  194   requestedAttributeDetails.reserve( requestedAttributesVector.size() );
 
  197     if ( requestedAttribute.name().compare( QLatin1String( 
"X" ), Qt::CaseInsensitive ) == 0 )
 
  199       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::X, requestedAttribute.type(), requestedAttribute.size() ) );
 
  201     else if ( requestedAttribute.name().compare( QLatin1String( 
"Y" ), Qt::CaseInsensitive ) == 0 )
 
  203       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Y, requestedAttribute.type(), requestedAttribute.size() ) );
 
  205     else if ( requestedAttribute.name().compare( QLatin1String( 
"Z" ), Qt::CaseInsensitive ) == 0 )
 
  207       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Z, requestedAttribute.type(), requestedAttribute.size() ) );
 
  209     else if ( requestedAttribute.name().compare( QLatin1String( 
"Classification" ), Qt::CaseInsensitive ) == 0 )
 
  211       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Classification, requestedAttribute.type(), requestedAttribute.size() ) );
 
  213     else if ( requestedAttribute.name().compare( QLatin1String( 
"Intensity" ), Qt::CaseInsensitive ) == 0 )
 
  215       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Intensity, requestedAttribute.type(), requestedAttribute.size() ) );
 
  217     else if ( requestedAttribute.name().compare( QLatin1String( 
"ReturnNumber" ), Qt::CaseInsensitive ) == 0 )
 
  219       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ReturnNumber, requestedAttribute.type(), requestedAttribute.size() ) );
 
  221     else if ( requestedAttribute.name().compare( QLatin1String( 
"NumberOfReturns" ), Qt::CaseInsensitive ) == 0 )
 
  223       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::NumberOfReturns, requestedAttribute.type(), requestedAttribute.size() ) );
 
  225     else if ( requestedAttribute.name().compare( QLatin1String( 
"ScanDirectionFlag" ), Qt::CaseInsensitive ) == 0 )
 
  227       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ScanDirectionFlag, requestedAttribute.type(), requestedAttribute.size() ) );
 
  229     else if ( requestedAttribute.name().compare( QLatin1String( 
"EdgeOfFlightLine" ), Qt::CaseInsensitive ) == 0 )
 
  231       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::EdgeOfFlightLine, requestedAttribute.type(), requestedAttribute.size() ) );
 
  233     else if ( requestedAttribute.name().compare( QLatin1String( 
"ScanAngleRank" ), Qt::CaseInsensitive ) == 0 )
 
  235       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ScanAngleRank, requestedAttribute.type(), requestedAttribute.size() ) );
 
  237     else if ( requestedAttribute.name().compare( QLatin1String( 
"UserData" ), Qt::CaseInsensitive ) == 0 )
 
  239       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::UserData, requestedAttribute.type(), requestedAttribute.size() ) );
 
  241     else if ( requestedAttribute.name().compare( QLatin1String( 
"PointSourceId" ), Qt::CaseInsensitive ) == 0 )
 
  243       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::PointSourceId, requestedAttribute.type(), requestedAttribute.size() ) );
 
  245     else if ( requestedAttribute.name().compare( QLatin1String( 
"GpsTime" ), Qt::CaseInsensitive ) == 0 )
 
  247       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::GpsTime, requestedAttribute.type(), requestedAttribute.size() ) );
 
  249     else if ( requestedAttribute.name().compare( QLatin1String( 
"Red" ), Qt::CaseInsensitive ) == 0 )
 
  251       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Red, requestedAttribute.type(), requestedAttribute.size() ) );
 
  253     else if ( requestedAttribute.name().compare( QLatin1String( 
"Green" ), Qt::CaseInsensitive ) == 0 )
 
  255       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Green, requestedAttribute.type(), requestedAttribute.size() ) );
 
  257     else if ( requestedAttribute.name().compare( QLatin1String( 
"Blue" ), Qt::CaseInsensitive ) == 0 )
 
  259       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::Blue, requestedAttribute.type(), requestedAttribute.size() ) );
 
  261     else if ( requestedAttribute.name().compare( QLatin1String( 
"ScannerChannel" ), Qt::CaseInsensitive ) == 0 )
 
  263       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ScannerChannel, requestedAttribute.type(), requestedAttribute.size() ) );
 
  265     else if ( requestedAttribute.name().compare( QLatin1String( 
"ClassificationFlags" ), Qt::CaseInsensitive ) == 0 )
 
  267       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ClassificationFlags, requestedAttribute.type(), requestedAttribute.size() ) );
 
  269     else if ( requestedAttribute.name().compare( QLatin1String( 
"Infrared" ), Qt::CaseInsensitive ) == 0 )
 
  271       requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::NIR, requestedAttribute.type(), requestedAttribute.size() ) );
 
  275       bool foundAttr = 
false;
 
  278         if ( requestedAttribute.name().compare( eba.attribute.trimmed() ) == 0 )
 
  280           requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::ExtraBytes, eba.type, eba.size, eba.offset ) );
 
  288         requestedAttributeDetails.emplace_back( QgsLazDecoder::RequestedAttributeDetails( QgsLazDecoder::LazAttribute::MissingOrUnknown, requestedAttribute.type(), requestedAttribute.size() ) );
 
  292   return requestedAttributeDetails;
 
  295 void decodePoint( 
char *buf, 
int lasPointFormat, 
char *dataBuffer, std::size_t &outputOffset, std::vector< QgsLazDecoder::RequestedAttributeDetails > &requestedAttributeDetails )
 
  297   lazperf::las::point10 p10;
 
  298   lazperf::las::gpstime gps;
 
  299   lazperf::las::rgb rgb;
 
  300   lazperf::las::nir14 nir;
 
  301   lazperf::las::point14 p14;
 
  303   bool isLas14 = ( lasPointFormat == 6 || lasPointFormat == 7 || lasPointFormat == 8 );
 
  305   switch ( lasPointFormat )
 
  313       gps.unpack( buf + 
sizeof( lazperf::las::point10 ) );
 
  317       rgb.unpack( buf + 
sizeof( lazperf::las::point10 ) );
 
  321       gps.unpack( buf + 
sizeof( lazperf::las::point10 ) );
 
  322       rgb.unpack( buf + 
sizeof( lazperf::las::point10 ) + 
sizeof( lazperf::las::gpstime ) );
 
  331       rgb.unpack( buf + 
sizeof( lazperf::las::point14 ) );
 
  335       rgb.unpack( buf + 
sizeof( lazperf::las::point14 ) );
 
  336       nir.unpack( buf + 
sizeof( lazperf::las::point14 ) + 
sizeof( lazperf::las::rgb ) );
 
  343   for ( 
const QgsLazDecoder::RequestedAttributeDetails &requestedAttribute : requestedAttributeDetails )
 
  345     switch ( requestedAttribute.attribute )
 
  347       case QgsLazDecoder::LazAttribute::X:
 
  348         _lazStoreToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.x() : p10.x );
 
  350       case QgsLazDecoder::LazAttribute::Y:
 
  351         _lazStoreToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.y() : p10.y );
 
  353       case QgsLazDecoder::LazAttribute::Z:
 
  354         _lazStoreToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.z() : p10.z );
 
  356       case QgsLazDecoder::LazAttribute::Classification:
 
  357         _lazStoreToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.classification() : p10.classification );
 
  359       case QgsLazDecoder::LazAttribute::Intensity:
 
  360         _lazStoreToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.intensity() : p10.intensity );
 
  362       case QgsLazDecoder::LazAttribute::ReturnNumber:
 
  363         _lazStoreToStream<unsigned char>( dataBuffer,  outputOffset, requestedAttribute.type, isLas14 ? p14.returnNum() : p10.return_number );
 
  365       case QgsLazDecoder::LazAttribute::NumberOfReturns:
 
  366         _lazStoreToStream<unsigned char>( dataBuffer,  outputOffset, requestedAttribute.type, isLas14 ? p14.numReturns() : p10.number_of_returns_of_given_pulse );
 
  368       case QgsLazDecoder::LazAttribute::ScanDirectionFlag:
 
  369         _lazStoreToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.scanDirFlag() : p10.scan_direction_flag );
 
  371       case QgsLazDecoder::LazAttribute::EdgeOfFlightLine:
 
  372         _lazStoreToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.eofFlag() : p10.edge_of_flight_line );
 
  374       case QgsLazDecoder::LazAttribute::ScanAngleRank:
 
  375         _lazStoreToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.scanAngle() : p10.scan_angle_rank );
 
  377       case QgsLazDecoder::LazAttribute::UserData:
 
  378         _lazStoreToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.userData() : p10.user_data );
 
  380       case QgsLazDecoder::LazAttribute::PointSourceId:
 
  381         _lazStoreToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, isLas14 ? p14.pointSourceID() : p10.point_source_ID );
 
  383       case QgsLazDecoder::LazAttribute::GpsTime:
 
  385         _lazStoreToStream<double>( dataBuffer, outputOffset, requestedAttribute.type,
 
  386                                    isLas14 ? p14.gpsTime() : *
reinterpret_cast<const double *
>( 
reinterpret_cast<const void *
>( &gps.value ) ) );
 
  388       case QgsLazDecoder::LazAttribute::Red:
 
  389         _lazStoreToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.r );
 
  391       case QgsLazDecoder::LazAttribute::Green:
 
  392         _lazStoreToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.g );
 
  394       case QgsLazDecoder::LazAttribute::Blue:
 
  395         _lazStoreToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.b );
 
  397       case QgsLazDecoder::LazAttribute::ScannerChannel:
 
  398         _lazStoreToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, p14.scannerChannel() );
 
  400       case QgsLazDecoder::LazAttribute::ClassificationFlags:
 
  401         _lazStoreToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, p14.classFlags() );
 
  403       case QgsLazDecoder::LazAttribute::NIR:
 
  405         if ( lasPointFormat == 8 || lasPointFormat == 10 )
 
  407           _lazStoreToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, nir.val );
 
  412           _lazStoreToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, 0 );
 
  417       case QgsLazDecoder::LazAttribute::ExtraBytes:
 
  419         switch ( requestedAttribute.type )
 
  422             _lazStoreToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<char * 
>( &buf[requestedAttribute.offset] ) );
 
  425             _lazStoreToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<unsigned char * 
>( &buf[requestedAttribute.offset] ) );
 
  428             _lazStoreToStream<qint16>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint16 * 
>( &buf[requestedAttribute.offset] ) );
 
  431             _lazStoreToStream<quint16>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint16 * 
>( &buf[requestedAttribute.offset] ) );
 
  434             _lazStoreToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint32 * 
>( &buf[requestedAttribute.offset] ) );
 
  437             _lazStoreToStream<quint32>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint32 * 
>( &buf[requestedAttribute.offset] ) );
 
  440             _lazStoreToStream<qint64>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint64 * 
>( &buf[requestedAttribute.offset] ) );
 
  443             _lazStoreToStream<quint64>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint64 * 
>( &buf[requestedAttribute.offset] ) );
 
  446             _lazStoreToStream<float>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<float * 
>( &buf[requestedAttribute.offset] ) );
 
  449             _lazStoreToStream<double>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<double * 
>( &buf[requestedAttribute.offset] ) );
 
  454       case QgsLazDecoder::LazAttribute::MissingOrUnknown:
 
  456         _lazStoreToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, 0 );
 
  460     outputOffset += requestedAttribute.size;
 
  464 template<
typename FileType>
 
  478     lazperf::reader::generic_file f( file );
 
  485     int lasPointFormat = f.header().pointFormat();
 
  486     if ( lasPointFormat != 0 && lasPointFormat != 1 && lasPointFormat != 2 && lasPointFormat != 3 &&
 
  487          lasPointFormat != 6 && lasPointFormat != 7 && lasPointFormat != 8 )
 
  489       QgsDebugMsg( QStringLiteral( 
"Unexpected point format record (%1) - only 0, 1, 2, 3, 6, 7, 8 are supported" ).arg( lasPointFormat ) );
 
  493     const size_t count = f.header().point_count;
 
  494     const QgsVector3D scale( f.header().scale.x, f.header().scale.y, f.header().scale.z );
 
  495     const QgsVector3D offset( f.header().offset.x, f.header().offset.y, f.header().offset.z );
 
  497     QByteArray bufArray( f.header().point_record_length, 0 );
 
  498     char *buf = bufArray.data();
 
  500     const size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
 
  502     data.resize( requestedPointRecordSize * count );
 
  503     char *dataBuffer = data.data();
 
  505     std::size_t outputOffset = 0;
 
  507     std::unique_ptr< QgsPointCloudBlock > block = std::make_unique< QgsPointCloudBlock >(
 
  513     int skippedPoints = 0;
 
  514     const bool filterIsValid = filterExpression.isValid();
 
  515     if ( !filterExpression.prepare( block.get() ) && filterIsValid )
 
  518       block->setPointCount( 0 );
 
  519       return block.release();
 
  522     std::vector<char> rawExtrabytes = f.vlrData( 
"LASF_Spec", 4 );
 
  523     QVector<QgsLazInfo::ExtraBytesAttributeDetails> extrabyteAttributesDetails = 
QgsLazInfo::parseExtrabytes( rawExtrabytes.data(), rawExtrabytes.size(), f.header().point_record_length );
 
  524     std::vector< QgsLazDecoder::RequestedAttributeDetails > requestedAttributeDetails = __prepareRequestedAttributeDetails( requestedAttributes, extrabyteAttributesDetails );
 
  526     for ( 
size_t i = 0 ; i < count ; i ++ )
 
  530       decodePoint( buf, lasPointFormat, dataBuffer, outputOffset, requestedAttributeDetails );
 
  536         double eval = filterExpression.evaluate( i - skippedPoints );
 
  537         if ( !eval || std::isnan( eval ) )
 
  540           outputOffset -= requestedPointRecordSize;
 
  547     QgsDebugMsgLevel( QStringLiteral( 
"LAZ-PERF Read through the points in %1 seconds." ).arg( t.elapsed() / 1000. ), 2 );
 
  549     block->setPointCount( count - skippedPoints );
 
  550     return block.release();
 
  552   catch ( std::exception &e )
 
  554     QgsDebugMsg( 
"Error decompressing laz file: " + QString::fromLatin1( e.what() ) );
 
  561     QgsPointCloudExpression &filterExpression )
 
  563   std::ifstream file( toNativePath( filename ), std::ios::binary );
 
  565   return __decompressLaz<std::ifstream>( file, requestedAttributes, filterExpression );
 
  570     QgsPointCloudExpression &filterExpression )
 
  572   std::istringstream file( byteArrayData.toStdString() );
 
  573   return __decompressLaz<std::istringstream>( file, requestedAttributes, filterExpression );
 
  580   if ( lasPointFormat != 6 && lasPointFormat != 7 && lasPointFormat != 8 )
 
  582     QgsDebugMsg( QStringLiteral( 
"Unexpected point format record (%1) - only 6, 7, 8 are supported for COPC format" ).arg( lasPointFormat ) );
 
  588   lazperf::reader::chunk_decompressor decompressor( lasPointFormat, lazInfo.
extrabytesCount(), data.data() );
 
  590   const size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
 
  591   QByteArray blockData;
 
  592   blockData.resize( requestedPointRecordSize * pointCount );
 
  593   char *dataBuffer = blockData.data();
 
  595   std::size_t outputOffset = 0;
 
  597   QVector<QgsLazInfo::ExtraBytesAttributeDetails> extrabyteAttributesDetails = lazInfo.
extrabytes();
 
  598   std::vector< RequestedAttributeDetails > requestedAttributeDetails = __prepareRequestedAttributeDetails( requestedAttributes, extrabyteAttributesDetails );
 
  599   std::unique_ptr< QgsPointCloudBlock > block = std::make_unique< QgsPointCloudBlock >(
 
  600         pointCount, requestedAttributes,
 
  604   int skippedPoints = 0;
 
  605   const bool filterIsValid = filterExpression.isValid();
 
  606   if ( !filterExpression.prepare( block.get() ) && filterIsValid )
 
  609     block->setPointCount( 0 );
 
  610     return block.release();
 
  613   for ( 
int i = 0 ; i < pointCount; ++i )
 
  615     decompressor.decompress( decodedData.get() );
 
  616     char *buf = decodedData.get();
 
  618     decodePoint( buf, lasPointFormat, dataBuffer, outputOffset, requestedAttributeDetails );
 
  624       double eval = filterExpression.evaluate( i - skippedPoints );
 
  625       if ( !eval || std::isnan( eval ) )
 
  628         outputOffset -= requestedPointRecordSize;
 
  634   block->setPointCount( pointCount - skippedPoints );
 
  635   return block.release();
 
  638 #if defined(_MSC_VER) 
  639 std::wstring QgsLazDecoder::toNativePath( 
const QString &filename )
 
  641   std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > converter;
 
  642   return converter.from_bytes( filename.toStdString() );
 
  645 std::string QgsLazDecoder::toNativePath( 
const QString &filename )
 
  647   return filename.toStdString();