[api] Add a proper registry for 3D symbol types

This commit is contained in:
Nyall Dawson 2020-07-14 19:59:33 +10:00
parent f60b79fcea
commit a34eabd1fb
10 changed files with 556 additions and 0 deletions

View File

@ -0,0 +1,117 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/./3d/qgs3dsymbolregistry.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class Qgs3DSymbolAbstractMetadata
{
%Docstring
Stores metadata about one 3D symbol class.
.. note::
It's necessary to implement :py:func:`~createSymbol` function.
In C++ you can use Qgs3DSymbolMetadata convenience class.
.. versionadded:: 3.16
%End
%TypeHeaderCode
#include "qgs3dsymbolregistry.h"
%End
public:
Qgs3DSymbolAbstractMetadata( const QString &type, const QString &visibleName );
%Docstring
Constructor for Qgs3DSymbolAbstractMetadata, with the specified ``type`` and ``visibleName``.
%End
virtual ~Qgs3DSymbolAbstractMetadata();
QString type() const;
%Docstring
Returns the unique symbol type string.
%End
QString visibleName() const;
%Docstring
Returns the symbol's visible (translated) name.
%End
virtual QgsAbstract3DSymbol *create() = 0 /Factory/;
%Docstring
Creates a new instance of this symbol type.
Caller takes ownership of the returned symbol.
%End
};
class Qgs3DSymbolRegistry
{
%Docstring
Registry of available 3D symbol classes.
Qgs3DSymbolRegistry is not usually directly created, but rather accessed through
:py:func:`QgsApplication.symbol3DRegistry()`.
.. versionadded:: 3.16
%End
%TypeHeaderCode
#include "qgs3dsymbolregistry.h"
%End
public:
Qgs3DSymbolRegistry();
~Qgs3DSymbolRegistry();
Qgs3DSymbolAbstractMetadata *symbolMetadata( const QString &type ) const;
%Docstring
Returns metadata for specified symbol ``type``. Returns ``None`` if not found
%End
QStringList symbolTypes() const;
%Docstring
Returns a list of all available symbol types.
%End
bool addSymbolType( Qgs3DSymbolAbstractMetadata *metadata /Transfer/ );
%Docstring
Registers a new symbol type. Takes ownership of the ``metadata`` instance.
%End
QgsAbstract3DSymbol *createSymbol( const QString &type ) const /Factory/;
%Docstring
Creates a new instance of a symbol of the specified ``type``.
The caller takes ownership of the returned symbol.
Returns ``None`` if the specified type is not found in the registry.
%End
private:
Qgs3DSymbolRegistry( const Qgs3DSymbolRegistry &rh );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/./3d/qgs3dsymbolregistry.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -850,6 +850,13 @@ Gets the registry of available field formatters.
Returns registry of available 3D renderers. Returns registry of available 3D renderers.
.. versionadded:: 3.0 .. versionadded:: 3.0
%End
static Qgs3DSymbolRegistry *symbol3DRegistry() /KeepReference/;
%Docstring
Returns registry of available 3D symbols.
.. versionadded:: 3.16
%End %End
static QgsScaleBarRendererRegistry *scaleBarRendererRegistry() /KeepReference/; static QgsScaleBarRendererRegistry *scaleBarRendererRegistry() /KeepReference/;

View File

@ -251,6 +251,7 @@
%Include auto_generated/qgsxmlutils.sip %Include auto_generated/qgsxmlutils.sip
%Include auto_generated/qgsziputils.sip %Include auto_generated/qgsziputils.sip
%Include auto_generated/./3d/qgs3drendererregistry.sip %Include auto_generated/./3d/qgs3drendererregistry.sip
%Include auto_generated/./3d/qgs3dsymbolregistry.sip
%Include auto_generated/./3d/qgsabstract3dsymbol.sip %Include auto_generated/./3d/qgsabstract3dsymbol.sip
%Include auto_generated/./3d/qgsabstract3drenderer.sip %Include auto_generated/./3d/qgsabstract3drenderer.sip
%Include auto_generated/annotations/qgsannotation.sip %Include auto_generated/annotations/qgsannotation.sip

View File

@ -0,0 +1,52 @@
/***************************************************************************
qgs3dsymbolregistry.cpp
--------------------------------------
Date : July 2020
Copyright : (C) 2020 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 "qgs3dsymbolregistry.h"
Qgs3DSymbolRegistry::Qgs3DSymbolRegistry()
{
}
Qgs3DSymbolRegistry::~Qgs3DSymbolRegistry()
{
qDeleteAll( mMetadata );
}
bool Qgs3DSymbolRegistry::addSymbolType( Qgs3DSymbolAbstractMetadata *metadata )
{
if ( !metadata || mMetadata.contains( metadata->type() ) )
return false;
mMetadata[metadata->type()] = metadata;
return true;
}
QgsAbstract3DSymbol *Qgs3DSymbolRegistry::createSymbol( const QString &type ) const
{
if ( !mMetadata.contains( type ) )
return nullptr;
return mMetadata[type]->create();
}
Qgs3DSymbolAbstractMetadata *Qgs3DSymbolRegistry::symbolMetadata( const QString &type ) const
{
return mMetadata.value( type );
}
QStringList Qgs3DSymbolRegistry::symbolTypes() const
{
return mMetadata.keys();
}

View File

@ -0,0 +1,201 @@
/***************************************************************************
qgs3dsymbolregistry.h
--------------------------------------
Date : July 2020
Copyright : (C) 2020 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 QGS3DSYMBOLREGISTRY_H
#define QGS3DSYMBOLREGISTRY_H
#include "qgis_core.h"
#include "qgis_sip.h"
#include <QDomElement>
#include <QMap>
class QgsAbstract3DSymbol;
class QgsReadWriteContext;
class Qgs3DSymbolWidget;
class QgsVectorLayer;
/**
* \ingroup core
* Stores metadata about one 3D symbol class.
*
* \note It's necessary to implement createSymbol() function.
* In C++ you can use Qgs3DSymbolMetadata convenience class.
*
* \since QGIS 3.16
*/
class CORE_EXPORT Qgs3DSymbolAbstractMetadata
{
public:
/**
* Constructor for Qgs3DSymbolAbstractMetadata, with the specified \a type and \a visibleName.
*/
Qgs3DSymbolAbstractMetadata( const QString &type, const QString &visibleName )
: mType( type )
, mVisibleName( visibleName )
{}
virtual ~Qgs3DSymbolAbstractMetadata() = default;
/**
* Returns the unique symbol type string.
*/
QString type() const { return mType; }
/**
* Returns the symbol's visible (translated) name.
*/
QString visibleName() const { return mVisibleName; }
/**
* Creates a new instance of this symbol type.
*
* Caller takes ownership of the returned symbol.
*/
virtual QgsAbstract3DSymbol *create() = 0 SIP_FACTORY;
#ifndef SIP_RUN
/**
* Create a widget for configuring a symbol of this type.
*
* Can return NULLPTR if there's no GUI.
*
* \note Not available in Python bindings
*/
virtual Qgs3DSymbolWidget *createSymbolWidget( QgsVectorLayer * ) SIP_FACTORY { return nullptr; }
#endif
private:
QString mType;
QString mVisibleName;
};
//! 3D symbol creation function
typedef QgsAbstract3DSymbol *( *Qgs3DSymbolCreateFunc )() SIP_SKIP;
//! 3D symbol widget creation function
typedef Qgs3DSymbolWidget *( *Qgs3DSymbolWidgetFunc )( QgsVectorLayer * ) SIP_SKIP;
#ifndef SIP_RUN
/**
* \ingroup core
* Convenience metadata class that uses static functions to create a 3D symbol and its widget.
*
* \note Not available in Python bindings.
*
* \since QGIS 3.16
*/
class CORE_EXPORT Qgs3DSymbolMetadata : public Qgs3DSymbolAbstractMetadata
{
public:
/**
* Constructor for Qgs3DSymbolMetadata, with the specified \a type and \a visibleName.
*
* The \a pfCreate and \a pfWidget arguments are used to specify
* static functions for creating the symbol type and configuration widget.
*/
Qgs3DSymbolMetadata( const QString &type, const QString &visibleName,
Qgs3DSymbolCreateFunc pfCreate,
Qgs3DSymbolWidgetFunc pfWidget = nullptr ) SIP_SKIP
: Qgs3DSymbolAbstractMetadata( type, visibleName )
, mCreateFunc( pfCreate )
, mWidgetFunc( pfWidget )
{}
/**
* Returns the symbol type's creation function.
*/
Qgs3DSymbolCreateFunc createFunction() const { return mCreateFunc; }
/**
* Returns the symbol type's widget creation function.
*
* \see setWidgetFunction()
*/
Qgs3DSymbolWidgetFunc widgetFunction() const { return mWidgetFunc; }
/**
* Sets the symbol type's widget creation \a function.
*
* \see widgetFunction()
*/
void setWidgetFunction( Qgs3DSymbolWidgetFunc function ) { mWidgetFunc = function; }
QgsAbstract3DSymbol *create() override SIP_FACTORY { return mCreateFunc ? mCreateFunc() : nullptr; }
Qgs3DSymbolWidget *createSymbolWidget( QgsVectorLayer *vl ) override SIP_FACTORY { return mWidgetFunc ? mWidgetFunc( vl ) : nullptr; }
private:
Qgs3DSymbolCreateFunc mCreateFunc;
Qgs3DSymbolWidgetFunc mWidgetFunc;
};
#endif
/**
* \ingroup core
* Registry of available 3D symbol classes.
*
* Qgs3DSymbolRegistry is not usually directly created, but rather accessed through
* QgsApplication::symbol3DRegistry().
*
* \since QGIS 3.16
*/
class CORE_EXPORT Qgs3DSymbolRegistry
{
public:
Qgs3DSymbolRegistry();
~Qgs3DSymbolRegistry();
//! Qgs3DSymbolRegistry cannot be copied.
Qgs3DSymbolRegistry( const Qgs3DSymbolRegistry &rh ) = delete;
//! Qgs3DSymbolRegistry cannot be copied.
Qgs3DSymbolRegistry &operator=( const Qgs3DSymbolRegistry &rh ) = delete;
//! Returns metadata for specified symbol \a type. Returns NULLPTR if not found
Qgs3DSymbolAbstractMetadata *symbolMetadata( const QString &type ) const;
/**
* Returns a list of all available symbol types.
*/
QStringList symbolTypes() const;
//! Registers a new symbol type. Takes ownership of the \a metadata instance.
bool addSymbolType( Qgs3DSymbolAbstractMetadata *metadata SIP_TRANSFER );
/**
* Creates a new instance of a symbol of the specified \a type.
*
* The caller takes ownership of the returned symbol.
*
* Returns NULLPTR if the specified type is not found in the registry.
*/
QgsAbstract3DSymbol *createSymbol( const QString &type ) const SIP_FACTORY;
private:
#ifdef SIP_RUN
Qgs3DSymbolRegistry( const Qgs3DSymbolRegistry &rh );
#endif
QMap<QString, Qgs3DSymbolAbstractMetadata *> mMetadata;
};
#endif // QGS3DSYMBOLREGISTRY_H

View File

@ -654,6 +654,7 @@ SET(QGIS_CORE_SRCS
geometry/qgswkbtypes.cpp geometry/qgswkbtypes.cpp
3d/qgs3drendererregistry.cpp 3d/qgs3drendererregistry.cpp
3d/qgs3dsymbolregistry.cpp
3d/qgsabstract3dsymbol.cpp 3d/qgsabstract3dsymbol.cpp
3d/qgsabstract3drenderer.cpp 3d/qgsabstract3drenderer.cpp
@ -1033,6 +1034,7 @@ SET(QGIS_CORE_HDRS
qobjectuniqueptr.h qobjectuniqueptr.h
3d/qgs3drendererregistry.h 3d/qgs3drendererregistry.h
3d/qgs3dsymbolregistry.h
3d/qgsabstract3dsymbol.h 3d/qgsabstract3dsymbol.h
3d/qgsabstract3drenderer.h 3d/qgsabstract3drenderer.h

View File

@ -54,6 +54,7 @@
#include "qgsuserprofilemanager.h" #include "qgsuserprofilemanager.h"
#include "qgsreferencedgeometry.h" #include "qgsreferencedgeometry.h"
#include "qgs3drendererregistry.h" #include "qgs3drendererregistry.h"
#include "qgs3dsymbolregistry.h"
#include "qgslayoutrendercontext.h" #include "qgslayoutrendercontext.h"
#include "qgssqliteutils.h" #include "qgssqliteutils.h"
#include "qgsstyle.h" #include "qgsstyle.h"
@ -2235,6 +2236,11 @@ Qgs3DRendererRegistry *QgsApplication::renderer3DRegistry()
return members()->m3DRendererRegistry; return members()->m3DRendererRegistry;
} }
Qgs3DSymbolRegistry *QgsApplication::symbol3DRegistry()
{
return members()->m3DSymbolRegistry;
}
QgsScaleBarRendererRegistry *QgsApplication::scaleBarRendererRegistry() QgsScaleBarRendererRegistry *QgsApplication::scaleBarRendererRegistry()
{ {
return members()->mScaleBarRendererRegistry; return members()->mScaleBarRendererRegistry;
@ -2355,6 +2361,11 @@ QgsApplication::ApplicationMembers::ApplicationMembers()
mAnnotationRegistry = new QgsAnnotationRegistry(); mAnnotationRegistry = new QgsAnnotationRegistry();
profiler->end(); profiler->end();
} }
{
profiler->start( tr( "Setup 3D symbol registry" ) );
m3DSymbolRegistry = new Qgs3DSymbolRegistry();
profiler->end();
}
{ {
profiler->start( tr( "Setup 3D renderer registry" ) ); profiler->start( tr( "Setup 3D renderer registry" ) );
m3DRendererRegistry = new Qgs3DRendererRegistry(); m3DRendererRegistry = new Qgs3DRendererRegistry();
@ -2399,6 +2410,7 @@ QgsApplication::ApplicationMembers::~ApplicationMembers()
delete mValidityCheckRegistry; delete mValidityCheckRegistry;
delete mActionScopeRegistry; delete mActionScopeRegistry;
delete m3DRendererRegistry; delete m3DRendererRegistry;
delete m3DSymbolRegistry;
delete mAnnotationRegistry; delete mAnnotationRegistry;
delete mColorSchemeRegistry; delete mColorSchemeRegistry;
delete mFieldFormatterRegistry; delete mFieldFormatterRegistry;

View File

@ -60,6 +60,7 @@ class QgsStyleModel;
class QgsNumericFormatRegistry; class QgsNumericFormatRegistry;
class QgsConnectionRegistry; class QgsConnectionRegistry;
class QgsScaleBarRendererRegistry; class QgsScaleBarRendererRegistry;
class Qgs3DSymbolRegistry;
/** /**
* \ingroup core * \ingroup core
@ -785,6 +786,12 @@ class CORE_EXPORT QgsApplication : public QApplication
*/ */
static Qgs3DRendererRegistry *renderer3DRegistry() SIP_KEEPREFERENCE; static Qgs3DRendererRegistry *renderer3DRegistry() SIP_KEEPREFERENCE;
/**
* Returns registry of available 3D symbols.
* \since QGIS 3.16
*/
static Qgs3DSymbolRegistry *symbol3DRegistry() SIP_KEEPREFERENCE;
/** /**
* Gets the registry of available scalebar renderers. * Gets the registry of available scalebar renderers.
* *
@ -928,6 +935,7 @@ class CORE_EXPORT QgsApplication : public QApplication
struct ApplicationMembers struct ApplicationMembers
{ {
Qgs3DRendererRegistry *m3DRendererRegistry = nullptr; Qgs3DRendererRegistry *m3DRendererRegistry = nullptr;
Qgs3DSymbolRegistry *m3DSymbolRegistry = nullptr;
QgsActionScopeRegistry *mActionScopeRegistry = nullptr; QgsActionScopeRegistry *mActionScopeRegistry = nullptr;
QgsAnnotationRegistry *mAnnotationRegistry = nullptr; QgsAnnotationRegistry *mAnnotationRegistry = nullptr;
QgsColorSchemeRegistry *mColorSchemeRegistry = nullptr; QgsColorSchemeRegistry *mColorSchemeRegistry = nullptr;

View File

@ -79,3 +79,4 @@ ADD_QGIS_TEST(3dutilstest testqgs3dutils.cpp)
ADD_QGIS_TEST(3drenderingtest testqgs3drendering.cpp) ADD_QGIS_TEST(3drenderingtest testqgs3drendering.cpp)
ADD_QGIS_TEST(layout3dmaptest testqgslayout3dmap.cpp) ADD_QGIS_TEST(layout3dmaptest testqgslayout3dmap.cpp)
ADD_QGIS_TEST(tessellatortest testqgstessellator.cpp) ADD_QGIS_TEST(tessellatortest testqgstessellator.cpp)
ADD_QGIS_TEST(3dsymbolregistrytest testqgs3dsymbolregistry.cpp)

View File

@ -0,0 +1,155 @@
/***************************************************************************
TestQgs3DSymbolRegistry.cpp
-----------------------
begin : July 2019
copyright : (C) 2019 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 "qgs3dsymbolregistry.h"
#include "qgsabstract3dsymbol.h"
#include <QObject>
#include "qgstest.h"
//dummy symbol for testing
class Dummy3DSymbol : public QgsAbstract3DSymbol
{
public:
Dummy3DSymbol() = default;
QString type() const override { return QStringLiteral( "Dummy" ); }
QgsAbstract3DSymbol *clone() const override { return new Dummy3DSymbol(); }
void writeXml( QDomElement &, const QgsReadWriteContext & ) const override {}
void readXml( const QDomElement &, const QgsReadWriteContext & ) override {}
static QgsAbstract3DSymbol *create() { return new Dummy3DSymbol(); }
};
class TestQgs3DSymbolRegistry : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void metadata();
void createInstance();
void instanceHasDefaultSymbols();
void addSymbol();
void fetchTypes();
void createSymbol();
private:
};
void TestQgs3DSymbolRegistry::initTestCase()
{
QgsApplication::init(); // init paths for CRS lookup
QgsApplication::initQgis();
}
void TestQgs3DSymbolRegistry::cleanupTestCase()
{
QgsApplication::exitQgis();
}
void TestQgs3DSymbolRegistry::init()
{
}
void TestQgs3DSymbolRegistry::cleanup()
{
}
void TestQgs3DSymbolRegistry::metadata()
{
Qgs3DSymbolMetadata metadata = Qgs3DSymbolMetadata( QStringLiteral( "name" ), QStringLiteral( "display name" ), Dummy3DSymbol::create );
QCOMPARE( metadata.type(), QString( "name" ) );
QCOMPARE( metadata.visibleName(), QString( "display name" ) );
//test creating symbol from metadata
QVariantMap map;
std::unique_ptr< QgsAbstract3DSymbol > symbol( metadata.create() );
QVERIFY( symbol );
Dummy3DSymbol *dummySymbol = dynamic_cast<Dummy3DSymbol *>( symbol.get() );
QVERIFY( dummySymbol );
}
void TestQgs3DSymbolRegistry::createInstance()
{
Qgs3DSymbolRegistry *registry = QgsApplication::symbol3DRegistry();
QVERIFY( registry );
}
void TestQgs3DSymbolRegistry::instanceHasDefaultSymbols()
{
//check that symbol registry is initially populated with some symbols
//(assumes that there is some default symbols)
Qgs3DSymbolRegistry *registry = QgsApplication::symbol3DRegistry();
QVERIFY( registry->symbolTypes().length() > 0 );
}
void TestQgs3DSymbolRegistry::addSymbol()
{
Qgs3DSymbolRegistry *registry = QgsApplication::symbol3DRegistry();
int previousCount = registry->symbolTypes().length();
registry->addSymbolType( new Qgs3DSymbolMetadata( QStringLiteral( "Dummy" ), QStringLiteral( "Dummy symbol" ), Dummy3DSymbol::create ) );
QCOMPARE( registry->symbolTypes().length(), previousCount + 1 );
//try adding again, should have no effect
Qgs3DSymbolMetadata *dupe = new Qgs3DSymbolMetadata( QStringLiteral( "Dummy" ), QStringLiteral( "Dummy symbol" ), Dummy3DSymbol::create );
QVERIFY( ! registry->addSymbolType( dupe ) );
QCOMPARE( registry->symbolTypes().length(), previousCount + 1 );
delete dupe;
//try adding empty metadata
registry->addSymbolType( nullptr );
QCOMPARE( registry->symbolTypes().length(), previousCount + 1 );
}
void TestQgs3DSymbolRegistry::fetchTypes()
{
Qgs3DSymbolRegistry *registry = QgsApplication::symbol3DRegistry();
QStringList types = registry->symbolTypes();
QVERIFY( types.contains( "Dummy" ) );
Qgs3DSymbolAbstractMetadata *metadata = registry->symbolMetadata( QStringLiteral( "Dummy" ) );
QCOMPARE( metadata->type(), QString( "Dummy" ) );
//metadata for bad symbol
metadata = registry->symbolMetadata( QStringLiteral( "bad symbol" ) );
QVERIFY( !metadata );
}
void TestQgs3DSymbolRegistry::createSymbol()
{
Qgs3DSymbolRegistry *registry = QgsApplication::symbol3DRegistry();
std::unique_ptr< QgsAbstract3DSymbol > symbol( registry->createSymbol( QStringLiteral( "Dummy" ) ) );
QVERIFY( symbol.get() );
Dummy3DSymbol *dummySymbol = dynamic_cast<Dummy3DSymbol *>( symbol.get() );
QVERIFY( dummySymbol );
//try creating a bad symbol
symbol.reset( registry->createSymbol( QStringLiteral( "bad symbol" ) ) );
QVERIFY( !symbol.get() );
}
QGSTEST_MAIN( TestQgs3DSymbolRegistry )
#include "testqgs3dsymbolregistry.moc"