Initial implementation of point-cloud 3D GUI

This commit is contained in:
NEDJIMAbelgacem 2020-11-13 15:58:41 +01:00
parent 928997d557
commit c220bb47a3
23 changed files with 627 additions and 37 deletions

View File

@ -43,6 +43,15 @@ Returns point cloud layer associated with the renderer
virtual QgsPointCloudLayer3DRenderer *clone() const /Factory/;
void setSymbol( QgsPointCloud3DSymbol *symbol );
%Docstring
Sets 3D symbol associated with the renderer
%End
const QgsPointCloud3DSymbol *symbol() const;
%Docstring
Returns 3D symbol associated with the renderer
%End
virtual void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const;
virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context );

View File

@ -69,6 +69,7 @@ SET(QGIS_3D_SRCS
symbols/qgspoint3dsymbol_p.cpp
symbols/qgspolygon3dsymbol.cpp
symbols/qgspolygon3dsymbol_p.cpp
symbols/qgspointcloud3dsymbol.cpp
terrain/qgsdemterraingenerator.cpp
terrain/qgsdemterraintilegeometry_p.cpp
@ -135,6 +136,7 @@ SET(QGIS_3D_HDRS
symbols/qgspoint3dbillboardmaterial.h
symbols/qgspoint3dsymbol.h
symbols/qgspolygon3dsymbol.h
symbols/qgspointcloud3dsymbol.h
terrain/qgsdemterraingenerator.h
terrain/qgsflatterraingenerator.h

View File

@ -36,6 +36,7 @@
#include "qgsline3dsymbol.h"
#include "qgspoint3dsymbol.h"
#include "qgspolygon3dsymbol.h"
//#include "qgspointcloud3dsymbol.h"
#include <Qt3DExtras/QPhongMaterial>

View File

@ -24,6 +24,7 @@
#include "qgsxmlutils.h"
#include "qgsapplication.h"
#include "qgs3dsymbolregistry.h"
#include "qgspointcloud3dsymbol.h"
QgsPointCloudLayer3DRendererMetadata::QgsPointCloudLayer3DRendererMetadata()
@ -64,6 +65,11 @@ QString QgsPointCloudLayer3DRenderer::type() const
QgsPointCloudLayer3DRenderer *QgsPointCloudLayer3DRenderer::clone() const
{
QgsPointCloudLayer3DRenderer *r = new QgsPointCloudLayer3DRenderer;
if ( mSymbol )
{
QgsAbstract3DSymbol *symbolClone = mSymbol->clone();
r->setSymbol( dynamic_cast<QgsPointCloud3DSymbol *>( symbolClone ) );
}
return r;
}
@ -73,7 +79,12 @@ Qt3DCore::QEntity *QgsPointCloudLayer3DRenderer::createEntity( const Qgs3DMapSet
if ( !pcl || !pcl->dataProvider() || !pcl->dataProvider()->index() )
return nullptr;
return new QgsPointCloudLayerChunkedEntity( pcl->dataProvider()->index(), map );
return new QgsPointCloudLayerChunkedEntity( pcl->dataProvider()->index(), map, mSymbol );
}
void QgsPointCloudLayer3DRenderer::setSymbol( QgsPointCloud3DSymbol *symbol )
{
mSymbol = dynamic_cast<QgsPointCloud3DSymbol *>( symbol->clone() );
}
void QgsPointCloudLayer3DRenderer::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
@ -83,13 +94,23 @@ void QgsPointCloudLayer3DRenderer::writeXml( QDomElement &elem, const QgsReadWri
QDomDocument doc = elem.ownerDocument();
elem.setAttribute( QStringLiteral( "layer" ), mLayerRef.layerId );
QDomElement elemSymbol = doc.createElement( QStringLiteral( "symbol" ) );
if ( mSymbol )
{
elemSymbol.setAttribute( QStringLiteral( "type" ), mSymbol->type() );
mSymbol->writeXml( elemSymbol, context );
}
elem.appendChild( elemSymbol );
}
void QgsPointCloudLayer3DRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
{
Q_UNUSED( context )
mLayerRef = QgsMapLayerRef( elem.attribute( QStringLiteral( "layer" ) ) );
QDomElement elemSymbol = elem.firstChildElement( QStringLiteral( "symbol" ) );
if ( !mSymbol ) mSymbol = new QgsPointCloud3DSymbol;
mSymbol->readXml( elemSymbol, context );
}
void QgsPointCloudLayer3DRenderer::resolveReferences( const QgsProject &project )

View File

@ -26,6 +26,7 @@
#include <QObject>
class QgsPointCloudLayer;
class QgsPointCloud3DSymbol;
#ifndef SIP_RUN
@ -69,12 +70,18 @@ class _3D_EXPORT QgsPointCloudLayer3DRenderer : public QgsAbstract3DRenderer
QgsPointCloudLayer3DRenderer *clone() const override SIP_FACTORY;
Qt3DCore::QEntity *createEntity( const Qgs3DMapSettings &map ) const override SIP_SKIP;
//! Sets 3D symbol associated with the renderer
void setSymbol( QgsPointCloud3DSymbol *symbol );
//! Returns 3D symbol associated with the renderer
const QgsPointCloud3DSymbol *symbol() const { return mSymbol; }
void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const override;
void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) override;
void resolveReferences( const QgsProject &project ) override;
private:
QgsMapLayerRef mLayerRef; //!< Layer used to extract mesh data from
QgsPointCloud3DSymbol *mSymbol = nullptr;
private:
#ifdef SIP_RUN

View File

@ -26,6 +26,8 @@
#include "qgspoint3dsymbol.h"
#include "qgsphongmaterialsettings.h"
#include "qgspointcloud3dsymbol.h"
#include "qgsapplication.h"
#include "qgs3dsymbolregistry.h"
#include "qgspointcloudattribute.h"
@ -93,7 +95,8 @@ void QgsPointCloud3DGeometry::makeVertexBuffer( const QgsPointCloud3DSymbolHandl
}
QgsPointCloud3DSymbolHandler::QgsPointCloud3DSymbolHandler()
QgsPointCloud3DSymbolHandler::QgsPointCloud3DSymbolHandler( QgsPointCloud3DSymbol *symbol )
: mSymbol( symbol )
{
}
@ -167,6 +170,9 @@ void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const
// Material
Qt3DRender::QMaterial *mat = new Qt3DRender::QMaterial;
Qt3DRender::QParameter *pointSizeParameter = new Qt3DRender::QParameter( "u_pointSize", QVariant::fromValue( mSymbol->pointSize() ) );
mat->addParameter( pointSizeParameter );
Qt3DRender::QShaderProgram *shaderProgram = new Qt3DRender::QShaderProgram( mat );
shaderProgram->setVertexShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/pointcloud.vert" ) ) ) );
shaderProgram->setFragmentShaderCode( Qt3DRender::QShaderProgram::loadSource( QUrl( QStringLiteral( "qrc:/shaders/pointcloud.frag" ) ) ) );
@ -176,6 +182,7 @@ void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const
Qt3DRender::QPointSize *pointSize = new Qt3DRender::QPointSize( renderPass );
pointSize->setSizeMode( Qt3DRender::QPointSize::Programmable ); // supported since OpenGL 3.2
pointSize->setValue( mSymbol->pointSize() );
renderPass->addRenderState( pointSize );
// without this filter the default forward renderer would not render this
@ -206,7 +213,7 @@ void QgsPointCloud3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const
}
QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node )
QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, QgsPointCloud3DSymbol *symbol )
: QgsChunkLoader( node )
, mFactory( factory )
, mContext( factory->mMap )
@ -219,7 +226,7 @@ QgsPointCloudLayerChunkLoader::QgsPointCloudLayerChunkLoader( const QgsPointClou
QgsDebugMsgLevel( QStringLiteral( "loading entity %1" ).arg( node->tileId().text() ), 2 );
QgsPointCloud3DSymbolHandler *handler = new QgsPointCloud3DSymbolHandler;
QgsPointCloud3DSymbolHandler *handler = new QgsPointCloud3DSymbolHandler( symbol );
mHandler.reset( handler );
//
@ -274,9 +281,10 @@ Qt3DCore::QEntity *QgsPointCloudLayerChunkLoader::createEntity( Qt3DCore::QEntit
///////////////
QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc )
QgsPointCloudLayerChunkLoaderFactory::QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol )
: mMap( map )
, mPointCloudIndex( pc )
, mSymbol( symbol )
{
}
@ -284,7 +292,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 );
return new QgsPointCloudLayerChunkLoader( this, node, mSymbol );
}
QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset, QgsVector3D scale, const Qgs3DMapSettings &map );
@ -343,12 +351,12 @@ QgsAABB nodeBoundsToAABB( QgsPointCloudDataBounds nodeBounds, QgsVector3D offset
}
QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map )
QgsPointCloudLayerChunkedEntity::QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol )
: QgsChunkedEntity( 5, // max. allowed screen error (in pixels) -- // TODO
new QgsPointCloudLayerChunkLoaderFactory( map, pc ), true )
new QgsPointCloudLayerChunkLoaderFactory( map, pc, symbol ), true )
{
setUsingAdditiveStrategy( true );
setShowBoundingBoxes( true );
setShowBoundingBoxes( false );
}
QgsPointCloudLayerChunkedEntity::~QgsPointCloudLayerChunkedEntity()

