Skip to content

Commit fef8c1f

Browse files
committed
[FEATURE] add setting to control centroid fill point rendering
on all parts or a single part of multi-features (fixes #9199)
1 parent 77d95b0 commit fef8c1f

15 files changed

+314
-9
lines changed

python/core/symbology-ng/qgsfillsymbollayerv2.sip

+7
Original file line numberDiff line numberDiff line change
@@ -893,4 +893,11 @@ class QgsCentroidFillSymbolLayerV2 : QgsFillSymbolLayerV2
893893

894894
void setPointOnSurface( bool pointOnSurface );
895895
bool pointOnSurface() const;
896+
897+
/** Sets whether a point is drawn for all parts or only on the biggest part of multi-part features.
898+
* @note added in 2.16 */
899+
void setPointOnAllParts( bool pointOnAllParts );
900+
/** Returns whether a point is drawn for all parts or only on the biggest part of multi-part features.
901+
* @note added in 2.16 */
902+
bool pointOnAllParts() const;
896903
};

python/core/symbology-ng/qgssymbolv2.sip

+18
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,24 @@ class QgsSymbolV2RenderContext
317317
//! @note added in 2.4
318318
const QgsFields* fields() const;
319319

320+
/** Part count of current geometry
321+
* @note added in QGIS 2.16
322+
*/
323+
int geometryPartCount() const;
324+
/** Sets the part count of current geometry
325+
* @note added in QGIS 2.16
326+
*/
327+
void setGeometryPartCount( int count );
328+
329+
/** Part number of current geometry
330+
* @note added in QGIS 2.16
331+
*/
332+
int geometryPartNum() const;
333+
/** Sets the part number of current geometry
334+
* @note added in QGIS 2.16
335+
*/
336+
void setGeometryPartNum( int num );
337+
320338
double outputLineWidth( double width ) const;
321339
double outputPixelSize( double size ) const;
322340

src/core/symbology-ng/qgsfillsymbollayerv2.cpp

+48-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "qgssymbollayerv2utils.h"
2020
#include "qgsdxfexport.h"
2121
#include "qgsexpression.h"
22+
#include "qgsgeometry.h"
23+
#include "qgsgeometrycollectionv2.h"
2224
#include "qgsrendercontext.h"
2325
#include "qgsproject.h"
2426
#include "qgssvgcache.h"
@@ -3384,7 +3386,7 @@ QSet<QString> QgsPointPatternFillSymbolLayer::usedAttributes() const
33843386
//////////////
33853387

33863388

3387-
QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( nullptr ), mPointOnSurface( false )
3389+
QgsCentroidFillSymbolLayerV2::QgsCentroidFillSymbolLayerV2(): mMarker( nullptr ), mPointOnSurface( false ), mPointOnAllParts( true )
33883390
{
33893391
setSubSymbol( new QgsMarkerSymbolV2() );
33903392
}
@@ -3400,6 +3402,8 @@ QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2::create( const QgsStringMap& prop
34003402

34013403
if ( properties.contains( "point_on_surface" ) )
34023404
sl->setPointOnSurface( properties["point_on_surface"].toInt() != 0 );
3405+
if ( properties.contains( "point_on_all_parts" ) )
3406+
sl->setPointOnAllParts( properties["point_on_all_parts"].toInt() != 0 );
34033407

34043408
return sl;
34053409
}
@@ -3419,6 +3423,9 @@ void QgsCentroidFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& contex
34193423
{
34203424
mMarker->setAlpha( context.alpha() );
34213425
mMarker->startRender( context.renderContext(), context.fields() );
3426+
3427+
mCurrentFeatureId = -1;
3428+
mBiggestPartIndex = 0;
34223429
}
34233430

