Skip to content
Permalink
Browse files

return maximum screen space in 3D

  • Loading branch information
NEDJIMAbelgacem authored and wonder-sk committed Feb 10, 2021
1 parent 86a7139 commit 5de28dd580a6d5f260c948a1cf6cba1f0f62b492
@@ -62,6 +62,24 @@ Returns 3D symbol associated with the renderer
virtual void resolveReferences( const QgsProject &project );


double maximumScreenError() const;
%Docstring
Returns the maximum screen error allowed when rendering the point cloud.

Larger values result in a faster render with less points rendered.

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

void setMaximumScreenError( double error );
%Docstring
Sets the maximum screen ``error`` allowed when rendering the point cloud.

Larger values result in a faster render with less points rendered.

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

bool showBoundingBoxes() const;
%Docstring
Returns whether bounding boxes will be visible when rendering the point cloud.
@@ -248,6 +248,7 @@ int QgsChunkedEntity::pendingJobsCount() const
void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
{
QSet<QgsChunkNode *> nodes;
QVector<std::pair<QgsChunkNode *, float>> residencyRequests;

using slot = std::pair<QgsChunkNode *, float>;
auto cmp_funct = []( slot & p1, slot & p2 )
@@ -272,22 +273,7 @@ void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
if ( renderedCount > mPrimitivesBudget )
break;

QgsChunkNode *const *children = node->children();
for ( int i = 0; i < node->childCount(); ++i )
pq.push( std::make_pair( children[i], screenSpaceError( children[i], state ) ) );
// We won't render the primitives of the parent unless we are using additive strategy
if ( !mAdditiveStrategy && node->parent() )
{
nodes.remove( node->parent() );
renderedCount -= mChunkLoaderFactory->primitivesCount( node->parent() );
}
renderedCount += mChunkLoaderFactory->primitivesCount( node );
nodes.insert( node );
}

QVector<std::pair<QgsChunkNode *, float>> residencyRequests;
for ( QgsChunkNode *node : nodes )
{
// ensure we have child nodes (at least skeletons) available, if any
if ( node->childCount() == -1 )
{
@@ -303,6 +289,7 @@ void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
// this happens initially when root node is not ready yet
continue;
}
bool toBeAdded = false;

//QgsDebugMsgLevel( QStringLiteral( "%1|%2|%3 %4 %5" ).arg( node->tileX() ).arg( node->tileY() ).arg( node->tileZ() ).arg( mTau ).arg( screenSpaceError( node, state ) ), 2 );
if ( node->childCount() == 0 )
@@ -326,6 +313,8 @@ void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
// coarser data in parents. We use this e.g. with point cloud data.
mActiveNodes << node;
}

toBeAdded = true;
}
else
{
@@ -336,7 +325,21 @@ void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
for ( int i = 0; i < node->childCount(); ++i )
residencyRequests.push_back( std::make_pair( children[i], children[i]->bbox().distanceFromPoint( state.cameraPos ) ) );
}
if ( toBeAdded )
{
QgsChunkNode *const *children = node->children();
for ( int i = 0; i < node->childCount(); ++i )
pq.push( std::make_pair( children[i], screenSpaceError( children[i], state ) ) );
// We won't render the primitives of the parent unless we are using additive strategy
if ( !mAdditiveStrategy && node->parent() )
{
nodes.remove( node->parent() );
renderedCount -= mChunkLoaderFactory->primitivesCount( node->parent() );
}
renderedCount += mChunkLoaderFactory->primitivesCount( node );
}
}