View File

@ -37,6 +37,7 @@ class Qgs3DMapSettings;
class QgsPointCloudLayer;
class IndexedPointCloudNode;
class QgsPointCloudIndex;
class QgsPointCloud3DSymbol;
#include <QFutureWatcher>
#include <Qt3DRender/QGeometry>
@ -47,7 +48,7 @@ class QgsPointCloudIndex;
class QgsPointCloud3DSymbolHandler // : public QgsFeature3DHandler
{
public:
QgsPointCloud3DSymbolHandler( );
QgsPointCloud3DSymbolHandler( QgsPointCloud3DSymbol *symbol );
bool prepare( const Qgs3DRenderContext &context );// override;
void processNode( QgsPointCloudIndex *pc, const IndexedPointCloudNode &n, const Qgs3DRenderContext &context ); // override;
@ -85,6 +86,8 @@ class QgsPointCloud3DSymbolHandler // : public QgsFeature3DHandler
// outputs
PointData outNormal; //!< Features that are not selected
// PointData outSelected; //!< Features that are selected
QgsPointCloud3DSymbol *mSymbol = nullptr;
};
class QgsPointCloud3DGeometry: public Qt3DRender::QGeometry
@ -112,7 +115,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory
{
public:
//! Constructs the factory
QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc );
QgsPointCloudLayerChunkLoaderFactory( const Qgs3DMapSettings &map, QgsPointCloudIndex *pc, QgsPointCloud3DSymbol *symbol );
//! Creates loader for the given chunk node. Ownership of the returned is passed to the caller.
virtual QgsChunkLoader *createChunkLoader( QgsChunkNode *node ) const override;
@ -121,6 +124,7 @@ class QgsPointCloudLayerChunkLoaderFactory : public QgsChunkLoaderFactory
const Qgs3DMapSettings &mMap;
QgsPointCloudIndex *mPointCloudIndex;
QgsPointCloud3DSymbol *mSymbol = nullptr;
};
@ -136,7 +140,7 @@ class QgsPointCloudLayerChunkLoader : public QgsChunkLoader
{
public:
//! Constructs the loader
QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node );
QgsPointCloudLayerChunkLoader( const QgsPointCloudLayerChunkLoaderFactory *factory, QgsChunkNode *node, QgsPointCloud3DSymbol *symbol );
~QgsPointCloudLayerChunkLoader() override;
virtual void cancel() override;
@ -165,7 +169,7 @@ class QgsPointCloudLayerChunkedEntity : public QgsChunkedEntity
{
Q_OBJECT
public:
explicit QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map );
explicit QgsPointCloudLayerChunkedEntity( QgsPointCloudIndex *pc, const Qgs3DMapSettings &map, QgsPointCloud3DSymbol *symbol );
~QgsPointCloudLayerChunkedEntity();
};