34243431
void QgsCentroidFillSymbolLayerV2::stopRender( QgsSymbolV2RenderContext& context )
@@ -3430,14 +3437,51 @@ void QgsCentroidFillSymbolLayerV2::renderPolygon( const QPolygonF& points, QList
34303437
{
34313438
Q_UNUSED( rings );
34323439

3433-
QPointF centroid = mPointOnSurface ? QgsSymbolLayerV2Utils::polygonPointOnSurface( points ) : QgsSymbolLayerV2Utils::polygonCentroid( points );
3434-
mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
3440+
if ( !mPointOnAllParts )
3441+
{
3442+
const QgsFeature* feature = context.feature();
3443+
if ( feature )
3444+
{
3445+
if ( feature->id() != mCurrentFeatureId )
3446+
{
3447+
mCurrentFeatureId = feature->id();
3448+
mBiggestPartIndex = 1;
3449+
3450+
if ( context.geometryPartCount() > 1 )
3451+
{
3452+
const QgsGeometry *geom = feature->constGeometry();
3453+
const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );
3454+
3455+
double area = 0;
3456+
double areaBiggest = 0;
3457+
for ( int i = 0; i < context.geometryPartCount(); ++i )
3458+
{
3459+
area = geomCollection->geometryN( i )->area();
3460+
if ( area > areaBiggest )
3461+
{
3462+
areaBiggest = area;
3463+
mBiggestPartIndex = i + 1;
3464+
}
3465+
}
3466+
}
3467+
}
3468+
}
3469+
}
3470+
3471+
QgsDebugMsg( QString( "num: %1, count: %2" ).arg( context.geometryPartNum() ).arg( context.geometryPartCount() ) );
3472+
3473+
if ( mPointOnAllParts || ( context.geometryPartNum() == mBiggestPartIndex ) )
3474+
{
3475+
QPointF centroid = mPointOnSurface ? QgsSymbolLayerV2Utils::polygonPointOnSurface( points ) : QgsSymbolLayerV2Utils::polygonCentroid( points );
3476+
mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
3477+
}
34353478
}
34363479

34373480
QgsStringMap QgsCentroidFillSymbolLayerV2::properties() const
34383481
{
34393482
QgsStringMap map;
34403483
map["point_on_surface"] = QString::number( mPointOnSurface );
3484+
map["point_on_all_parts"] = QString::number( mPointOnAllParts );
34413485
return map;
34423486
}
34433487

@@ -3448,6 +3492,7 @@ QgsCentroidFillSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
34483492
x->mColor = mColor;
34493493
x->setSubSymbol( mMarker->clone() );
34503494
x->setPointOnSurface( mPointOnSurface );
3495+
x->setPointOnAllParts( mPointOnAllParts );
34513496
copyPaintEffect( x );
34523497
return x;
34533498
}

src/core/symbology-ng/qgsfillsymbollayerv2.h

+11
Original file line numberDiff line numberDiff line change
@@ -1095,9 +1095,20 @@ class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2
10951095
void setPointOnSurface( bool pointOnSurface ) { mPointOnSurface = pointOnSurface; }
10961096
bool pointOnSurface() const { return mPointOnSurface; }
10971097

1098+
/** Sets whether a point is drawn for all parts or only on the biggest part of multi-part features.
1099+
* @note added in 2.16 */
1100+
void setPointOnAllParts( bool pointOnAllParts ) { mPointOnAllParts = pointOnAllParts; }
1101+
/** Returns whether a point is drawn for all parts or only on the biggest part of multi-part features.
1102+
* @note added in 2.16 */
1103+
bool pointOnAllParts() const { return mPointOnAllParts; }
1104+
10981105
protected:
10991106
QgsMarkerSymbolV2* mMarker;
11001107
bool mPointOnSurface;
1108+
bool mPointOnAllParts;
1109+
1110+
QgsFeatureId mCurrentFeatureId;
1111+
int mBiggestPartIndex;
11011112
};
11021113

11031114
#endif

src/core/symbology-ng/qgssymbolv2.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -733,11 +733,14 @@ void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& co
733733
deleteSegmentizedGeometry = true;
734734
}
735735

736+
mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry->geometry()->partCount() );
737+
mSymbolRenderContext->setGeometryPartNum( 1 );
738+
736739
if ( mSymbolRenderContext->expressionContextScope() )
737740
{
738741
context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
739742
QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
740-
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, segmentizedGeometry->geometry()->partCount() );
743+
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount() );
741744
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1 );
742745
}
743746

