Skip to content
Permalink
Browse files

Merge pull request #3026 from nirvn/centroid_fill_parts

[FEATURE] add setting to control centroid fill point rendering on all parts or a single part of multi-features
  • Loading branch information
nyalldawson committed Apr 28, 2016
2 parents d69910a + fef8c1f commit 93d984e504016b75d190976b33a1733868da6e3b
@@ -893,4 +893,11 @@ class QgsCentroidFillSymbolLayerV2 : QgsFillSymbolLayerV2

void setPointOnSurface( bool pointOnSurface );
bool pointOnSurface() const;

/** Sets whether a point is drawn for all parts or only on the biggest part of multi-part features.
* @note added in 2.16 */
void setPointOnAllParts( bool pointOnAllParts );
/** Returns whether a point is drawn for all parts or only on the biggest part of multi-part features.
* @note added in 2.16 */
bool pointOnAllParts() const;
};
@@ -317,6 +317,24 @@ class QgsSymbolV2RenderContext
//! @note added in 2.4
const QgsFields* fields() const;

/** Part count of current geometry
* @note added in QGIS 2.16
*/
int geometryPartCount() const;
/** Sets the part count of current geometry
* @note added in QGIS 2.16
*/
void setGeometryPartCount( int count );

/** Part number of current geometry
* @note added in QGIS 2.16
*/
int geometryPartNum() const;
/** Sets the part number of current geometry
* @note added in QGIS 2.16
*/
void setGeometryPartNum( int num );

double outputLineWidth( double width ) const;
double outputPixelSize( double size ) const;

@@ -19,6 +19,8 @@
#include "qgssymbollayerv2utils.h"
#include "qgsdxfexport.h"
#include "qgsexpression.h"
#include "qgsgeometry.h"
#include "qgsgeometrycollectionv2.h"
#include "qgsrendercontext.h"
#include "qgsproject.h"
#include "qgssvgcache.h"
@@ -3384,7 +3386,7 @@ QSet<QString> QgsPointPatternFillSymbolLayer::usedAttributes() const
//////////////


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

if ( properties.contains( "point_on_surface" ) )
sl->setPointOnSurface( properties["point_on_surface"].toInt() != 0 );
if ( properties.contains( "point_on_all_parts" ) )
sl->setPointOnAllParts( properties["point_on_all_parts"].toInt() != 0 );

return sl;
}
@@ -3419,6 +3423,9 @@ void QgsCentroidFillSymbolLayerV2::startRender( QgsSymbolV2RenderContext& contex
{
mMarker->setAlpha( context.alpha() );
mMarker->startRender( context.renderContext(), context.fields() );

mCurrentFeatureId = -1;
mBiggestPartIndex = 0;
}

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

QPointF centroid = mPointOnSurface ? QgsSymbolLayerV2Utils::polygonPointOnSurface( points ) : QgsSymbolLayerV2Utils::polygonCentroid( points );
mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
if ( !mPointOnAllParts )
{
const QgsFeature* feature = context.feature();
if ( feature )
{
if ( feature->id() != mCurrentFeatureId )
{
mCurrentFeatureId = feature->id();
mBiggestPartIndex = 1;

if ( context.geometryPartCount() > 1 )
{
const QgsGeometry *geom = feature->constGeometry();
const QgsGeometryCollectionV2* geomCollection = dynamic_cast<const QgsGeometryCollectionV2*>( geom->geometry() );

double area = 0;
double areaBiggest = 0;
for ( int i = 0; i < context.geometryPartCount(); ++i )
{
area = geomCollection->geometryN( i )->area();
if ( area > areaBiggest )
{
areaBiggest = area;
mBiggestPartIndex = i + 1;
}
}
}
}
}
}

QgsDebugMsg( QString( "num: %1, count: %2" ).arg( context.geometryPartNum() ).arg( context.geometryPartCount() ) );

if ( mPointOnAllParts || ( context.geometryPartNum() == mBiggestPartIndex ) )
{
QPointF centroid = mPointOnSurface ? QgsSymbolLayerV2Utils::polygonPointOnSurface( points ) : QgsSymbolLayerV2Utils::polygonCentroid( points );
mMarker->renderPoint( centroid, context.feature(), context.renderContext(), -1, context.selected() );
}
}

QgsStringMap QgsCentroidFillSymbolLayerV2::properties() const
{
QgsStringMap map;
map["point_on_surface"] = QString::number( mPointOnSurface );
map["point_on_all_parts"] = QString::number( mPointOnAllParts );
return map;
}

@@ -3448,6 +3492,7 @@ QgsCentroidFillSymbolLayerV2* QgsCentroidFillSymbolLayerV2::clone() const
x->mColor = mColor;
x->setSubSymbol( mMarker->clone() );
x->setPointOnSurface( mPointOnSurface );
x->setPointOnAllParts( mPointOnAllParts );
copyPaintEffect( x );
return x;
}
@@ -1095,9 +1095,20 @@ class CORE_EXPORT QgsCentroidFillSymbolLayerV2 : public QgsFillSymbolLayerV2
void setPointOnSurface( bool pointOnSurface ) { mPointOnSurface = pointOnSurface; }
bool pointOnSurface() const { return mPointOnSurface; }