View File

@ -4,6 +4,7 @@ uniform mat4 modelViewProjection;
uniform mat4 projectionMatrix;
uniform mat4 viewportMatrix;
uniform float u_pointSize;
in vec3 vertexPosition;
in float cls;
@ -17,7 +18,7 @@ void main(void)
//else
gl_Position = modelViewProjection * vec4(vertexPosition, 1);
gl_PointSize = 2; //5 + vertexPosition.x * 10 + vertexPosition.y * 10;
gl_PointSize = u_pointSize; //5 + vertexPosition.x * 10 + vertexPosition.y * 10;
//gl_PointSize = viewportMatrix[1][1] * projectionMatrix[1][1] * 1.0 / gl_Position.w;
//gl_PointSize = 100.0;

View File

@ -0,0 +1,47 @@
#include "qgspointcloud3dsymbol.h"
// TODO: For some reason whwn I define function on a .cpp file they don't get included in the qgis_app target
//QgsPointCloud3DSymbol::QgsPointCloud3DSymbol()
//: QgsAbstract3DSymbol()
//{
//}
//QgsPointCloud3DSymbol::~QgsPointCloud3DSymbol() { }
//QgsAbstract3DSymbol *QgsPointCloud3DSymbol::clone() const
//{
// // TODO: fix memory leak
// QgsPointCloud3DSymbol *result = new QgsPointCloud3DSymbol;
// result->mEnabled = mEnabled;
// result->mPointSize = mPointSize;
// copyBaseSettings( result );
// return result;
//}
//void QgsPointCloud3DSymbol::writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const
//{
// Q_UNUSED( context )
// elem.setAttribute( QStringLiteral( "enabled" ), mEnabled );
// elem.setAttribute( QStringLiteral( "point-size" ), mPointSize );
//}
//void QgsPointCloud3DSymbol::readXml( const QDomElement &elem, const QgsReadWriteContext &context )
//{
// Q_UNUSED( context )
// mEnabled = elem.attribute( "enabled", QStringLiteral( "0" ) ).toInt();
// mPointSize = elem.attribute( "point-size", QStringLiteral( "5.0" ) ).toFloat();
//}
//void QgsPointCloud3DSymbol::setIsEnabled( bool enabled )
//{
// mEnabled = enabled;
//}
//void QgsPointCloud3DSymbol::setPointSize( float size )
//{
// mPointSize = size * 1.0f;
//}

View File

