[FEATURE] Random marker fill symbol layer type

This commit adds a new fill symbol layer type "Random marker fill". It
allows polygon features to be rendered using a marker symbol placed
at random locations within the polygon boundary.

Options include:
- number of marker symbols to render for the polygon
- whether markers rendered near the edges of polygons should be clipped
to the polygon boundary or not
- an optional random number seed, to give consistent placement
of markers whenever maps are refreshed (also allows random placement
to play nice with QGIS server and tile-based rendering)

Sponsored by the SLYR project
This commit is contained in:
Nyall Dawson 2019-10-05 19:37:32 +10:00
parent fc6d01b77a
commit b5e92d41f5
12 changed files with 735 additions and 3 deletions

View File

@ -1891,6 +1891,117 @@ Returns the unit scale for the vertical offset between rows in the pattern.
QgsPointPatternFillSymbolLayer( const QgsPointPatternFillSymbolLayer &other );
};
class QgsRandomMarkerFillSymbolLayer : QgsFillSymbolLayer
{
%Docstring
A fill symbol layer which places markers at random locations within polygons.
.. versionadded:: 3.12
%End
%TypeHeaderCode
#include "qgsfillsymbollayer.h"
%End
public:
QgsRandomMarkerFillSymbolLayer( int pointCount = 1, unsigned long seed = 0 );
%Docstring
Constructor for QgsRandomMarkerFillSymbolLayer, with the specified ``pointCount``.
Optionally a specific random number ``seed`` can be used when generating points. A ``seed`` of 0 indicates that
a truely random sequence should be used.
%End
static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) /Factory/;
virtual QString layerType() const;
virtual void startRender( QgsSymbolRenderContext &context );
virtual void stopRender( QgsSymbolRenderContext &context );
virtual void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context );
virtual QgsStringMap properties() const;
virtual QgsRandomMarkerFillSymbolLayer *clone() const /Factory/;
virtual void setColor( const QColor &color );
virtual QColor color() const;
virtual QgsSymbol *subSymbol();
virtual bool setSubSymbol( QgsSymbol *symbol /Transfer/ );
virtual void setOutputUnit( QgsUnitTypes::RenderUnit unit );
virtual QgsUnitTypes::RenderUnit outputUnit() const;
virtual void setMapUnitScale( const QgsMapUnitScale &scale );
virtual QgsMapUnitScale mapUnitScale() const;
virtual QSet<QString> usedAttributes( const QgsRenderContext &context ) const;
virtual bool hasDataDefinedProperties() const;
int pointCount() const;
%Docstring
Returns the count of random points to render in the fill.
.. seealso:: :py:func:`setPointCount`
%End
void setPointCount( int count );
%Docstring
Sets the ``count`` of random points to render in the fill.
.. seealso:: :py:func:`pointCount`
%End
unsigned long seed() const;
%Docstring
Returns the random number seed to use when generating points, or 0 if
a truely random sequence should be used.
.. seealso:: :py:func:`setSeed`
%End
void setSeed( unsigned long seed );
%Docstring
Sets the random number ``seed`` to use when generating points, or 0 if
a truely random sequence should be used.
.. seealso:: :py:func:`seed`
%End
bool clipPoints() const;
%Docstring
Returns ``True`` if point markers should be clipped to the polygon boundary.
.. seealso:: :py:func:`setClipPoints`
%End
void setClipPoints( bool clipped );
%Docstring
Sets whether point markers should be ``clipped`` to the polygon boundary.
.. seealso:: :py:func:`clipPoints`
%End
private:
QgsRandomMarkerFillSymbolLayer( const QgsRandomMarkerFillSymbolLayer &other );
};
class QgsCentroidFillSymbolLayer : QgsFillSymbolLayer
{

View File

@ -135,6 +135,9 @@ class QgsSymbolLayer
PropertyArrowType,
PropertyOffsetX,
PropertyOffsetY,
PropertyPointCount,
PropertyRandomSeed,
PropertyClipPoints,
};
static const QgsPropertiesDefinition &propertyDefinitions();

View File

