Skip to content
Permalink
Browse files

Also add scaling factor option, test

  • Loading branch information
nyalldawson committed Dec 16, 2020
1 parent e4c8ce8 commit 7b141e92f061f1da330be035a37f6ca885cd9ea4
@@ -46,6 +46,10 @@ the layer.

This can be used to correct or manually adjust for incorrect elevation values in a point cloud layer.

.. note::

Any scaling specified via :py:func:`~QgsPointCloudLayerElevationProperties.zScale` is applied before any offset value specified via :py:func:`~QgsPointCloudLayerElevationProperties.zOffset`

.. seealso:: :py:func:`setZOffset`
%End

@@ -56,7 +60,41 @@ the layer.

This can be used to correct or manually adjust for incorrect elevation values in a point cloud layer.

.. note::

Any scaling specified via :py:func:`~QgsPointCloudLayerElevationProperties.zScale` is applied before any offset value specified via :py:func:`~QgsPointCloudLayerElevationProperties.zOffset`

.. seealso:: :py:func:`zOffset`
%End

double zScale() const;
%Docstring
Returns the z scale, which is a scaling factor which should be applied to z values from
the layer.

This can be used to correct or manually adjust for incorrect elevation values in a point cloud layer, such
as conversion of elevation values in feet to meters.

.. note::

Any scaling specified via :py:func:`~QgsPointCloudLayerElevationProperties.zScale` is applied before any offset value specified via :py:func:`~QgsPointCloudLayerElevationProperties.zOffset`

.. seealso:: :py:func:`setZScale`
%End

void setZScale( double scale );
%Docstring
Sets the z ``scale``, which is a scaling factor which will be applied to z values from
the layer.

This can be used to correct or manually adjust for incorrect elevation values in a point cloud layer, such
as conversion of elevation values in feet to meters.

.. note::

Any scaling specified via :py:func:`~QgsPointCloudLayerElevationProperties.zScale` is applied before any offset value specified via :py:func:`~QgsPointCloudLayerElevationProperties.zOffset`

.. seealso:: :py:func:`zScale`
%End

};
@@ -26,13 +26,16 @@ Encapsulates the render context for a 2D point cloud rendering operation.
public:

QgsPointCloudRenderContext( QgsRenderContext &context, const QgsVector3D &scale, const QgsVector3D &offset,
double zValueFixedOffset );
double zValueScale, double zValueFixedOffset );
%Docstring
Constructor for QgsPointCloudRenderContext.

The ``scale`` and ``offset`` arguments specify the scale and offset of the layer's int32 coordinates
compared to CRS coordinates respectively.

The ``zValueScale`` argument specifies any constant scaling factor which must be applied to z values
taken from the point cloud index.

The ``zValueFixedOffset`` argument specifies any constant offset value which must be added to z values
taken from the point cloud index.
%End
@@ -114,9 +117,22 @@ Returns the offset for the y value in a point record.
.. seealso:: :py:func:`yOffset`
%End

double zValueScale() const;
%Docstring
Returns any constant scaling factor which must be applied to z values taken from the point cloud index.

.. note::

Scaling of z values should be applied before the :py:func:`~QgsPointCloudRenderContext.zValueFixedOffset`.
%End

double zValueFixedOffset() const;
%Docstring
Returns any constant offset which must be applied to z values taken from the point cloud index.

.. note::

Scaling of z values via :py:func:`~QgsPointCloudRenderContext.zValueScale` should be applied before the :py:func:`~QgsPointCloudRenderContext.zValueFixedOffset`.
%End


@@ -29,9 +29,10 @@

#include "qgis.h"