/** Sets whether a point is drawn for all parts or only on the biggest part of multi-part features.
* @note added in 2.16 */
void setPointOnAllParts( bool pointOnAllParts ) { mPointOnAllParts = pointOnAllParts; }
/** Returns whether a point is drawn for all parts or only on the biggest part of multi-part features.
* @note added in 2.16 */
bool pointOnAllParts() const { return mPointOnAllParts; }

protected:
QgsMarkerSymbolV2* mMarker;
bool mPointOnSurface;
bool mPointOnAllParts;

QgsFeatureId mCurrentFeatureId;
int mBiggestPartIndex;
};

#endif
@@ -733,11 +733,14 @@ void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& co
deleteSegmentizedGeometry = true;
}

mSymbolRenderContext->setGeometryPartCount( segmentizedGeometry->geometry()->partCount() );
mSymbolRenderContext->setGeometryPartNum( 1 );

if ( mSymbolRenderContext->expressionContextScope() )
{
context.expressionContext().appendScope( mSymbolRenderContext->expressionContextScope() );
QgsExpressionContextUtils::updateSymbolScope( this, mSymbolRenderContext->expressionContextScope() );
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, segmentizedGeometry->geometry()->partCount() );
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_COUNT, mSymbolRenderContext->geometryPartCount() );
mSymbolRenderContext->expressionContextScope()->setVariable( QgsExpressionContext::EXPR_GEOMETRY_PART_NUM, 1 );
}

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

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

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

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

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

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

if ( geomCollection )
@@ -1002,7 +1008,9 @@ QgsSymbolV2RenderContext::QgsSymbolV2RenderContext( QgsRenderContext& c, QgsSymb
mSelected( selected ),
mRenderHints( renderHints ),
mFeature( f ),
mFields( fields )
mFields( fields ),
mGeometryPartCount( 0 ),
mGeometryPartNum( 0 )
{
}

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

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

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

if ( layerIdx != -1 )
{
@@ -379,6 +379,24 @@ class CORE_EXPORT QgsSymbolV2RenderContext
//! @note added in 2.4
const QgsFields* fields() const { return mFields; }

/** Part count of current geometry
* @note added in QGIS 2.16
*/
int geometryPartCount() const { return mGeometryPartCount; }
/** Sets the part count of current geometry
* @note added in QGIS 2.16
*/
void setGeometryPartCount( int count ) { mGeometryPartCount = count; }

/** Part number of current geometry
* @note added in QGIS 2.16
*/
int geometryPartNum() const { return mGeometryPartNum; }
/** Sets the part number of current geometry
* @note added in QGIS 2.16
*/
void setGeometryPartNum( int num ) { mGeometryPartNum = num; }

double outputLineWidth( double width ) const;
double outputPixelSize( double size ) const;

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


QgsSymbolV2RenderContext( const QgsSymbolV2RenderContext& rh );
@@ -2737,9 +2737,8 @@ void QgsCentroidFillSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer
mLayer = static_cast<QgsCentroidFillSymbolLayerV2*>( layer );

// set values
mDrawInsideCheckBox->blockSignals( true );
mDrawInsideCheckBox->setChecked( mLayer->pointOnSurface() );
mDrawInsideCheckBox->blockSignals( false );
whileBlocking( mDrawInsideCheckBox )->setChecked( mLayer->pointOnSurface() );
whileBlocking( mDrawAllPartsCheckBox )->setChecked( mLayer->pointOnAllParts() );
}

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

void QgsCentroidFillSymbolLayerV2Widget::on_mDrawAllPartsCheckBox_stateChanged( int state )
{
mLayer->setPointOnAllParts( state == Qt::Checked );
emit changed();
}

///////////////

QgsRasterFillSymbolLayerWidget::QgsRasterFillSymbolLayerWidget( const QgsVectorLayer *vl, QWidget *parent )
@@ -627,6 +627,7 @@ class GUI_EXPORT QgsCentroidFillSymbolLayerV2Widget : public QgsSymbolLayerV2Wid

private slots:
void on_mDrawInsideCheckBox_stateChanged( int state );
void on_mDrawAllPartsCheckBox_stateChanged( int state );

};

@@ -15,7 +15,7 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<item>
<widget class="QCheckBox" name="mDrawInsideCheckBox">
<property name="text">
@@ -41,6 +41,20 @@
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="mDrawAllPartsCheckBox">
<property name="text">
<string>Draw point on every part of multi-part features</string>
</property>
<property name="toolTip">
<string>When unchecked, a single point will be drawn on the biggest part of multi-part features</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer>
<property name="orientation">
@@ -145,6 +145,7 @@ ADD_QGIS_TEST(invertedpolygontest testqgsinvertedpolygonrenderer.cpp )
ADD_QGIS_TEST(labelingenginev2 testqgslabelingenginev2.cpp)
ADD_QGIS_TEST(layertree testqgslayertree.cpp)
ADD_QGIS_TEST(legendrenderertest testqgslegendrenderer.cpp )
ADD_QGIS_TEST(centroidfillsymboltest testqgscentroidfillsymbol.cpp )
ADD_QGIS_TEST(linefillsymboltest testqgslinefillsymbol.cpp )
ADD_QGIS_TEST(maplayerstylemanager testqgsmaplayerstylemanager.cpp )
ADD_QGIS_TEST(maplayertest testqgsmaplayer.cpp)

0 comments on commit 93d984e

Please sign in to comment.
You can’t perform that action at this time.