22 #include "qgsconfig.h"
32 #include "laz-perf/io.hpp"
33 #include "laz-perf/common/common.hpp"
44 char val = char( value );
50 short val = short( value );
51 memcpy( s + position,
reinterpret_cast<char *
>( &val ),
sizeof(
short ) );
57 unsigned short val =
static_cast< unsigned short>( value );
58 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof(
unsigned short ) );
64 float val = float( value );
65 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof(
float ) );
70 qint32 val = qint32( value );
71 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof( qint32 ) );
76 double val = double( value );
77 memcpy( s + position,
reinterpret_cast< char *
>( &val ),
sizeof(
double ) );
88 if ( outputType == inputType )
90 memcpy( data + outputPosition, input + inputPosition, inputSize );
98 char val = *( input + inputPosition );
99 return _storeToStream<char>( data, outputPosition, outputType, val );
103 const short val = *
reinterpret_cast< const short *
>( input + inputPosition );
104 return _storeToStream<short>( data, outputPosition, outputType, val );
108 const unsigned short val = *
reinterpret_cast< const unsigned short *
>( input + inputPosition );
109 return _storeToStream<unsigned short>( data, outputPosition, outputType, val );
113 const float val = *
reinterpret_cast< const float *
>( input + inputPosition );
114 return _storeToStream<float>( data, outputPosition, outputType, val );
118 const qint32 val = *
reinterpret_cast<const qint32 *
>( input + inputPosition );
119 return _storeToStream<qint32>( data, outputPosition, outputType, val );
123 const double val = *
reinterpret_cast< const double *
>( input + inputPosition );
124 return _storeToStream<double>( data, outputPosition, outputType, val );
135 const std::size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
136 const int count = dataUncompressed.size() / pointRecordSize;
138 data.resize( requestedPointRecordSize * count );
139 char *destinationBuffer = data.data();
140 const char *s = dataUncompressed.data();
142 const QVector<QgsPointCloudAttribute> requestedAttributesVector = requestedAttributes.
attributes();
149 : inputOffset( inputOffset )
150 , inputSize( inputSize )
151 , inputType( inputType )
152 , requestedSize( requestedSize )
153 , requestedType( requestedType )
163 std::vector< AttributeData > attributeData;
164 attributeData.reserve( requestedAttributesVector.size() );
167 int inputAttributeOffset;
169 if ( !inputAttribute )
173 attributeData.emplace_back( AttributeData( inputAttributeOffset, inputAttribute->
size(), inputAttribute->
type(),
174 requestedAttribute.size(), requestedAttribute.type() ) );
178 size_t outputOffset = 0;
179 for (
int i = 0; i < count; ++i )
181 for (
const AttributeData &attribute : attributeData )
183 _serialize( destinationBuffer, outputOffset,
184 attribute.requestedType, s,
185 attribute.inputType, attribute.inputSize, i * pointRecordSize + attribute.inputOffset );
187 outputOffset += attribute.requestedSize;
200 if ( ! QFile::exists( filename ) )
204 bool r = f.open( QIODevice::ReadOnly );
208 QByteArray dataUncompressed = f.read( f.size() );
209 return _decompressBinary( dataUncompressed, attributes, requestedAttributes );
214 QByteArray decompressZtdStream(
const QByteArray &dataCompressed )
219 const int MAXSIZE = 10000000;
220 QByteArray dataUncompressed;
221 dataUncompressed.resize( MAXSIZE );
223 ZSTD_DStream *strm = ZSTD_createDStream();
224 ZSTD_initDStream( strm );
226 ZSTD_inBuffer m_inBuf;
227 m_inBuf.src =
reinterpret_cast<const void *
>( dataCompressed.constData() );
228 m_inBuf.size = dataCompressed.size();
231 ZSTD_outBuffer outBuf {
reinterpret_cast<void *
>( dataUncompressed.data() ), MAXSIZE, 0 };
232 size_t ret = ZSTD_decompressStream( strm, &outBuf, &m_inBuf );
233 Q_ASSERT( !ZSTD_isError( ret ) );
234 Q_ASSERT( outBuf.pos );
235 Q_ASSERT( outBuf.pos < outBuf.size );
237 ZSTD_freeDStream( strm );
238 dataUncompressed.resize( outBuf.pos );
239 return dataUncompressed;
244 if ( ! QFile::exists( filename ) )
248 bool r = f.open( QIODevice::ReadOnly );
252 QByteArray dataCompressed = f.readAll();
253 QByteArray dataUncompressed = decompressZtdStream( dataCompressed );
254 return _decompressBinary( dataUncompressed, attributes, requestedAttributes );
263 Q_UNUSED( attributes )
265 const QByteArray arr = filename.toUtf8();
266 std::ifstream file( arr.constData(), std::ios::binary );
271 auto start = common::tick();
274 laszip::io::reader::file f( file );
276 const size_t count = f.get_header().point_count;
277 char buf[
sizeof( laszip::formats::las::point10 ) +
sizeof( laszip::formats::las::gpstime ) +
sizeof( laszip::formats::las::rgb ) ];
279 const size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
281 data.resize( requestedPointRecordSize * count );
282 char *dataBuffer = data.data();
284 const QVector<QgsPointCloudAttribute> requestedAttributesVector = requestedAttributes.
attributes();
286 std::size_t outputOffset = 0;
288 enum class LazAttribute
308 struct RequestedAttributeDetails
311 : attribute( attribute )
316 LazAttribute attribute;
321 std::vector< RequestedAttributeDetails > requestedAttributeDetails;
322 requestedAttributeDetails.reserve( requestedAttributesVector.size() );
325 if ( requestedAttribute.name().compare( QLatin1String(
"X" ), Qt::CaseInsensitive ) == 0 )
327 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::X, requestedAttribute.type(), requestedAttribute.size() ) );
329 else if ( requestedAttribute.name().compare( QLatin1String(
"Y" ), Qt::CaseInsensitive ) == 0 )
331 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Y, requestedAttribute.type(), requestedAttribute.size() ) );
333 else if ( requestedAttribute.name().compare( QLatin1String(
"Z" ), Qt::CaseInsensitive ) == 0 )
335 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Z, requestedAttribute.type(), requestedAttribute.size() ) );
337 else if ( requestedAttribute.name().compare( QLatin1String(
"Classification" ), Qt::CaseInsensitive ) == 0 )
339 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Classification, requestedAttribute.type(), requestedAttribute.size() ) );
341 else if ( requestedAttribute.name().compare( QLatin1String(
"Intensity" ), Qt::CaseInsensitive ) == 0 )
343 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Intensity, requestedAttribute.type(), requestedAttribute.size() ) );
345 else if ( requestedAttribute.name().compare( QLatin1String(
"ReturnNumber" ), Qt::CaseInsensitive ) == 0 )
347 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ReturnNumber, requestedAttribute.type(), requestedAttribute.size() ) );
349 else if ( requestedAttribute.name().compare( QLatin1String(
"NumberOfReturns" ), Qt::CaseInsensitive ) == 0 )
351 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::NumberOfReturns, requestedAttribute.type(), requestedAttribute.size() ) );
353 else if ( requestedAttribute.name().compare( QLatin1String(
"ScanDirectionFlag" ), Qt::CaseInsensitive ) == 0 )
355 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ScanDirectionFlag, requestedAttribute.type(), requestedAttribute.size() ) );
357 else if ( requestedAttribute.name().compare( QLatin1String(
"EdgeOfFlightLine" ), Qt::CaseInsensitive ) == 0 )
359 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::EdgeOfFlightLine, requestedAttribute.type(), requestedAttribute.size() ) );
361 else if ( requestedAttribute.name().compare( QLatin1String(
"ScanAngleRank" ), Qt::CaseInsensitive ) == 0 )
363 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::ScanAngleRank, requestedAttribute.type(), requestedAttribute.size() ) );
365 else if ( requestedAttribute.name().compare( QLatin1String(
"UserData" ), Qt::CaseInsensitive ) == 0 )
367 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::UserData, requestedAttribute.type(), requestedAttribute.size() ) );
369 else if ( requestedAttribute.name().compare( QLatin1String(
"PointSourceId" ), Qt::CaseInsensitive ) == 0 )
371 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::PointSourceId, requestedAttribute.type(), requestedAttribute.size() ) );
373 else if ( requestedAttribute.name().compare( QLatin1String(
"Red" ), Qt::CaseInsensitive ) == 0 )
375 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Red, requestedAttribute.type(), requestedAttribute.size() ) );
377 else if ( requestedAttribute.name().compare( QLatin1String(
"Green" ), Qt::CaseInsensitive ) == 0 )
379 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Green, requestedAttribute.type(), requestedAttribute.size() ) );
381 else if ( requestedAttribute.name().compare( QLatin1String(
"Blue" ), Qt::CaseInsensitive ) == 0 )
383 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::Blue, requestedAttribute.type(), requestedAttribute.size() ) );
388 requestedAttributeDetails.emplace_back( RequestedAttributeDetails( LazAttribute::MissingOrUnknown, requestedAttribute.type(), requestedAttribute.size() ) );
392 for (
size_t i = 0 ; i < count ; i ++ )
395 laszip::formats::las::point10 p = laszip::formats::packers<laszip::formats::las::point10>::unpack( buf );
396 laszip::formats::las::rgb rgb = laszip::formats::packers<laszip::formats::las::rgb>::unpack( buf +
sizeof( laszip::formats::las::point10 ) +
sizeof( laszip::formats::las::gpstime ) );
398 for (
const RequestedAttributeDetails &requestedAttribute : requestedAttributeDetails )
400 switch ( requestedAttribute.attribute )
402 case LazAttribute::X:
403 _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.x );
405 case LazAttribute::Y:
406 _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.y );
408 case LazAttribute::Z:
409 _storeToStream<qint32>( dataBuffer, outputOffset, requestedAttribute.type, p.z );
411 case LazAttribute::Classification:
412 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.classification );
414 case LazAttribute::Intensity:
415 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, p.intensity );
417 case LazAttribute::ReturnNumber:
418 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.return_number );
420 case LazAttribute::NumberOfReturns:
421 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.number_of_returns_of_given_pulse );
423 case LazAttribute::ScanDirectionFlag:
424 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.scan_direction_flag );
426 case LazAttribute::EdgeOfFlightLine:
427 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.edge_of_flight_line );
429 case LazAttribute::ScanAngleRank:
430 _storeToStream<char>( dataBuffer, outputOffset, requestedAttribute.type, p.scan_angle_rank );
432 case LazAttribute::UserData:
433 _storeToStream<unsigned char>( dataBuffer, outputOffset, requestedAttribute.type, p.user_data );
435 case LazAttribute::PointSourceId:
436 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, p.point_source_ID );
438 case LazAttribute::Red:
439 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.r );
441 case LazAttribute::Green:
442 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.g );
444 case LazAttribute::Blue:
445 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, rgb.b );
447 case LazAttribute::MissingOrUnknown:
449 _storeToStream<unsigned short>( dataBuffer, outputOffset, requestedAttribute.type, 0 );
453 outputOffset += requestedAttribute.size;
458 float t = common::since( start );
459 QgsDebugMsgLevel( QStringLiteral(
"LAZ-PERF Read through the points in %1 seconds." ).arg( t ), 2 );
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)