20#include <lazperf/readers.hpp>
21#include <lazperf/writers.hpp>
24static void updatePoint(
char *pointBuffer,
int pointFormat,
const QString &attributeName,
double newValue )
26 if ( attributeName == QLatin1String(
"Intensity" ) )
28 quint16 newValueShort =
static_cast<quint16
>( newValue );
29 memcpy( pointBuffer + 12, &newValueShort,
sizeof( qint16 ) );
31 else if ( attributeName == QLatin1String(
"ReturnNumber" ) )
33 uchar newByteValue =
static_cast<uchar
>( newValue ) & 0xf;
34 pointBuffer[14] =
static_cast<char>( ( pointBuffer[14] & 0xf0 ) | newByteValue );
36 else if ( attributeName == QLatin1String(
"NumberOfReturns" ) )
38 uchar newByteValue = (
static_cast<uchar
>( newValue ) & 0xf ) << 4;
39 pointBuffer[14] =
static_cast<char>( ( pointBuffer[14] & 0xf ) | newByteValue );
41 else if ( attributeName == QLatin1String(
"Synthetic" ) )
43 uchar newByteValue = (
static_cast<uchar
>( newValue ) & 0x1 );
44 pointBuffer[15] =
static_cast<char>( ( pointBuffer[15] & 0xfe ) | newByteValue );
46 else if ( attributeName == QLatin1String(
"KeyPoint" ) )
48 uchar newByteValue = (
static_cast<uchar
>( newValue ) & 0x1 ) << 1;
49 pointBuffer[15] =
static_cast<char>( ( pointBuffer[15] & 0xfd ) | newByteValue );
51 else if ( attributeName == QLatin1String(
"Withheld" ) )
53 uchar newByteValue = (
static_cast<uchar
>( newValue ) & 0x1 ) << 2;
54 pointBuffer[15] =
static_cast<char>( ( pointBuffer[15] & 0xfb ) | newByteValue );
56 else if ( attributeName == QLatin1String(
"Overlap" ) )
58 uchar newByteValue = (
static_cast<uchar
>( newValue ) & 0x1 ) << 3;
59 pointBuffer[15] =
static_cast<char>( ( pointBuffer[15] & 0xf7 ) | newByteValue );
61 else if ( attributeName == QLatin1String(
"ScannerChannel" ) )
63 uchar newByteValue = (
static_cast<uchar
>( newValue ) & 0x3 ) << 4;
64 pointBuffer[15] =
static_cast<char>( ( pointBuffer[15] & 0xcf ) | newByteValue );
66 else if ( attributeName == QLatin1String(
"ScanDirectionFlag" ) )
68 uchar newByteValue = (
static_cast<uchar
>( newValue ) & 0x1 ) << 6;
69 pointBuffer[15] =
static_cast<char>( ( pointBuffer[15] & 0xbf ) | newByteValue );
71 else if ( attributeName == QLatin1String(
"EdgeOfFlightLine" ) )
73 uchar newByteValue = (
static_cast<uchar
>( newValue ) & 0x1 ) << 7;
74 pointBuffer[15] =
static_cast<char>( ( pointBuffer[15] & 0x7f ) | newByteValue );
76 else if ( attributeName == QLatin1String(
"Classification" ) )
78 pointBuffer[16] =
static_cast<char>(
static_cast<uchar
>( newValue ) );
80 else if ( attributeName == QLatin1String(
"UserData" ) )
82 pointBuffer[17] =
static_cast<char>(
static_cast<uchar
>( newValue ) );
84 else if ( attributeName == QLatin1String(
"ScanAngleRank" ) )
86 qint16 newValueShort =
static_cast<qint16
>( newValue );
87 memcpy( pointBuffer + 18, &newValueShort,
sizeof( qint16 ) );
89 else if ( attributeName == QLatin1String(
"PointSourceId" ) )
91 quint16 newValueShort =
static_cast<quint16
>( newValue );
92 memcpy( pointBuffer + 20, &newValueShort,
sizeof( quint16 ) );
94 else if ( attributeName == QLatin1String(
"GpsTime" ) )
96 memcpy( pointBuffer + 22, &newValue,
sizeof(
double ) );
98 else if ( pointFormat == 7 || pointFormat == 8 )
100 if ( attributeName == QLatin1String(
"Red" ) )
102 quint16 newValueShort =
static_cast<quint16
>( newValue );
103 memcpy( pointBuffer + 30, &newValueShort,
sizeof( quint16 ) );
105 else if ( attributeName == QLatin1String(
"Green" ) )
107 quint16 newValueShort =
static_cast<quint16
>( newValue );
108 memcpy( pointBuffer + 32, &newValueShort,
sizeof( quint16 ) );
110 else if ( attributeName == QLatin1String(
"Blue" ) )
112 quint16 newValueShort =
static_cast<quint16
>( newValue );
113 memcpy( pointBuffer + 34, &newValueShort,
sizeof( quint16 ) );
115 else if ( pointFormat == 8 )
117 if ( attributeName == QLatin1String(
"Infrared" ) )
119 quint16 newValueShort =
static_cast<quint16
>( newValue );
120 memcpy( pointBuffer + 36, &newValueShort,
sizeof( quint16 ) );
129 Q_ASSERT( copcIndex->mHierarchy.contains( n ) );
130 Q_ASSERT( copcIndex->mHierarchyNodePos.contains( n ) );
132 int pointCount = copcIndex->mHierarchy[n];
134 lazperf::header14 header = copcIndex->mLazInfo->header();
136 lazperf::reader::chunk_decompressor decompressor( header.pointFormat(), header.ebCount(), chunkData.constData() );
137 lazperf::writer::chunk_compressor compressor( header.pointFormat(), header.ebCount() );
139 std::unique_ptr<char []> decodedData(
new char[ header.point_record_length ] );
142 Q_ASSERT( header.pointFormat() == 6 || header.pointFormat() == 7 || header.pointFormat() == 8 );
144 QString attributeName = attribute.
name();
146 for (
int i = 0 ; i < pointCount; ++i )
148 decompressor.decompress( decodedData.get() );
149 char *buf = decodedData.get();
151 if ( pointValues.contains( i ) )
154 updatePoint( buf, header.point_format_id, attributeName, newValue ? *newValue : pointValues[i] );
157 compressor.compress( decodedData.get() );
160 std::vector<unsigned char> data = compressor.done();
161 return QByteArray( (
const char * ) data.data(), (
int ) data.size() );
167 const QVector<QgsPointCloudAttribute> attributes = allAttributes.
attributes();
169 const char *ptr = data.data();
172 for (
int i = 0; i < nPoints; ++i )
178 outData.append( ptr, attr.size() );
192 const QString name = attribute.
name().toUpper();
194 if ( name == QLatin1String(
"INTENSITY" ) )
195 return value >= 0 && value <= 65535;
196 if ( name == QLatin1String(
"RETURNNUMBER" ) )
197 return value >= 0 && value <= 15;
198 if ( name == QLatin1String(
"NUMBEROFRETURNS" ) )
199 return value >= 0 && value <= 15;
200 if ( name == QLatin1String(
"SCANNERCHANNEL" ) )
201 return value >= 0 && value <= 3;
202 if ( name == QLatin1String(
"SCANDIRECTIONFLAG" ) )
203 return value >= 0 && value <= 1;
204 if ( name == QLatin1String(
"EDGEOFFLIGHTLINE" ) )
205 return value >= 0 && value <= 1;
206 if ( name == QLatin1String(
"CLASSIFICATION" ) )
207 return value >= 0 && value <= 255;
208 if ( name == QLatin1String(
"USERDATA" ) )
209 return value >= 0 && value <= 255;
210 if ( name == QLatin1String(
"SCANANGLERANK" ) )
211 return value >= -30'000 && value <= 30'000;
212 if ( name == QLatin1String(
"POINTSOURCEID" ) )
213 return value >= 0 && value <= 65535;
214 if ( name == QLatin1String(
"GPSTIME" ) )
216 if ( name == QLatin1String(
"SYNTHETIC" ) )
217 return value >= 0 && value <= 1;
218 if ( name == QLatin1String(
"KEYPOINT" ) )
219 return value >= 0 && value <= 1;
220 if ( name == QLatin1String(
"WITHHELD" ) )
221 return value >= 0 && value <= 1;
222 if ( name == QLatin1String(
"OVERLAP" ) )
223 return value >= 0 && value <= 1;
224 if ( name == QLatin1String(
"RED" ) )
225 return value >= 0 && value <= 65535;
226 if ( name == QLatin1String(
"GREEN" ) )
227 return value >= 0 && value <= 65535;
228 if ( name == QLatin1String(
"BLUE" ) )
229 return value >= 0 && value <= 65535;
230 if ( name == QLatin1String(
"INFRARED" ) )
231 return value >= 0 && value <= 65535;
Collection of point cloud attributes.
int pointRecordSize() const
Returns total size of record.
QVector< QgsPointCloudAttribute > attributes() const
Returns all attributes.
int indexOf(const QString &name) const
Returns the index of the attribute with the specified name.
Attribute for point cloud data pair of name and size in bytes.
QString name() const
Returns name of the attribute.
static QByteArray dataForAttributes(const QgsPointCloudAttributeCollection &allAttributes, const QByteArray &data, const QgsPointCloudRequest &request)
Takes data comprising of allAttributes and returns a QByteArray with data only for the attributes inc...
static QByteArray updateChunkValues(QgsCopcPointCloudIndex *copcIndex, const QByteArray &chunkData, const QgsPointCloudAttribute &attribute, const QgsPointCloudNodeId &n, const QHash< int, double > &pointValues, std::optional< double > newValue=std::nullopt)
Sets new classification value for the given points in voxel and return updated chunk data.
static bool isAttributeValueValid(const QgsPointCloudAttribute &attribute, double value)
Check if value is within proper range for the attribute.
Represents a indexed point cloud node's position in octree.
Point cloud data request.
QgsPointCloudAttributeCollection attributes() const
Returns attributes.