@ -0,0 +1,58 @@
#ifndef QGSPOINTCLOUD3DSYMBOL_H
#define QGSPOINTCLOUD3DSYMBOL_H
#include "qgis_3d.h"
#include "qgsabstract3dsymbol.h"
#define SIP_NO_FILE
class QgsPointCloud3DSymbol : public QgsAbstract3DSymbol
{
public:
//! Constructor for QgsPointCloud3DSymbol
QgsPointCloud3DSymbol() : QgsAbstract3DSymbol() { }
~QgsPointCloud3DSymbol() override = default;
QString type() const override { return "pointcloud"; }
QgsAbstract3DSymbol *clone() const override SIP_FACTORY
{
// TODO: use unique_ptr
QgsPointCloud3DSymbol *result = new QgsPointCloud3DSymbol;
result->mEnabled = mEnabled;
result->mPointSize = mPointSize;
copyBaseSettings( result );
return result;
}
void writeXml( QDomElement &elem, const QgsReadWriteContext &context ) const override
{
Q_UNUSED( context )
elem.setAttribute( QStringLiteral( "enabled" ), mEnabled );
elem.setAttribute( QStringLiteral( "point-size" ), mPointSize );
}
void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) override
{
Q_UNUSED( context )
mEnabled = elem.attribute( "enabled", QStringLiteral( "0" ) ).toInt();
mPointSize = elem.attribute( "point-size", QStringLiteral( "5.0" ) ).toFloat();
}
bool isEnabled() const { return mEnabled; }
void setIsEnabled( bool enabled ) { mEnabled = enabled; }
//! Returns the point size
float pointSize() const { return mPointSize; }
//! Sets the point size
void setPointSize( float size ) { mPointSize = size; }
private:
bool mEnabled;
float mPointSize = 10.0f;
};
#endif // QGSPOINTCLOUD3DSYMBOL_H

View File

@ -0,0 +1,71 @@
#include "qgspointcloud3dsymbolwidget.h"
#include "qgspointcloudlayer.h"
#include "qgspointcloud3dsymbol.h"
#include "qgspointcloudlayer3drenderer.h"
QgsPointCloud3DSymbolWidget::QgsPointCloud3DSymbolWidget( QgsPointCloudLayer *layer, QWidget *parent )
: QWidget( parent )
, mLayer( layer )
{
this->setupUi( this );
if ( layer )
{
QgsPointCloudLayer3DRenderer *renderer = dynamic_cast<QgsPointCloudLayer3DRenderer *>( layer->renderer3D() );
QgsPointCloud3DSymbol *symbol;
if ( renderer != nullptr )
{
symbol = const_cast<QgsPointCloud3DSymbol *>( renderer->symbol() );
setSymbol( symbol );
}
else
{
symbol = new QgsPointCloud3DSymbol;
setSymbol( symbol );
delete symbol;
}
}
// connect( mPointSizeSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &QgsPointCloud3DSymbolWidget::changed);
connect( mPointSizeSpinBox, QOverload<double>::of( &QDoubleSpinBox::valueChanged ), [&]( double value )
{
qDebug() << "mPointSizeSpinBox->valueChanged()";
emit changed();
} );
}
void QgsPointCloud3DSymbolWidget::setLayer( QgsPointCloudLayer *layer, bool updateSymbol )
{
mLayer = layer;
if ( layer )
{
QgsPointCloudLayer3DRenderer *renderer = dynamic_cast<QgsPointCloudLayer3DRenderer *>( layer->renderer3D() );
QgsPointCloud3DSymbol *symbol;
if ( renderer != nullptr )
{
symbol = const_cast<QgsPointCloud3DSymbol *>( renderer->symbol() );
setSymbol( symbol );
}
else
{
symbol = new QgsPointCloud3DSymbol;
setSymbol( symbol );
delete symbol;
}
}
}
void QgsPointCloud3DSymbolWidget::setSymbol( QgsPointCloud3DSymbol *symbol )
{
mPointSizeSpinBox->setValue( symbol->pointSize() );
}
QgsPointCloud3DSymbol *QgsPointCloud3DSymbolWidget::symbol() const
{
// TODO: fix memory leak
QgsPointCloud3DSymbol *symb = new QgsPointCloud3DSymbol;
symb->setPointSize( mPointSizeSpinBox->value() );
return symb;
}

View File

@ -0,0 +1,30 @@
#ifndef QGSPOINTCLOUD3DSYMBOLWIDGET_H
#define QGSPOINTCLOUD3DSYMBOLWIDGET_H
#include "ui_qgspointcloud3dsymbolwidget.h"
class QgsPointCloudLayer;
class QgsPointCloud3DSymbol;
class QgsPointCloud3DSymbolWidget : public QWidget, private Ui::QgsPointCloud3DSymbolWidget
{
Q_OBJECT
public:
explicit QgsPointCloud3DSymbolWidget( QgsPointCloudLayer *layer, QWidget *parent = nullptr );
void setLayer( QgsPointCloudLayer *meshLayer, bool updateSymbol = true );
QgsPointCloudLayer *pointCloudLayer() const { return mLayer; }
void setSymbol( QgsPointCloud3DSymbol *symbol );
QgsPointCloud3DSymbol *symbol() const;
signals:
void changed();
private:
QgsPointCloudLayer *mLayer = nullptr;
};
#endif // QGSPOINTCLOUD3DSYMBOLWIDGET_H

View File

