22 #include "qgsconfig.h"
30 #include <QTemporaryFile>
45 const char val = char( value );
51 const unsigned char val = (
unsigned char )( value );
58 short val = short( value );
59 memcpy( s + position,
reinterpret_cast<char *
>( &val ),
sizeof(
short ) );
64 unsigned short val =
static_cast< unsigned short>( value );
65 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof(
unsigned short ) );
71 qint32 val = qint32( value );
72 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof( qint32 ) );
77 quint32 val = quint32( value );
78 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof( quint32 ) );
84 qint64 val = qint64( value );
85 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof( qint64 ) );
90 quint64 val = quint64( value );
91 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof( quint64 ) );
97 float val = float( value );
98 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof(
float ) );
103 double val = double( value );
104 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof(
double ) );
115 if ( outputType == inputType )
117 memcpy( data + outputPosition, input + inputPosition, inputSize );
125 const char val = *( input + inputPosition );
126 return _storeToStream<char>( data, outputPosition, outputType, val );
130 const unsigned char val = *( input + inputPosition );
131 return _storeToStream<unsigned char>( data, outputPosition, outputType, val );
135 const short val = *
reinterpret_cast< const short *
>( input + inputPosition );
136 return _storeToStream<short>( data, outputPosition, outputType, val );
140 const unsigned short val = *
reinterpret_cast< const unsigned short *
>( input + inputPosition );
141 return _storeToStream<unsigned short>( data, outputPosition, outputType, val );
145 const qint32 val = *
reinterpret_cast<const qint32 *
>( input + inputPosition );
146 return _storeToStream<qint32>( data, outputPosition, outputType, val );
150 const quint32 val = *
reinterpret_cast<const quint32 *
>( input + inputPosition );
151 return _storeToStream<quint32>( data, outputPosition, outputType, val );
155 const qint64 val = *
reinterpret_cast<const qint64 *
>( input + inputPosition );
156 return _storeToStream<qint64>( data, outputPosition, outputType, val );
160 const quint64 val = *
reinterpret_cast<const quint64 *
>( input + inputPosition );
161 return _storeToStream<quint64>( data, outputPosition, outputType, val );
165 const float val = *
reinterpret_cast< const float *
>( input + inputPosition );
166 return _storeToStream<float>( data, outputPosition, outputType, val );
170 const double val = *
reinterpret_cast< const double *
>( input + inputPosition );
171 return _storeToStream<double>( data, outputPosition, outputType, val );
182 const std::size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
183 const int count = dataUncompressed.size() / pointRecordSize;
185 data.resize( requestedPointRecordSize * count );
186 char *destinationBuffer = data.data();
187 const char *s = dataUncompressed.data();
189 const QVector<QgsPointCloudAttribute> requestedAttributesVector = requestedAttributes.
attributes();
196 : inputOffset( inputOffset )
197 , inputSize( inputSize )
198 , inputType( inputType )
199 , requestedSize( requestedSize )
200 , requestedType( requestedType )
210 std::vector< AttributeData > attributeData;
211 attributeData.reserve( requestedAttributesVector.size() );
214 int inputAttributeOffset;
216 if ( !inputAttribute )
220 attributeData.emplace_back( AttributeData( inputAttributeOffset, inputAttribute->
size(), inputAttribute->
type(),
221 requestedAttribute.size(), requestedAttribute.type() ) );
225 size_t outputOffset = 0;
226 for (
int i = 0; i < count; ++i )
228 for (
const AttributeData &attribute : attributeData )
230 __serialize( destinationBuffer, outputOffset,
231 attribute.requestedType, s,
232 attribute.inputType, attribute.inputSize, i * pointRecordSize + attribute.inputOffset );
234 outputOffset += attribute.requestedSize;
246 if ( ! QFile::exists( filename ) )
250 const bool r = f.open( QIODevice::ReadOnly );
254 const QByteArray dataUncompressed = f.read( f.size() );
255 return _decompressBinary( dataUncompressed, attributes, requestedAttributes, scale, offset );
260 return _decompressBinary( data, attributes, requestedAttributes, scale, offset );
265 QByteArray decompressZtdStream(
const QByteArray &dataCompressed )
270 const int MAXSIZE = 10000000;
271 QByteArray dataUncompressed;
272 dataUncompressed.resize( MAXSIZE );
274 ZSTD_DStream *strm = ZSTD_createDStream();
275 ZSTD_initDStream( strm );
277 ZSTD_inBuffer m_inBuf;
278 m_inBuf.src =
reinterpret_cast<const void *
>( dataCompressed.constData() );
279 m_inBuf.size = dataCompressed.size();
282 ZSTD_outBuffer outBuf {
reinterpret_cast<void *
>( dataUncompressed.data() ), MAXSIZE, 0 };
283 const size_t ret = ZSTD_decompressStream( strm, &outBuf, &m_inBuf );
284 Q_ASSERT( !ZSTD_isError( ret ) );
285 Q_ASSERT( outBuf.pos );
286 Q_ASSERT( outBuf.pos < outBuf.size );
288 ZSTD_freeDStream( strm );
289 dataUncompressed.resize( outBuf.pos );
290 return dataUncompressed;
295 if ( ! QFile::exists( filename ) )
299 const bool r = f.open( QIODevice::ReadOnly );
303 const QByteArray dataCompressed = f.readAll();
304 const QByteArray dataUncompressed = decompressZtdStream( dataCompressed );
305 return _decompressBinary( dataUncompressed, attributes, requestedAttributes, scale, offset );
310 const QByteArray dataUncompressed = decompressZtdStream( data );
311 return _decompressBinary( dataUncompressed, attributes, requestedAttributes, scale, offset );
317 template<
typename FileType>
320 Q_UNUSED( attributes );
328 const auto start = common::tick();
331 laszip::io::reader::basic_file<FileType> f( file );
333 const size_t count = f.get_header().point_count;
334 const QgsVector3D scale( f.get_header().scale.x, f.get_header().scale.y, f.get_header().scale.z );
335 const QgsVector3D offset( f.get_header().offset.x, f.get_header().offset.y, f.get_header().offset.z );
337 QByteArray bufArray( f.get_header().point_record_length, 0 );
338 char *buf = bufArray.data();
340 const size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
342 data.resize( requestedPointRecordSize * count );
343 char *dataBuffer = data.data();
345 const QVector<QgsPointCloudAttribute> requestedAttributesVector = requestedAttributes.
attributes();
347 std::size_t outputOffset = 0;
349 enum class LazAttribute
371 struct RequestedAttributeDetails
374 : attribute( attribute )
380 LazAttribute attribute;
386 QVector<QgsEptDecoder::ExtraBytesAttributeDetails> extrabytesAttr = QgsEptDecoder::readExtraByteAttributes<FileType>( file );
388 std::vector< RequestedAttributeDetails > requestedAttributeDetails;
389 requestedAttributeDetails.reserve( requestedAttributesVector.size() );
392 if ( requestedAttribute.name().compare( QLatin1String(
"X" ), Qt::CaseInsensitive ) == 0 )
394 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::X, requestedAttribute.type(), requestedAttribute.size() ) );
396 else if ( requestedAttribute.name().compare( QLatin1String(
"Y" ), Qt::CaseInsensitive ) == 0 )
398 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Y, requestedAttribute.type(), requestedAttribute.size() ) );
400 else if ( requestedAttribute.name().compare( QLatin1String(
"Z" ), Qt::CaseInsensitive ) == 0 )
402 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Z, requestedAttribute.type(), requestedAttribute.size() ) );
404 else if ( requestedAttribute.name().compare( QLatin1String(
"Classification" ), Qt::CaseInsensitive ) == 0 )
406 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Classification, requestedAttribute.type(), requestedAttribute.size() ) );
408 else if ( requestedAttribute.name().compare( QLatin1String(
"Intensity" ), Qt::CaseInsensitive ) == 0 )
410 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Intensity, requestedAttribute.type(), requestedAttribute.size() ) );
412 else if ( requestedAttribute.name().compare( QLatin1String(
"ReturnNumber" ), Qt::CaseInsensitive ) == 0 )
414 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ReturnNumber, requestedAttribute.type(), requestedAttribute.size() ) );
416 else if ( requestedAttribute.name().compare( QLatin1String(
"NumberOfReturns" ), Qt::CaseInsensitive ) == 0 )
418 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::NumberOfReturns, requestedAttribute.type(), requestedAttribute.size() ) );
420 else if ( requestedAttribute.name().compare( QLatin1String(
"ScanDirectionFlag" ), Qt::CaseInsensitive ) == 0 )
422 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ScanDirectionFlag, requestedAttribute.type(), requestedAttribute.size() ) );
424 else if ( requestedAttribute.name().compare( QLatin1String(
"EdgeOfFlightLine" ), Qt::CaseInsensitive ) == 0 )
426 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::EdgeOfFlightLine, requestedAttribute.type(), requestedAttribute.size() ) );
428 else if ( requestedAttribute.name().compare( QLatin1String(
"ScanAngleRank" ), Qt::CaseInsensitive ) == 0 )
430 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ScanAngleRank, requestedAttribute.type(), requestedAttribute.size() ) );
432 else if ( requestedAttribute.name().compare( QLatin1String(
"UserData" ), Qt::CaseInsensitive ) == 0 )
434 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::UserData, requestedAttribute.type(), requestedAttribute.size() ) );
436 else if ( requestedAttribute.name().compare( QLatin1String(
"PointSourceId" ), Qt::CaseInsensitive ) == 0 )
438 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::PointSourceId, requestedAttribute.type(), requestedAttribute.size() ) );
440 else if ( requestedAttribute.name().compare( QLatin1String(
"GpsTime" ), Qt::CaseInsensitive ) == 0 )
442 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::GpsTime, requestedAttribute.type(), requestedAttribute.size() ) );
444 else if ( requestedAttribute.name().compare( QLatin1String(
"Red" ), Qt::CaseInsensitive ) == 0 )
446 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Red, requestedAttribute.type(), requestedAttribute.size() ) );
448 else if ( requestedAttribute.name().compare( QLatin1String(
"Green" ), Qt::CaseInsensitive ) == 0 )
450 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Green, requestedAttribute.type(), requestedAttribute.size() ) );
452 else if ( requestedAttribute.name().compare( QLatin1String(
"Blue" ), Qt::CaseInsensitive ) == 0 )
454 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Blue, requestedAttribute.type(), requestedAttribute.size() ) );
458 bool foundAttr =
false;
459 for ( QgsEptDecoder::ExtraBytesAttributeDetails &eba : extrabytesAttr )
461 if ( requestedAttribute.name().compare( eba.attribute.trimmed() ) == 0 )
463 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ExtraBytes, eba.type, eba.size, eba.offset ) );
471 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::MissingOrUnknown, requestedAttribute.type(), requestedAttribute.size() ) );
476 for (
size_t i = 0 ; i < count ; i ++ )
479 const laszip::formats::las::point10 p = laszip::formats::packers<laszip::formats::las::point10>::unpack( buf );
480 const laszip::formats::las::gpstime gps = laszip::formats::packers<laszip::formats::las::gpstime>::unpack( buf +
sizeof( laszip::formats::las::point10 ) );
481 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 ) );
483 for (
const RequestedAttributeDetails &requestedAttribute : requestedAttributeDetails )
485 switch ( requestedAttribute.attribute )
487 case LazAttribute::X:
488 _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.x );
490 case LazAttribute::Y:
491 _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.y );
493 case LazAttribute::Z:
494 _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.z );
496 case LazAttribute::Classification:
497 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.classification );
499 case LazAttribute::Intensity:
500 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, p.intensity );
502 case LazAttribute::ReturnNumber:
503 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.return_number );
505 case LazAttribute::NumberOfReturns:
506 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.number_of_returns_of_given_pulse );
508 case LazAttribute::ScanDirectionFlag:
509 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.scan_direction_flag );
511 case LazAttribute::EdgeOfFlightLine:
512 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.edge_of_flight_line );
514 case LazAttribute::ScanAngleRank:
515 _storeToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, p.scan_angle_rank );
517 case LazAttribute::UserData:
518 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.user_data );
520 case LazAttribute::PointSourceId:
521 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, p.point_source_ID );
523 case LazAttribute::GpsTime:
525 _storeToStream<double>( dataBuffer, outputOffset, requestedAttribute.type,
526 *
reinterpret_cast<const double *
>(
reinterpret_cast<const void *
>( &gps.value ) ) );
528 case LazAttribute::Red:
529 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.r );
531 case LazAttribute::Green:
532 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.g );
534 case LazAttribute::Blue:
535 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.b );
537 case LazAttribute::ExtraBytes:
539 switch ( requestedAttribute.type )
542 _storeToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<char *
>( &buf[requestedAttribute.offset] ) );
545 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<unsigned char *
>( &buf[requestedAttribute.offset] ) );
548 _storeToStream<qint16>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint16 *
>( &buf[requestedAttribute.offset] ) );
551 _storeToStream<quint16>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint16 *
>( &buf[requestedAttribute.offset] ) );
554 _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint32 *
>( &buf[requestedAttribute.offset] ) );
557 _storeToStream<quint32>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint32 *
>( &buf[requestedAttribute.offset] ) );
560 _storeToStream<qint64>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<qint64 *
>( &buf[requestedAttribute.offset] ) );
563 _storeToStream<quint64>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<quint64 *
>( &buf[requestedAttribute.offset] ) );
566 _storeToStream<float>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<float *
>( &buf[requestedAttribute.offset] ) );
569 _storeToStream<double>( dataBuffer, outputOffset, requestedAttribute.type, *
reinterpret_cast<double *
>( &buf[requestedAttribute.offset] ) );
574 case LazAttribute::MissingOrUnknown:
576 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, 0 );
580 outputOffset += requestedAttribute.size;
585 const float t = common::since( start );
586 QgsDebugMsgLevel( QStringLiteral(
"LAZ-PERF Read through the points in %1 seconds." ).arg( t ), 2 );
601 const QByteArray arr = filename.toUtf8();
602 std::ifstream file( arr.constData(), std::ios::binary );
604 return __decompressLaz<std::ifstream>( file, attributes, requestedAttributes, scale, offset );
612 std::istringstream file( byteArrayData.toStdString() );
613 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.
@ UChar
Unsigned char 1 byte.
@ UInt32
Unsigned int32 4 bytes.
@ UInt64
Unsigned int64 8 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)