22#include <lazperf/readers.hpp> 
   23#include <lazperf/writers.hpp> 
   26static void updatePoint( 
char *pointBuffer, 
int pointFormat, 
const QString &attributeName, 
double newValue )
 
   28  if ( attributeName == QLatin1String( 
"Intensity" ) )  
 
   30    quint16 newValueShort = 
static_cast<quint16
>( newValue );
 
   31    memcpy( pointBuffer + 12, &newValueShort, 
sizeof( qint16 ) );
 
   33  else if ( attributeName == QLatin1String( 
"ReturnNumber" ) )  
 
   35    uchar newByteValue = 
static_cast<uchar
>( newValue ) & 0xf;
 
   36    pointBuffer[14] = 
static_cast<char>( ( pointBuffer[14] & 0xf0 ) | newByteValue );
 
   38  else if ( attributeName == QLatin1String( 
"NumberOfReturns" ) )  
 
   40    uchar newByteValue = ( 
static_cast<uchar
>( newValue ) & 0xf ) << 4;
 
   41    pointBuffer[14] = 
static_cast<char>( ( pointBuffer[14] & 0xf ) | newByteValue );
 
   43  else if ( attributeName == QLatin1String( 
"Synthetic" ) )  
 
   45    uchar newByteValue = ( 
static_cast<uchar
>( newValue ) & 0x1 );
 
   46    pointBuffer[15] = 
static_cast<char>( ( pointBuffer[15] & 0xfe ) | newByteValue );
 
   48  else if ( attributeName == QLatin1String( 
"KeyPoint" ) )  
 
   50    uchar newByteValue = ( 
static_cast<uchar
>( newValue ) & 0x1 ) << 1;
 
   51    pointBuffer[15] = 
static_cast<char>( ( pointBuffer[15] & 0xfd ) | newByteValue );
 
   53  else if ( attributeName == QLatin1String( 
"Withheld" ) )  
 
   55    uchar newByteValue = ( 
static_cast<uchar
>( newValue ) & 0x1 ) << 2;
 
   56    pointBuffer[15] = 
static_cast<char>( ( pointBuffer[15] & 0xfb ) | newByteValue );
 
   58  else if ( attributeName == QLatin1String( 
"Overlap" ) )  
 
   60    uchar newByteValue = ( 
static_cast<uchar
>( newValue ) & 0x1 ) << 3;
 
   61    pointBuffer[15] = 
static_cast<char>( ( pointBuffer[15] & 0xf7 ) | newByteValue );
 
   63  else if ( attributeName == QLatin1String( 
"ScannerChannel" ) )  
 
   65    uchar newByteValue = ( 
static_cast<uchar
>( newValue ) & 0x3 ) << 4;
 
   66    pointBuffer[15] = 
static_cast<char>( ( pointBuffer[15] & 0xcf ) | newByteValue );
 
   68  else if ( attributeName == QLatin1String( 
"ScanDirectionFlag" ) )  
 
   70    uchar newByteValue = ( 
static_cast<uchar
>( newValue ) & 0x1 ) << 6;
 
   71    pointBuffer[15] = 
static_cast<char>( ( pointBuffer[15] & 0xbf ) | newByteValue );
 
   73  else if ( attributeName == QLatin1String( 
"EdgeOfFlightLine" ) )  
 
   75    uchar newByteValue = ( 
static_cast<uchar
>( newValue ) & 0x1 ) << 7;
 
   76    pointBuffer[15] = 
static_cast<char>( ( pointBuffer[15] & 0x7f ) | newByteValue );
 
   78  else if ( attributeName == QLatin1String( 
"Classification" ) )  
 
   80    pointBuffer[16] = 
static_cast<char>( 
static_cast<uchar
>( newValue ) );
 
   82  else if ( attributeName == QLatin1String( 
"UserData" ) )  
 
   84    pointBuffer[17] = 
static_cast<char>( 
static_cast<uchar
>( newValue ) );
 
   86  else if ( attributeName == QLatin1String( 
"ScanAngleRank" ) )  
 
   88    qint16 newValueShort = 
static_cast<qint16
>( std::round( newValue / 0.006 ) );  
 
   89    memcpy( pointBuffer + 18, &newValueShort, 
sizeof( qint16 ) );
 
   91  else if ( attributeName == QLatin1String( 
"PointSourceId" ) )  
 
   93    quint16 newValueShort = 
static_cast<quint16
>( newValue );
 
   94    memcpy( pointBuffer + 20, &newValueShort, 
sizeof( quint16 ) );
 
   96  else if ( attributeName == QLatin1String( 
"GpsTime" ) )  
 
   98    memcpy( pointBuffer + 22, &newValue, 
sizeof( 
double ) );
 
  100  else if ( pointFormat == 7 || pointFormat == 8 )
 
  102    if ( attributeName == QLatin1String( 
"Red" ) )  
 
  104      quint16 newValueShort = 
static_cast<quint16
>( newValue );
 
  105      memcpy( pointBuffer + 30, &newValueShort, 
sizeof( quint16 ) );
 
  107    else if ( attributeName == QLatin1String( 
"Green" ) )  
 
  109      quint16 newValueShort = 
