22 #include "qgsconfig.h" 
   30 #include <QTemporaryFile> 
   34 #include "laz-perf/io.hpp" 
   35 #include "laz-perf/common/common.hpp" 
   46       char val = char( value );
 
   52       short val = short( value );
 
   53       memcpy( s + position, 
reinterpret_cast<char * 
>( &val ), 
sizeof( 
short ) );
 
   59       unsigned short val = 
static_cast< unsigned short>( value );
 
   60       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( 
unsigned short ) );
 
   66       float val = float( value );
 
   67       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ),  
sizeof( 
float ) );
 
   72       qint32 val = qint32( value );
 
   73       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( qint32 ) );
 
   78       double val = double( value );
 
   79       memcpy( s + position, 
reinterpret_cast< char * 
>( &val ), 
sizeof( 
double ) );
 
   90   if ( outputType == inputType )
 
   92     memcpy( data + outputPosition, input + inputPosition, inputSize );
 
  100       char val = *( input + inputPosition );
 
  101       return _storeToStream<char>( data, outputPosition, outputType, val );
 
  105       const short val = *
reinterpret_cast< const short * 
>( input + inputPosition );
 
  106       return _storeToStream<short>( data, outputPosition, outputType, val );
 
  110       const unsigned short val = *
reinterpret_cast< const unsigned short * 
>( input + inputPosition );
 
  111       return _storeToStream<unsigned short>( data, outputPosition, outputType, val );
 
  115       const float val = *
reinterpret_cast< const float * 
>( input + inputPosition );
 
  116       return _storeToStream<float>( data, outputPosition, outputType, val );
 
  120       const qint32 val = *
reinterpret_cast<const qint32 * 
>( input + inputPosition );
 
  121       return _storeToStream<qint32>( data, outputPosition, outputType, val );
 
  125       const double val = *
reinterpret_cast< const double * 
>( input + inputPosition );
 
  126       return _storeToStream<double>( data, outputPosition, outputType, val );
 
  137   const std::size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
 
  138   const int count = dataUncompressed.size() / pointRecordSize;
 
  140   data.resize( requestedPointRecordSize * count );
 
  141   char *destinationBuffer = data.data();
 
  142   const char *s = dataUncompressed.data();
 
  144   const QVector<QgsPointCloudAttribute> requestedAttributesVector = requestedAttributes.
attributes();
 
  151       : inputOffset( inputOffset )
 
  152       , inputSize( inputSize )
 
  153       , inputType( inputType )
 
  154       , requestedSize( requestedSize )
 
  155       , requestedType( requestedType )
 
  165   std::vector< AttributeData > attributeData;
 
  166   attributeData.reserve( requestedAttributesVector.size() );
 
  169     int inputAttributeOffset;
 
  171     if ( !inputAttribute )
 
  175     attributeData.emplace_back( AttributeData( inputAttributeOffset, inputAttribute->
size(), inputAttribute->
type(),
 
  176                                 requestedAttribute.size(), requestedAttribute.type() ) );
 
  180   size_t outputOffset = 0;
 
  181   for ( 
int i = 0; i < count; ++i )
 
  183     for ( 
const AttributeData &attribute : attributeData )
 
  185       _serialize( destinationBuffer, outputOffset,
 
  186                   attribute.requestedType, s,
 
  187                   attribute.inputType, attribute.inputSize, i * pointRecordSize + attribute.inputOffset );
 
  189       outputOffset += attribute.requestedSize;
 
  201   if ( ! QFile::exists( filename ) )
 
  205   bool r = f.open( QIODevice::ReadOnly );
 
  209   QByteArray dataUncompressed = f.read( f.size() );
 
  210   return _decompressBinary( dataUncompressed, attributes, requestedAttributes, scale, offset );
 
  215   return _decompressBinary( data, attributes, requestedAttributes, scale, offset );
 
  220 QByteArray decompressZtdStream( 
const QByteArray &dataCompressed )
 
  225   const int MAXSIZE = 10000000;
 
  226   QByteArray dataUncompressed;
 
  227   dataUncompressed.resize( MAXSIZE );
 
  229   ZSTD_DStream *strm = ZSTD_createDStream();
 
  230   ZSTD_initDStream( strm );
 
  232   ZSTD_inBuffer m_inBuf;
 
  233   m_inBuf.src = 
