Setup core infrastructure for tiled scene 2d renderers

This commit is contained in:
Nyall Dawson 2023-08-06 17:30:02 +10:00
parent fb3c25e1a5
commit c8658efde4
16 changed files with 1381 additions and 2 deletions

View File

@ -745,6 +745,13 @@ Returns the application's renderer registry, used for managing vector layer rend
Returns the application's point cloud renderer registry, used for managing point cloud layer 2D renderers. Returns the application's point cloud renderer registry, used for managing point cloud layer 2D renderers.
.. versionadded:: 3.18 .. versionadded:: 3.18
%End
static QgsTiledSceneRendererRegistry *tiledSceneRendererRegistry() /KeepReference/;
%Docstring
Returns the application's tiled scene renderer registry, used for managing tiled scene layer 2D renderers.
.. versionadded:: 3.34
%End %End
static QgsDataItemProviderRegistry *dataItemProviderRegistry() /KeepReference/; static QgsDataItemProviderRegistry *dataItemProviderRegistry() /KeepReference/;

View File

@ -9,6 +9,7 @@
class QgsTiledSceneLayer : QgsMapLayer class QgsTiledSceneLayer : QgsMapLayer
{ {
%Docstring(signature="appended") %Docstring(signature="appended")
@ -89,6 +90,23 @@ QgsTiledSceneLayer cannot be copied.
virtual QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) /Factory/; virtual QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) /Factory/;
QgsTiledSceneRenderer *renderer();
%Docstring
Returns the 2D renderer for the tiled scene.
.. seealso:: :py:func:`setRenderer`
%End
void setRenderer( QgsTiledSceneRenderer *renderer /Transfer/ );
%Docstring
Sets the 2D ``renderer`` for the tiled scene.
Ownership of ``renderer`` is transferred to the layer.
.. seealso:: :py:func:`renderer`
%End
private: private:
QgsTiledSceneLayer( const QgsTiledSceneLayer &rhs ); QgsTiledSceneLayer( const QgsTiledSceneLayer &rhs );
}; };

View File