static_cast<quint16
>( newValue );
 
  110      memcpy( pointBuffer + 32, &newValueShort, 
sizeof( quint16 ) );
 
  112    else if ( attributeName == QLatin1String( 
"Blue" ) )  
 
  114      quint16 newValueShort = 
static_cast<quint16
>( newValue );
 
  115      memcpy( pointBuffer + 34, &newValueShort, 
sizeof( quint16 ) );
 
  117    else if ( pointFormat == 8 )
 
  119      if ( attributeName == QLatin1String( 
"Infrared" ) )  
 
  121        quint16 newValueShort = 
static_cast<quint16
>( newValue );
 
  122        memcpy( pointBuffer + 36, &newValueShort, 
sizeof( quint16 ) );
 
  131  QgsEventTracing::ScopedEvent _trace( QStringLiteral( 
"PointCloud" ), QStringLiteral( 
"QgsPointCloudLayerEditUtils::updateChunkValues" ) );
 
  136    QMutexLocker locker( &copcIndex->mHierarchyMutex );
 
  138    Q_ASSERT( copcIndex->mHierarchy.contains( n ) );
 
  139    Q_ASSERT( copcIndex->mHierarchyNodePos.contains( n ) );
 
  141    pointCount = copcIndex->mHierarchy[n];
 
  144  lazperf::header14 header = copcIndex->mLazInfo->header();
 
  146  lazperf::reader::chunk_decompressor decompressor( header.pointFormat(), header.ebCount(), chunkData.constData() );
 
  147  lazperf::writer::chunk_compressor compressor( header.pointFormat(), header.ebCount() );
 
  149  std::unique_ptr<char[]> decodedData( 
new char[header.point_record_length] );
 
  152  Q_ASSERT( header.pointFormat() == 6 || header.pointFormat() == 7 || header.pointFormat() == 8 );
 
  154  QString attributeName = attribute.
name();
 
  156  for ( 
int i = 0; i < pointCount; ++i )
 
  158    decompressor.decompress( decodedData.get() );
 
  159    char *buf = decodedData.get();
 
  161    if ( pointValues.contains( i ) )
 
  164      updatePoint( buf, header.point_format_id, attributeName, newValue ? *newValue : pointValues[i] );
 
  167    compressor.compress( decodedData.get() );
 
  170  std::vector<unsigned char> data = compressor.done();
 
  171  return QByteArray( ( 
const char * ) data.data(), ( 
int ) data.size() ); 
 
 
  176  const QString name = attribute.
name().toUpper();
 
  178  if ( name == QLatin1String( 
"INTENSITY" ) )
 
  179    return value >= 0 && value <= 65535;
 
  180  if ( name == QLatin1String( 
"RETURNNUMBER" ) )
 
  181    return value >= 0 && value <= 15;
 
  182  if ( name == QLatin1String( 
"NUMBEROFRETURNS" ) )
 
  183    return value >= 0 && value <= 15;
 
  184  if ( name == QLatin1String( 
"SCANNERCHANNEL" ) )
 
  185    return value >= 0 && value <= 3;
 
  186  if ( name == QLatin1String( 
"SCANDIRECTIONFLAG" ) )
 
  187    return value >= 0 && value <= 1;
 
  188  if ( name == QLatin1String( 
"EDGEOFFLIGHTLINE" ) )
 
  189    return value >= 0 && value <= 1;
 
  190  if ( name == QLatin1String( 
"CLASSIFICATION" ) )
 
  191    return value >= 0 && value <= 255;
 
  192  if ( name == QLatin1String( 
"USERDATA" ) )
 
  193    return value >= 0 && value <= 255;
 
  194  if ( name == QLatin1String( 
"SCANANGLERANK" ) )
 
  195    return value >= -180 && value <= 180;
 
  196  if ( name == QLatin1String( 
"POINTSOURCEID" ) )
 
  197    return value >= 0 && value <= 65535;
 
  198  if ( name == QLatin1String( 
"GPSTIME" ) )
 
  200  if ( name == QLatin1String( 
"SYNTHETIC" ) )
 
  201    return value >= 0 && value <= 1;
 
  202  if ( name == QLatin1String( 
"KEYPOINT" ) )
 
  203    return value >= 0 && value <= 1;
 
  204  if ( name == QLatin1String( 
"WITHHELD" ) )
 
  205    return value >= 0 && value <= 1;
 
  206  if ( name == QLatin1String( 
"OVERLAP" ) )
 
  207    return value >= 0 && value <= 1;
 
  208  if ( name == QLatin1String( 
"RED" ) )
 
  209    return value >= 0 && value <= 65535;
 
  210  if ( name == QLatin1String( 
"GREEN" ) )
 
  211    return value >= 0 && value <= 65535;
 
  212  if ( name == QLatin1String( 
"BLUE" ) )
 
  213    return value >= 0 && value <= 65535;
 
  214  if ( name == QLatin1String( 
"INFRARED" ) )
 
  215    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 an indexed point cloud node's position in octree.