QgsPointCloud3DRenderContext::QgsPointCloud3DRenderContext( const Qgs3DMapSettings &map, std::unique_ptr<QgsPointCloud3DSymbol> symbol, double zValueFixedOffset )
QgsPointCloud3DRenderContext::QgsPointCloud3DRenderContext( const Qgs3DMapSettings &map, std::unique_ptr<QgsPointCloud3DSymbol> symbol, double zValueScale, double zValueFixedOffset )
: Qgs3DRenderContext( map )
, mSymbol( std::move( symbol ) )
, mZValueScale( zValueScale )
, mZValueFixedOffset( zValueFixedOffset )
{

@@ -115,6 +116,7 @@ Qt3DCore::QEntity *QgsPointCloudLayer3DRenderer::createEntity( const Qgs3DMapSet
return nullptr;

return new QgsPointCloudLayerChunkedEntity( pcl->dataProvider()->index(), map, dynamic_cast<QgsPointCloud3DSymbol *>( mSymbol->clone() ), maximumScreenError(), showBoundingBoxes(),
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zScale(),
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zOffset() );
}

@@ -46,11 +46,14 @@ class _3D_NO_EXPORT QgsPointCloud3DRenderContext : public Qgs3DRenderContext
/**
* Constructor for QgsPointCloud3DRenderContext.
*
* The \a zValueScale argument specifies any constant scaling factor which must be applied to z values
* taken from the point cloud index.
*
* The \a zValueFixedOffset argument specifies any constant offset value which must be added to z values
* taken from the point cloud index.
*/
QgsPointCloud3DRenderContext( const Qgs3DMapSettings &map, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
double zValueFixedOffset );
double zValueScale, double zValueFixedOffset );

//! QgsPointCloudRenderContext cannot be copied.
QgsPointCloud3DRenderContext( const QgsPointCloud3DRenderContext &rh ) = delete;
@@ -133,8 +136,17 @@ class _3D_NO_EXPORT QgsPointCloud3DRenderContext : public Qgs3DRenderContext
}
}

/**
* Returns any constant scaling factor which must be applied to z values taken from the point cloud index.
*
* \note Scaling of z values should be applied before the zValueFixedOffset().
*/
double zValueScale() const { return mZValueScale; }

/**
* Returns any constant offset which must be applied to z values taken from the point cloud index.
*
* \note Scaling of z values via zValueScale() should be applied before the zValueFixedOffset().
*/
double zValueFixedOffset() const { return mZValueFixedOffset; }

@@ -145,6 +157,7 @@ class _3D_NO_EXPORT QgsPointCloud3DRenderContext : public Qgs3DRenderContext
QgsPointCloudAttributeCollection mAttributes;
std::unique_ptr<QgsPointCloud3DSymbol> mSymbol;
QgsPointCloudCategoryList mFilteredOutCategories;
double mZValueScale = 1.0;
double mZValueFixedOffset = 0;
};

@@ -46,10 +46,11 @@

///////////////

QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol, double zValueOffset )
QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol,
double zValueScale, double zValueOffset )
: QgsChunkLoader( node )
, mFactory( factory )
, mContext( factory->mMap, std::move( symbol ), zValueOffset )
, mContext( factory->mMap, std::move( symbol ), zValueScale, zValueOffset )
{
QgsPointCloudIndex *pc = mFactory->mPointCloudIndex;
mContext.setAttributes( pc->attributes() );
@@ -126,9 +127,11 @@ Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntit
///////////////


QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol, double zValueOffset )
QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol,
double zValueScale, double zValueOffset )
: mMap( map )
, mPointCloudIndex( pc )
, mZValueScale( zValueScale )
, mZValueOffset( zValueOffset )
{
mSymbol.reset( symbol );
@@ -138,7 +141,7 @@ QgsChunkLoader *QgsPointCloudLayerChunkLoaderFactory::createChunkLoader( QgsChun
{
QgsChunkNodeId id = node->tileId();
Q_ASSERT( mPointCloudIndex->hasNode( IndexedPointCloudNode( id.d, id.x, id.y, id.z ) ) );
return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr< QgsPointCloud3DSymbol >( static_cast< QgsPointCloud3DSymbol * >( mSymbol->clone() ) ), mZValueOffset );
return new QgsPointCloudLayerChunkLoader( this, node, std::unique_ptr< QgsPointCloud3DSymbol >( static_cast< QgsPointCloud3DSymbol * >( mSymbol->clone() ) ), mZValueScale, mZValueOffset );
}

QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset, QgsVector3D scale, const Qgs3DMapSettings &map, double zValueOffset );
@@ -197,9 +200,9 @@ QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset
}


QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes, double zValueOffset )
QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes, double zValueScale, double zValueOffset )
: QgsChunkedEntity( maxScreenError,
new QgsPointCloudLayerChunkLoaderFactory( map, pc, symbol, zValueOffset ), true )
new QgsPointCloudLayerChunkLoaderFactory( map, pc, symbol, zValueScale, zValueOffset ), true )
{
setUsingAdditiveStrategy( true );
setShowBoundingBoxes( showBoundingBoxes );
@@ -54,11 +54,13 @@
class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory
{
public:
/*

/**
* Constructs the factory
* The factory takes ownership over the passed \a symbol
*/
QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol, double zValueOffset );
QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol,
double zValueScale, double zValueOffset );