@ -655,6 +655,40 @@ Creates a new QgsPointPatternFillSymbolLayerWidget.
class QgsRandomMarkerFillSymbolLayerWidget: QgsSymbolLayerWidget
{
%TypeHeaderCode
#include "qgssymbollayerwidget.h"
%End
public:
QgsRandomMarkerFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent /TransferThis/ = 0 );
%Docstring
Constructor for QgsRandomMarkerFillSymbolLayerWidget.
:param vl: associated vector layer
:param parent: parent widget
%End
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) /Factory/;
%Docstring
Creates a new QgsRandomMarkerFillSymbolLayerWidget.
:param vl: associated vector layer
%End
virtual void setSymbolLayer( QgsSymbolLayer *layer );
virtual QgsSymbolLayer *symbolLayer();
};
class QgsFontMarkerSymbolLayerWidget : QgsSymbolLayerWidget
{

View File

@ -31,6 +31,8 @@
#include "qgsmessagelog.h"
#include "qgsapplication.h"
#include "qgsimageoperation.h"
#include "qgspolygon.h"
#include "qgslinestring.h"
#include <QPainter>
#include <QFile>
@ -3909,3 +3911,250 @@ void QgsRasterFillSymbolLayer::applyPattern( QBrush &brush, const QString &image
brush.setTextureImage( img );
}
//
// QgsRandomMarkerFillSymbolLayer
//
QgsRandomMarkerFillSymbolLayer::QgsRandomMarkerFillSymbolLayer( int pointCount, unsigned long seed )
: mPointCount( pointCount )
, mSeed( seed )
{
setSubSymbol( new QgsMarkerSymbol() );
}
QgsSymbolLayer *QgsRandomMarkerFillSymbolLayer::create( const QgsStringMap &properties )
{
const int pointCount = properties.value( QStringLiteral( "point_count" ), QStringLiteral( "1" ) ).toInt();
const unsigned long seed = properties.value( QStringLiteral( "seed" ), QStringLiteral( "0" ) ).toULong();
std::unique_ptr< QgsRandomMarkerFillSymbolLayer > sl = qgis::make_unique< QgsRandomMarkerFillSymbolLayer >( pointCount, seed );
if ( properties.contains( QStringLiteral( "clip_points" ) ) )
{
sl->setClipPoints( properties[QStringLiteral( "clip_points" )].toInt() );
}
return sl.release();
}
QString QgsRandomMarkerFillSymbolLayer::layerType() const
{
return QStringLiteral( "RandomMarkerFill" );
}
void QgsRandomMarkerFillSymbolLayer::setColor( const QColor &color )
{
mMarker->setColor( color );
mColor = color;
}
QColor QgsRandomMarkerFillSymbolLayer::color() const
{
return mMarker ? mMarker->color() : mColor;
}
void QgsRandomMarkerFillSymbolLayer::startRender( QgsSymbolRenderContext &context )
{
mMarker->setOpacity( context.opacity() );
mMarker->startRender( context.renderContext(), context.fields() );
}
void QgsRandomMarkerFillSymbolLayer::stopRender( QgsSymbolRenderContext &context )
{
mMarker->stopRender( context.renderContext() );
}
void QgsRandomMarkerFillSymbolLayer::renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context )
{
QgsGeometry geom = QgsGeometry::fromQPolygonF( points );
if ( !geom.isNull() && rings )
{
QgsPolygon *poly = qgsgeometry_cast< QgsPolygon * >( geom.get() );
const QList< QPolygonF > constRings = *rings;
for ( const QPolygonF &ring : constRings )
{
poly->addInteriorRing( QgsLineString::fromQPolygonF( ring ) );
}
}
if ( !geom.isGeosValid() )
{
geom = geom.buffer( 0, 0 );
}
bool clipPoints = mClipPoints;
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyClipPoints ) )
{
context.setOriginalValueVariable( clipPoints );
clipPoints = mDataDefinedProperties.valueAsBool( QgsSymbolLayer::PropertyClipPoints, context.renderContext().expressionContext(), clipPoints );
}
if ( clipPoints )
{
QPainterPath path;
path.addPolygon( points );
if ( rings )
{
const QList< QPolygonF > constRings = *rings;
for ( const QPolygonF &ring : constRings )
{
path.addPolygon( ring );
}
}
context.renderContext().painter()->save();
context.renderContext().painter()->setClipPath( path );
}
int count = mPointCount;
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyPointCount ) )
{
context.setOriginalValueVariable( count );
count = mDataDefinedProperties.valueAsInt( QgsSymbolLayer::PropertyPointCount, context.renderContext().expressionContext(), count );
}
unsigned long seed = mSeed;
if ( mDataDefinedProperties.isActive( QgsSymbolLayer::PropertyRandomSeed ) )
{
context.setOriginalValueVariable( static_cast< unsigned long long >( seed ) );
seed = mDataDefinedProperties.valueAsInt( QgsSymbolLayer::PropertyRandomSeed, context.renderContext().expressionContext(), seed );
}
QVector< QgsPointXY > randomPoints = geom.randomPointsInPolygon( count, seed );
#if 0
std::sort( randomPoints.begin(), randomPoints.end(), []( const QgsPointXY & a, const QgsPointXY & b )->bool
{
return a.y() < b.y();
} );
#endif
for ( const QgsPointXY &p : qgis::as_const( randomPoints ) )
{
mMarker->renderPoint( QPointF( p.x(), p.y() ), context.feature(), context.renderContext(), -1, context.selected() );
}
if ( clipPoints )
{
context.renderContext().painter()->restore();
}
}
QgsStringMap QgsRandomMarkerFillSymbolLayer::properties() const
{
QgsStringMap map;
map.insert( QStringLiteral( "point_count" ), QString::number( mPointCount ) );
map.insert( QStringLiteral( "seed" ), QString::number( mSeed ) );
map.insert( QStringLiteral( "clip_points" ), QString::number( mClipPoints ) );
return map;
}
QgsRandomMarkerFillSymbolLayer *QgsRandomMarkerFillSymbolLayer::clone() const
{
std::unique_ptr< QgsRandomMarkerFillSymbolLayer > x = qgis::make_unique< QgsRandomMarkerFillSymbolLayer >( mPointCount, mSeed );
x->mAngle = mAngle;
x->mColor = mColor;
x->mClipPoints = mClipPoints;
x->setSubSymbol( mMarker->clone() );
copyDataDefinedProperties( x.get() );
copyPaintEffect( x.get() );
return x.release();
}
QgsSymbol *QgsRandomMarkerFillSymbolLayer::subSymbol()
{
return mMarker.get();
}
bool QgsRandomMarkerFillSymbolLayer::setSubSymbol( QgsSymbol *symbol )
{
if ( !symbol || symbol->type() != QgsSymbol::Marker )
{
delete symbol;
return false;
}
mMarker.reset( static_cast<QgsMarkerSymbol *>( symbol ) );
mColor = mMarker->color();
return true;
}
QSet<QString> QgsRandomMarkerFillSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
{
QSet<QString> attributes = QgsFillSymbolLayer::usedAttributes( context );
if ( mMarker )
attributes.unite( mMarker->usedAttributes( context ) );
return attributes;
}
bool QgsRandomMarkerFillSymbolLayer::hasDataDefinedProperties() const
{
if ( QgsSymbolLayer::hasDataDefinedProperties() )
return true;
if ( mMarker && mMarker->hasDataDefinedProperties() )
return true;
return false;
}
int QgsRandomMarkerFillSymbolLayer::pointCount() const
{
return mPointCount;
}
void QgsRandomMarkerFillSymbolLayer::setPointCount( int pointCount )
{
mPointCount = pointCount;
}
unsigned long QgsRandomMarkerFillSymbolLayer::seed() const
{
return mSeed;
}
void QgsRandomMarkerFillSymbolLayer::setSeed( unsigned long seed )
{
mSeed = seed;
}
bool QgsRandomMarkerFillSymbolLayer::clipPoints() const
{
return mClipPoints;
}
void QgsRandomMarkerFillSymbolLayer::setClipPoints( bool clipPoints )
{
mClipPoints = clipPoints;
}
void QgsRandomMarkerFillSymbolLayer::setOutputUnit( QgsUnitTypes::RenderUnit unit )
{
if ( mMarker )
{
mMarker->setOutputUnit( unit );
}
}
QgsUnitTypes::RenderUnit QgsRandomMarkerFillSymbolLayer::outputUnit() const
{
if ( mMarker )
{
return mMarker->outputUnit();
}
return QgsUnitTypes::RenderUnknownUnit; //mOutputUnit;
}
void QgsRandomMarkerFillSymbolLayer::setMapUnitScale( const QgsMapUnitScale &scale )
{
if ( mMarker )
{
mMarker->setMapUnitScale( scale );
}
}
QgsMapUnitScale QgsRandomMarkerFillSymbolLayer::mapUnitScale() const
{
if ( mMarker )
{
return mMarker->mapUnitScale();
}
return QgsMapUnitScale();
}

