22 #include "qgsconfig.h" 
   30 #include <QTemporaryFile> 
   34 #include "laz-perf/io.hpp" 
   35 #include "laz-perf/common/common.hpp" 
   46       const 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       const 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   const bool r = f.open( QIODevice::ReadOnly );
 
  209   const 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   const 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   const bool r = f.open( QIODevice::ReadOnly );
 
  258   const QByteArray dataCompressed = f.readAll();
 
  259   const QByteArray dataUncompressed = decompressZtdStream( dataCompressed );
 
  260   return _decompressBinary( dataUncompressed, attributes, requestedAttributes, scale, offset );
 
  265   const QByteArray dataUncompressed = decompressZtdStream( data );
 
  266   return _decompressBinary( dataUncompressed, attributes, requestedAttributes, scale, offset );
 
  271 template<
typename FileType>
 
  274   Q_UNUSED( attributes );
 
  282   const auto start = common::tick();
 
  285   laszip::io::reader::basic_file<FileType> f( file );
 
  287   const size_t count = f.get_header().point_count;
 
  288   const QgsVector3D scale( f.get_header().scale.x, f.get_header().scale.y, f.get_header().scale.z );
 
  289   const 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
 
  324   struct RequestedAttributeDetails
 
  327       : attribute( attribute )
 
  332     LazAttribute attribute;
 
  337   std::vector< RequestedAttributeDetails > requestedAttributeDetails;
 
  338   requestedAttributeDetails.reserve( requestedAttributesVector.size() );
 
  341     if ( requestedAttribute.name().compare( QLatin1String( 
"X" ), Qt::CaseInsensitive ) == 0 )
 
  343       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::X, requestedAttribute.type(), requestedAttribute.size() ) );
 
  345     else if ( requestedAttribute.name().compare( QLatin1String( 
"Y" ), Qt::CaseInsensitive ) == 0 )
 
  347       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Y, requestedAttribute.type(), requestedAttribute.size() ) );
 
  349     else if ( requestedAttribute.name().compare( QLatin1String( 
"Z" ), Qt::CaseInsensitive ) == 0 )
 
  351       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Z, requestedAttribute.type(), requestedAttribute.size() ) );
 
  353     else if ( requestedAttribute.name().compare( QLatin1String( 
"Classification" ), Qt::CaseInsensitive ) == 0 )
 
  355       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Classification, requestedAttribute.type(), requestedAttribute.size() ) );
 
  357     else if ( requestedAttribute.name().compare( QLatin1String( 
"Intensity" ), Qt::CaseInsensitive ) == 0 )
 
  359       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Intensity, requestedAttribute.type(), requestedAttribute.size() ) );
 
  361     else if ( requestedAttribute.name().compare( QLatin1String( 
"ReturnNumber" ), Qt::CaseInsensitive ) == 0 )
 
  363       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ReturnNumber, requestedAttribute.type(), requestedAttribute.size() ) );
 
  365     else if ( requestedAttribute.name().compare( QLatin1String( 
"NumberOfReturns" ), Qt::CaseInsensitive ) == 0 )
 
  367       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::NumberOfReturns, requestedAttribute.type(), requestedAttribute.size() ) );
 
  369     else if ( requestedAttribute.name().compare( QLatin1String( 
"ScanDirectionFlag" ), Qt::CaseInsensitive ) == 0 )
 
  371       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ScanDirectionFlag, requestedAttribute.type(), requestedAttribute.size() ) );
 
  373     else if ( requestedAttribute.name().compare( QLatin1String( 
"EdgeOfFlightLine" ), Qt::CaseInsensitive ) == 0 )
 
  375       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::EdgeOfFlightLine, requestedAttribute.type(), requestedAttribute.size() ) );
 
  377     else if ( requestedAttribute.name().compare( QLatin1String( 
"ScanAngleRank" ), Qt::CaseInsensitive ) == 0 )
 
  379       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ScanAngleRank, requestedAttribute.type(), requestedAttribute.size() ) );
 
  381     else if ( requestedAttribute.name().compare( QLatin1String( 
"UserData" ), Qt::CaseInsensitive ) == 0 )
 
  383       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::UserData, requestedAttribute.type(), requestedAttribute.size() ) );
 
  385     else if ( requestedAttribute.name().compare( QLatin1String( 
"PointSourceId" ), Qt::CaseInsensitive ) == 0 )
 
  387       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::PointSourceId, requestedAttribute.type(), requestedAttribute.size() ) );
 
  389     else if ( requestedAttribute.name().compare( QLatin1String( 
"GpsTime" ), Qt::CaseInsensitive ) == 0 )
 
  391       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::GpsTime, requestedAttribute.type(), requestedAttribute.size() ) );
 
  393     else if ( requestedAttribute.name().compare( QLatin1String( 
"Red" ), Qt::CaseInsensitive ) == 0 )
 
  395       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Red, requestedAttribute.type(), requestedAttribute.size() ) );
 
  397     else if ( requestedAttribute.name().compare( QLatin1String( 
"Green" ), Qt::CaseInsensitive ) == 0 )
 
  399       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Green, requestedAttribute.type(), requestedAttribute.size() ) );
 
  401     else if ( requestedAttribute.name().compare( QLatin1String( 
"Blue" ), Qt::CaseInsensitive ) == 0 )
 
  403       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Blue, requestedAttribute.type(), requestedAttribute.size() ) );
 
  408       requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::MissingOrUnknown, requestedAttribute.type(), requestedAttribute.size() ) );
 
  412   for ( 
size_t i = 0 ; i < count ; i ++ )
 
  415     const laszip::formats::las::point10 p = laszip::formats::packers<laszip::formats::las::point10>::unpack( buf );
 
  416     const laszip::formats::las::gpstime gps = laszip::formats::packers<laszip::formats::las::gpstime>::unpack( buf + 
sizeof( laszip::formats::las::point10 ) );
 
  417     const laszip::formats::las::rgb rgb = laszip::formats::packers<laszip::formats::las::rgb>::unpack( buf + 
sizeof( laszip::formats::las::point10 ) + 
sizeof( laszip::formats::las::gpstime ) );
 
  419     for ( 
const RequestedAttributeDetails &requestedAttribute : requestedAttributeDetails )
 
  421       switch ( requestedAttribute.attribute )
 
  423         case LazAttribute::X:
 
  424           _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.x );
 
  426         case LazAttribute::Y:
 
  427           _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.y );
 
  429         case LazAttribute::Z:
 
  430           _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.z );
 
  432         case LazAttribute::Classification:
 
  433           _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.classification );
 
  435         case LazAttribute::Intensity:
 
  436           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, p.intensity );
 
  438         case LazAttribute::ReturnNumber:
 
  439           _storeToStream<unsigned char>( dataBuffer,  outputOffset, requestedAttribute.type, p.return_number );
 
  441         case LazAttribute::NumberOfReturns:
 
  442           _storeToStream<unsigned char>( dataBuffer,  outputOffset, requestedAttribute.type, p.number_of_returns_of_given_pulse );
 
  444         case LazAttribute::ScanDirectionFlag:
 
  445           _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.scan_direction_flag );
 
  447         case LazAttribute::EdgeOfFlightLine:
 
  448           _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.edge_of_flight_line );
 
  450         case LazAttribute::ScanAngleRank:
 
  451           _storeToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, p.scan_angle_rank );
 
  453         case LazAttribute::UserData:
 
  454           _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.user_data );
 
  456         case LazAttribute::PointSourceId:
 
  457           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, p.point_source_ID );
 
  459         case LazAttribute::GpsTime:
 
  461           _storeToStream<double>( dataBuffer, outputOffset, requestedAttribute.type,
 
  462                                   *
reinterpret_cast<const double *
>( 
reinterpret_cast<const void *
>( &gps.value ) ) );
 
  464         case LazAttribute::Red:
 
  465           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.r );
 
  467         case LazAttribute::Green:
 
  468           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.g );
 
  470         case LazAttribute::Blue:
 
  471           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.b );
 
  473         case LazAttribute::MissingOrUnknown:
 
  475           _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, 0 );
 
  479       outputOffset += requestedAttribute.size;
 
  484   const float t = common::since( start );
 
  485   QgsDebugMsgLevel( QStringLiteral( 
"LAZ-PERF Read through the points in %1 seconds." ).arg( t ), 2 );
 
  500   const QByteArray arr = filename.toUtf8();
 
  501   std::ifstream file( arr.constData(), std::ios::binary );
 
  503   return __decompressLaz<std::ifstream>( file, attributes, requestedAttributes, scale, offset );
 
  511   std::istringstream file( byteArrayData.toStdString() );
 
  512   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)