//! Creates loader for the given chunk node. Ownership of the returned is passed to the caller.
virtual QgsChunkLoader *createChunkLoader( QgsChunkNode *node ) const override;
@@ -67,6 +69,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory
const Qgs3DMapSettings &mMap;
QgsPointCloudIndex *mPointCloudIndex;
std::unique_ptr< QgsPointCloud3DSymbol > mSymbol;
double mZValueScale = 1.0;
double mZValueOffset = 0;
};

@@ -87,7 +90,7 @@ class QgsPointCloudLayerChunkLoader : public QgsChunkLoader
* Constructs the loader
* QgsPointCloudLayerChunkLoader takes ownership over symbol
*/
QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol, double zValueOffset );
QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, std::unique_ptr< QgsPointCloud3DSymbol > symbol, double zValueScale, double zValueOffset );
~QgsPointCloudLayerChunkLoader() override;

virtual void cancel() override;
@@ -117,7 +120,7 @@ class QgsPointCloudLayerChunkedEntity : public QgsChunkedEntity
Q_OBJECT
public:
explicit QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, float maxScreenError, bool showBoundingBoxes,
double zValueOffset );
double zValueScale, double zValueOffset );

~QgsPointCloudLayerChunkedEntity();
};
@@ -260,6 +260,7 @@ void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *p

const QgsVector3D scale = pc->scale();
const QgsVector3D offset = pc->offset();
const double zValueScale = context.zValueScale();
const double zValueOffset = context.zValueFixedOffset();

for ( int i = 0; i < count; ++i )
@@ -270,7 +271,7 @@ void QgsSingleColorPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *p

double x = offset.x() + scale.x() * ix;
double y = offset.y() + scale.y() * iy;
double z = offset.z() + scale.z() * iz + zValueOffset;
double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
QgsVector3D point( x, y, z );
QgsVector3D p = context.map().mapToWorldCoordinates( point );
outNormal.positions.push_back( QVector3D( p.x(), p.y(), p.z() ) );
@@ -315,6 +316,7 @@ void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc,
bool attrIsZ = false;
QgsPointCloudAttribute::DataType attributeType = QgsPointCloudAttribute::Float;
int attributeOffset = 0;
const double zValueScale = context.zValueScale();
const double zValueOffset = context.zValueFixedOffset();
QgsColorRampPointCloud3DSymbol *symbol = dynamic_cast<QgsColorRampPointCloud3DSymbol *>( context.symbol() );
if ( symbol )
@@ -371,7 +373,7 @@ void QgsColorRampPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc,

double x = offset.x() + scale.x() * ix;
double y = offset.y() + scale.y() * iy;
double z = offset.z() + scale.z() * iz + zValueOffset;
double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
QgsVector3D point( x, y, z );

QgsVector3D p = context.map().mapToWorldCoordinates( point );
@@ -453,6 +455,7 @@ void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const

const QgsVector3D scale = pc->scale();
const QgsVector3D offset = pc->offset();
const double zValueScale = context.zValueScale();
const double zValueOffset = context.zValueFixedOffset();

QgsContrastEnhancement *redContrastEnhancement = symbol->redContrastEnhancement();
@@ -473,7 +476,7 @@ void QgsRGBPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex *pc, const
qint32 iz = *( qint32 * )( ptr + i * recordSize + 8 );
double x = offset.x() + scale.x() * ix;
double y = offset.y() + scale.y() * iy;
double z = offset.z() + scale.z() * iz + zValueOffset;
double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
QgsVector3D point( x, y, z );
QgsVector3D p = context.map().mapToWorldCoordinates( point );

@@ -598,6 +601,7 @@ void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex

const QgsVector3D scale = pc->scale();
const QgsVector3D offset = pc->offset();
const double zValueScale = context.zValueScale();
const double zValueOffset = context.zValueFixedOffset();

