mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Move generation of default symbol random colors to
QgsColorSchemeRegistry and add API to set a QgsColorScheme from which to pull colors when creating a random symbol color.
This commit is contained in:
parent
40ceb7bdce
commit
bc449c401b
@ -104,6 +104,63 @@ Returns all color schemes in the registry which have a specified flag set
|
||||
|
||||
|
||||
|
||||
void setRandomStyleColorScheme( QgsColorScheme *scheme );
|
||||
%Docstring
|
||||
Sets the color ``scheme`` to use when fetching random colors to use for symbol styles.
|
||||
|
||||
``scheme`` should match a color scheme which is already present in the registry.
|
||||
|
||||
Note that calling this method takes a snapshot of the colors from the scheme's
|
||||
QgsColorScheme.fetchColors() list. Accordingly, any future changes to the colors
|
||||
in ``scheme`` are not automatically reflected by calls to fetchRandomStyleColor().
|
||||
If ``scheme`` is updated, then another call to setRandomStyleColorScheme() must
|
||||
be made in order to update the cached list of available style colors.
|
||||
|
||||
.. seealso:: :py:func:`randomStyleColorScheme`
|
||||
|
||||
.. seealso:: :py:func:`fetchRandomStyleColor`
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
QgsColorScheme *randomStyleColorScheme();
|
||||
%Docstring
|
||||
Returns the color scheme used when fetching random colors to use for symbol styles.
|
||||
|
||||
This may be None, in which case totally random colors are used for styles.
|
||||
|
||||
.. seealso:: :py:func:`setRandomStyleColorScheme`
|
||||
|
||||
.. seealso:: :py:func:`fetchRandomStyleColor`
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
QColor fetchRandomStyleColor() const;
|
||||
%Docstring
|
||||
Returns a random color for use with a new symbol style (e.g. for a newly created
|
||||
map layer).
|
||||
|
||||
If a randomStyleColorScheme() is set then this color will be randomly taken from that
|
||||
color scheme. If no randomStyleColorScheme() is set then a totally random color
|
||||
will be generated.
|
||||
|
||||
Note that calling setRandomStyleColorScheme() takes a snapshot of the colors from the scheme's
|
||||
QgsColorScheme.fetchColors() list. Accordingly, any future changes to the colors
|
||||
in the scheme are not automatically reflected by calls to fetchRandomStyleColor().
|
||||
If the scheme is updated, then another call to setRandomStyleColorScheme() must
|
||||
be made in order to update the cached list of available style colors from which
|
||||
fetchRandomStyleColor() selects colors.
|
||||
|
||||
This method is thread safe.
|
||||
|
||||
.. seealso:: :py:func:`randomStyleColorScheme`
|
||||
|
||||
.. seealso:: :py:func:`setRandomStyleColorScheme`
|
||||
|
||||
.. versionadded:: 3.2
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -20,7 +20,8 @@
|
||||
#include "qgsapplication.h"
|
||||
#include <QDir>
|
||||
#include <QFileInfoList>
|
||||
|
||||
#include <QMutex>
|
||||
#include <random>
|
||||
|
||||
QgsColorSchemeRegistry::~QgsColorSchemeRegistry()
|
||||
{
|
||||
@ -98,8 +99,67 @@ QList<QgsColorScheme *> QgsColorSchemeRegistry::schemes( const QgsColorScheme::S
|
||||
return matchingSchemes;
|
||||
}
|
||||
|
||||
void QgsColorSchemeRegistry::setRandomStyleColorScheme( QgsColorScheme *scheme )
|
||||
{
|
||||
mRandomStyleColorScheme = scheme;
|
||||
if ( scheme )
|
||||
{
|
||||
mRandomStyleColors = scheme->fetchColors();
|
||||
|
||||
std::random_device rd;
|
||||
std::mt19937 mt( rd() );
|
||||
std::uniform_int_distribution<int> colorDist( 0, mRandomStyleColors.count() - 1 );
|
||||
mNextRandomStyleColorIndex = colorDist( mt );
|
||||
std::uniform_int_distribution<int> colorDir( 0, 1 );
|
||||
mNextRandomStyleColorDirection = colorDir( mt ) == 0 ? -1 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRandomStyleColors.clear();
|
||||
}
|
||||
}
|
||||
|
||||
QgsColorScheme *QgsColorSchemeRegistry::randomStyleColorScheme()
|
||||
{
|
||||
return mRandomStyleColorScheme;
|
||||
}
|
||||
|
||||
QColor QgsColorSchemeRegistry::fetchRandomStyleColor() const
|
||||
{
|
||||
if ( mRandomStyleColors.empty() )
|
||||
{
|
||||
// no random color scheme available - so just use totally random colors
|
||||
|
||||
// Make sure we use get uniquely seeded random numbers, and not the same sequence of numbers
|
||||
std::random_device rd;
|
||||
std::mt19937 mt( rd() );
|
||||
std::uniform_int_distribution<int> hueDist( 0, 359 );
|
||||
std::uniform_int_distribution<int> satDist( 64, 255 );
|
||||
std::uniform_int_distribution<int> valueDist( 128, 255 );
|
||||
return QColor::fromHsv( hueDist( mt ), satDist( mt ), valueDist( mt ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
static QMutex sMutex;
|
||||
QMutexLocker locker( &sMutex );
|
||||
QColor res = mRandomStyleColors.at( mNextRandomStyleColorIndex ).first;
|
||||
mNextRandomStyleColorIndex += mNextRandomStyleColorDirection;
|
||||
if ( mNextRandomStyleColorIndex < 0 )
|
||||
mNextRandomStyleColorIndex = mRandomStyleColors.count() - 1;
|
||||
if ( mNextRandomStyleColorIndex >= mRandomStyleColors.count() )
|
||||
mNextRandomStyleColorIndex = 0;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsColorSchemeRegistry::removeColorScheme( QgsColorScheme *scheme )
|
||||
{
|
||||
if ( mRandomStyleColorScheme == scheme )
|
||||
{
|
||||
mRandomStyleColorScheme = nullptr;
|
||||
mRandomStyleColors.clear();
|
||||
}
|
||||
|
||||
if ( mColorSchemeList.indexOf( scheme ) != -1 )
|
||||
{
|
||||
mColorSchemeList.removeAll( scheme );
|
||||
|
@ -119,10 +119,70 @@ class CORE_EXPORT QgsColorSchemeRegistry
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Sets the color \a scheme to use when fetching random colors to use for symbol styles.
|
||||
*
|
||||
* \a scheme should match a color scheme which is already present in the registry.
|
||||
*
|
||||
* Note that calling this method takes a snapshot of the colors from the scheme's
|
||||
* QgsColorScheme::fetchColors() list. Accordingly, any future changes to the colors
|
||||
* in \a scheme are not automatically reflected by calls to fetchRandomStyleColor().
|
||||
* If \a scheme is updated, then another call to setRandomStyleColorScheme() must
|
||||
* be made in order to update the cached list of available style colors.
|
||||
*
|
||||
* \see randomStyleColorScheme()
|
||||
* \see fetchRandomStyleColor()
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
void setRandomStyleColorScheme( QgsColorScheme *scheme );
|
||||
|
||||
/**
|
||||
* Returns the color scheme used when fetching random colors to use for symbol styles.
|
||||
*
|
||||
* This may be nullptr, in which case totally random colors are used for styles.
|
||||
*
|
||||
* \see setRandomStyleColorScheme()
|
||||
* \see fetchRandomStyleColor()
|
||||
*
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
QgsColorScheme *randomStyleColorScheme();
|
||||
|
||||
/**
|
||||
* Returns a random color for use with a new symbol style (e.g. for a newly created
|
||||
* map layer).
|
||||
*
|
||||
* If a randomStyleColorScheme() is set then this color will be randomly taken from that
|
||||
* color scheme. If no randomStyleColorScheme() is set then a totally random color
|
||||
* will be generated.
|
||||
*
|
||||
* Note that calling setRandomStyleColorScheme() takes a snapshot of the colors from the scheme's
|
||||
* QgsColorScheme::fetchColors() list. Accordingly, any future changes to the colors
|
||||
* in the scheme are not automatically reflected by calls to fetchRandomStyleColor().
|
||||
* If the scheme is updated, then another call to setRandomStyleColorScheme() must
|
||||
* be made in order to update the cached list of available style colors from which
|
||||
* fetchRandomStyleColor() selects colors.
|
||||
*
|
||||
* This method is thread safe.
|
||||
*
|
||||
* \see randomStyleColorScheme()
|
||||
* \see setRandomStyleColorScheme()
|
||||
* \since QGIS 3.2
|
||||
*/
|
||||
QColor fetchRandomStyleColor() const;
|
||||
|
||||
private:
|
||||
|
||||
QList< QgsColorScheme * > mColorSchemeList;
|
||||
|
||||
QgsColorScheme *mRandomStyleColorScheme = nullptr;
|
||||
QgsNamedColorList mRandomStyleColors;
|
||||
|
||||
mutable int mNextRandomStyleColorIndex = 0;
|
||||
|
||||
int mNextRandomStyleColorDirection = 1;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "qgspolygon.h"
|
||||
#include "qgsclipper.h"
|
||||
#include "qgsproperty.h"
|
||||
#include "qgscolorschemeregistry.h"
|
||||
|
||||
#include <QColor>
|
||||
#include <QImage>
|
||||
@ -322,13 +323,7 @@ QgsSymbol *QgsSymbol::defaultSymbol( QgsWkbTypes::GeometryType geomType )
|
||||
if ( defaultSymbol.isEmpty() ||
|
||||
QgsProject::instance()->readBoolEntry( QStringLiteral( "DefaultStyles" ), QStringLiteral( "/RandomColors" ), true ) )
|
||||
{
|
||||
// Make sure we use get uniquely seeded random numbers, and not the same sequence of numbers
|
||||
std::random_device rd;
|
||||
std::mt19937 mt( rd() );
|
||||
std::uniform_int_distribution<int> hueDist( 0, 359 );
|
||||
std::uniform_int_distribution<int> satDist( 64, 255 );
|
||||
std::uniform_int_distribution<int> valueDist( 128, 255 );
|
||||
s->setColor( QColor::fromHsv( hueDist( mt ), satDist( mt ), valueDist( mt ) ) );
|
||||
s->setColor( QgsApplication::colorSchemeRegistry()->fetchRandomStyleColor() );
|
||||
}
|
||||
|
||||
return s;
|
||||
|
@ -56,6 +56,29 @@ class DummyColorScheme : public QgsColorScheme
|
||||
|
||||
};
|
||||
|
||||
class DummyColorScheme2 : public QgsColorScheme
|
||||
{
|
||||
public:
|
||||
|
||||
DummyColorScheme2() = default;
|
||||
|
||||
QString schemeName() const override { return QStringLiteral( "Dummy scheme2" ); }
|
||||
|
||||
QgsNamedColorList fetchColors( const QString & = QString(),
|
||||
const QColor & = QColor() ) override
|
||||
{
|
||||
QList< QPair< QColor, QString> > colors;
|
||||
colors << qMakePair( QColor( 255, 255, 0 ), QStringLiteral( "schemetest" ) );
|
||||
return colors;
|
||||
}
|
||||
|
||||
QgsColorScheme *clone() const override
|
||||
{
|
||||
return new DummyColorScheme2();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class TestQgsColorSchemeRegistry : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -73,6 +96,7 @@ class TestQgsColorSchemeRegistry : public QObject
|
||||
void populateFromInstance(); // check populating an empty scheme from the registry
|
||||
void removeScheme(); // check removing a scheme from a registry
|
||||
void matchingSchemes(); //check fetching schemes of specific type
|
||||
void fetchRandomStyleColor();
|
||||
|
||||
private:
|
||||
|
||||
@ -185,5 +209,47 @@ void TestQgsColorSchemeRegistry::matchingSchemes()
|
||||
QCOMPARE( dummySchemes.at( 0 ), dummyScheme );
|
||||
}
|
||||
|
||||
void TestQgsColorSchemeRegistry::fetchRandomStyleColor()
|
||||
{
|
||||
std::unique_ptr<QgsColorSchemeRegistry> registry = qgis::make_unique< QgsColorSchemeRegistry >();
|
||||
|
||||
// no randomStyleColorScheme set - test lots of colors to make sure their valid
|
||||
for ( int i = 0; i < 10000; ++i )
|
||||
{
|
||||
QVERIFY( registry->fetchRandomStyleColor().isValid() );
|
||||
}
|
||||
|
||||
// set a randomStyleColorScheme
|
||||
DummyColorScheme2 *dummyScheme = new DummyColorScheme2();
|
||||
registry->addColorScheme( dummyScheme );
|
||||
registry->setRandomStyleColorScheme( dummyScheme );
|
||||
|
||||
// only one color in scheme
|
||||
|
||||
for ( int i = 0; i < 10; ++i )
|
||||
{
|
||||
QCOMPARE( registry->fetchRandomStyleColor().name(), QStringLiteral( "#ffff00" ) );
|
||||
}
|
||||
|
||||
DummyColorScheme *dummyScheme2 = new DummyColorScheme();
|
||||
registry->addColorScheme( dummyScheme2 );
|
||||
registry->setRandomStyleColorScheme( dummyScheme2 );
|
||||
for ( int i = 0; i < 10; ++i )
|
||||
{
|
||||
QString color = registry->fetchRandomStyleColor().name();
|
||||
QVERIFY( color == QStringLiteral( "#ff0000" ) || color == QStringLiteral( "#00ff00" ) );
|
||||
}
|
||||
|
||||
// remove current random style color scheme
|
||||
registry->removeColorScheme( dummyScheme2 );
|
||||
QVERIFY( !registry->randomStyleColorScheme() );
|
||||
// no crash!
|
||||
for ( int i = 0; i < 10; ++i )
|
||||
{
|
||||
QVERIFY( registry->fetchRandomStyleColor().isValid() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsColorSchemeRegistry )
|
||||
#include "testqgscolorschemeregistry.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user