@ -0,0 +1,222 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/tiledscene/qgstiledscenerenderer.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsTiledSceneRenderContext
{
%Docstring(signature="appended")
Encapsulates the render context for a 2D tiled scene rendering operation.
.. versionadded:: 3.34
%End
%TypeHeaderCode
#include "qgstiledscenerenderer.h"
%End
public:
QgsTiledSceneRenderContext( QgsRenderContext &context, QgsFeedback *feedback = 0 );
%Docstring
Constructor for QgsTiledSceneRenderContext.
%End
QgsRenderContext &renderContext();
%Docstring
Returns a reference to the context's render context.
%End
QgsFeedback *feedback() const;
%Docstring
Returns the feedback object used to cancel rendering
.. versionadded:: 3.20
%End
private:
QgsTiledSceneRenderContext( const QgsTiledSceneRenderContext &rh );
};
class QgsTiledSceneRenderer
{
%Docstring(signature="appended")
Abstract base class for 2d tiled scene renderers.
.. versionadded:: 3.34
%End
%TypeHeaderCode
#include "qgstiledscenerenderer.h"
%End
%ConvertToSubClassCode
const QString type = sipCpp->type();
sipType = 0;
%End
public:
QgsTiledSceneRenderer();
%Docstring
Constructor for QgsTiledSceneRenderer.
%End
virtual ~QgsTiledSceneRenderer();
virtual QString type() const = 0;
%Docstring
Returns the identifier of the renderer type.
%End
virtual QgsTiledSceneRenderer *clone() const = 0 /Factory/;
%Docstring
Create a deep copy of this renderer. Should be implemented by all subclasses
and generate a proper subclass.
%End
static QgsTiledSceneRenderer *load( QDomElement &element, const QgsReadWriteContext &context ) /Factory/;
%Docstring
Creates a renderer from an XML ``element``.
Caller takes ownership of the returned renderer.
.. seealso:: :py:func:`save`
%End
virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const = 0;
%Docstring
Saves the renderer configuration to an XML element.
.. seealso:: :py:func:`load`
%End
double maximumScreenError() const;
%Docstring
Returns the maximum screen error allowed when rendering the tiled scene.
Larger values result in a faster render with less detailed features rendered.
Units are retrieved via :py:func:`~QgsTiledSceneRenderer.maximumScreenErrorUnit`.
.. seealso:: :py:func:`setMaximumScreenError`
.. seealso:: :py:func:`maximumScreenErrorUnit`
%End
void setMaximumScreenError( double error );
%Docstring
Sets the maximum screen ``error`` allowed when rendering the tiled scene.
Larger values result in a faster render with less detailed features rendered.
Units are set via :py:func:`~QgsTiledSceneRenderer.setMaximumScreenErrorUnit`.
.. seealso:: :py:func:`maximumScreenError`
.. seealso:: :py:func:`setMaximumScreenErrorUnit`
%End
Qgis::RenderUnit maximumScreenErrorUnit() const;
%Docstring
Returns the unit for the maximum screen error allowed when rendering the tiled scene.
.. seealso:: :py:func:`maximumScreenError`
.. seealso:: :py:func:`setMaximumScreenErrorUnit`
%End
void setMaximumScreenErrorUnit( Qgis::RenderUnit unit );
%Docstring
Sets the ``unit`` for the maximum screen error allowed when rendering the tiled scene.
.. seealso:: :py:func:`setMaximumScreenError`
.. seealso:: :py:func:`maximumScreenErrorUnit`
%End
virtual void startRender( QgsTiledSceneRenderContext &context );
%Docstring
Must be called when a new render cycle is started. A call to :py:func:`~QgsTiledSceneRenderer.startRender` must always
be followed by a corresponding call to :py:func:`~QgsTiledSceneRenderer.stopRender` after all features have been rendered.
.. seealso:: :py:func:`stopRender`
.. warning::
This method is not thread safe. Before calling :py:func:`~QgsTiledSceneRenderer.startRender` in a non-main thread,
the renderer should instead be cloned and :py:func:`~QgsTiledSceneRenderer.startRender`/:py:func:`~QgsTiledSceneRenderer.stopRender` called on the clone.
%End
virtual void stopRender( QgsTiledSceneRenderContext &context );
%Docstring
Must be called when a render cycle has finished, to allow the renderer to clean up.
Calls to :py:func:`~QgsTiledSceneRenderer.stopRender` must always be preceded by a call to :py:func:`~QgsTiledSceneRenderer.startRender`.
.. warning::
This method is not thread safe. Before calling :py:func:`~QgsTiledSceneRenderer.startRender` in a non-main thread,
the renderer should instead be cloned and :py:func:`~QgsTiledSceneRenderer.startRender`/:py:func:`~QgsTiledSceneRenderer.stopRender` called on the clone.
.. seealso:: :py:func:`startRender`
%End
virtual QList<QgsLayerTreeModelLegendNode *> createLegendNodes( QgsLayerTreeLayer *nodeLayer ) /Factory/;
%Docstring
Creates a set of legend nodes representing the renderer.
%End
virtual QStringList legendRuleKeys() const;
%Docstring
Returns a list of all rule keys for legend nodes created by the renderer.
%End
protected:
void copyCommonProperties( QgsTiledSceneRenderer *destination ) const;
%Docstring
Copies common tiled scene renderer properties (such as screen error) to the ``destination`` renderer.
%End
void restoreCommonProperties( const QDomElement &element, const QgsReadWriteContext &context );
%Docstring
Restores common renderer properties (such as screen error) from the
specified DOM ``element``.
.. seealso:: :py:func:`saveCommonProperties`
%End
void saveCommonProperties( QDomElement &element, const QgsReadWriteContext &context ) const;
%Docstring
Saves common renderer properties (such as point size and screen error) to the
specified DOM ``element``.
.. seealso:: :py:func:`restoreCommonProperties`
%End
private:
QgsTiledSceneRenderer( const QgsTiledSceneRenderer &other );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/tiledscene/qgstiledscenerenderer.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -0,0 +1,173 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/tiledscene/qgstiledscenerendererregistry.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsTiledSceneRendererAbstractMetadata
{
%Docstring(signature="appended")
Stores metadata about one tiled scene renderer class.
.. note::
It's necessary to implement :py:func:`~createRenderer` function.
In C++ you can use :py:class:`QgsTiledSceneRendererMetadata` convenience class.
.. versionadded:: 3.34
%End
%TypeHeaderCode
#include "qgstiledscenerendererregistry.h"
%End
public:
QgsTiledSceneRendererAbstractMetadata( const QString &name, const QString &visibleName, const QIcon &icon = QIcon() );
%Docstring
Constructor for QgsTiledSceneRendererAbstractMetadata, with the specified ``name``.
The ``visibleName`` argument gives a translated, user friendly string identifying the renderer type.
The ``icon`` argument can be used to specify an icon representing the renderer.
%End
virtual ~QgsTiledSceneRendererAbstractMetadata();
QString name() const;
%Docstring
Returns the unique name of the renderer. This value is not translated.
.. seealso:: :py:func:`visibleName`
%End
QString visibleName() const;
%Docstring
Returns a friendly display name of the renderer. This value is translated.
.. seealso:: :py:func:`name`
%End
QIcon icon() const;
%Docstring
Returns an icon representing the renderer.
.. seealso:: :py:func:`setIcon`
%End
void setIcon( const QIcon &icon );
%Docstring
Sets an ``icon`` representing the renderer.
.. seealso:: :py:func:`icon`
%End
virtual QgsTiledSceneRenderer *createRenderer( QDomElement &elem, const QgsReadWriteContext &context ) = 0 /Factory/;
%Docstring
Returns new instance of the renderer given the DOM element. Returns ``None`` on error.
Pure virtual function: must be implemented in derived classes.
%End
protected:
};
class QgsTiledSceneRendererMetadata : QgsTiledSceneRendererAbstractMetadata
{
%Docstring(signature="appended")
Convenience metadata class that uses static functions to create tiled scene renderer and its widget.
.. versionadded:: 3.34
%End
%TypeHeaderCode
#include "qgstiledscenerendererregistry.h"
%End
public:
virtual QgsTiledSceneRenderer *createRenderer( QDomElement &elem, const QgsReadWriteContext &context ) /Factory/;
protected:
private:
QgsTiledSceneRendererMetadata();
};
class QgsTiledSceneRendererRegistry
{
%Docstring(signature="appended")
Registry of 2D renderers for tiled scenes.
:py:class:`QgsTiledSceneRendererRegistry` is not usually directly created, but rather accessed through
:py:func:`QgsApplication.tiledSceneRendererRegistry()`.
.. versionadded:: 3.34
%End
%TypeHeaderCode
#include "qgstiledscenerendererregistry.h"
%End
public:
QgsTiledSceneRendererRegistry();
~QgsTiledSceneRendererRegistry();
bool addRenderer( QgsTiledSceneRendererAbstractMetadata *metadata /Transfer/ );
%Docstring
Adds a renderer to the registry. Takes ownership of the metadata object.
:param metadata: renderer metadata
:return: ``True`` if renderer was added successfully, or ``False`` if renderer could not
be added (e.g., a renderer with a duplicate name already exists)
%End
bool removeRenderer( const QString &rendererName );
%Docstring
Removes a renderer from registry.
:param rendererName: name of renderer to remove from registry
:return: ``True`` if renderer was successfully removed, or ``False`` if matching
renderer could not be found
%End
QgsTiledSceneRendererAbstractMetadata *rendererMetadata( const QString &rendererName );
%Docstring
Returns the metadata for a specified renderer. Returns ``None`` if a matching
renderer was not found in the registry.
%End
QStringList renderersList() const;
%Docstring
Returns a list of available renderers.
%End
static QgsTiledSceneRenderer *defaultRenderer( const QgsTiledSceneLayer *layer ) /Factory/;
%Docstring
Returns a new default tiled scene renderer for a specified ``layer``.
Caller takes ownership of the returned renderer.
%End
private:
QgsTiledSceneRendererRegistry( const QgsTiledSceneRendererRegistry &rh );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/tiledscene/qgstiledscenerendererregistry.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -717,6 +717,8 @@
%Include auto_generated/tiledscene/qgstiledscenedataprovider.sip %Include auto_generated/tiledscene/qgstiledscenedataprovider.sip
%Include auto_generated/tiledscene/qgstiledsceneindex.sip %Include auto_generated/tiledscene/qgstiledsceneindex.sip
%Include auto_generated/tiledscene/qgstiledscenelayer.sip %Include auto_generated/tiledscene/qgstiledscenelayer.sip
%Include auto_generated/tiledscene/qgstiledscenerenderer.sip
%Include auto_generated/tiledscene/qgstiledscenerendererregistry.sip
%Include auto_generated/tiledscene/qgstiledscenerequest.sip %Include auto_generated/tiledscene/qgstiledscenerequest.sip
%Include auto_generated/tiledscene/qgstiledscenetile.sip %Include auto_generated/tiledscene/qgstiledscenetile.sip
%Include auto_generated/sensor/qgssensormodel.sip %Include auto_generated/sensor/qgssensormodel.sip

View File

@ -347,6 +347,8 @@ set(QGIS_CORE_SRCS
tiledscene/qgstiledscenelayerrenderer.cpp tiledscene/qgstiledscenelayerrenderer.cpp
tiledscene/qgstiledscenenode.cpp tiledscene/qgstiledscenenode.cpp
tiledscene/qgstiledsceneprovidermetadata.cpp tiledscene/qgstiledsceneprovidermetadata.cpp
tiledscene/qgstiledscenerenderer.cpp
tiledscene/qgstiledscenerendererregistry.cpp
tiledscene/qgstiledscenerequest.cpp tiledscene/qgstiledscenerequest.cpp
tiledscene/qgstiledscenetile.cpp tiledscene/qgstiledscenetile.cpp
@ -1921,6 +1923,8 @@ set(QGIS_CORE_HDRS
tiledscene/qgstiledscenelayerrenderer.h tiledscene/qgstiledscenelayerrenderer.h
tiledscene/qgstiledscenenode.h tiledscene/qgstiledscenenode.h
tiledscene/qgstiledsceneprovidermetadata.h tiledscene/qgstiledsceneprovidermetadata.h
tiledscene/qgstiledscenerenderer.h
tiledscene/qgstiledscenerendererregistry.h
tiledscene/qgstiledscenerequest.h tiledscene/qgstiledscenerequest.h
tiledscene/qgstiledscenetile.h tiledscene/qgstiledscenetile.h

View File

@ -57,6 +57,7 @@
#include "qgssettings.h" #include "qgssettings.h"
#include "qgssettingsregistrycore.h" #include "qgssettingsregistrycore.h"
#include "qgstiledownloadmanager.h" #include "qgstiledownloadmanager.h"
#include "qgstiledscenerendererregistry.h"
#include "qgsunittypes.h" #include "qgsunittypes.h"
#include "qgsuserprofile.h" #include "qgsuserprofile.h"
#include "qgsuserprofilemanager.h" #include "qgsuserprofilemanager.h"
@ -2428,6 +2429,11 @@ QgsPointCloudRendererRegistry *QgsApplication::pointCloudRendererRegistry()
return members()->mPointCloudRendererRegistry; return members()->mPointCloudRendererRegistry;
} }
QgsTiledSceneRendererRegistry *QgsApplication::tiledSceneRendererRegistry()
{
return members()->mTiledSceneRendererRegistry;
}
QgsDataItemProviderRegistry *QgsApplication::dataItemProviderRegistry() QgsDataItemProviderRegistry *QgsApplication::dataItemProviderRegistry()
{ {
if ( auto *lInstance = instance() ) if ( auto *lInstance = instance() )
@ -2737,6 +2743,11 @@ QgsApplication::ApplicationMembers::ApplicationMembers()
mPointCloudRendererRegistry = new QgsPointCloudRendererRegistry(); mPointCloudRendererRegistry = new QgsPointCloudRendererRegistry();
profiler->end(); profiler->end();
} }
{
profiler->start( tr( "Setup tiled scene renderer registry" ) );
mTiledSceneRendererRegistry = new QgsTiledSceneRendererRegistry();
profiler->end();
}
{ {
profiler->start( tr( "Setup GPS registry" ) ); profiler->start( tr( "Setup GPS registry" ) );
mGpsConnectionRegistry = new QgsGpsConnectionRegistry(); mGpsConnectionRegistry = new QgsGpsConnectionRegistry();
@ -2851,6 +2862,7 @@ QgsApplication::ApplicationMembers::~ApplicationMembers()
delete mSensorRegistry; delete mSensorRegistry;
delete mLayoutItemRegistry; delete mLayoutItemRegistry;
delete mPointCloudRendererRegistry; delete mPointCloudRendererRegistry;
delete mTiledSceneRendererRegistry;
delete mRasterRendererRegistry; delete mRasterRendererRegistry;
delete mRendererRegistry; delete mRendererRegistry;
delete mSvgCache; delete mSvgCache;

View File

@ -70,6 +70,7 @@ class QgsConnectionRegistry;
class QgsScaleBarRendererRegistry; class QgsScaleBarRendererRegistry;
class Qgs3DSymbolRegistry; class Qgs3DSymbolRegistry;
class QgsPointCloudRendererRegistry; class QgsPointCloudRendererRegistry;
class QgsTiledSceneRendererRegistry;
class QgsTileDownloadManager; class QgsTileDownloadManager;
class QgsCoordinateReferenceSystemRegistry; class QgsCoordinateReferenceSystemRegistry;
class QgsRecentStyleHandler; class QgsRecentStyleHandler;
@ -721,6 +722,12 @@ class CORE_EXPORT QgsApplication : public QApplication
*/ */
static QgsPointCloudRendererRegistry *pointCloudRendererRegistry() SIP_KEEPREFERENCE; static QgsPointCloudRendererRegistry *pointCloudRendererRegistry() SIP_KEEPREFERENCE;
/**
* Returns the application's tiled scene renderer registry, used for managing tiled scene layer 2D renderers.
* \since QGIS 3.34
*/
static QgsTiledSceneRendererRegistry *tiledSceneRendererRegistry() SIP_KEEPREFERENCE;
/** /**
* Returns the application's data item provider registry, which keeps a list of data item * Returns the application's data item provider registry, which keeps a list of data item
* providers that may add items to the browser tree. * providers that may add items to the browser tree.
@ -1170,6 +1177,7 @@ class CORE_EXPORT QgsApplication : public QApplication
QgsRasterRendererRegistry *mRasterRendererRegistry = nullptr; QgsRasterRendererRegistry *mRasterRendererRegistry = nullptr;
QgsRendererRegistry *mRendererRegistry = nullptr; QgsRendererRegistry *mRendererRegistry = nullptr;
QgsPointCloudRendererRegistry *mPointCloudRendererRegistry = nullptr; QgsPointCloudRendererRegistry *mPointCloudRendererRegistry = nullptr;
QgsTiledSceneRendererRegistry *mTiledSceneRendererRegistry = nullptr;
QgsSvgCache *mSvgCache = nullptr; QgsSvgCache *mSvgCache = nullptr;
QgsImageCache *mImageCache = nullptr; QgsImageCache *mImageCache = nullptr;
QgsSourceCache *mSourceCache = nullptr; QgsSourceCache *mSourceCache = nullptr;

View File

@ -21,10 +21,12 @@
#include "qgspainting.h" #include "qgspainting.h"
#include "qgsproviderregistry.h" #include "qgsproviderregistry.h"
#include "qgslayermetadataformatter.h" #include "qgslayermetadataformatter.h"
#include "qgstiledscenerenderer.h"
#include "qgsxmlutils.h" #include "qgsxmlutils.h"
#include "qgsruntimeprofiler.h" #include "qgsruntimeprofiler.h"
#include "qgsapplication.h" #include "qgsapplication.h"
#include "qgstiledscenelayerrenderer.h" #include "qgstiledscenelayerrenderer.h"
#include "qgstiledscenerendererregistry.h"
QgsTiledSceneLayer::QgsTiledSceneLayer( const QString &uri, QgsTiledSceneLayer::QgsTiledSceneLayer( const QString &uri,
const QString &baseName, const QString &baseName,
@ -62,6 +64,9 @@ QgsTiledSceneLayer *QgsTiledSceneLayer::clone() const
QgsTiledSceneLayer *layer = new QgsTiledSceneLayer( source(), name(), mProviderKey, mLayerOptions ); QgsTiledSceneLayer *layer = new QgsTiledSceneLayer( source(), name(), mProviderKey, mLayerOptions );
QgsMapLayer::clone( layer ); QgsMapLayer::clone( layer );
if ( mRenderer )
layer->setRenderer( mRenderer->clone() );
layer->mLayerOptions = mLayerOptions; layer->mLayerOptions = mLayerOptions;
return layer; return layer;
@ -84,6 +89,32 @@ QgsMapLayerRenderer *QgsTiledSceneLayer::createMapRenderer( QgsRenderContext &co
return new QgsTiledSceneLayerRenderer( this, context ); return new QgsTiledSceneLayerRenderer( this, context );
} }
QgsTiledSceneRenderer *QgsTiledSceneLayer::renderer()
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
return mRenderer.get();
}
const QgsTiledSceneRenderer *QgsTiledSceneLayer::renderer() const
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
return mRenderer.get();
}
void QgsTiledSceneLayer::setRenderer( QgsTiledSceneRenderer *renderer )
{
QGIS_PROTECT_QOBJECT_THREAD_ACCESS
if ( renderer == mRenderer.get() )
return;
mRenderer.reset( renderer );
emit rendererChanged();
emitStyleChanged();
}
QgsTiledSceneDataProvider *QgsTiledSceneLayer::dataProvider() QgsTiledSceneDataProvider *QgsTiledSceneLayer::dataProvider()
{ {
QGIS_PROTECT_QOBJECT_THREAD_ACCESS QGIS_PROTECT_QOBJECT_THREAD_ACCESS
@ -172,7 +203,7 @@ bool QgsTiledSceneLayer::readSymbology( const QDomNode &node, QString &errorMess
return true; return true;
} }
bool QgsTiledSceneLayer::readStyle( const QDomNode &node, QString &, QgsReadWriteContext &, QgsMapLayer::StyleCategories categories ) bool QgsTiledSceneLayer::readStyle( const QDomNode &node, QString &, QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories )
{ {
QGIS_PROTECT_QOBJECT_THREAD_ACCESS QGIS_PROTECT_QOBJECT_THREAD_ACCESS
@ -187,6 +218,25 @@ bool QgsTiledSceneLayer::readStyle( const QDomNode &node, QString &, QgsReadWrit
const QDomElement e = blendModeNode.toElement(); const QDomElement e = blendModeNode.toElement();
setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) ); setBlendMode( QgsPainting::getCompositionMode( static_cast< Qgis::BlendMode >( e.text().toInt() ) ) );
} }
QDomElement rendererElement = node.firstChildElement( QStringLiteral( "renderer" ) );
if ( !rendererElement.isNull() )
{
std::unique_ptr< QgsTiledSceneRenderer > r( QgsTiledSceneRenderer::load( rendererElement, context ) );
if ( r )
{
setRenderer( r.release() );
}
else
{
result = false;
}
}
// make sure layer has a renderer - if none exists, fallback to a default renderer
if ( !mRenderer )
{
setRenderer( QgsTiledSceneRendererRegistry::defaultRenderer( this ) );
}
} }
// get and set the layer transparency and scale visibility if they exists // get and set the layer transparency and scale visibility if they exists
@ -231,7 +281,7 @@ bool QgsTiledSceneLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QStr
return true; return true;
} }
bool QgsTiledSceneLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &, const QgsReadWriteContext &, QgsMapLayer::StyleCategories categories ) const bool QgsTiledSceneLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString &, const QgsReadWriteContext &context, QgsMapLayer::StyleCategories categories ) const
{ {
QGIS_PROTECT_QOBJECT_THREAD_ACCESS QGIS_PROTECT_QOBJECT_THREAD_ACCESS
@ -250,6 +300,12 @@ bool QgsTiledSceneLayer::writeStyle( QDomNode &node, QDomDocument &doc, QString
const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) ); const QDomText blendModeText = doc.createTextNode( QString::number( static_cast< int >( QgsPainting::getBlendModeEnum( blendMode() ) ) ) );
blendModeElem.appendChild( blendModeText ); blendModeElem.appendChild( blendModeText );
node.appendChild( blendModeElem ); node.appendChild( blendModeElem );
if ( mRenderer )
{
const QDomElement rendererElement = mRenderer->save( doc, context );
node.appendChild( rendererElement );
}
} }
// add the layer opacity and scale visibility // add the layer opacity and scale visibility
@ -321,6 +377,32 @@ void QgsTiledSceneLayer::setDataSourcePrivate( const QString &dataSource, const
{ {
setExtent( mDataProvider->extent() ); setExtent( mDataProvider->extent() );
} }
bool loadDefaultStyleFlag = false;
if ( flags & QgsDataProvider::FlagLoadDefaultStyle )
{
loadDefaultStyleFlag = true;
}
if ( !mRenderer || loadDefaultStyleFlag )
{
std::unique_ptr< QgsScopedRuntimeProfile > profile;
if ( QgsApplication::profiler()->groupIsActive( QStringLiteral( "projectload" ) ) )
profile = std::make_unique< QgsScopedRuntimeProfile >( tr( "Load layer style" ), QStringLiteral( "projectload" ) );
bool defaultLoadedFlag = false;
if ( !defaultLoadedFlag && loadDefaultStyleFlag )
{
loadDefaultStyle( defaultLoadedFlag );
}
if ( !defaultLoadedFlag )
{
// all else failed, create default renderer
setRenderer( QgsTiledSceneRendererRegistry::defaultRenderer( this ) );
}
}
} }
QString QgsTiledSceneLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const QString QgsTiledSceneLayer::encodedSource( const QString &source, const QgsReadWriteContext &context ) const

View File

@ -22,6 +22,8 @@
#include "qgsmaplayer.h" #include "qgsmaplayer.h"
#include "qgstiledscenedataprovider.h" #include "qgstiledscenedataprovider.h"
class QgsTiledSceneRenderer;
/** /**
* \ingroup core * \ingroup core
* *
@ -112,6 +114,30 @@ class CORE_EXPORT QgsTiledSceneLayer : public QgsMapLayer
QString htmlMetadata() const override; QString htmlMetadata() const override;
QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) override SIP_FACTORY; QgsMapLayerRenderer *createMapRenderer( QgsRenderContext &rendererContext ) override SIP_FACTORY;
/**
* Returns the 2D renderer for the tiled scene.
*
* \see setRenderer()
*/
QgsTiledSceneRenderer *renderer();
/**
* Returns the 2D renderer for the tiled scene.
* \note not available in Python bindings
*
* \see setRenderer()
*/
const QgsTiledSceneRenderer *renderer() const SIP_SKIP;
/**
* Sets the 2D \a renderer for the tiled scene.
*
* Ownership of \a renderer is transferred to the layer.
*
* \see renderer()
*/
void setRenderer( QgsTiledSceneRenderer *renderer SIP_TRANSFER );
private slots: private slots:
void setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags ) override; void setDataSourcePrivate( const QString &dataSource, const QString &baseName, const QString &provider, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags ) override;
@ -124,6 +150,7 @@ class CORE_EXPORT QgsTiledSceneLayer : public QgsMapLayer
#endif #endif
std::unique_ptr<QgsTiledSceneDataProvider> mDataProvider; std::unique_ptr<QgsTiledSceneDataProvider> mDataProvider;
std::unique_ptr<QgsTiledSceneRenderer> mRenderer;
LayerOptions mLayerOptions; LayerOptions mLayerOptions;
}; };

View File

@ -0,0 +1,124 @@
/***************************************************************************
qgstiledscenerenderer.cpp
--------------------
begin : August 2023
copyright : (C) 2023 by Nyall Dawson
email : nyall dot dawson 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 "qgstiledscenerenderer.h"
#include "qgsunittypes.h"
#include "qgsapplication.h"
#include "qgstiledscenerendererregistry.h"
#include <QThread>
//
// QgsTiledSceneRenderContext
//
QgsTiledSceneRenderContext::QgsTiledSceneRenderContext( QgsRenderContext &context, QgsFeedback *feedback )
: mRenderContext( context )
, mFeedback( feedback )
{
}
//
// QgsTiledSceneRenderer
//
QgsTiledSceneRenderer *QgsTiledSceneRenderer::load( QDomElement &element, const QgsReadWriteContext &context )
{
if ( element.isNull() )
return nullptr;
// load renderer
const QString rendererType = element.attribute( QStringLiteral( "type" ) );
QgsTiledSceneRendererAbstractMetadata *m = QgsApplication::tiledSceneRendererRegistry()->rendererMetadata( rendererType );
if ( !m )
return nullptr;
std::unique_ptr< QgsTiledSceneRenderer > r( m->createRenderer( element, context ) );
return r.release();
}
void QgsTiledSceneRenderer::startRender( QgsTiledSceneRenderContext & )
{
#ifdef QGISDEBUG
if ( !mThread )
{
mThread = QThread::currentThread();
}
else
{
Q_ASSERT_X( mThread == QThread::currentThread(), "QgsTiledSceneRenderer::startRender", "startRender called in a different thread - use a cloned renderer instead" );
}
#endif
}
void QgsTiledSceneRenderer::stopRender( QgsTiledSceneRenderContext & )
{
#ifdef QGISDEBUG
Q_ASSERT_X( mThread == QThread::currentThread(), "QgsTiledSceneRenderer::stopRender", "stopRender called in a different thread - use a cloned renderer instead" );
#endif
}
double QgsTiledSceneRenderer::maximumScreenError() const
{
return mMaximumScreenError;
}
void QgsTiledSceneRenderer::setMaximumScreenError( double error )
{
mMaximumScreenError = error;
}
Qgis::RenderUnit QgsTiledSceneRenderer::maximumScreenErrorUnit() const
{
return mMaximumScreenErrorUnit;
}
void QgsTiledSceneRenderer::setMaximumScreenErrorUnit( Qgis::RenderUnit unit )
{
mMaximumScreenErrorUnit = unit;
}
QList<QgsLayerTreeModelLegendNode *> QgsTiledSceneRenderer::createLegendNodes( QgsLayerTreeLayer * )
{
return QList<QgsLayerTreeModelLegendNode *>();
}
QStringList QgsTiledSceneRenderer::legendRuleKeys() const
{
return QStringList();
}
void QgsTiledSceneRenderer::copyCommonProperties( QgsTiledSceneRenderer *destination ) const
{
destination->setMaximumScreenError( mMaximumScreenError );
destination->setMaximumScreenErrorUnit( mMaximumScreenErrorUnit );
}
void QgsTiledSceneRenderer::restoreCommonProperties( const QDomElement &element, const QgsReadWriteContext & )
{
mMaximumScreenError = element.attribute( QStringLiteral( "maximumScreenError" ), QStringLiteral( "0.3" ) ).toDouble();
mMaximumScreenErrorUnit = QgsUnitTypes::decodeRenderUnit( element.attribute( QStringLiteral( "maximumScreenErrorUnit" ), QStringLiteral( "MM" ) ) );
}
void QgsTiledSceneRenderer::saveCommonProperties( QDomElement &element, const QgsReadWriteContext & ) const
{
element.setAttribute( QStringLiteral( "maximumScreenError" ), qgsDoubleToString( mMaximumScreenError ) );
element.setAttribute( QStringLiteral( "maximumScreenErrorUnit" ), QgsUnitTypes::encodeUnit( mMaximumScreenErrorUnit ) );
}

View File

@ -0,0 +1,251 @@
/***************************************************************************
qgstiledscenerenderer.h
--------------------
begin : August 2023
copyright : (C) 2023 by Nyall Dawson
email : nyall dot dawson 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 QGSTILEDSCENERENDERER_H
#define QGSTILEDSCENERENDERER_H
#include "qgsrendercontext.h"
#include "qgis_core.h"
#include "qgis_sip.h"
class QgsLayerTreeLayer;
class QgsLayerTreeModelLegendNode;
/**
* \ingroup core
* \class QgsTiledSceneRenderContext
*
* \brief Encapsulates the render context for a 2D tiled scene rendering operation.
*
* \since QGIS 3.34
*/
class CORE_EXPORT QgsTiledSceneRenderContext
{
public:
/**
* Constructor for QgsTiledSceneRenderContext.
*/
QgsTiledSceneRenderContext( QgsRenderContext &context, QgsFeedback *feedback = nullptr );
//! QgsTiledSceneRenderContext cannot be copied.
QgsTiledSceneRenderContext( const QgsTiledSceneRenderContext &rh ) = delete;
//! QgsTiledSceneRenderContext cannot be copied.
QgsTiledSceneRenderContext &operator=( const QgsTiledSceneRenderContext & ) = delete;
/**
* Returns a reference to the context's render context.
*/
QgsRenderContext &renderContext() { return mRenderContext; }
/**
* Returns a reference to the context's render context.
* \note Not available in Python bindings.
*/
const QgsRenderContext &renderContext() const { return mRenderContext; } SIP_SKIP
/**
* Returns the feedback object used to cancel rendering
*
* \since QGIS 3.20
*/
QgsFeedback *feedback() const { return mFeedback; }
private:
#ifdef SIP_RUN
QgsTiledSceneRenderContext( const QgsTiledSceneRenderContext &rh );
#endif
QgsRenderContext &mRenderContext;
QgsFeedback *mFeedback = nullptr;
};
/**
* \ingroup core
* \class QgsTiledSceneRenderer
*
* \brief Abstract base class for 2d tiled scene renderers.
*
* \since QGIS 3.34
*/
class CORE_EXPORT QgsTiledSceneRenderer
{
#ifdef SIP_RUN
SIP_CONVERT_TO_SUBCLASS_CODE
const QString type = sipCpp->type();
sipType = 0;
SIP_END
#endif
public:
/**
* Constructor for QgsTiledSceneRenderer.
*/
QgsTiledSceneRenderer() = default;
virtual ~QgsTiledSceneRenderer() = default;
/**
* Returns the identifier of the renderer type.
*/
virtual QString type() const = 0;
/**
* Create a deep copy of this renderer. Should be implemented by all subclasses
* and generate a proper subclass.
*/
virtual QgsTiledSceneRenderer *clone() const = 0 SIP_FACTORY;
//! QgsTiledSceneRenderer cannot be copied -- use clone() instead
QgsTiledSceneRenderer( const QgsTiledSceneRenderer &other ) = delete;
//! QgsTiledSceneRenderer cannot be copied -- use clone() instead
QgsTiledSceneRenderer &operator=( const QgsTiledSceneRenderer &other ) = delete;
/**
* Creates a renderer from an XML \a element.
*
* Caller takes ownership of the returned renderer.
*
* \see save()
*/
static QgsTiledSceneRenderer *load( QDomElement &element, const QgsReadWriteContext &context ) SIP_FACTORY;
/**
* Saves the renderer configuration to an XML element.
* \see load()
*/
virtual QDomElement save( QDomDocument &doc, const QgsReadWriteContext &context ) const = 0;
/**
* Returns the maximum screen error allowed when rendering the tiled scene.
*
* Larger values result in a faster render with less detailed features rendered.
*
* Units are retrieved via maximumScreenErrorUnit().
*
* \see setMaximumScreenError()
* \see maximumScreenErrorUnit()
*/
double maximumScreenError() const;
/**
* Sets the maximum screen \a error allowed when rendering the tiled scene.
*
* Larger values result in a faster render with less detailed features rendered.
*
* Units are set via setMaximumScreenErrorUnit().
*
* \see maximumScreenError()
* \see setMaximumScreenErrorUnit()
*/
void setMaximumScreenError( double error );
/**
* Returns the unit for the maximum screen error allowed when rendering the tiled scene.
*
* \see maximumScreenError()
* \see setMaximumScreenErrorUnit()
*/
Qgis::RenderUnit maximumScreenErrorUnit() const;
/**
* Sets the \a unit for the maximum screen error allowed when rendering the tiled scene.
*
* \see setMaximumScreenError()
* \see maximumScreenErrorUnit()
*/
void setMaximumScreenErrorUnit( Qgis::RenderUnit unit );
/**
* Must be called when a new render cycle is started. A call to startRender() must always
* be followed by a corresponding call to stopRender() after all features have been rendered.
*
* \see stopRender()
*
* \warning This method is not thread safe. Before calling startRender() in a non-main thread,
* the renderer should instead be cloned and startRender()/stopRender() called on the clone.
*/
virtual void startRender( QgsTiledSceneRenderContext &context );
/**
* Must be called when a render cycle has finished, to allow the renderer to clean up.
*
* Calls to stopRender() must always be preceded by a call to startRender().
*
* \warning This method is not thread safe. Before calling startRender() in a non-main thread,
* the renderer should instead be cloned and startRender()/stopRender() called on the clone.
*
* \see startRender()
*/
virtual void stopRender( QgsTiledSceneRenderContext &context );
/**
* Creates a set of legend nodes representing the renderer.
*/
virtual QList<QgsLayerTreeModelLegendNode *> createLegendNodes( QgsLayerTreeLayer *nodeLayer ) SIP_FACTORY;
/**
* Returns a list of all rule keys for legend nodes created by the renderer.
*/
virtual QStringList legendRuleKeys() const;
protected:
/**
* Copies common tiled scene renderer properties (such as screen error) to the \a destination renderer.
*/
void copyCommonProperties( QgsTiledSceneRenderer *destination ) const;
/**
* Restores common renderer properties (such as screen error) from the
* specified DOM \a element.
*
* \see saveCommonProperties()
*/
void restoreCommonProperties( const QDomElement &element, const QgsReadWriteContext &context );
/**
* Saves common renderer properties (such as point size and screen error) to the
* specified DOM \a element.
*
* \see restoreCommonProperties()
*/
void saveCommonProperties( QDomElement &element, const QgsReadWriteContext &context ) const;
private:
#ifdef SIP_RUN
QgsTiledSceneRenderer( const QgsTiledSceneRenderer &other );
#endif
#ifdef QGISDEBUG
//! Pointer to thread in which startRender was first called
QThread *mThread = nullptr;
#endif
double mMaximumScreenError = 0.3;
Qgis::RenderUnit mMaximumScreenErrorUnit = Qgis::RenderUnit::Millimeters;
};
#endif // QGSTILEDSCENERENDERER_H

View File

@ -0,0 +1,70 @@
/***************************************************************************
qgstiledscenerendererregistry.cpp
---------------------
begin : August 2023
copyright : (C) 2023 by Nyall Dawson
email : nyall dot dawson 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 "qgstiledscenerendererregistry.h"
#include "qgstiledscenerenderer.h"
QgsTiledSceneRendererRegistry::QgsTiledSceneRendererRegistry()
{
// add default renderers
}
QgsTiledSceneRendererRegistry::~QgsTiledSceneRendererRegistry()
{
qDeleteAll( mRenderers );
}
bool QgsTiledSceneRendererRegistry::addRenderer( QgsTiledSceneRendererAbstractMetadata *metadata )
{
if ( !metadata || mRenderers.contains( metadata->name() ) )
return false;
mRenderers[metadata->name()] = metadata;
mRenderersOrder << metadata->name();
return true;
}
bool QgsTiledSceneRendererRegistry::removeRenderer( const QString &rendererName )
{
if ( !mRenderers.contains( rendererName ) )
return false;
delete mRenderers[rendererName];
mRenderers.remove( rendererName );
mRenderersOrder.removeAll( rendererName );
return true;
}
QgsTiledSceneRendererAbstractMetadata *QgsTiledSceneRendererRegistry::rendererMetadata( const QString &rendererName )
{
return mRenderers.value( rendererName );
}
QStringList QgsTiledSceneRendererRegistry::renderersList() const
{
QStringList renderers;
for ( const QString &renderer : mRenderersOrder )
{
QgsTiledSceneRendererAbstractMetadata *r = mRenderers.value( renderer );
if ( r )
renderers << renderer;
}
return renderers;
}
QgsTiledSceneRenderer *QgsTiledSceneRendererRegistry::defaultRenderer( const QgsTiledSceneLayer * )
{
return nullptr;
}

View File

@ -0,0 +1,239 @@
/***************************************************************************
qgstiledscenerendererregistry.h
---------------------
begin : August 2023
copyright : (C) 2023 by Nyall Dawson
email : nyall dot dawson 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 QGSTILEDSCENERENDERERREGISTRY_H
#define QGSTILEDSCENERENDERERREGISTRY_H
#include "qgis_core.h"
#include "qgis_sip.h"
#include <QIcon>
#include <QMap>
#include <QStringList>
#include <QDomElement>
class QgsTiledSceneRenderer;
class QgsReadWriteContext;
class QgsTiledSceneLayer;
class QgsStyle;
#ifndef SIP_RUN
class QgsTiledSceneRendererWidget SIP_EXTERNAL;
#endif
/**
* \ingroup core
* \brief Stores metadata about one tiled scene renderer class.
*
* \note It's necessary to implement createRenderer() function.
* In C++ you can use QgsTiledSceneRendererMetadata convenience class.
*
* \since QGIS 3.34
*/
class CORE_EXPORT QgsTiledSceneRendererAbstractMetadata
{
public:
/**
* Constructor for QgsTiledSceneRendererAbstractMetadata, with the specified \a name.
*
* The \a visibleName argument gives a translated, user friendly string identifying the renderer type.
*
* The \a icon argument can be used to specify an icon representing the renderer.
*/
QgsTiledSceneRendererAbstractMetadata( const QString &name, const QString &visibleName, const QIcon &icon = QIcon() )
: mName( name )
, mVisibleName( visibleName )
, mIcon( icon )
{}
virtual ~QgsTiledSceneRendererAbstractMetadata() = default;
/**
* Returns the unique name of the renderer. This value is not translated.
* \see visibleName()
*/
QString name() const { return mName; }
/**
* Returns a friendly display name of the renderer. This value is translated.
* \see name()
*/
QString visibleName() const { return mVisibleName; }
/**
* Returns an icon representing the renderer.
* \see setIcon()
*/
QIcon icon() const { return mIcon; }
/**
* Sets an \a icon representing the renderer.
* \see icon()
*/
void setIcon( const QIcon &icon ) { mIcon = icon; }
/**
* Returns new instance of the renderer given the DOM element. Returns NULLPTR on error.
* Pure virtual function: must be implemented in derived classes.
*/
virtual QgsTiledSceneRenderer *createRenderer( QDomElement &elem, const QgsReadWriteContext &context ) = 0 SIP_FACTORY;
#ifndef SIP_RUN
/**
* Returns new instance of settings widget for the renderer. Returns NULLPTR on error.
*
* The \a oldRenderer argument may refer to previously used renderer (or it is NULLPTR).
* If not NULLPTR, it may be used to initialize GUI of the widget from the previous settings.
* The old renderer does not have to be of the same type as returned by createRenderer().
*
* \note Not available in Python bindings
*/
virtual QgsTiledSceneRendererWidget *createRendererWidget( QgsTiledSceneLayer *layer, QgsStyle *style, QgsTiledSceneRenderer *oldRenderer ) SIP_FACTORY
{ Q_UNUSED( layer ) Q_UNUSED( style ); Q_UNUSED( oldRenderer ); return nullptr; }
#endif
protected:
//! name used within QGIS for identification (the same what renderer's type() returns)
QString mName;
//! name visible for users (translatable)
QString mVisibleName;
//! icon to be shown in the renderer properties dialog
QIcon mIcon;
};
typedef QgsTiledSceneRenderer *( *QgsTiledSceneRendererCreateFunc )( QDomElement &, const QgsReadWriteContext & ) SIP_SKIP;
typedef QgsTiledSceneRendererWidget *( *QgsTiledSceneRendererWidgetFunc )( QgsTiledSceneLayer *, QgsStyle *, QgsTiledSceneRenderer * ) SIP_SKIP;
/**
* \ingroup core
* \brief Convenience metadata class that uses static functions to create tiled scene renderer and its widget.
* \since QGIS 3.34
*/
class CORE_EXPORT QgsTiledSceneRendererMetadata : public QgsTiledSceneRendererAbstractMetadata
{
public:
/**
* Construct metadata
* \note not available in Python bindings
*/
QgsTiledSceneRendererMetadata( const QString &name,
const QString &visibleName,
QgsTiledSceneRendererCreateFunc pfCreate,
const QIcon &icon = QIcon(),
QgsTiledSceneRendererWidgetFunc pfWidget = nullptr ) SIP_SKIP
: QgsTiledSceneRendererAbstractMetadata( name, visibleName, icon )
, mCreateFunc( pfCreate )
, mWidgetFunc( pfWidget )
{}
QgsTiledSceneRenderer *createRenderer( QDomElement &elem, const QgsReadWriteContext &context ) override SIP_FACTORY
{ return mCreateFunc ? mCreateFunc( elem, context ) : nullptr; }
#ifndef SIP_RUN
QgsTiledSceneRendererWidget *createRendererWidget( QgsTiledSceneLayer *layer, QgsStyle *style, QgsTiledSceneRenderer *renderer ) override SIP_FACTORY
{ return mWidgetFunc ? mWidgetFunc( layer, style, renderer ) : nullptr; }
#endif
//! \note not available in Python bindings
QgsTiledSceneRendererCreateFunc createFunction() const { return mCreateFunc; } SIP_SKIP
//! \note not available in Python bindings
QgsTiledSceneRendererWidgetFunc widgetFunction() const { return mWidgetFunc; } SIP_SKIP
//! \note not available in Python bindings
void setWidgetFunction( QgsTiledSceneRendererWidgetFunc f ) { mWidgetFunc = f; } SIP_SKIP
protected:
//! pointer to function that creates an instance of the renderer when loading project / style
QgsTiledSceneRendererCreateFunc mCreateFunc;
//! pointer to function that creates a widget for configuration of renderer's params
QgsTiledSceneRendererWidgetFunc mWidgetFunc;
private:
#ifdef SIP_RUN
QgsTiledSceneRendererMetadata();
#endif
};
/**
* \ingroup core
* \class QgsTiledSceneRendererRegistry
* \brief Registry of 2D renderers for tiled scenes.
*
* QgsTiledSceneRendererRegistry is not usually directly created, but rather accessed through
* QgsApplication::tiledSceneRendererRegistry().
*
* \since QGIS 3.34
*/
class CORE_EXPORT QgsTiledSceneRendererRegistry
{
public:
QgsTiledSceneRendererRegistry();
~QgsTiledSceneRendererRegistry();
//! QgsTiledSceneRendererRegistry cannot be copied.
QgsTiledSceneRendererRegistry( const QgsTiledSceneRendererRegistry &rh ) = delete;
//! QgsTiledSceneRendererRegistry cannot be copied.
QgsTiledSceneRendererRegistry &operator=( const QgsTiledSceneRendererRegistry &rh ) = delete;
/**
* Adds a renderer to the registry. Takes ownership of the metadata object.
* \param metadata renderer metadata
* \returns TRUE if renderer was added successfully, or FALSE if renderer could not
* be added (e.g., a renderer with a duplicate name already exists)
*/
bool addRenderer( QgsTiledSceneRendererAbstractMetadata *metadata SIP_TRANSFER );
/**
* Removes a renderer from registry.
* \param rendererName name of renderer to remove from registry
* \returns TRUE if renderer was successfully removed, or FALSE if matching
* renderer could not be found
*/
bool removeRenderer( const QString &rendererName );
/**
* Returns the metadata for a specified renderer. Returns NULLPTR if a matching
* renderer was not found in the registry.
*/
QgsTiledSceneRendererAbstractMetadata *rendererMetadata( const QString &rendererName );
/**
* Returns a list of available renderers.
*/
QStringList renderersList() const;
/**
* Returns a new default tiled scene renderer for a specified \a layer.
*
* Caller takes ownership of the returned renderer.
*/
static QgsTiledSceneRenderer *defaultRenderer( const QgsTiledSceneLayer *layer ) SIP_FACTORY;
private:
#ifdef SIP_RUN
QgsTiledSceneRendererRegistry( const QgsTiledSceneRendererRegistry &rh );
#endif
//! Map of name to renderer
QMap<QString, QgsTiledSceneRendererAbstractMetadata *> mRenderers;
//! List of renderers, maintained in the order that they have been added
QStringList mRenderersOrder;
};
#endif // QGSTILEDSCENERENDERERREGISTRY_H

View File

@ -194,6 +194,7 @@ set(TESTS
testqgstemporalproperty.cpp testqgstemporalproperty.cpp
testqgstemporalrangeobject.cpp testqgstemporalrangeobject.cpp
testqgstiledsceneconnection.cpp testqgstiledsceneconnection.cpp
testqgstiledscenerendererregistry.cpp
testqgstiledownloadmanager.cpp testqgstiledownloadmanager.cpp
testqgstracer.cpp testqgstracer.cpp
testqgstranslateproject.cpp testqgstranslateproject.cpp

View File

@ -0,0 +1,139 @@
/***************************************************************************
testqgstiledscenerendererregistry.cpp
-----------------------
begin : August 2023
copyright : (C) 2023 by Nyall Dawson
email : nyall dot dawson 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 "qgstiledscenerendererregistry.h"
#include "qgstiledscenerenderer.h"
#include "qgsreadwritecontext.h"
#include <QObject>
#include "qgstest.h"
//dummy renderer for testing
class DummyRenderer : public QgsTiledSceneRenderer
{
public:
DummyRenderer() = default;
QString type() const override { return QStringLiteral( "dummy" ); }
QgsTiledSceneRenderer *clone() const override { return new DummyRenderer(); }
static QgsTiledSceneRenderer *create( QDomElement &, const QgsReadWriteContext & ) { return new DummyRenderer(); }
QDomElement save( QDomDocument &doc, const QgsReadWriteContext & ) const override { return doc.createElement( QStringLiteral( "test" ) ); }
};
class TestQgsTiledSceneRendererRegistry : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void metadata();
void createInstance();
void instanceHasDefaultRenderers();
void addRenderer();
void fetchTypes();
private:
};
void TestQgsTiledSceneRendererRegistry::initTestCase()
{
QgsApplication::init(); // init paths for CRS lookup
QgsApplication::initQgis();
}
void TestQgsTiledSceneRendererRegistry::cleanupTestCase()
{
QgsApplication::exitQgis();
}
void TestQgsTiledSceneRendererRegistry::init()
{
}
void TestQgsTiledSceneRendererRegistry::cleanup()
{
}
void TestQgsTiledSceneRendererRegistry::metadata()
{
QgsTiledSceneRendererMetadata metadata = QgsTiledSceneRendererMetadata( QStringLiteral( "name" ), QStringLiteral( "display name" ), DummyRenderer::create, QIcon() );
QCOMPARE( metadata.name(), QString( "name" ) );
QCOMPARE( metadata.visibleName(), QString( "display name" ) );
//test creating renderer from metadata
QDomElement elem;
const std::unique_ptr< QgsTiledSceneRenderer > renderer( metadata.createRenderer( elem, QgsReadWriteContext() ) );
QVERIFY( renderer );
DummyRenderer *dummyRenderer = dynamic_cast<DummyRenderer *>( renderer.get() );
QVERIFY( dummyRenderer );
}
void TestQgsTiledSceneRendererRegistry::createInstance()
{
QgsTiledSceneRendererRegistry *registry = QgsApplication::tiledSceneRendererRegistry();
QVERIFY( registry );
}
void TestQgsTiledSceneRendererRegistry::instanceHasDefaultRenderers()
{
//check that callout registry is initially populated with some renderers
//(assumes that there is some default renderers)
QgsTiledSceneRendererRegistry *registry = QgsApplication::tiledSceneRendererRegistry();
QVERIFY( registry->renderersList().length() > 0 );
}
void TestQgsTiledSceneRendererRegistry::addRenderer()
{
QgsTiledSceneRendererRegistry *registry = QgsApplication::tiledSceneRendererRegistry();
const int previousCount = registry->renderersList().length();
registry->addRenderer( new QgsTiledSceneRendererMetadata( QStringLiteral( "Dummy" ), QStringLiteral( "Dummy renderer" ), DummyRenderer::create, QIcon() ) );
QCOMPARE( registry->renderersList().length(), previousCount + 1 );
//try adding again, should have no effect
QgsTiledSceneRendererMetadata *dupe = new QgsTiledSceneRendererMetadata( QStringLiteral( "Dummy" ), QStringLiteral( "Dummy callout" ), DummyRenderer::create, QIcon() );
QVERIFY( ! registry->addRenderer( dupe ) );
QCOMPARE( registry->renderersList().length(), previousCount + 1 );
delete dupe;
//try adding empty metadata
registry->addRenderer( nullptr );
QCOMPARE( registry->renderersList().length(), previousCount + 1 );
}
void TestQgsTiledSceneRendererRegistry::fetchTypes()
{
QgsTiledSceneRendererRegistry *registry = QgsApplication::tiledSceneRendererRegistry();
const QStringList types = registry->renderersList();
QVERIFY( types.contains( "Dummy" ) );
QgsTiledSceneRendererAbstractMetadata *metadata = registry->rendererMetadata( QStringLiteral( "Dummy" ) );
QCOMPARE( metadata->name(), QString( "Dummy" ) );
//metadata for bad renderer
metadata = registry->rendererMetadata( QStringLiteral( "bad renderer" ) );
QVERIFY( !metadata );
}
QGSTEST_MAIN( TestQgsTiledSceneRendererRegistry )
#include "testqgstiledscenerendererregistry.moc"