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
>( std::round( newValue / 0.006 ) );
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() );
166 const QString name = attribute.
name().toUpper();
168 if ( name == QLatin1String(
"INTENSITY" ) )
169 return value >= 0 && value <= 65535;
170 if ( name == QLatin1String(
"RETURNNUMBER" ) )
171 return value >= 0 && value <= 15;
172 if ( name == QLatin1String(
"NUMBEROFRETURNS" ) )
173 return value >= 0 && value <= 15;
174 if ( name == QLatin1String(
"SCANNERCHANNEL" ) )
175 return value >= 0 && value <= 3;
176 if ( name == QLatin1String(
"SCANDIRECTIONFLAG" ) )
177 return value >= 0 && value <= 1;
178 if ( name == QLatin1String(
"EDGEOFFLIGHTLINE" ) )
179 return value >= 0 && value <= 1;
180 if ( name == QLatin1String(
"CLASSIFICATION" ) )
181 return value >= 0 && value <= 255;
182 if ( name == QLatin1String(
"USERDATA" ) )
183 return value >= 0 && value <= 255;
184 if ( name == QLatin1String(
"SCANANGLERANK" ) )
185 return value >= -180 && value <= 180;
186 if ( name == QLatin1String(
"POINTSOURCEID" ) )
187 return value >= 0 && value <= 65535;
188 if ( name == QLatin1String(
"GPSTIME" ) )
190 if ( name == QLatin1String(
"SYNTHETIC" ) )
191 return value >= 0 && value <= 1;
192 if ( name == QLatin1String(
"KEYPOINT" ) )
193 return value >= 0 && value <= 1;
194 if ( name == QLatin1String(
"WITHHELD" ) )
195 return value >= 0 && value <= 1;
196 if ( name == QLatin1String(
"OVERLAP" ) )
197 return value >= 0 && value <= 1;
198 if ( name == QLatin1String(
"RED" ) )
199 return value >= 0 && value <= 65535;
200 if ( name == QLatin1String(
"GREEN" ) )
201 return value >= 0 && value <= 65535;
202 if ( name == QLatin1String(
"BLUE" ) )
203 return value >= 0 && value <= 65535;
204 if ( name == QLatin1String(
"INFRARED" ) )
205 return value >= 0 && value <= 65535;
Attribute for point cloud data pair of name and size in bytes.
QString name() const
Returns name of the attribute.
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.