QSet<int> filteredOutValues = context.getFilteredOutValues();
@@ -609,7 +613,7 @@ void QgsClassificationPointCloud3DSymbolHandler::processNode( QgsPointCloudIndex

double x = offset.x() + scale.x() * ix;
double y = offset.y() + scale.y() * iy;
double z = offset.z() + scale.z() * iz + zValueOffset;
double z = ( offset.z() + scale.z() * iz ) * zValueScale + zValueOffset;
QgsVector3D point( x, y, z );

QgsVector3D p = context.map().mapToWorldCoordinates( point );
@@ -27,10 +27,12 @@ QgsPointCloudElevationPropertiesWidget::QgsPointCloudElevationPropertiesWidget(
setupUi( this );

mOffsetZSpinBox->setClearValue( 0 );
mScaleZSpinBox->setClearValue( 1 );

syncToLayer( layer );

connect( mOffsetZSpinBox, qgis::overload<double >::of( &QDoubleSpinBox::valueChanged ), this, &QgsPointCloudElevationPropertiesWidget::onChanged );
connect( mScaleZSpinBox, qgis::overload<double >::of( &QDoubleSpinBox::valueChanged ), this, &QgsPointCloudElevationPropertiesWidget::onChanged );
}

void QgsPointCloudElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer )
@@ -41,6 +43,7 @@ void QgsPointCloudElevationPropertiesWidget::syncToLayer( QgsMapLayer *layer )

mBlockUpdates = true;
mOffsetZSpinBox->setValue( static_cast< const QgsPointCloudLayerElevationProperties * >( mLayer->elevationProperties() )->zOffset() );
mScaleZSpinBox->setValue( static_cast< const QgsPointCloudLayerElevationProperties * >( mLayer->elevationProperties() )->zScale() );
mBlockUpdates = false;
}

@@ -50,6 +53,7 @@ void QgsPointCloudElevationPropertiesWidget::apply()
return;

static_cast< QgsPointCloudLayerElevationProperties * >( mLayer->elevationProperties() )->setZOffset( mOffsetZSpinBox->value() );
static_cast< QgsPointCloudLayerElevationProperties * >( mLayer->elevationProperties() )->setZScale( mScaleZSpinBox->value() );
mLayer->trigger3DUpdate();
}

@@ -111,7 +111,7 @@ void QgsPointCloudAttributeByRampRenderer::renderBlock( const QgsPointCloudBlock
if ( applyYOffset )
attributeValue = context.offset().y() + context.scale().y() * attributeValue;
if ( applyZOffset )
attributeValue = context.offset().z() + context.scale().z() * attributeValue + context.zValueFixedOffset();
attributeValue = ( context.offset().z() + context.scale().z() * attributeValue ) * context.zValueScale() + context.zValueFixedOffset();

mColorRampShader.shade( attributeValue, &red, &green, &blue, &alpha );
drawPoint( x, y, QColor( red, green, blue, alpha ), context );
@@ -32,6 +32,7 @@ QDomElement QgsPointCloudLayerElevationProperties::writeXml( QDomElement &parent
{
QDomElement element = document.createElement( QStringLiteral( "elevation" ) );
element.setAttribute( QStringLiteral( "zoffset" ), qgsDoubleToString( mZOffset ) );
element.setAttribute( QStringLiteral( "zscale" ), qgsDoubleToString( mZScale ) );
parentElement.appendChild( element );
return element;
}
@@ -40,6 +41,7 @@ bool QgsPointCloudLayerElevationProperties::readXml( const QDomElement &element,
{
QDomElement elevationElement = element.firstChildElement( QStringLiteral( "elevation" ) ).toElement();
mZOffset = elevationElement.attribute( QStringLiteral( "zoffset" ), QStringLiteral( "0" ) ).toDouble();
mZScale = elevationElement.attribute( QStringLiteral( "zscale" ), QStringLiteral( "1" ) ).toDouble();
return true;
}

@@ -60,7 +62,7 @@ QgsDoubleRange QgsPointCloudLayerElevationProperties::calculateZRange( QgsMapLay
const QVariant zMax = pcLayer->dataProvider()->metadataStatistic( QStringLiteral( "Z" ), QgsStatisticalSummary::Max );
if ( zMin.isValid() && zMax.isValid() )
{
return QgsDoubleRange( zMin.toDouble() + mZOffset, zMax.toDouble() + mZOffset );
return QgsDoubleRange( zMin.toDouble() * mZScale + mZOffset, zMax.toDouble() * mZScale + mZOffset );
}
}
}

0 comments on commit 7b141e9

Please sign in to comment.
You can’t perform that action at this time.