std::sort( residencyRequests.begin(), residencyRequests.end(), [&]( std::pair<QgsChunkNode *, float> n1, std::pair<QgsChunkNode *, float> n2 )
{
return n1.second > n2.second;
@@ -345,7 +348,6 @@ void QgsChunkedEntity::update( QgsChunkNode *root, const SceneState &state )
requestResidency( n.first );
}


void QgsChunkedEntity::requestResidency( QgsChunkNode *node )
{
if ( node->state() == QgsChunkNode::Loaded || node->state() == QgsChunkNode::QueuedForUpdate || node->state() == QgsChunkNode::Updating )
@@ -108,6 +108,7 @@ QgsPointCloudLayer3DRenderer *QgsPointCloudLayer3DRenderer::clone() const
QgsAbstract3DSymbol *symbolClone = mSymbol->clone();
r->setSymbol( dynamic_cast<QgsPointCloud3DSymbol *>( symbolClone ) );
}
r->setMaximumScreenError( mMaximumScreenError );
r->setShowBoundingBoxes( mShowBoundingBoxes );
return r;
}
@@ -120,7 +121,7 @@ Qt3DCore::QEntity *QgsPointCloudLayer3DRenderer::createEntity( const Qgs3DMapSet
if ( !mSymbol )
return nullptr;

return new QgsPointCloudLayerChunkedEntity( pcl->dataProvider()->index(), map, dynamic_cast<QgsPointCloud3DSymbol *>( mSymbol->clone() ), showBoundingBoxes(),
return new QgsPointCloudLayerChunkedEntity( pcl->dataProvider()->index(), map, dynamic_cast<QgsPointCloud3DSymbol *>( mSymbol->clone() ), mMaximumScreenError, showBoundingBoxes(),
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zScale(),
static_cast< const QgsPointCloudLayerElevationProperties * >( pcl->elevationProperties() )->zOffset(), mPointBudget );
}
@@ -137,6 +138,7 @@ void QgsPointCloudLayer3DRenderer::writeXml( QDomElement &elem, const QgsReadWri
QDomDocument doc = elem.ownerDocument();

elem.setAttribute( QStringLiteral( "layer" ), mLayerRef.layerId );
elem.setAttribute( QStringLiteral( "max-screen-error" ), maximumScreenError() );
elem.setAttribute( QStringLiteral( "show-bounding-boxes" ), showBoundingBoxes() ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
elem.setAttribute( QStringLiteral( "point-budget" ), mPointBudget );

@@ -157,6 +159,7 @@ void QgsPointCloudLayer3DRenderer::readXml( const QDomElement &elem, const QgsRe

const QString symbolType = elemSymbol.attribute( QStringLiteral( "type" ) );
mShowBoundingBoxes = elem.attribute( QStringLiteral( "show-bounding-boxes" ), QStringLiteral( "0" ) ).toInt();
mMaximumScreenError = elem.attribute( QStringLiteral( "max-screen-error" ), QStringLiteral( "1.0" ) ).toDouble();
mPointBudget = elem.attribute( QStringLiteral( "point-budget" ), QStringLiteral( "1000000" ) ).toInt();

if ( symbolType == QLatin1String( "single-color" ) )
@@ -179,6 +182,16 @@ void QgsPointCloudLayer3DRenderer::resolveReferences( const QgsProject &project
mLayerRef.setLayer( project.mapLayer( mLayerRef.layerId ) );
}

double QgsPointCloudLayer3DRenderer::maximumScreenError() const
{
return mMaximumScreenError;
}

void QgsPointCloudLayer3DRenderer::setMaximumScreenError( double error )
{
mMaximumScreenError = error;
}

bool QgsPointCloudLayer3DRenderer::showBoundingBoxes() const
{
return mShowBoundingBoxes;
@@ -228,6 +228,24 @@ class _3D_EXPORT QgsPointCloudLayer3DRenderer : public QgsAbstract3DRenderer
void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) override;
void resolveReferences( const QgsProject &project ) override;

/**
* Returns the maximum screen error allowed when rendering the point cloud.
*
* Larger values result in a faster render with less points rendered.
*
* \see setMaximumScreenError()
*/
double maximumScreenError() const;

/**
* Sets the maximum screen \a error allowed when rendering the point cloud.
*
* Larger values result in a faster render with less points rendered.
*
* \see maximumScreenError()
*/
void setMaximumScreenError( double error );

/**
* Returns whether bounding boxes will be visible when rendering the point cloud.
*
@@ -255,6 +273,7 @@ class _3D_EXPORT QgsPointCloudLayer3DRenderer : public QgsAbstract3DRenderer
private:
QgsMapLayerRef mLayerRef; //!< Layer used to extract mesh data from
std::unique_ptr< QgsPointCloud3DSymbol > mSymbol;
double mMaximumScreenError = 1.0;
bool mShowBoundingBoxes = false;
int mPointBudget = 1000000;

@@ -211,8 +211,8 @@ QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset
}


QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget )
: QgsChunkedEntity( 0.0f,
QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, double maximumScreenSpaceError, bool showBoundingBoxes, double zValueScale, double zValueOffset, int pointBudget )
: QgsChunkedEntity( maximumScreenSpaceError,
new QgsPointCloudLayerChunkLoaderFactory( map, pc, symbol, zValueScale, zValueOffset, pointBudget ), true, pointBudget )
{
setUsingAdditiveStrategy( true );
@@ -121,7 +121,7 @@ class QgsPointCloudLayerChunkedEntity : public QgsChunkedEntity
{
Q_OBJECT
public:
explicit QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, bool showBoundingBoxes,
explicit QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol, double maximumScreenSpaceError, bool showBoundingBoxes,
double zValueScale, double zValueOffset, int pointBudget );

~QgsPointCloudLayerChunkedEntity();
@@ -34,6 +34,7 @@ QgsPointCloud3DSymbolWidget::QgsPointCloud3DSymbolWidget( QgsPointCloudLayer *la
setupUi( this );

mPointSizeSpinBox->setClearValue( 2.0 );
mMaxScreenErrorSpinBox->setClearValue( 1.0 );

mColorRampShaderMinEdit->setShowClearButton( false );
mColorRampShaderMaxEdit->setShowClearButton( false );
@@ -110,6 +111,7 @@ QgsPointCloud3DSymbolWidget::QgsPointCloud3DSymbolWidget( QgsPointCloudLayer *la
connect( mColorRampShaderMinEdit, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsPointCloud3DSymbolWidget::minMaxChanged );
connect( mColorRampShaderMaxEdit, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsPointCloud3DSymbolWidget::minMaxChanged );

connect( mMaxScreenErrorSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, [&]() { emitChangedSignal(); } );
connect( mPointBudgetPercentageSlider, &QSlider::valueChanged, this, &QgsPointCloud3DSymbolWidget::pointBudgetSliderChanged );
connect( mPointBudgetPercentageSpinBox, qgis::overload<double>::of( &QDoubleSpinBox::valueChanged ), this, &QgsPointCloud3DSymbolWidget::pointBudgetSpinBoxChanged );
connect( mShowBoundingBoxesCheckBox, &QCheckBox::stateChanged, [&]() { emitChangedSignal(); } );
@@ -603,6 +605,16 @@ void QgsPointCloud3DSymbolWidget::blueAttributeChanged()
}
}

void QgsPointCloud3DSymbolWidget::setMaximumScreenError( double maxScreenError )
{
whileBlocking( mMaxScreenErrorSpinBox )->setValue( maxScreenError );
}

double QgsPointCloud3DSymbolWidget::maximumScreenError() const
{
return mMaxScreenErrorSpinBox->value();
}

void QgsPointCloud3DSymbolWidget::setShowBoundingBoxes( bool showBoundingBoxes )
{
whileBlocking( mShowBoundingBoxesCheckBox )->setChecked( showBoundingBoxes );
@@ -36,6 +36,9 @@ class QgsPointCloud3DSymbolWidget : public QWidget, private Ui::QgsPointCloud3DS

QgsPointCloud3DSymbol *symbol() const;

void setMaximumScreenError( double maxScreenError );
double maximumScreenError() const;

void setShowBoundingBoxes( bool showBoundingBoxes );
double showBoundingBoxes() const;

@@ -46,6 +46,7 @@ void QgsPointCloudLayer3DRendererWidget::setRenderer( const QgsPointCloudLayer3D
{
mWidgetPointCloudSymbol->setSymbol( const_cast<QgsPointCloud3DSymbol *>( renderer->symbol() ) );
mWidgetPointCloudSymbol->setPointBudget( renderer->pointRenderingBudget() );
mWidgetPointCloudSymbol->setMaximumScreenError( renderer->maximumScreenError() );
mWidgetPointCloudSymbol->setShowBoundingBoxes( renderer->showBoundingBoxes() );
}
}
@@ -57,6 +58,7 @@ QgsPointCloudLayer3DRenderer *QgsPointCloudLayer3DRendererWidget::renderer()
renderer->setSymbol( sym );
renderer->setLayer( qobject_cast<QgsPointCloudLayer *>( mLayer ) );
renderer->setPointRenderingBudget( mWidgetPointCloudSymbol->pointBudget() );
renderer->setMaximumScreenError( mWidgetPointCloudSymbol->maximumScreenError() );
renderer->setShowBoundingBoxes( mWidgetPointCloudSymbol->showBoundingBoxes() );
return renderer;
}
@@ -66,7 +68,9 @@ void QgsPointCloudLayer3DRendererWidget::apply()
QgsPointCloudLayer3DRenderer *r = nullptr;
r = renderer();
if ( r )
{
r->setSymbol( mWidgetPointCloudSymbol->symbol() );
}
mLayer->setRenderer3D( r );
}

@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>563</width>
<width>573</width>
<height>464</height>
</rect>
</property>
@@ -43,7 +43,21 @@
</property>
<item row="1" column="0">
<layout class="QGridLayout" name="gridLayout_7">
<item row="1" column="0">
<item row="2" column="1">
<widget class="QSlider" name="mPointBudgetPercentageSlider">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Maximum number of rendered points:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelPointBudget">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
@@ -72,10 +86,10 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="mPointBudgetPercentageSpinBox">
<property name="maximum">
<double>100.000000000000000</double>
<item row="3" column="1" colspan="2">
<widget class="QSpinBox" name="mRenderedPointsSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
@@ -92,24 +106,27 @@
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSlider" name="mPointBudgetPercentageSlider">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="2" column="2">
<widget class="QDoubleSpinBox" name="mPointBudgetPercentageSpinBox">
<property name="maximum">
<double>100.000000000000000</double>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Maximum number of rendered points:</string>
<string>Maximum screen space error</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSpinBox" name="mRenderedPointsSpinBox">
<property name="enabled">
<bool>false</bool>
<item row="1" column="1" colspan="2">
<widget class="QgsDoubleSpinBox" name="mMaxScreenErrorSpinBox">
<property name="maximum">
<double>100000.000000000000000</double>
</property>
<property name="value">
<double>1.000000000000000</double>
</property>
</widget>
</item>

0 comments on commit 5de28dd

Please sign in to comment.