Skip to content
Permalink
Browse files
Merge pull request #2964 from nirvn/simple_marker_join_style
[FEATURE] add outline join style settings to simple markers (fixes #3797)
  • Loading branch information
nyalldawson committed Apr 3, 2016
2 parents c08d359 + 3a2a099 commit ae9d089142b3d348d200c9f7f7f960c5bc180b56
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 12 deletions.
@@ -5,12 +5,24 @@ class QgsSimpleMarkerSymbolLayerV2 : QgsMarkerSymbolLayerV2
%End

public:
/** Constructor for QgsSimpleMarkerSymbolLayerV2.
* @param name symbol name, should be one of "square", "rectangle", "diamond",
* "pentagon", "triangle", "equilateral_triangle", "star", "regular_star", "arrow",
* "circle", "cross", "cross2", "line", "x", "arrowhead", "filled_arrowhead"
* @param color fill color for symbol
* @param borderColor border color for symbol
* @param size symbol size (in mm)
* @param angle symbol rotation angle
* @param scaleMethod scaling method for data defined scaling
* @param penJoinStyle join style for outline pen
*/
QgsSimpleMarkerSymbolLayerV2( const QString& name = DEFAULT_SIMPLEMARKER_NAME,
const QColor& color = DEFAULT_SIMPLEMARKER_COLOR,
const QColor& borderColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR,
double size = DEFAULT_SIMPLEMARKER_SIZE,
double angle = DEFAULT_SIMPLEMARKER_ANGLE,
QgsSymbolV2::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD );
QgsSymbolV2::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD,
Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEFILL_JOINSTYLE );

// static stuff

@@ -41,9 +53,20 @@ class QgsSimpleMarkerSymbolLayerV2 : QgsMarkerSymbolLayerV2
QColor borderColor() const;
void setBorderColor( const QColor& color );

/** Get outline join style.
* @note added in 2.4 */
Qt::PenStyle outlineStyle() const;
/** Set outline join style.
* @note added in 2.4 */
void setOutlineStyle( Qt::PenStyle outlineStyle );

/** Get outline join style.
* @note added in 2.16 */
Qt::PenJoinStyle penJoinStyle() const;
/** Set outline join style.
* @note added in 2.16 */
void setPenJoinStyle( Qt::PenJoinStyle style );

/** Get outline color.
* @note added in 2.1 */
QColor outlineColor() const;
@@ -48,8 +48,9 @@ static void _fixQPictureDPI( QPainter* p )

//////

QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( const QString& name, const QColor& color, const QColor& borderColor, double size, double angle, QgsSymbolV2::ScaleMethod scaleMethod )
: mOutlineStyle( Qt::SolidLine ), mOutlineWidth( 0 ), mOutlineWidthUnit( QgsSymbolV2::MM )
QgsSimpleMarkerSymbolLayerV2::QgsSimpleMarkerSymbolLayerV2( const QString& name, const QColor& color, const QColor& borderColor, double size, double angle, QgsSymbolV2::ScaleMethod scaleMethod,
Qt::PenJoinStyle penJoinStyle )
: mOutlineStyle( Qt::SolidLine ), mOutlineWidth( 0 ), mOutlineWidthUnit( QgsSymbolV2::MM ), mPenJoinStyle( penJoinStyle )
{
mName = name;
mColor = color;
@@ -68,6 +69,7 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::create( const QgsStringMap& prop
QString name = DEFAULT_SIMPLEMARKER_NAME;
QColor color = DEFAULT_SIMPLEMARKER_COLOR;
QColor borderColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR;
Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEMARKER_JOINSTYLE;
double size = DEFAULT_SIMPLEMARKER_SIZE;
double angle = DEFAULT_SIMPLEMARKER_ANGLE;
QgsSymbolV2::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD;
@@ -89,14 +91,18 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::create( const QgsStringMap& prop
{
borderColor = QgsSymbolLayerV2Utils::decodeColor( props["line_color"] );
}
if ( props.contains( "joinstyle" ) )
{
penJoinStyle = QgsSymbolLayerV2Utils::decodePenJoinStyle( props["joinstyle"] );
}
if ( props.contains( "size" ) )
size = props["size"].toDouble();
if ( props.contains( "angle" ) )
angle = props["angle"].toDouble();
if ( props.contains( "scale_method" ) )
scaleMethod = QgsSymbolLayerV2Utils::decodeScaleMethod( props["scale_method"] );

QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle, scaleMethod );
QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( name, color, borderColor, size, angle, scaleMethod, penJoinStyle );
if ( props.contains( "offset" ) )
m->setOffset( QgsSymbolLayerV2Utils::decodePoint( props["offset"] ) );
if ( props.contains( "offset_unit" ) )
@@ -168,6 +174,7 @@ void QgsSimpleMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& contex
mBrush = QBrush( brushColor );
mPen = QPen( penColor );
mPen.setStyle( mOutlineStyle );
mPen.setJoinStyle( mPenJoinStyle );
mPen.setWidthF( QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mOutlineWidth, mOutlineWidthUnit, mOutlineWidthMapUnitScale ) );

QColor selBrushColor = context.renderContext().selectionColor();
@@ -190,8 +197,8 @@ void QgsSimpleMarkerSymbolLayerV2::startRender( QgsSymbolV2RenderContext& contex
// - drawing to screen (not printer)
mUsingCache = !hasDataDefinedRotation && !hasDataDefinedSize && !context.renderContext().forceVectorOutput()
&& !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_NAME ) && !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR ) && !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_COLOR_BORDER )
&& !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH ) && !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE ) &&
!hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE );
&& !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_WIDTH ) && !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_OUTLINE_STYLE )
&& !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_JOIN_STYLE ) && !hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_SIZE );

// use either QPolygonF or QPainterPath for drawing
// TODO: find out whether drawing directly doesn't bring overhead - if not, use it for all shapes
@@ -259,7 +266,7 @@ bool QgsSimpleMarkerSymbolLayerV2::prepareCache( QgsSymbolV2RenderContext& conte
double scaledSize = QgsSymbolLayerV2Utils::convertToPainterUnits( context.renderContext(), mSize, mSizeUnit, mSizeMapUnitScale );

// calculate necessary image size for the cache
double pw = (( qgsDoubleNear( mPen.widthF(), 0.0 ) ? 1 : mPen.widthF() ) + 1 ) / 2 * 2; // make even (round up); handle cosmetic pen
double pw = qRound((( qgsDoubleNear( mPen.widthF(), 0.0 ) ? 1 : mPen.widthF() * 4 ) + 1 ) ) / 2 * 2; // make even (round up); handle cosmetic pen
int imageSize = ( static_cast< int >( scaledSize ) + pw ) / 2 * 2 + 1; // make image width, height odd; account for pen width
double center = imageSize / 2.0;

@@ -560,6 +567,16 @@ void QgsSimpleMarkerSymbolLayerV2::renderPoint( QPointF point, QgsSymbolV2Render
mSelPen.setStyle( QgsSymbolLayerV2Utils::decodePenStyle( outlineStyle ) );
}
}
if ( hasDataDefinedProperty( QgsSymbolLayerV2::EXPR_JOIN_STYLE ) )
{
context.setOriginalValueVariable( QgsSymbolLayerV2Utils::encodePenJoinStyle( mPenJoinStyle ) );
QString style = evaluateDataDefinedProperty( QgsSymbolLayerV2::EXPR_JOIN_STYLE, context, QVariant(), &ok ).toString();
if ( ok )
{
mPen.setJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( style ) );
mSelPen.setJoinStyle( QgsSymbolLayerV2Utils::decodePenJoinStyle( style ) );
}
}

p->setBrush( context.selected() ? mSelBrush : mBrush );
p->setPen( context.selected() ? mSelPen : mPen );
@@ -664,6 +681,7 @@ QgsStringMap QgsSimpleMarkerSymbolLayerV2::properties() const
map["outline_width"] = QString::number( mOutlineWidth );
map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
map["outline_width_map_unit_scale"] = QgsSymbolLayerV2Utils::encodeMapUnitScale( mOutlineWidthMapUnitScale );
map["joinstyle"] = QgsSymbolLayerV2Utils::encodePenJoinStyle( mPenJoinStyle );
map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );

@@ -675,7 +693,7 @@ QgsStringMap QgsSimpleMarkerSymbolLayerV2::properties() const

QgsSimpleMarkerSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
{
QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( mName, mColor, mBorderColor, mSize, mAngle, mScaleMethod );
QgsSimpleMarkerSymbolLayerV2* m = new QgsSimpleMarkerSymbolLayerV2( mName, mColor, mBorderColor, mSize, mAngle, mScaleMethod, mPenJoinStyle );
m->setOffset( mOffset );
m->setSizeUnit( mSizeUnit );
m->setSizeMapUnitScale( mSizeMapUnitScale );
@@ -22,6 +22,7 @@
#define DEFAULT_SIMPLEMARKER_NAME "circle"
#define DEFAULT_SIMPLEMARKER_COLOR QColor(255,0,0)
#define DEFAULT_SIMPLEMARKER_BORDERCOLOR QColor(0,0,0)
#define DEFAULT_SIMPLEMARKER_JOINSTYLE Qt::BevelJoin
#define DEFAULT_SIMPLEMARKER_SIZE DEFAULT_POINT_SIZE
#define DEFAULT_SIMPLEMARKER_ANGLE 0

@@ -34,12 +35,24 @@
class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
{
public:
/** Constructor for QgsSimpleMarkerSymbolLayerV2.
* @param name symbol name, should be one of "square", "rectangle", "diamond",
* "pentagon", "triangle", "equilateral_triangle", "star", "regular_star", "arrow",
* "circle", "cross", "cross2", "line", "x", "arrowhead", "filled_arrowhead"
* @param color fill color for symbol
* @param borderColor border color for symbol
* @param size symbol size (in mm)
* @param angle symbol rotation angle
* @param scaleMethod scaling method for data defined scaling
* @param penJoinStyle join style for outline pen
*/
QgsSimpleMarkerSymbolLayerV2( const QString& name = DEFAULT_SIMPLEMARKER_NAME,
const QColor& color = DEFAULT_SIMPLEMARKER_COLOR,
const QColor& borderColor = DEFAULT_SIMPLEMARKER_BORDERCOLOR,
double size = DEFAULT_SIMPLEMARKER_SIZE,
double angle = DEFAULT_SIMPLEMARKER_ANGLE,
QgsSymbolV2::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD );
QgsSymbolV2::ScaleMethod scaleMethod = DEFAULT_SCALE_METHOD,
Qt::PenJoinStyle penJoinStyle = DEFAULT_SIMPLEMARKER_JOINSTYLE );

// static stuff

@@ -70,9 +83,20 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
QColor borderColor() const { return mBorderColor; }
void setBorderColor( const QColor& color ) { mBorderColor = color; }

/** Get outline join style.
* @note added in 2.4 */
Qt::PenStyle outlineStyle() const { return mOutlineStyle; }
/** Set outline join style.
* @note added in 2.4 */
void setOutlineStyle( Qt::PenStyle outlineStyle ) { mOutlineStyle = outlineStyle; }

/** Get outline join style.
* @note added in 2.16 */
Qt::PenJoinStyle penJoinStyle() const { return mPenJoinStyle; }
/** Set outline join style.
* @note added in 2.16 */
void setPenJoinStyle( Qt::PenJoinStyle style ) { mPenJoinStyle = style; }

/** Get outline color.
* @note added in 2.1 */
QColor outlineColor() const override { return borderColor(); }
@@ -122,6 +146,7 @@ class CORE_EXPORT QgsSimpleMarkerSymbolLayerV2 : public QgsMarkerSymbolLayerV2
double mOutlineWidth;
QgsSymbolV2::OutputUnit mOutlineWidthUnit;
QgsMapUnitScale mOutlineWidthMapUnitScale;
Qt::PenJoinStyle mPenJoinStyle;
QPen mPen;
QBrush mBrush;
QPolygonF mPolygon;
@@ -455,6 +455,7 @@ QgsSimpleMarkerSymbolLayerV2Widget::QgsSimpleMarkerSymbolLayerV2Widget( const Qg
connect( lstNames, SIGNAL( currentRowChanged( int ) ), this, SLOT( setName() ) );
connect( btnChangeColorBorder, SIGNAL( colorChanged( const QColor& ) ), this, SLOT( setColorBorder( const QColor& ) ) );
connect( btnChangeColorFill, SIGNAL( colorChanged( const QColor& ) ), this, SLOT( setColorFill( const QColor& ) ) );
connect( cboJoinStyle, SIGNAL( currentIndexChanged( int ) ), this, SLOT( penJoinStyleChanged() ) );
connect( spinSize, SIGNAL( valueChanged( double ) ), this, SLOT( setSize() ) );
connect( spinAngle, SIGNAL( valueChanged( double ) ), this, SLOT( setAngle() ) );
connect( spinOffsetX, SIGNAL( valueChanged( double ) ), this, SLOT( setOffset() ) );
@@ -503,6 +504,9 @@ void QgsSimpleMarkerSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer
mOutlineWidthSpinBox->blockSignals( true );
mOutlineWidthSpinBox->setValue( mLayer->outlineWidth() );
mOutlineWidthSpinBox->blockSignals( false );
cboJoinStyle->blockSignals( true );
cboJoinStyle->setPenJoinStyle( mLayer->penJoinStyle() );
cboJoinStyle->blockSignals( false );

// without blocking signals the value gets changed because of slot setOffset()
spinOffsetX->blockSignals( true );
@@ -542,6 +546,7 @@ void QgsSimpleMarkerSymbolLayerV2Widget::setSymbolLayer( QgsSymbolLayerV2* layer
registerDataDefinedButton( mBorderColorDDBtn, "color_border", QgsDataDefinedButton::String, QgsDataDefinedButton::colorAlphaDesc() );
registerDataDefinedButton( mOutlineWidthDDBtn, "outline_width", QgsDataDefinedButton::Double, QgsDataDefinedButton::doublePosDesc() );
registerDataDefinedButton( mOutlineStyleDDBtn, "outline_style", QgsDataDefinedButton::String, QgsDataDefinedButton::lineStyleDesc() );
registerDataDefinedButton( mJoinStyleDDBtn, "join_style", QgsDataDefinedButton::String, QgsDataDefinedButton::penJoinStyleDesc() );
registerDataDefinedButton( mSizeDDBtn, "size", QgsDataDefinedButton::Double, QgsDataDefinedButton::doublePosDesc() );
registerDataDefinedButton( mAngleDDBtn, "angle", QgsDataDefinedButton::Double, QgsDataDefinedButton::double180RotDesc() );
registerDataDefinedButton( mOffsetDDBtn, "offset", QgsDataDefinedButton::String, QgsDataDefinedButton::doubleXYDesc() );
@@ -574,6 +579,12 @@ void QgsSimpleMarkerSymbolLayerV2Widget::setColorFill( const QColor& color )
emit changed();
}

void QgsSimpleMarkerSymbolLayerV2Widget::penJoinStyleChanged()
{
mLayer->setPenJoinStyle( cboJoinStyle->penJoinStyle() );
emit changed();
}

void QgsSimpleMarkerSymbolLayerV2Widget::setSize()
{
mLayer->setSize( spinSize->value() );
@@ -201,6 +201,7 @@ class GUI_EXPORT QgsSimpleMarkerSymbolLayerV2Widget : public QgsSymbolLayerV2Wid
private slots:

void updateAssistantSymbol();
void penJoinStyleChanged();

private:

@@ -70,7 +70,7 @@
</item>
</layout>
</item>
<item row="6" column="1">
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QgsDoubleSpinBox" name="mOutlineWidthSpinBox">
@@ -295,7 +295,7 @@
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="mOutlineWidthLabel">
<property name="text">
<string>Outline width</string>
@@ -323,6 +323,30 @@
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Join style</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="6" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="QgsPenJoinStyleComboBox" name="cboJoinStyle"/>
</item>
<item>
<widget class="QgsDataDefinedButton" name="mJoinStyleDDBtn">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@@ -491,6 +515,11 @@
<header>qgsunitselectionwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsPenJoinStyleComboBox</class>
<extends>QComboBox</extends>
<header>qgspenstylecombobox.h</header>
</customwidget>
<customwidget>
<class>QgsPenStyleComboBox</class>
<extends>QComboBox</extends>
@@ -507,9 +536,11 @@
<tabstop>mSizeUnitWidget</tabstop>
<tabstop>mOutlineStyleComboBox</tabstop>
<tabstop>mOutlineStyleDDBtn</tabstop>
<tabstop>cboJoinStyle</tabstop>
<tabstop>mJoinStyleDDBtn</tabstop>
<tabstop>mOutlineWidthSpinBox</tabstop>
<tabstop>mOutlineWidthDDBtn</tabstop>
<tabstop>mOutlineWidthUnitWidget</tabstop>
<tabstop>mOutlineWidthUnitWidget</tabstop>
<tabstop>spinAngle</tabstop>
<tabstop>mAngleDDBtn</tabstop>
<tabstop>spinOffsetX</tabstop>
@@ -59,6 +59,9 @@ class TestQgsSimpleMarkerSymbol : public QObject
void cleanup() {} // will be called after every testfunction.

void simpleMarkerSymbol();
void simpleMarkerSymbolBevelJoin();
void simpleMarkerSymbolMiterJoin();
void simpleMarkerSymbolRoundJoin();
void bounds();

private:
@@ -140,6 +143,45 @@ void TestQgsSimpleMarkerSymbol::simpleMarkerSymbol()
QVERIFY( imageCheck( "simplemarker" ) );
}

void TestQgsSimpleMarkerSymbol::simpleMarkerSymbolBevelJoin()
{
mReport += "<h2>Simple marker symbol layer test</h2>\n";

mSimpleMarkerLayer->setColor( Qt::blue );
mSimpleMarkerLayer->setBorderColor( Qt::black );
mSimpleMarkerLayer->setName( "triangle" );
mSimpleMarkerLayer->setSize( 25 );
mSimpleMarkerLayer->setOutlineWidth( 3 );
mSimpleMarkerLayer->setPenJoinStyle( Qt::BevelJoin );
QVERIFY( imageCheck( "simplemarker_beveljoin" ) );
}

void TestQgsSimpleMarkerSymbol::simpleMarkerSymbolMiterJoin()
{
mReport += "<h2>Simple marker symbol layer test</h2>\n";

mSimpleMarkerLayer->setColor( Qt::blue );
mSimpleMarkerLayer->setBorderColor( Qt::black );
mSimpleMarkerLayer->setName( "triangle" );
mSimpleMarkerLayer->setSize( 25 );
mSimpleMarkerLayer->setOutlineWidth( 3 );
mSimpleMarkerLayer->setPenJoinStyle( Qt::MiterJoin );
QVERIFY( imageCheck( "simplemarker_miterjoin" ) );
}

void TestQgsSimpleMarkerSymbol::simpleMarkerSymbolRoundJoin()
{
mReport += "<h2>Simple marker symbol layer test</h2>\n";

mSimpleMarkerLayer->setColor( Qt::blue );
mSimpleMarkerLayer->setBorderColor( Qt::black );
mSimpleMarkerLayer->setName( "triangle" );
mSimpleMarkerLayer->setSize( 25 );
mSimpleMarkerLayer->setOutlineWidth( 3 );
mSimpleMarkerLayer->setPenJoinStyle( Qt::RoundJoin );
QVERIFY( imageCheck( "simplemarker_roundjoin" ) );
}

void TestQgsSimpleMarkerSymbol::bounds()
{
mSimpleMarkerLayer->setColor( QColor( 200, 200, 200 ) );
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit ae9d089

Please sign in to comment.