@ -0,0 +1,127 @@
/***************************************************************************
qgspointcloudlayer3drendererwidget.cpp
------------------------------
Date : November 2020
Copyright : (C) 2020 by Nedjima Belgacem
Email : belgacem dot nedjima 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 "qgspointcloudlayer3drendererwidget.h"
#include "qgspointcloud3dsymbolwidget.h"
#include "qgspointcloudlayer3drenderer.h"
#include "qgspointcloudlayer.h"
#include "qgspointcloud3dsymbol.h"
#include <QBoxLayout>
#include <QCheckBox>
QgsPointCloudLayer3DRendererWidget::QgsPointCloudLayer3DRendererWidget( QgsPointCloudLayer *layer, QgsMapCanvas *canvas, QWidget *parent )
: QgsMapLayerConfigWidget( layer, canvas, parent )
{
setPanelTitle( tr( "3D View" ) );
QVBoxLayout *layout = new QVBoxLayout( this );
layout->setContentsMargins( 0, 0, 0, 0 );
// TODO: add enabled checkbox
// mChkEnabled = new QCheckBox( tr( "Enable 3D Renderer" ), this );
// layout->addWidget( mChkEnabled );
mWidgetPointCloudSymbol = new QgsPointCloud3DSymbolWidget( layer, this );
layout->addWidget( mWidgetPointCloudSymbol );
// connect( mChkEnabled, &QCheckBox::clicked, this, &QgsPointCloudLayer3DRendererWidget::onEnabledClicked );
connect( mWidgetPointCloudSymbol, &QgsPointCloud3DSymbolWidget::changed, this, &QgsPointCloudLayer3DRendererWidget::widgetChanged );
}
void QgsPointCloudLayer3DRendererWidget::setRenderer( const QgsPointCloudLayer3DRenderer *renderer )
{
mRenderer.reset( renderer ? renderer->clone() : nullptr );
if ( renderer != nullptr )
mWidgetPointCloudSymbol->setSymbol( const_cast<QgsPointCloud3DSymbol *>( renderer->symbol() ) );
// whileBlocking( mChkEnabled )->setChecked( renderer ? renderer->symbol()->isEnabled() : false );
}
QgsPointCloudLayer3DRenderer *QgsPointCloudLayer3DRendererWidget::renderer()
{
// TODO: use unique_ptr for point cloud symbol
QgsPointCloud3DSymbol *sym = mWidgetPointCloudSymbol->symbol();
mRenderer.reset( new QgsPointCloudLayer3DRenderer );
mRenderer->setSymbol( sym );
delete sym;
mRenderer->setLayer( qobject_cast<QgsPointCloudLayer *>( mLayer ) );
return mRenderer.get();
}
void QgsPointCloudLayer3DRendererWidget::apply()
{
QgsPointCloudLayer3DRenderer *r = renderer();
r->setSymbol( mWidgetPointCloudSymbol->symbol() );
mLayer->setRenderer3D( r ? r->clone() : nullptr );
}
//void QgsPointCloudLayer3DRendererWidget::onEnabledClicked()
//{
// mWidgetPointCloudSymbol->setEnabled( mChkEnabled->isChecked() );
// emit widgetChanged();
//}
void QgsPointCloudLayer3DRendererWidget::syncToLayer( QgsMapLayer *layer )
{
mLayer = layer ;
QgsPointCloudLayer *pointCloudLayer = qobject_cast<QgsPointCloudLayer *>( layer );
mWidgetPointCloudSymbol->setLayer( pointCloudLayer );
QgsAbstract3DRenderer *r = layer->renderer3D();
if ( r && r->type() == QLatin1String( "pointcloud" ) )
{
QgsPointCloudLayer3DRenderer *pointCloudRenderer = static_cast<QgsPointCloudLayer3DRenderer *>( r );
pointCloudRenderer->setSymbol( mWidgetPointCloudSymbol->symbol() );
setRenderer( pointCloudRenderer );
mWidgetPointCloudSymbol->setEnabled( pointCloudRenderer->symbol()->isEnabled() );
}
else
{
setRenderer( nullptr );
mWidgetPointCloudSymbol->setEnabled( false );
}
}
QgsPointCloudLayer3DRendererWidgetFactory::QgsPointCloudLayer3DRendererWidgetFactory( QObject *parent ):
QObject( parent )
{
setIcon( QIcon( ":/images/themes/default/3d.svg" ) );
setTitle( tr( "3D View" ) );
}
QgsMapLayerConfigWidget *QgsPointCloudLayer3DRendererWidgetFactory::createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool dockWidget, QWidget *parent ) const
{
Q_UNUSED( dockWidget )
QgsPointCloudLayer *pointCloudLayer = qobject_cast<QgsPointCloudLayer *>( layer );
if ( !pointCloudLayer )
return nullptr;
return new QgsPointCloudLayer3DRendererWidget( pointCloudLayer, canvas, parent );
}
bool QgsPointCloudLayer3DRendererWidgetFactory::supportLayerPropertiesDialog() const
{
return true;
}
bool QgsPointCloudLayer3DRendererWidgetFactory::supportsLayer( QgsMapLayer *layer ) const
{
return layer->type() == QgsMapLayerType::PointCloudLayer;
}
QString QgsPointCloudLayer3DRendererWidgetFactory::layerPropertiesPagePositionHint() const
{
return QStringLiteral( "mOptsPage_Rendering" );
}

View File

@ -0,0 +1,69 @@
/***************************************************************************
qgspointcloudlayer3drendererwidget.h
------------------------------
Date : November 2020
Copyright : (C) 2020 by Nedjima Belgacem
Email : belgacem dot nedjima 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. *
* *
***************************************************************************/
#ifndef QGSPOINTCLOUDLAYER3DRENDERERWIDGET_H
#define QGSPOINTCLOUDLAYER3DRENDERERWIDGET_H
#include <memory>
#include "qgsmaplayerconfigwidget.h"
#include "qgspointcloudlayer3drenderer.h"
#include "qgsmaplayerconfigwidgetfactory.h"
class QCheckBox;
class QgsPointCloudLayer;
class QgsMapCanvas;
class QgsPointCloud3DSymbolWidget;
//! Widget for configuration of 3D renderer of a point cloud layer
class QgsPointCloudLayer3DRendererWidget : public QgsMapLayerConfigWidget
{
Q_OBJECT
public:
explicit QgsPointCloudLayer3DRendererWidget( QgsPointCloudLayer *layer, QgsMapCanvas *canvas, QWidget *parent = nullptr );
void syncToLayer( QgsMapLayer *layer ) override;
//! no transfer of ownership
void setRenderer( const QgsPointCloudLayer3DRenderer *renderer );
//! no transfer of ownership
QgsPointCloudLayer3DRenderer *renderer();
public slots:
void apply() override;
private slots:
// void onEnabledClicked();
private:
// QCheckBox *mChkEnabled = nullptr;
QgsPointCloud3DSymbolWidget *mWidgetPointCloudSymbol = nullptr;
std::unique_ptr<QgsPointCloudLayer3DRenderer> mRenderer;
};
class QgsPointCloudLayer3DRendererWidgetFactory : public QObject, public QgsMapLayerConfigWidgetFactory
{
Q_OBJECT
public:
explicit QgsPointCloudLayer3DRendererWidgetFactory( QObject *parent = nullptr );
QgsMapLayerConfigWidget *createWidget( QgsMapLayer *layer, QgsMapCanvas *canvas, bool dockWidget, QWidget *parent ) const override;
bool supportLayerPropertiesDialog() const override;
bool supportsLayer( QgsMapLayer *layer ) const override;
QString layerPropertiesPagePositionHint() const override;
};
#endif // QGSPOINTCLOUDLAYER3DRENDERERWIDGET_H