View File

@ -1702,6 +1702,106 @@ class CORE_EXPORT QgsPointPatternFillSymbolLayer: public QgsImageFillSymbolLayer
double displacementX, double displacementY, double offsetX, double offsetY );
};
/**
* \ingroup core
* \class QgsRandomMarkerFillSymbolLayer
*
* A fill symbol layer which places markers at random locations within polygons.
*
* \since QGIS 3.12
*/
class CORE_EXPORT QgsRandomMarkerFillSymbolLayer : public QgsFillSymbolLayer
{
public:
/**
* Constructor for QgsRandomMarkerFillSymbolLayer, with the specified \a pointCount.
*
* Optionally a specific random number \a seed can be used when generating points. A \a seed of 0 indicates that
* a truely random sequence should be used.
*/
QgsRandomMarkerFillSymbolLayer( int pointCount = 1, unsigned long seed = 0 );
static QgsSymbolLayer *create( const QgsStringMap &properties = QgsStringMap() ) SIP_FACTORY;
QString layerType() const override;
void startRender( QgsSymbolRenderContext &context ) override;
void stopRender( QgsSymbolRenderContext &context ) override;
void renderPolygon( const QPolygonF &points, QList<QPolygonF> *rings, QgsSymbolRenderContext &context ) override;
QgsStringMap properties() const override;
QgsRandomMarkerFillSymbolLayer *clone() const override SIP_FACTORY;
void setColor( const QColor &color ) override;
QColor color() const override;
QgsSymbol *subSymbol() override;
bool setSubSymbol( QgsSymbol *symbol SIP_TRANSFER ) override;
void setOutputUnit( QgsUnitTypes::RenderUnit unit ) override;
QgsUnitTypes::RenderUnit outputUnit() const override;
void setMapUnitScale( const QgsMapUnitScale &scale ) override;
QgsMapUnitScale mapUnitScale() const override;
QSet<QString> usedAttributes( const QgsRenderContext &context ) const override;
bool hasDataDefinedProperties() const override;
/**
* Returns the count of random points to render in the fill.
*
* \see setPointCount()
*/
int pointCount() const;
/**
* Sets the \a count of random points to render in the fill.
*
* \see pointCount()
*/
void setPointCount( int count );
/**
* Returns the random number seed to use when generating points, or 0 if
* a truely random sequence should be used.
*
* \see setSeed()
*/
unsigned long seed() const;
/**
* Sets the random number \a seed to use when generating points, or 0 if
* a truely random sequence should be used.
*
* \see seed()
*/
void setSeed( unsigned long seed );
/**
* Returns TRUE if point markers should be clipped to the polygon boundary.
*
* \see setClipPoints()
*/
bool clipPoints() const;
/**
* Sets whether point markers should be \a clipped to the polygon boundary.
*
* \see clipPoints()
*/
void setClipPoints( bool clipped );
private:
#ifdef SIP_RUN
QgsRandomMarkerFillSymbolLayer( const QgsRandomMarkerFillSymbolLayer &other );
#endif
std::unique_ptr< QgsMarkerSymbol > mMarker;
int mPointCount = 1;
unsigned long mSeed = 0;
bool mClipPoints = false;
};
/**
* \ingroup core
* \class QgsCentroidFillSymbolLayer

View File

@ -93,9 +93,11 @@ void QgsSymbolLayer::initPropertyDefinitions()
{ QgsSymbolLayer::PropertyArrowStartWidth, QgsPropertyDefinition( "arrowStartWidth", QObject::tr( "Arrow line start width" ), QgsPropertyDefinition::StrokeWidth, origin )},
{ QgsSymbolLayer::PropertyArrowHeadLength, QgsPropertyDefinition( "arrowHeadLength", QObject::tr( "Arrow head length" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyArrowHeadThickness, QgsPropertyDefinition( "arrowHeadThickness", QObject::tr( "Arrow head thickness" ), QgsPropertyDefinition::DoublePositive, origin )},
{ QgsSymbolLayer::PropertyArrowHeadType, QgsPropertyDefinition( "arrowHeadType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow head type" ), QObject::tr( "string " ) + QLatin1String( "[<b>single</b>|<b>reversed</b>|<b>double</b>]" ) )},
{ QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow type" ), QObject::tr( "string " ) + QLatin1String( "[<b>plain</b>|<b>lefthalf</b>|<b>righthalf</b>]" ) )},
{ QgsSymbolLayer::PropertyArrowHeadType, QgsPropertyDefinition( "arrowHeadType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow head type" ), QObject::tr( "string " ) + QLatin1String( "[<b>single</b>|<b>reversed</b>|<b>double</b>]" ), origin )},
{ QgsSymbolLayer::PropertyArrowType, QgsPropertyDefinition( "arrowType", QgsPropertyDefinition::DataTypeString, QObject::tr( "Arrow type" ), QObject::tr( "string " ) + QLatin1String( "[<b>plain</b>|<b>lefthalf</b>|<b>righthalf</b>]" ), origin )},
{ QgsSymbolLayer::PropertyPointCount, QgsPropertyDefinition( "pointCount", QObject::tr( "Point count" ), QgsPropertyDefinition::IntegerPositive, origin )},
{ QgsSymbolLayer::PropertyRandomSeed, QgsPropertyDefinition( "randomSeed", QgsPropertyDefinition::DataTypeNumeric, QObject::tr( "Random number seed" ), QObject::tr( "integer > 0, or 0 for completely random sequence" ), origin )},
{ QgsSymbolLayer::PropertyClipPoints, QgsPropertyDefinition( "clipPoints", QObject::tr( "Clip markers" ), QgsPropertyDefinition::Boolean, origin )},
};
}

View File

@ -177,6 +177,9 @@ class CORE_EXPORT QgsSymbolLayer
PropertyArrowType, //!< Arrow type
PropertyOffsetX, //!< Horizontal offset
PropertyOffsetY, //!< Vertical offset
PropertyPointCount, //!< Point count
PropertyRandomSeed, //!< Random number seed
PropertyClipPoints, //!< Whether markers should be clipped to polygon boundaries
};
/**

View File

@ -61,6 +61,8 @@ QgsSymbolLayerRegistry::QgsSymbolLayerRegistry()
QgsSVGFillSymbolLayer::create, QgsSVGFillSymbolLayer::createFromSld, QgsSVGFillSymbolLayer::resolvePaths ) );
addSymbolLayerType( new QgsSymbolLayerMetadata( QStringLiteral( "CentroidFill" ), QObject::tr( "Centroid fill" ), QgsSymbol::Fill,
QgsCentroidFillSymbolLayer::create, QgsCentroidFillSymbolLayer::createFromSld ) );
addSymbolLayerType( new QgsSymbolLayerMetadata( QStringLiteral( "RandomMarkerFill" ), QObject::tr( "Random marker fill" ), QgsSymbol::Fill,
QgsRandomMarkerFillSymbolLayer::create ) );
addSymbolLayerType( new QgsSymbolLayerMetadata( QStringLiteral( "LinePatternFill" ), QObject::tr( "Line pattern fill" ), QgsSymbol::Fill,
QgsLinePatternFillSymbolLayer::create, QgsLinePatternFillSymbolLayer::createFromSld ) );
addSymbolLayerType( new QgsSymbolLayerMetadata( QStringLiteral( "PointPatternFill" ), QObject::tr( "Point pattern fill" ), QgsSymbol::Fill,

View File

@ -87,6 +87,7 @@ static void _initWidgetFunctions()
_initWidgetFunction( QStringLiteral( "CentroidFill" ), QgsCentroidFillSymbolLayerWidget::create );
_initWidgetFunction( QStringLiteral( "LinePatternFill" ), QgsLinePatternFillSymbolLayerWidget::create );
_initWidgetFunction( QStringLiteral( "PointPatternFill" ), QgsPointPatternFillSymbolLayerWidget::create );
_initWidgetFunction( QStringLiteral( "RandomMarkerFill" ), QgsRandomMarkerFillSymbolLayerWidget::create );
_initWidgetFunction( QStringLiteral( "GeometryGenerator" ), QgsGeometryGeneratorSymbolLayerWidget::create );

View File

@ -4109,3 +4109,68 @@ void QgsGeometryGeneratorSymbolLayerWidget::updateSymbolType()
emit symbolChanged();
}
//
// QgsRandomMarkerFillSymbolLayerWidget
//
QgsRandomMarkerFillSymbolLayerWidget::QgsRandomMarkerFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent ):
QgsSymbolLayerWidget( parent, vl )
{
setupUi( this );
mPointCountSpinBox->setShowClearButton( true );
mPointCountSpinBox->setClearValue( 100 );
mSeedSpinBox->setShowClearButton( true );
mSeedSpinBox->setClearValue( 0 );
connect( mPointCountSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsRandomMarkerFillSymbolLayerWidget::countChanged );
connect( mSeedSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsRandomMarkerFillSymbolLayerWidget::seedChanged );
connect( mClipPointsCheckBox, &QCheckBox::toggled, this, [ = ]( bool checked )
{
if ( mLayer )
{
mLayer->setClipPoints( checked );
emit changed();
}
} );
}
void QgsRandomMarkerFillSymbolLayerWidget::setSymbolLayer( QgsSymbolLayer *layer )
{
if ( !layer || layer->layerType() != QLatin1String( "RandomMarkerFill" ) )
{
return;
}
mLayer = static_cast<QgsRandomMarkerFillSymbolLayer *>( layer );
whileBlocking( mPointCountSpinBox )->setValue( mLayer->pointCount() );
whileBlocking( mSeedSpinBox )->setValue( mLayer->seed() );
whileBlocking( mClipPointsCheckBox )->setChecked( mLayer->clipPoints() );
registerDataDefinedButton( mPointCountDdbtn, QgsSymbolLayer::PropertyPointCount );
registerDataDefinedButton( mSeedDdbtn, QgsSymbolLayer::PropertyRandomSeed );
registerDataDefinedButton( mClipPointsDdbtn, QgsSymbolLayer::PropertyClipPoints );
}
QgsSymbolLayer *QgsRandomMarkerFillSymbolLayerWidget::symbolLayer()
{
return mLayer;
}
void QgsRandomMarkerFillSymbolLayerWidget::countChanged( int d )
{
if ( mLayer )
{
mLayer->setPointCount( d );
emit changed();
}
}
void QgsRandomMarkerFillSymbolLayerWidget::seedChanged( int d )
{
if ( mLayer )
{
mLayer->setSeed( d );
emit changed();
}
}

View File

@ -888,6 +888,48 @@ class GUI_EXPORT QgsPointPatternFillSymbolLayerWidget: public QgsSymbolLayerWidg
void mVerticalOffsetUnitWidget_changed();
};
//////////
#include "ui_widget_randommarkerfill.h"
class QgsRandomMarkerFillSymbolLayer;
/**
* \ingroup gui
* \class QgsRandomMarkerFillSymbolLayerWidget
*/
class GUI_EXPORT QgsRandomMarkerFillSymbolLayerWidget: public QgsSymbolLayerWidget, private Ui::WidgetRandomMarkerFill
{
Q_OBJECT
public:
/**
* Constructor for QgsRandomMarkerFillSymbolLayerWidget.
* \param vl associated vector layer
* \param parent parent widget
*/
QgsRandomMarkerFillSymbolLayerWidget( QgsVectorLayer *vl, QWidget *parent SIP_TRANSFERTHIS = nullptr );
/**
* Creates a new QgsRandomMarkerFillSymbolLayerWidget.
* \param vl associated vector layer
*/
static QgsSymbolLayerWidget *create( QgsVectorLayer *vl ) SIP_FACTORY { return new QgsRandomMarkerFillSymbolLayerWidget( vl ); }
void setSymbolLayer( QgsSymbolLayer *layer ) override;
QgsSymbolLayer *symbolLayer() override;
private:
QgsRandomMarkerFillSymbolLayer *mLayer = nullptr;
private slots:
void countChanged( int d );
void seedChanged( int d );
};
/////////
#include "ui_widget_fontmarker.h"

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WidgetRandomMarkerFill</class>
<widget class="QWidget" name="WidgetRandomMarkerFill">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>401</width>
<height>225</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0">
<item row="1" column="2">
<widget class="QgsPropertyOverrideButton" name="mSeedDdbtn">
<property name="text">
<string>…</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Seed</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mPointCountLabel">
<property name="text">
<string>Point count</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="3">
<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>
<item row="0" column="1">
<widget class="QgsSpinBox" name="mPointCountSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QgsSpinBox" name="mSeedSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="specialValueText">
<string>randomised</string>
</property>
<property name="maximum">
<number>999999999</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QgsPropertyOverrideButton" name="mPointCountDdbtn">
<property name="text">
<string>…</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="2">
<widget class="QCheckBox" name="mClipPointsCheckBox">
<property name="text">
<string>Clip markers to polygon boundary</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QgsPropertyOverrideButton" name="mClipPointsDdbtn">
<property name="text">
<string>…</string>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsPropertyOverrideButton</class>
<extends>QToolButton</extends>
<header>qgspropertyoverridebutton.h</header>
</customwidget>
<customwidget>
<class>QgsSpinBox</class>
<extends>QSpinBox</extends>
<header>qgsspinbox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mPointCountDdbtn</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>