Skip to content
Permalink
Browse files

[FEATURE] Add option for simple line symbols to be drawn only inside a

polygon. Allows for creation of "national geographic" style borders on
maps where a thick border does not overlap into neighbouring polygons.
  • Loading branch information
nyalldawson committed Jan 21, 2014
1 parent 6d663c5 commit 7d2bf150edad92cfe5e8d3a565fc033b65975dd9
@@ -55,6 +55,12 @@ class QgsSimpleLineSymbolLayerV2 : QgsLineSymbolLayerV2

QVector<qreal> customDashVector() const;
void setCustomDashVector( const QVector<qreal>& vector );

//Returns true if the line should only be drawn inside the polygon
bool drawInsidePolygon() const;
//Set to true if the line should only be drawn inside the polygon
void setDrawInsidePolygon( bool drawInsidePolygon );

};

/////////
@@ -43,6 +43,7 @@ class QgsSimpleLineSymbolLayerV2Widget : QgsSymbolLayerV2Widget
void on_mOffsetUnitComboBox_currentIndexChanged( int index );
void on_mDashPatternUnitComboBox_currentIndexChanged( int index );
void on_mDataDefinedPropertiesButton_clicked();
void on_mDrawInsideCheckBox_stateChanged( int state );

protected:
//creates a new icon for the 'change pattern' button
@@ -30,7 +30,7 @@

QgsSimpleLineSymbolLayerV2::QgsSimpleLineSymbolLayerV2( QColor color, double width, Qt::PenStyle penStyle )
: mPenStyle( penStyle ), mPenJoinStyle( DEFAULT_SIMPLELINE_JOINSTYLE ), mPenCapStyle( DEFAULT_SIMPLELINE_CAPSTYLE ), mOffset( 0 ), mOffsetUnit( QgsSymbolV2::MM ),
mUseCustomDashPattern( false ), mCustomDashPatternUnit( QgsSymbolV2::MM )
mUseCustomDashPattern( false ), mCustomDashPatternUnit( QgsSymbolV2::MM ), mDrawInsidePolygon( false )
{
mColor = color;
mWidth = width;
@@ -94,6 +94,11 @@ QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::create( const QgsStringMap& props
l->setCustomDashPatternUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["customdash_unit"] ) );
}

if ( props.contains( "draw_inside_polygon" ) )
{
l->setDrawInsidePolygon( props["draw_inside_polygon"].toInt() );
}

//data defined properties
if ( props.contains( "color_expression" ) )
l->setDataDefinedProperty( "color", props["color_expression"] );
@@ -191,6 +196,15 @@ void QgsSimpleLineSymbolLayerV2::renderPolyline( const QPolygonF& points, QgsSym
return;
}

if ( mDrawInsidePolygon )
{
//only drawing the line on the interior of the polygon, so set clip path for painter
p->save();
QPainterPath clipPath;
clipPath.addPolygon( points );
p->setClipPath( clipPath, Qt::IntersectClip );
}

if ( offset == 0 )
{
p->drawPolyline( points );
@@ -200,6 +214,12 @@ void QgsSimpleLineSymbolLayerV2::renderPolyline( const QPolygonF& points, QgsSym
double scaledOffset = offset * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
p->drawPolyline( ::offsetLine( points, scaledOffset ) );
}

if ( mDrawInsidePolygon )
{
//restore painter to reset clip path
p->restore();
}
}