reinterpret_cast<const void *
>( dataCompressed.constData() );
 
  234   m_inBuf.size = dataCompressed.size();
 
  237   ZSTD_outBuffer outBuf { 
reinterpret_cast<void *
>( dataUncompressed.data() ), MAXSIZE, 0 };
 
  238   size_t ret = ZSTD_decompressStream( strm, &outBuf, &m_inBuf );
 
  239   Q_ASSERT( !ZSTD_isError( ret ) );
 
  240   Q_ASSERT( outBuf.pos );
 
  241   Q_ASSERT( outBuf.pos < outBuf.size );
 
  243   ZSTD_freeDStream( strm );
 
  244   dataUncompressed.resize( outBuf.pos );
 
  245   return dataUncompressed;
 
  250   if ( ! QFile::exists( filename ) )
 
  254   bool r = f.open( QIODevice::ReadOnly );
 
  258   QByteArray dataCompressed = f.readAll();
 
  259   QByteArray dataUncompressed = decompressZtdStream( dataCompressed );
 
  260   return _decompressBinary( dataUncompressed, attributes, requestedAttributes, scale, offset );
 
  265   QByteArray dataUncompressed = decompressZtdStream( data );
 
  266   return _decompressBinary( dataUncompressed, attributes, requestedAttributes, scale, offset );
 
  271 template<
typename FileType>
 
  274   Q_UNUSED( attributes );
 
  282   auto start = common::tick();
 
  285   laszip::io::reader::basic_file<FileType> f( file );
 
  287   const size_t count = f.get_header().point_count;
 
  288   QgsVector3D scale( f.get_header().scale.x, f.get_header().scale.y, f.get_header().scale.z );
 
  289   QgsVector3D offset( f.get_header().offset.x, f.get_header().offset.y, f.get_header().offset.z );
 
  291   QByteArray bufArray( f.get_header().point_record_length, 0 );
 
  292   char *buf = bufArray.data();
 
  294   const size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
 
  296   data.resize( requestedPointRecordSize * count );
 
  297   char *dataBuffer = data.data();
 
  299   const QVector<QgsPointCloudAttribute> requestedAttributesVector = requestedAttributes.