View File

@ -286,6 +286,8 @@ IF (WITH_3D)
layout/qgslayout3dmapwidget.cpp
3d/qgsskyboxrenderingsettingswidget.cpp
3d/qgsshadowrenderingsettingswidget.cpp
3d/qgspointcloud3dsymbolwidget.cpp
3d/qgspointcloudlayer3drendererwidget.cpp
)
ENDIF (WITH_3D)

View File

@ -30,6 +30,8 @@
#include <QMessageBox>
#include <QDesktopServices>
#include "qgspointcloudlayer3drendererwidget.h"
QgsPointCloudLayerProperties::QgsPointCloudLayerProperties( QgsPointCloudLayer *lyr, QgsMapCanvas *canvas, QgsMessageBar *, QWidget *parent, Qt::WindowFlags flags )
: QgsOptionsDialogBase( QStringLiteral( "PointCloudLayerProperties" ), parent, flags )
, mLayer( lyr )
@ -103,6 +105,13 @@ void QgsPointCloudLayerProperties::apply()
{
mMetadataWidget->acceptMetadata();
for ( QgsMapLayerConfigWidget *configWidget : mLayerPropertiesPages )
{
QgsPointCloudLayer3DRendererWidget *pointCloudRendererWidget = dynamic_cast<QgsPointCloudLayer3DRendererWidget *>( configWidget );
if ( pointCloudRendererWidget )
pointCloudRendererWidget->apply();
}
// TODO -- move to proper widget classes!
mLayer->setCustomProperty( QStringLiteral( "pcMin" ), mMinZSpin->value() );
mLayer->setCustomProperty( QStringLiteral( "pcMax" ), mMaxZSpin->value() );
@ -142,6 +151,12 @@ void QgsPointCloudLayerProperties::syncToLayer()
mMaxZSpin->setValue( mLayer->customProperty( QStringLiteral( "pcMax" ), 600 ).toInt() );
mBtnColorRamp->setColorRampFromName( mLayer->customProperty( QStringLiteral( "pcRamp" ), QStringLiteral( "Viridis" ) ).toString() );
mBtnColorRamp->setColorRampName( mLayer->customProperty( QStringLiteral( "pcRamp" ), QStringLiteral( "Viridis" ) ).toString() );
const auto constMLayerPropertiesPages = mLayerPropertiesPages;
for ( QgsMapLayerConfigWidget *page : constMLayerPropertiesPages )
{
page->syncToLayer( mLayer );
}
}
@ -376,3 +391,19 @@ void QgsPointCloudLayerProperties::optionsStackedWidget_CurrentChanged( int inde
mBtnStyle->setVisible( ! isMetadataPanel );
mBtnMetadata->setVisible( isMetadataPanel );
}
void QgsPointCloudLayerProperties::addPropertiesPageFactory( QgsMapLayerConfigWidgetFactory *factory )
{
if ( !factory->supportsLayer( mLayer ) || !factory->supportLayerPropertiesDialog() )
return;
QgsMapLayerConfigWidget *page = factory->createWidget( mLayer, nullptr, false, this );
mLayerPropertiesPages << page;
const QString beforePage = factory->layerPropertiesPagePositionHint();
if ( beforePage.isEmpty() )
addPage( factory->title(), factory->title(), factory->icon(), page );
else
insertPage( factory->title(), factory->title(), factory->icon(), page, beforePage );
}