@@ -833,6 +836,7 @@ void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& co
833836

834837
for ( int i = 0; i < mp->numGeometries(); ++i )
835838
{
839+
mSymbolRenderContext->setGeometryPartNum( i + 1 );
836840
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1 );
837841

838842
const QgsPointV2* point = static_cast< const QgsPointV2* >( mp->geometryN( i ) );
@@ -868,6 +872,7 @@ void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& co
868872

869873
for ( unsigned int i = 0; i < num && wkbPtr; ++i )
870874
{
875+
mSymbolRenderContext->setGeometryPartNum( i + 1 );
871876
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1 );
872877

873878
if ( geomCollection )
@@ -914,6 +919,7 @@ void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& co
914919

915920
for ( unsigned int i = 0; i < num && wkbPtr; ++i )
916921
{
922+
mSymbolRenderContext->setGeometryPartNum( i + 1 );
917923
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, i + 1 );
918924

919925
if ( geomCollection )
@@ -1002,7 +1008,9 @@ QgsSymbolV2RenderContext::QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymb
10021008
mSelected( selected ),
10031009
mRenderHints( renderHints ),
10041010
mFeature( f ),
1005-
mFields( fields )
1011+
mFields( fields ),
1012+
mGeometryPartCount( 0 ),
1013+
mGeometryPartNum( 0 )
10061014
{
10071015
}
10081016