attributes();
 
  301   std::size_t outputOffset = 0;
 
  303   enum class LazAttribute
 
  323   struct RequestedAttributeDetails
 
  326       : attribute( attribute )
 
  331     LazAttribute attribute;
 
  336   std::vector< RequestedAttributeDetails > requestedAttributeDetails;
 
  337   requestedAttributeDetails.reserve( requestedAttributesVector.size() );
 
  340     if ( requestedAttribute.name().compare( QLatin1String( 
"X" ), Qt::CaseInsensitive ) == 0 )
 
  342       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::X, requestedAttribute.type(), requestedAttribute.size() ) );
 
  344     else if ( requestedAttribute.name().compare( QLatin1String( 
"Y" ), Qt::CaseInsensitive ) == 0 )
 
  346       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Y, requestedAttribute.type(), requestedAttribute.size() ) );
 
  348     else if ( requestedAttribute.name().compare( QLatin1String( 
"Z" ), Qt::CaseInsensitive ) == 0 )
 
  350       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Z, requestedAttribute.type(), requestedAttribute.size() ) );
 
  352     else if ( requestedAttribute.name().compare( QLatin1String( 
"Classification" ), Qt::CaseInsensitive ) == 0 )
 
  354       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Classification, requestedAttribute.type(), requestedAttribute.size() ) );
 
  356     else if ( requestedAttribute.name().compare( QLatin1String( 
"Intensity" ), Qt::CaseInsensitive ) == 0 )
 
  358       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Intensity, requestedAttribute.type(), requestedAttribute.size() ) );
 
  360     else if ( requestedAttribute.name().compare( QLatin1String( 
"ReturnNumber" ), Qt::CaseInsensitive ) == 0 )
 
  362       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ReturnNumber, requestedAttribute.type(), requestedAttribute.size() ) );
 
  364     else if ( requestedAttribute.name().compare( QLatin1String( 
"NumberOfReturns" ), Qt::CaseInsensitive ) == 0 )
 
  366       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::NumberOfReturns, requestedAttribute.type(), requestedAttribute.size() ) );
 
  368     else if ( requestedAttribute.name().compare( QLatin1String( 
"ScanDirectionFlag" ), Qt::CaseInsensitive ) == 0 )
 
  370       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ScanDirectionFlag, requestedAttribute.type(), requestedAttribute.size() ) );
 
  372     else if ( requestedAttribute.name().compare( QLatin1String( 
"EdgeOfFlightLine" ), Qt::CaseInsensitive ) == 0 )
 
  374       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::EdgeOfFlightLine, requestedAttribute.type(), requestedAttribute.size() ) );
 
  376     else if ( requestedAttribute.name().compare( QLatin1String( 
"ScanAngleRank" ), Qt::CaseInsensitive ) == 0 )
 
  378       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ScanAngleRank, requestedAttribute.type(), requestedAttribute.size() ) );
 
  380     else if ( requestedAttribute.name().compare( QLatin1String( 
"UserData" ), Qt::CaseInsensitive ) == 0 )
 
  382       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::UserData, requestedAttribute.type(), requestedAttribute.size() ) );
 
  384     else if ( requestedAttribute.name().compare( QLatin1String( 
"PointSourceId" ), Qt::CaseInsensitive ) == 0 )
 
  386       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::PointSourceId, requestedAttribute.type(), requestedAttribute.size() ) );
 
  388     else if ( requestedAttribute.name().compare( QLatin1String( 
"Red" ), Qt::CaseInsensitive ) == 0 )
 
  390       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Red, requestedAttribute.type(), requestedAttribute.size() ) );
 
  392     else if ( requestedAttribute.name().compare( QLatin1String( 
"Green" ), Qt::CaseInsensitive ) == 0 )
 
  394       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Green, requestedAttribute.type(), requestedAttribute.size() ) );
 
  396     else if ( requestedAttribute.name().compare( QLatin1String( 
"Blue" ), Qt::CaseInsensitive ) == 0 )
 
  398       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Blue, requestedAttribute.type(), requestedAttribute.size() ) );
 
  403       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::MissingOrUnknown, requestedAttribute.type(), requestedAttribute.size() ) );
 
  407   for ( 
size_t i = 0 ; i < count ; i ++ )
 
  410     laszip::formats::las::point10 p = laszip::formats::packers<laszip::formats::las::point10>::unpack( buf );
 
  411     laszip::formats::las::rgb rgb = laszip::formats::packers<laszip::formats::las::rgb>::unpack( buf + 
sizeof( laszip::formats::las::point10 ) + 
sizeof( laszip::formats::las::gpstime ) );
 
  413     for ( 
const RequestedAttributeDetails &requestedAttribute : requestedAttributeDetails )
 
  415       switch ( requestedAttribute.attribute )
 
  417         case LazAttribute::X:
 
  418           _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.x );
 
  420         case LazAttribute::Y:
 
  421           _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.y );
 
  423         case LazAttribute::Z:
 
  424           _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.z );
 
  426         case LazAttribute::Classification:
 
  427           _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.classification );
 
  429         case LazAttribute::Intensity:
 
  430           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, p.intensity );
 
  432         case LazAttribute::ReturnNumber:
 
  433           _storeToStream<unsigned char>( dataBuffer,  outputOffset, requestedAttribute.type, p.return_number );
 
  435         case LazAttribute::NumberOfReturns:
 
  436           _storeToStream<unsigned char>( dataBuffer,  outputOffset, requestedAttribute.type, p.number_of_returns_of_given_pulse );
 
  438         case LazAttribute::ScanDirectionFlag:
 
  439           _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.scan_direction_flag );
 
  441         case LazAttribute::EdgeOfFlightLine:
 
  442           _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.edge_of_flight_line );
 
  444         case LazAttribute::ScanAngleRank:
 
  445           _storeToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, p.scan_angle_rank );
 
  447         case LazAttribute::UserData:
 
  448           _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.user_data );
 
  450         case LazAttribute::PointSourceId:
 
  451           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, p.point_source_ID );
 
  453         case LazAttribute::Red:
 
  454           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.r );
 
  456         case LazAttribute::Green:
 
  457           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.g );
 
  459         case LazAttribute::Blue:
 
  460           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.b );
 
  462         case LazAttribute::MissingOrUnknown:
 
  464           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, 0 );
 
  468       outputOffset += requestedAttribute.size;
 
  473   float t = common::since( start );
 
  474   QgsDebugMsgLevel( QStringLiteral( 
"LAZ-PERF Read through the points in %1 seconds." ).arg( t ), 2 );
 
  489   const QByteArray arr = filename.toUtf8();
 
  490   std::ifstream file( arr.constData(), std::ios::binary );
 
  492   return __decompressLaz<std::ifstream>( file, attributes, requestedAttributes, scale, offset );
 
  500   std::istringstream file( byteArrayData.toStdString() );
 
  501   return __decompressLaz<std::istringstream>( file, attributes, requestedAttributes, scale, offset );
 
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.
int size() const
Returns size of the attribute in bytes.
DataType type() const
Returns the data type.
Base class for storing raw data from point cloud nodes.
#define QgsDebugMsgLevel(str, level)