24#include "qgspointcloudexpression.h"
28#include <QElapsedTimer>
29#include <QTemporaryFile>
37#include "lazperf/las.hpp"
38#include "lazperf/readers.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 );
189std::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;
295void 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,
char( 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,
char( p14.scannerChannel() ) );
400 case QgsLazDecoder::LazAttribute::ClassificationFlags:
401 lazStoreToStream_<char>( dataBuffer, outputOffset, requestedAttribute.type,
char( 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;
464template<
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 int xAttributeOffset, yAttributeOffset;
525 const bool hasFilterRect = !filterRect.
isEmpty();
528 attributeX = requestedAttributes.
find( QLatin1String(
"X" ), xAttributeOffset );
529 attributeY = requestedAttributes.
find( QLatin1String(
"Y" ), yAttributeOffset );
536 std::vector<char> rawExtrabytes = f.vlrData(
"LASF_Spec", 4 );
537 QVector<QgsLazInfo::ExtraBytesAttributeDetails> extrabyteAttributesDetails =
QgsLazInfo::parseExtrabytes( rawExtrabytes.data(), rawExtrabytes.size(), f.header().point_record_length );
538 std::vector< QgsLazDecoder::RequestedAttributeDetails > requestedAttributeDetails = prepareRequestedAttributeDetails_( requestedAttributes, extrabyteAttributesDetails );
540 for (
size_t i = 0 ; i < count ; i ++ )
544 decodePoint( buf, lasPointFormat, dataBuffer, outputOffset, requestedAttributeDetails );
547 bool skipThisPoint =
false;
548 if ( hasFilterRect && attributeX && attributeY )
550 const double x = attributeX->
convertValueToDouble( dataBuffer + outputOffset - requestedPointRecordSize + xAttributeOffset );
551 const double y = attributeY->
convertValueToDouble( dataBuffer + outputOffset - requestedPointRecordSize + yAttributeOffset );
553 skipThisPoint =
true;
555 if ( !skipThisPoint && filterIsValid )
558 double eval = filterExpression.evaluate( i - skippedPoints );
559 if ( !eval || std::isnan( eval ) )
560 skipThisPoint =
true;
565 outputOffset -= requestedPointRecordSize;
571 QgsDebugMsgLevel( QStringLiteral(
"LAZ-PERF Read through the points in %1 seconds." ).arg( t.elapsed() / 1000. ), 2 );
573 block->setPointCount( count - skippedPoints );
574 return block.release();
576 catch ( std::exception &e )
578 QgsDebugMsg(
"Error decompressing laz file: " + QString::fromLatin1( e.what() ) );
585 QgsPointCloudExpression &filterExpression,
QgsRectangle &filterRect )
587 std::ifstream file( toNativePath( filename ), std::ios::binary );
589 return decompressLaz_<std::ifstream>( file, requestedAttributes, filterExpression, filterRect );
594 QgsPointCloudExpression &filterExpression,
QgsRectangle &filterRect )
596 std::istringstream file( byteArrayData.toStdString() );
597 return decompressLaz_<std::istringstream>( file, requestedAttributes, filterExpression, filterRect );
604 if ( lasPointFormat != 6 && lasPointFormat != 7 && lasPointFormat != 8 )
606 QgsDebugMsg( QStringLiteral(
"Unexpected point format record (%1) - only 6, 7, 8 are supported for COPC format" ).arg( lasPointFormat ) );
612 lazperf::reader::chunk_decompressor decompressor( lasPointFormat, lazInfo.
extrabytesCount(), data.data() );
614 const size_t requestedPointRecordSize = requestedAttributes.
pointRecordSize();
615 QByteArray blockData;
616 blockData.resize( requestedPointRecordSize * pointCount );
617 char *dataBuffer = blockData.data();
619 std::size_t outputOffset = 0;
621 QVector<QgsLazInfo::ExtraBytesAttributeDetails> extrabyteAttributesDetails = lazInfo.
extrabytes();
622 std::vector< RequestedAttributeDetails > requestedAttributeDetails = prepareRequestedAttributeDetails_( requestedAttributes, extrabyteAttributesDetails );
623 std::unique_ptr< QgsPointCloudBlock > block = std::make_unique< QgsPointCloudBlock >(
624 pointCount, requestedAttributes,
628 int skippedPoints = 0;
629 const bool filterIsValid = filterExpression.isValid();
630 if ( !filterExpression.prepare( block.get() ) && filterIsValid )
633 block->setPointCount( 0 );
634 return block.release();
637 int xAttributeOffset, yAttributeOffset;
640 const bool hasFilterRect = !filterRect.
isEmpty();
643 attributeX = requestedAttributes.
find( QLatin1String(
"X" ), xAttributeOffset );
644 attributeY = requestedAttributes.
find( QLatin1String(
"Y" ), yAttributeOffset );
650 for (
int i = 0 ; i < pointCount; ++i )
652 decompressor.decompress( decodedData.get() );
653 char *buf = decodedData.get();
655 decodePoint( buf, lasPointFormat, dataBuffer, outputOffset, requestedAttributeDetails );
658 bool skipThisPoint =
false;
660 if ( hasFilterRect && attributeX && attributeY )
662 const double x = attributeX->
convertValueToDouble( dataBuffer + outputOffset - requestedPointRecordSize + xAttributeOffset );
663 const double y = attributeY->
convertValueToDouble( dataBuffer + outputOffset - requestedPointRecordSize + yAttributeOffset );
665 skipThisPoint =
true;
667 if ( !skipThisPoint && filterIsValid )
670 double eval = filterExpression.evaluate( i - skippedPoints );
671 if ( !eval || std::isnan( eval ) )
672 skipThisPoint =
true;
677 outputOffset -= requestedPointRecordSize;
682 block->setPointCount( pointCount - skippedPoints );
683 return block.release();
687std::wstring QgsLazDecoder::toNativePath(
const QString &filename )
689 std::wstring_convert< std::codecvt_utf8_utf16< wchar_t > > converter;
690 return converter.from_bytes( filename.toStdString() );
693std::string QgsLazDecoder::toNativePath(
const QString &filename )
695 return filename.toStdString();
Class for extracting information contained in LAZ file such as the public header block and variable l...
int extrabytesCount() const
Returns the number of extrabytes contained in the LAZ dataset.
QgsVector3D scale() const
Returns the scale of the points coordinates.
int pointFormat() const
Returns the point format of the point records contained in the LAZ file.
QVector< ExtraBytesAttributeDetails > extrabytes() const
Returns the list of extrabytes contained in the LAZ file.
QgsVector3D offset() const
Returns the offset of the points coordinates.
int pointRecordLength() const
Returns the length of each point record in bytes.
static QVector< ExtraBytesAttributeDetails > parseExtrabytes(char *rawData, int length, int pointRecordLength)
Static function to parse the raw extrabytes VLR into a list of recognizable extrabyte attributes.
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.
double convertValueToDouble(const char *ptr) const
Returns the attribute's value as a double for data pointed to by ptr.
Base class for storing raw data from point cloud nodes.
A rectangle specified with double values.
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
void setYMinimum(double y) SIP_HOLDGIL
Set the minimum y value.
void setXMaximum(double x) SIP_HOLDGIL
Set the maximum x value.
void setXMinimum(double x) SIP_HOLDGIL
Set the minimum x value.
void setYMaximum(double y) SIP_HOLDGIL
Set the maximum y value.
bool isEmpty() const
Returns true if the rectangle is empty.
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
double y() const
Returns Y coordinate.
double x() const
Returns X coordinate.
#define QgsDebugMsgLevel(str, level)