mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-31 00:04:24 -05:00
151 lines
5.4 KiB
C++
151 lines
5.4 KiB
C++
/***************************************************************************
|
|
qgspointcloudlayereditutils.cpp
|
|
---------------------
|
|
begin : December 2024
|
|
copyright : (C) 2024 by Stefanos Natsis
|
|
email : uclaros at gmail dot com
|
|
***************************************************************************
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
#include "qgspointcloudlayereditutils.h"
|
|
#include "qgspointcloudlayer.h"
|
|
#include "qgslazdecoder.h"
|
|
|
|
|
|
QgsPointCloudLayerEditUtils::QgsPointCloudLayerEditUtils( QgsPointCloudLayer *layer )
|
|
: mIndex( layer->index() )
|
|
{
|
|
}
|
|
|
|
bool QgsPointCloudLayerEditUtils::changeAttributeValue( const QgsPointCloudNodeId &n, const QVector<int> &pts, const QgsPointCloudAttribute &attribute, double value )
|
|
{
|
|
// Cannot allow x,y,z editing as points may get moved outside the node extents
|
|
if ( attribute.name().compare( QLatin1String( "X" ), Qt::CaseInsensitive ) == 0 ||
|
|
attribute.name().compare( QLatin1String( "Y" ), Qt::CaseInsensitive ) == 0 ||
|
|
attribute.name().compare( QLatin1String( "Z" ), Qt::CaseInsensitive ) == 0 )
|
|
return false;
|
|
|
|
if ( !n.isValid() || !mIndex.hasNode( n ) ) // todo: should not have to check if n.isValid
|
|
return false;
|
|
|
|
const QgsPointCloudAttributeCollection attributeCollection = mIndex.attributes();
|
|
|
|
int attributeOffset;
|
|
const QgsPointCloudAttribute *at = attributeCollection.find( attribute.name(), attributeOffset );
|
|
|
|
if ( !at ||
|
|
at->size() != attribute.size() ||
|
|
at->type() != attribute.type() )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if ( !isAttributeValueValid( attribute, value ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
const QSet<int> uniquePoints( pts.constBegin(), pts.constEnd() );
|
|
QVector<int> sortedPoints( uniquePoints.constBegin(), uniquePoints.constEnd() );
|
|
std::sort( sortedPoints.begin(), sortedPoints.end() );
|
|
|
|
if ( sortedPoints.constFirst() < 0 ||
|
|
sortedPoints.constLast() > mIndex.getNode( n ).pointCount() )
|
|
return false;
|
|
|
|
QgsPointCloudRequest req;
|
|
req.setAttributes( attributeCollection );
|
|
|
|
std::unique_ptr<QgsPointCloudBlock> block = mIndex.nodeData( n, req );
|
|
const int count = block->pointCount();
|
|
const int recordSize = attributeCollection.pointRecordSize();
|
|
|
|
// copy data
|
|
QByteArray data( block->data(), count * recordSize );
|
|
|
|
char *ptr = data.data();
|
|
|
|
for ( int i : sortedPoints )
|
|
{
|
|
// replace attribute for selected point
|
|
lazStoreToStream_<double>( ptr, i * recordSize + attributeOffset, attribute.type(), value );
|
|
}
|
|
|
|
return mIndex.updateNodeData( {{n, data}} );;
|
|
}
|
|
|
|
QByteArray QgsPointCloudLayerEditUtils::dataForAttributes( const QgsPointCloudAttributeCollection &allAttributes, const QByteArray &data, const QgsPointCloudRequest &request )
|
|
{
|
|
const QVector<QgsPointCloudAttribute> attributes = allAttributes.attributes();
|
|
const int nPoints = data.size() / allAttributes.pointRecordSize();
|
|
const char *ptr = data.data();
|
|
|
|
QByteArray outData;
|
|
for ( int i = 0; i < nPoints; ++i )
|
|
{
|
|
for ( const QgsPointCloudAttribute &attr : attributes )
|
|
{
|
|
if ( request.attributes().indexOf( attr.name() ) >= 0 )
|
|
{
|
|
outData.append( ptr, attr.size() );
|
|
}
|
|
ptr += attr.size();
|
|
}
|
|
}
|
|
|
|
//
|
|
Q_ASSERT( nPoints == outData.size() / request.attributes().pointRecordSize() );
|
|
|
|
return outData;
|
|
}
|
|
|
|
bool QgsPointCloudLayerEditUtils::isAttributeValueValid( const QgsPointCloudAttribute &attribute, double value )
|
|
{
|
|
const QString name = attribute.name().toUpper();
|
|
|
|
if ( name == QLatin1String( "INTENSITY" ) )
|
|
return value >= 0 && value <= 65535;
|
|
if ( name == QLatin1String( "RETURNNUMBER" ) )
|
|
return value >= 0 && value <= 15;
|
|
if ( name == QLatin1String( "NUMBEROFRETURNS" ) )
|
|
return value >= 0 && value <= 15;
|
|
if ( name == QLatin1String( "SCANCHANNEL" ) )
|
|
return value >= 0 && value <= 3;
|
|
if ( name == QLatin1String( "SCANDIRECTIONFLAG" ) )
|
|
return value >= 0 && value <= 1;
|
|
if ( name == QLatin1String( "EDGEOFFLIGHTLINE" ) )
|
|
return value >= 0 && value <= 1;
|
|
if ( name == QLatin1String( "CLASSIFICATION" ) )
|
|
return value >= 0 && value <= 255;
|
|
if ( name == QLatin1String( "USERDATA" ) )
|
|
return value >= 0 && value <= 255;
|
|
if ( name == QLatin1String( "SCANANGLE" ) )
|
|
return value >= -30'000 && value <= 30'000;
|
|
if ( name == QLatin1String( "POINTSOURCEID" ) )
|
|
return value >= 0 && value <= 65535;
|
|
if ( name == QLatin1String( "GPSTIME" ) )
|
|
return value >= 0;
|
|
if ( name == QLatin1String( "SYNTHETIC" ) )
|
|
return value >= 0 && value <= 1;
|
|
if ( name == QLatin1String( "KEYPOINT" ) )
|
|
return value >= 0 && value <= 1;
|
|
if ( name == QLatin1String( "WITHHELD" ) )
|
|
return value >= 0 && value <= 1;
|
|
if ( name == QLatin1String( "OVERLAP" ) )
|
|
return value >= 0 && value <= 1;
|
|
if ( name == QLatin1String( "RED" ) )
|
|
return value >= 0 && value <= 65535;
|
|
if ( name == QLatin1String( "GREEN" ) )
|
|
return value >= 0 && value <= 65535;
|
|
if ( name == QLatin1String( "BLUE" ) )
|
|
return value >= 0 && value <= 65535;
|
|
|
|
return true;
|
|
}
|