@@ -1440,6 +1448,8 @@ void QgsMarkerSymbolV2::renderPointUsingLayer( QgsMarkerSymbolLayerV2* layer, QP
14401448
void QgsMarkerSymbolV2::renderPoint( QPointF point, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
14411449
{
14421450
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1451+
symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1452+
symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
14431453

14441454
if ( layerIdx != -1 )
14451455
{
@@ -1646,6 +1656,8 @@ void QgsLineSymbolV2::renderPolyline( const QPolygonF& points, const QgsFeature*
16461656
//save old painter
16471657
QPainter* renderPainter = context.painter();
16481658
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1659+
symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1660+
symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
16491661

16501662
if ( layerIdx != -1 )
16511663
{
@@ -1723,6 +1735,8 @@ QgsFillSymbolV2::QgsFillSymbolV2( const QgsSymbolLayerV2List& layers )
17231735
void QgsFillSymbolV2::renderPolygon( const QPolygonF& points, QList<QPolygonF>* rings, const QgsFeature* f, QgsRenderContext& context, int layerIdx, bool selected )
17241736
{
17251737
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, selected, mRenderHints, f, nullptr, mapUnitScale() );
1738+
symbolContext.setGeometryPartCount( symbolRenderContext()->geometryPartCount() );
1739+
symbolContext.setGeometryPartNum( symbolRenderContext()->geometryPartNum() );
17261740

17271741
if ( layerIdx != -1 )
17281742
{

src/core/symbology-ng/qgssymbolv2.h

+20
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,24 @@ class CORE_EXPORT QgsSymbolV2RenderContext
379379
//! @note added in 2.4
380380
const QgsFields* fields() const { return mFields; }
381381

382+
/** Part count of current geometry
383+
* @note added in QGIS 2.16
384+
*/
385+
int geometryPartCount() const { return mGeometryPartCount; }
386+
/** Sets the part count of current geometry
387+
* @note added in QGIS 2.16
388+
*/
389+
void setGeometryPartCount( int count ) { mGeometryPartCount = count; }
390+
391+
/** Part number of current geometry
392+
* @note added in QGIS 2.16
393+
*/
394+
int geometryPartNum() const { return mGeometryPartNum; }
395+
/** Sets the part number of current geometry
396+
* @note added in QGIS 2.16
397+
*/
398+
void setGeometryPartNum( int num ) { mGeometryPartNum = num; }
399+
382400
double outputLineWidth( double width ) const;
383401
double outputPixelSize( double size ) const;
384402

@@ -410,6 +428,8 @@ class CORE_EXPORT QgsSymbolV2RenderContext
410428
int mRenderHints;
411429
const QgsFeature* mFeature; //current feature
412430
const QgsFields* mFields;
431+
int mGeometryPartCount;
432+
int mGeometryPartNum;
413433

414434

415435
QgsSymbolV2RenderContext( const QgsSymbolV2RenderContext& rh );

src/gui/symbology-ng/qgssymbollayerv2widget.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -2737,9 +2737,8 @@ void QgsCentroidFillSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer
27372737
mLayer = static_cast<QgsCentroidFillSymbolLayerV2*>( layer );
27382738

27392739
// set values
2740-
mDrawInsideCheckBox->blockSignals( true );
2741-
mDrawInsideCheckBox->setChecked( mLayer->pointOnSurface() );
2742-
mDrawInsideCheckBox->blockSignals( false );
2740+
whileBlocking( mDrawInsideCheckBox )->setChecked( mLayer->pointOnSurface() );
2741+
whileBlocking( mDrawAllPartsCheckBox )->setChecked( mLayer->pointOnAllParts() );
27432742
}
27442743

27452744
QgsSymbolLayerV2* QgsCentroidFillSymbolLayerV2Widget::symbolLayer()
@@ -2753,6 +2752,12 @@ void QgsCentroidFillSymbolLayerV2Widget::on_mDrawInsideCheckBox_stateChanged( in
27532752
emit changed();
27542753
}
27552754

2755+
void QgsCentroidFillSymbolLayerV2Widget::on_mDrawAllPartsCheckBox_stateChanged( int state )
2756+
{
2757+
mLayer->setPointOnAllParts( state == Qt::Checked );
2758+
emit changed();
2759+
}
2760+
27562761
///////////////
27572762

27582763
QgsRasterFillSymbolLayerWidget::QgsRasterFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )

src/gui/symbology-ng/qgssymbollayerv2widget.h

+1
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ class GUI_EXPORT QgsCentroidFillSymbolLayerV2Widget : public QgsSymbolLayerV2Wid
627627

628628
private slots:
629629
void on_mDrawInsideCheckBox_stateChanged( int state );
630+
void on_mDrawAllPartsCheckBox_stateChanged( int state );
630631

631632
};
632633

src/ui/symbollayer/widget_centroidfill.ui

+15-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
</property>
1616
<layout class="QVBoxLayout" name="verticalLayout">
1717
<item>
18-
<layout class="QHBoxLayout" name="horizontalLayout">
18+
<layout class="QHBoxLayout" name="horizontalLayout_1">
1919
<item>
2020
<widget class="QCheckBox" name="mDrawInsideCheckBox">
2121
<property name="text">
@@ -41,6 +41,20 @@
4141
</item>
4242
</layout>
4343
</item>
44+
<item>
45+
<layout class="QHBoxLayout" name="horizontalLayout">
46+
<item>
47+
<widget class="QCheckBox" name="mDrawAllPartsCheckBox">
48+
<property name="text">
49+
<string>Draw point on every part of multi-part features</string>
50+
</property>
51+
<property name="toolTip">
52+
<string>When unchecked, a single point will be drawn on the biggest part of multi-part features</string>
53+
</property>
54+
</widget>
55+
</item>
56+
</layout>
57+
</item>
4458
<item>
4559
<spacer>
4660
<property name="orientation">

tests/src/core/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ ADD_QGIS_TEST(invertedpolygontest testqgsinvertedpolygonrenderer.cpp )
145145
ADD_QGIS_TEST(labelingenginev2 testqgslabelingenginev2.cpp)
146146
ADD_QGIS_TEST(layertree testqgslayertree.cpp)
147147
ADD_QGIS_TEST(legendrenderertest testqgslegendrenderer.cpp )
148+
ADD_QGIS_TEST(centroidfillsymboltest testqgscentroidfillsymbol.cpp )
148149
ADD_QGIS_TEST(linefillsymboltest testqgslinefillsymbol.cpp )
149150
ADD_QGIS_TEST(maplayerstylemanager testqgsmaplayerstylemanager.cpp )
150151
ADD_QGIS_TEST(maplayertest testqgsmaplayer.cpp)

0 commit comments

Comments
 (0)