View File

@ -27,7 +27,8 @@ class QgsMapCanvas;
class QgsMessageBar;
class QgsPointCloudLayer;
class QgsMetadataWidget;
class QgsMapLayerConfigWidgetFactory;
class QgsMapLayerConfigWidget;
class QgsPointCloudLayerProperties : public QgsOptionsDialogBase, private Ui::QgsPointCloudLayerPropertiesBase
{
@ -35,6 +36,9 @@ class QgsPointCloudLayerProperties : public QgsOptionsDialogBase, private Ui::Qg
public:
QgsPointCloudLayerProperties( QgsPointCloudLayer *lyr, QgsMapCanvas *canvas, QgsMessageBar *messageBar, QWidget *parent = nullptr, Qt::WindowFlags = QgsGuiUtils::ModalDialogFlags );
//! Adds a properties page factory to the vector layer properties dialog.
void addPropertiesPageFactory( QgsMapLayerConfigWidgetFactory *factory );
private slots:
void apply();
void onCancel();
@ -68,6 +72,9 @@ class QgsPointCloudLayerProperties : public QgsOptionsDialogBase, private Ui::Qg
QgsMapCanvas *mMapCanvas = nullptr;
QgsMetadataWidget *mMetadataWidget = nullptr;
//! A list of additional pages provided by plugins
QList<QgsMapLayerConfigWidget *> mLayerPropertiesPages;
/**
* Previous layer style. Used to reset style to previous state if new style
* was loaded but dialog is canceled.

View File

@ -116,6 +116,7 @@
#include "layout/qgslayoutviewrubberband.h"
#include "qgsvectorlayer3drendererwidget.h"
#include "qgsmeshlayer3drendererwidget.h"
#include "qgspointcloudlayer3drendererwidget.h"
#include "qgs3dapputils.h"
#endif
@ -1332,6 +1333,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
#ifdef HAVE_3D
registerMapLayerPropertiesFactory( new QgsVectorLayer3DRendererWidgetFactory( this ) );
registerMapLayerPropertiesFactory( new QgsMeshLayer3DRendererWidgetFactory( this ) );
registerMapLayerPropertiesFactory( new QgsPointCloudLayer3DRendererWidgetFactory( this ) );
#endif
activateDeactivateLayerRelatedActions( nullptr ); // after members were created
@ -16252,6 +16254,32 @@ void QgisApp::showLayerProperties( QgsMapLayer *mapLayer, const QString &page )
case QgsMapLayerType::PointCloudLayer:
{
QgsPointCloudLayerProperties pointCloudLayerPropertiesDialog( qobject_cast<QgsPointCloudLayer *>( mapLayer ), mMapCanvas, visibleMessageBar(), this );
//
// connect(
// pointCloudLayerPropertiesDialog, static_cast<void ( QgsPointCloudLayerProperties::* )( QgsMapLayer * )>( &QgsPointCloudLayerProperties::toggleEditing ),
// this, [ = ]( QgsMapLayer * layer ) { toggleEditing( layer ); }
// );
// connect( pointCloudLayerPropertiesDialog, &QgsVectorLayerProperties::exportAuxiliaryLayer, this, [ = ]( QgsAuxiliaryLayer * layer )
// {
// if ( layer )
// {
// std::unique_ptr<QgsVectorLayer> clone;
// clone.reset( layer->toSpatialLayer() );
// saveAsFile( clone.get() );
// }
// } );
for ( QgsMapLayerConfigWidgetFactory *factory : qgis::as_const( mMapLayerPanelFactories ) )
{
pointCloudLayerPropertiesDialog.addPropertiesPageFactory( factory );
}
if ( !page.isEmpty() )
pointCloudLayerPropertiesDialog.setCurrentPage( page );
else
pointCloudLayerPropertiesDialog.restoreLastPage();
if ( !page.isEmpty() )
pointCloudLayerPropertiesDialog.setCurrentPage( page );

View File

@ -57,8 +57,7 @@
#ifdef HAVE_3D
#include "qgsvectorlayer3drendererwidget.h"
#include "qgsmeshlayer3drendererwidget.h"
#include "qgspointcloudlayer3drenderer.h" // TODO remove
#include "qgspointcloudlayer3drendererwidget.h"
#endif
@ -146,17 +145,6 @@ void QgsLayerStylingWidget::setLayer( QgsMapLayer *layer )
if ( layer == mCurrentLayer )
return;
#ifdef HAVE_3D
QgsPointCloudLayer *pcLayer = qobject_cast<QgsPointCloudLayer *>( layer );
if ( pcLayer )
{
//TODO remove this ugly hack!
QgsPointCloudLayer3DRenderer *r = new QgsPointCloudLayer3DRenderer();
r->setLayer( pcLayer );
r->resolveReferences( *QgsProject::instance() );
pcLayer->setRenderer3D( r );
}
#endif
// when current layer is changed, apply the main panel stack to allow it to gracefully clean up
mWidgetStack->acceptAllPanels();
@ -268,6 +256,12 @@ void QgsLayerStylingWidget::setLayer( QgsMapLayer *layer )
case QgsMapLayerType::PointCloudLayer:
{
#ifdef HAVE_3D
QListWidgetItem *symbol3DItem = new QListWidgetItem( QgsApplication::getThemeIcon( QStringLiteral( "3d.svg" ) ), QString() );
symbol3DItem->setData( Qt::UserRole, Symbology3D );
symbol3DItem->setToolTip( tr( "3D View" ) );
mOptionsListWidget->addItem( symbol3DItem );
#endif
break;
}
@ -444,6 +438,10 @@ void QgsLayerStylingWidget::updateCurrentWidgetLayer()
{
mMesh3DWidget = widget;
}
else if ( QgsPointCloudLayer3DRendererWidget *widget = qobject_cast<QgsPointCloudLayer3DRendererWidget *>( current ) )
{
mPointCloud3DWidget = widget;
}
#endif
}
@ -678,9 +676,24 @@ void QgsLayerStylingWidget::updateCurrentWidgetLayer()
{
QgsPointCloudLayer *pcLayer = qobject_cast<QgsPointCloudLayer *>( mCurrentLayer );
( void )pcLayer;
switch ( row )
{
case 0:
{
#ifdef HAVE_3D
if ( !mPointCloud3DWidget )
{
mPointCloud3DWidget = new QgsPointCloudLayer3DRendererWidget( nullptr, mMapCanvas, mWidgetStack );
mPointCloud3DWidget->setDockMode( true );
connect( mPointCloud3DWidget, &QgsPointCloudLayer3DRendererWidget::widgetChanged, this, &QgsLayerStylingWidget::autoApply );
}
mPointCloud3DWidget->syncToLayer( pcLayer );
mWidgetStack->setMainPanel( mPointCloud3DWidget );
#endif
break;
}
}
//TODO
mStackedWidget->setCurrentIndex( mNotSupportedPage );
break;
}
@ -816,7 +829,7 @@ bool QgsLayerStyleManagerWidgetFactory::supportsLayer( QgsMapLayer *layer ) cons
return false; // TODO
case QgsMapLayerType::PointCloudLayer:
return false; // TODO
return true;
case QgsMapLayerType::PluginLayer:
case QgsMapLayerType::AnnotationLayer:

View File

@ -43,6 +43,7 @@ class QgsRasterHistogramWidget;
class QgsMapLayerStyleManagerWidget;
class QgsVectorLayer3DRendererWidget;
class QgsMeshLayer3DRendererWidget;
class QgsPointCloudLayer3DRendererWidget;
class QgsMessageBar;
class QgsVectorTileBasicRendererWidget;
class QgsVectorTileBasicLabelingWidget;
@ -148,6 +149,7 @@ class APP_EXPORT QgsLayerStylingWidget : public QWidget, private Ui::QgsLayerSty
#ifdef HAVE_3D
QgsVectorLayer3DRendererWidget *mVector3DWidget = nullptr;
QgsMeshLayer3DRendererWidget *mMesh3DWidget = nullptr;
QgsPointCloudLayer3DRendererWidget *mPointCloud3DWidget = nullptr;
#endif
QgsRendererRasterPropertiesWidget *mRasterStyleWidget = nullptr;
QgsRendererMeshPropertiesWidget *mMeshStyleWidget = nullptr;

View File

@ -53,7 +53,8 @@ bool QgsMapLayerProxyModel::layerMatchesFilters( const QgsMapLayer *layer, const
( filters.testFlag( VectorLayer ) && layer->type() == QgsMapLayerType::VectorLayer ) ||
( filters.testFlag( MeshLayer ) && layer->type() == QgsMapLayerType::MeshLayer ) ||
( filters.testFlag( VectorTileLayer ) && layer->type() == QgsMapLayerType::VectorTileLayer ) ||
( filters.testFlag( PluginLayer ) && layer->type() == QgsMapLayerType::PluginLayer ) )
( filters.testFlag( PluginLayer ) && layer->type() == QgsMapLayerType::PluginLayer ) ||
filters.testFlag( PointCloudLayer ) && layer->type() == QgsMapLayerType::PointCloudLayer )
return true;
// geometry type

View File

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsPointCloud3DSymbolWidget</class>
<widget class="QWidget" name="QgsPointCloud3DSymbolWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="mPointSizeSpinBox">
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="value">
<double>2.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Point size</string>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -35,12 +35,12 @@
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="text">
<string>Not supported or no layer</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>