QgsStringMap QgsSimpleLineSymbolLayerV2::properties() const
@@ -216,6 +236,7 @@ QgsStringMap QgsSimpleLineSymbolLayerV2::properties() const
map["use_custom_dash"] = ( mUseCustomDashPattern ? "1" : "0" );
map["customdash"] = QgsSymbolLayerV2Utils::encodeRealVector( mCustomDashVector );
map["customdash_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mCustomDashPatternUnit );
map["draw_inside_polygon"] = ( mDrawInsidePolygon ? "1" : "0" );
saveDataDefinedProperties( map );
return map;
}
@@ -231,6 +252,7 @@ QgsSymbolLayerV2* QgsSimpleLineSymbolLayerV2::clone() const
l->setPenCapStyle( mPenCapStyle );
l->setUseCustomDashPattern( mUseCustomDashPattern );
l->setCustomDashVector( mCustomDashVector );
l->setDrawInsidePolygon( mDrawInsidePolygon );
copyDataDefinedProperties( l );
return l;
}
@@ -387,7 +409,15 @@ void QgsSimpleLineSymbolLayerV2::applyDataDefinedSymbology( QgsSymbolV2RenderCon

double QgsSimpleLineSymbolLayerV2::estimateMaxBleed() const
{
return ( mWidth / 2.0 ) + mOffset;
if ( mDrawInsidePolygon )
{
//set to clip line to the interior of polygon, so we expect no bleed
return 0;
}
else
{
return ( mWidth / 2.0 ) + mOffset;
}
}

QVector<qreal> QgsSimpleLineSymbolLayerV2::dxfCustomDashPattern( QgsSymbolV2::OutputUnit& unit ) const
@@ -91,6 +91,11 @@ class CORE_EXPORT QgsSimpleLineSymbolLayerV2 : public QgsLineSymbolLayerV2
QVector<qreal> customDashVector() const { return mCustomDashVector; }
void setCustomDashVector( const QVector<qreal>& vector ) { mCustomDashVector = vector; }

//Returns true if the line should only be drawn inside the polygon
bool drawInsidePolygon() const { return mDrawInsidePolygon; }
//Set to true if the line should only be drawn inside the polygon
void setDrawInsidePolygon( bool drawInsidePolygon ) { mDrawInsidePolygon = drawInsidePolygon; }

QVector<qreal> dxfCustomDashPattern( QgsSymbolV2::OutputUnit& unit ) const;

double dxfWidth( const QgsDxfExport& e, const QgsSymbolV2RenderContext& context ) const;
@@ -112,6 +117,8 @@ class CORE_EXPORT QgsSimpleLineSymbolLayerV2 : public QgsLineSymbolLayerV2
/**Vector with an even number of entries for the */
QVector<qreal> mCustomDashVector;

bool mDrawInsidePolygon;

private:
//helper functions for data defined symbology
void applyDataDefinedSymbology( QgsSymbolV2RenderContext& context, QPen& pen, QPen& selPen, double& offset );
@@ -52,6 +52,12 @@ QgsSimpleLineSymbolLayerV2Widget::QgsSimpleLineSymbolLayerV2Widget( const QgsVec

setupUi( this );

if ( vl && vl->geometryType() != QGis::Polygon )
{
//draw inside polygon checkbox only makes sense for polygon layers
mDrawInsideCheckBox->hide();
}

connect( spinWidth, SIGNAL( valueChanged( double ) ), this, SLOT( penWidthChanged() ) );
connect( btnChangeColor, SIGNAL( colorChanged( const QColor& ) ), this, SLOT( colorChanged( const QColor& ) ) );
connect( cboPenStyle, SIGNAL( currentIndexChanged( int ) ), this, SLOT( penStyleChanged() ) );
@@ -104,6 +110,13 @@ void QgsSimpleLineSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer )
mCustomCheckBox->blockSignals( true );
mCustomCheckBox->setCheckState( useCustomDashPattern ? Qt::Checked : Qt::Unchecked );
mCustomCheckBox->blockSignals( false );

//draw inside polygon?
bool drawInsidePolygon = mLayer->drawInsidePolygon();
mDrawInsideCheckBox->blockSignals( true );
mDrawInsideCheckBox->setCheckState( drawInsidePolygon ? Qt::Checked : Qt::Unchecked );
mDrawInsideCheckBox->blockSignals( false );

updatePatternIcon();
}

@@ -189,6 +202,13 @@ void QgsSimpleLineSymbolLayerV2Widget::on_mDashPatternUnitComboBox_currentIndexC
emit changed();
}

void QgsSimpleLineSymbolLayerV2Widget::on_mDrawInsideCheckBox_stateChanged( int state )
{
bool checked = ( state == Qt::Checked );
mLayer->setDrawInsidePolygon( checked );
emit changed();
}

void QgsSimpleLineSymbolLayerV2Widget::on_mDataDefinedPropertiesButton_clicked()
{
if ( !mLayer )
@@ -71,6 +71,7 @@ class GUI_EXPORT QgsSimpleLineSymbolLayerV2Widget : public QgsSymbolLayerV2Widge
void on_mOffsetUnitComboBox_currentIndexChanged( int index );
void on_mDashPatternUnitComboBox_currentIndexChanged( int index );
void on_mDataDefinedPropertiesButton_clicked();
void on_mDrawInsideCheckBox_stateChanged( int state );

protected:
QgsSimpleLineSymbolLayerV2* mLayer;
@@ -23,7 +23,16 @@
<property name="horizontalSpacing">
<number>28</number>
</property>
<property name="margin">
<property name="leftMargin">
<number>1</number>
</property>
<property name="topMargin">
<number>1</number>
</property>
<property name="rightMargin">
<number>1</number>
</property>
<property name="bottomMargin">
<number>1</number>
</property>
<item row="0" column="0">
@@ -242,7 +251,7 @@
</item>
</widget>
</item>
<item row="8" column="0" colspan="2">
<item row="11" column="0" colspan="2">
<widget class="QPushButton" name="mDataDefinedPropertiesButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
@@ -255,6 +264,17 @@
</property>
</widget>
</item>
<item row="9" column="0" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="mDrawInsideCheckBox">
<property name="text">
<string>Draw line only inside polygon</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>

0 comments on commit 7d2bf15

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