Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[Feature]: Add anchor point setting for marker symbol layers
  • Loading branch information
mhugent committed Sep 23, 2013
2 parents 9bc8c80 + 186b6bd commit 8a94505
Show file tree
Hide file tree
Showing 14 changed files with 915 additions and 461 deletions.
20 changes: 19 additions & 1 deletion src/core/symbology-ng/qgsellipsesymbollayerv2.cpp
Expand Up @@ -92,6 +92,14 @@ QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::create( const QgsStringMap& propertie
{
layer->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( properties["offset_unit"] ) );
}
if ( properties.contains( "horizontal_anchor_point" ) )
{
layer->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( properties[ "horizontal_anchor_point" ].toInt() ) );
}
if ( properties.contains( "vertical_anchor_point" ) )
{
layer->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( properties[ "vertical_anchor_point" ].toInt() ) );
}

//data defined properties
if ( properties.contains( "width_expression" ) )
Expand Down Expand Up @@ -126,6 +134,14 @@ QgsSymbolLayerV2* QgsEllipseSymbolLayerV2::create( const QgsStringMap& propertie
{
layer->setDataDefinedProperty( "offset", properties["offset_expression"] );
}
if ( properties.contains( "horizontal_anchor_point_expression" ) )
{
layer->setDataDefinedProperty( "horizontal_anchor_point", properties[ "horizontal_anchor_point_expression" ] );
}
if ( properties.contains( "vertical_anchor_point_expression" ) )
{
layer->setDataDefinedProperty( "vertical_anchor_point", properties[ "vertical_anchor_point_expression" ] );
}

//compatibility with old project file format
if ( !properties["width_field"].isEmpty() )
Expand Down Expand Up @@ -199,7 +215,7 @@ void QgsEllipseSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Rend
//offset
double offsetX = 0;
double offsetY = 0;
markerOffset( context, offsetX, offsetY );
markerOffset( context, mSymbolWidth, mSymbolHeight, mSymbolWidthUnit, mSymbolHeightUnit, offsetX, offsetY );
QPointF off( offsetX, offsetY );

QPainter* p = context.renderContext().painter();
Expand Down Expand Up @@ -385,6 +401,8 @@ QgsStringMap QgsEllipseSymbolLayerV2::properties() const
map["outline_color"] = QgsSymbolLayerV2Utils::encodeColor( mOutlineColor );
map["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
map["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
saveDataDefinedProperties( map );
return map;
}
Expand Down
74 changes: 63 additions & 11 deletions src/core/symbology-ng/qgsmarkersymbollayerv2.cpp
Expand Up @@ -85,6 +85,15 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::create( const QgsStringMap& prop
m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );
}

if ( props.contains( "horizontal_anchor_point" ) )
{
m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
}
if ( props.contains( "vertical_anchor_point" ) )
{
m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
}

//data defined properties
if ( props.contains( "name_expression" ) )
{
Expand Down Expand Up @@ -114,6 +123,14 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::create( const QgsStringMap& prop
{
m->setDataDefinedProperty( "offset", props["offset_expression"] );
}
if ( props.contains( "horizontal_anchor_point_expression" ) )
{
m->setDataDefinedProperty( "horizontal_anchor_point", props[ "horizontal_anchor_point_expression" ] );
}
if ( props.contains( "vertical_anchor_point_expression" ) )
{
m->setDataDefinedProperty( "vertical_anchor_point", props[ "vertical_anchor_point_expression" ] );
}
return m;
}

Expand Down Expand Up @@ -546,6 +563,8 @@ QgsStringMap QgsSimpleMarkerSymbolLayerV2::properties() const
map["scale_method"] = QgsSymbolLayerV2Utils::encodeScaleMethod( mScaleMethod );
map["outline_width"] = QString::number( mOutlineWidth );
map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );

//data define properties
saveDataDefinedProperties( map );
Expand All @@ -560,6 +579,8 @@ QgsSymbolLayerV2* QgsSimpleMarkerSymbolLayerV2::clone() const
m->setOffsetUnit( mOffsetUnit );
m->setOutlineWidth( mOutlineWidth );
m->setOutlineWidthUnit( mOutlineWidthUnit );
m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
m->setVerticalAnchorPoint( mVerticalAnchorPoint );
copyDataDefinedProperties( m );
return m;
}
Expand Down Expand Up @@ -767,6 +788,15 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props )
if ( props.contains( "outline_width_unit" ) )
m->setOutlineWidthUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["outline_width_unit"] ) );

if ( props.contains( "horizontal_anchor_point" ) )
{
m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
}
if ( props.contains( "vertical_anchor_point" ) )
{
m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
}

//data defined properties
if ( props.contains( "size_expression" ) )
{
Expand Down Expand Up @@ -796,6 +826,14 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::create( const QgsStringMap& props )
{
m->setDataDefinedProperty( "outline", props["outline_expression"] );
}
if ( props.contains( "horizontal_anchor_point_expression" ) )
{
m->setDataDefinedProperty( "horizontal_anchor_point", props[ "horizontal_anchor_point_expression" ] );
}
if ( props.contains( "vertical_anchor_point_expression" ) )
{
m->setDataDefinedProperty( "vertical_anchor_point", props[ "vertical_anchor_point_expression" ] );
}
return m;
}

Expand Down Expand Up @@ -874,15 +912,10 @@ void QgsSvgMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2Re

p->save();

QPointF offset = mOffset;
QgsExpression* offsetExpression = expression( "offset" );
if ( offsetExpression )
{
QString offsetString = offsetExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString();
offset = QgsSymbolLayerV2Utils::decodePoint( offsetString );
}
double offsetX = offset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
double offsetY = offset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
//offset
double offsetX = 0;
double offsetY = 0;
markerOffset( context, offsetX, offsetY );
QPointF outputOffset( offsetX, offsetY );

double angle = mAngle;
Expand Down Expand Up @@ -1003,6 +1036,9 @@ QgsStringMap QgsSvgMarkerSymbolLayerV2::properties() const
map["outline"] = mOutlineColor.name();
map["outline-width"] = QString::number( mOutlineWidth );
map["outline_width_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOutlineWidthUnit );
map["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
map["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );

saveDataDefinedProperties( map );
return map;
}
Expand All @@ -1017,6 +1053,8 @@ QgsSymbolLayerV2* QgsSvgMarkerSymbolLayerV2::clone() const
m->setOffset( mOffset );
m->setOffsetUnit( mOffsetUnit );
m->setSizeUnit( mSizeUnit );
m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
m->setVerticalAnchorPoint( mVerticalAnchorPoint );
copyDataDefinedProperties( m );
return m;
}
Expand Down Expand Up @@ -1145,6 +1183,14 @@ QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::create( const QgsStringMap& props
m->setOffsetUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["offset_unit" ] ) );
if ( props.contains( "size_unit" ) )
m->setSizeUnit( QgsSymbolLayerV2Utils::decodeOutputUnit( props["size_unit"] ) );
if ( props.contains( "horizontal_anchor_point" ) )
{
m->setHorizontalAnchorPoint( QgsMarkerSymbolLayerV2::HorizontalAnchorPoint( props[ "horizontal_anchor_point" ].toInt() ) );
}
if ( props.contains( "vertical_anchor_point" ) )
{
m->setVerticalAnchorPoint( QgsMarkerSymbolLayerV2::VerticalAnchorPoint( props[ "vertical_anchor_point" ].toInt() ) );
}
return m;
}

Expand Down Expand Up @@ -1180,8 +1226,10 @@ void QgsFontMarkerSymbolLayerV2::renderPoint( const QPointF& point, QgsSymbolV2R
p->setFont( mFont );

p->save();
double offsetX = mOffset.x() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
double offsetY = mOffset.y() * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
//offset
double offsetX = 0;
double offsetY = 0;
markerOffset( context, offsetX, offsetY );
QPointF outputOffset( offsetX, offsetY );
if ( mAngle )
outputOffset = _rotatedOffset( outputOffset, mAngle );
Expand Down Expand Up @@ -1211,6 +1259,8 @@ QgsStringMap QgsFontMarkerSymbolLayerV2::properties() const
props["angle"] = QString::number( mAngle );
props["offset"] = QgsSymbolLayerV2Utils::encodePoint( mOffset );
props["offset_unit"] = QgsSymbolLayerV2Utils::encodeOutputUnit( mOffsetUnit );
props["horizontal_anchor_point"] = QString::number( mHorizontalAnchorPoint );
props["vertical_anchor_point"] = QString::number( mVerticalAnchorPoint );
return props;
}

Expand All @@ -1220,6 +1270,8 @@ QgsSymbolLayerV2* QgsFontMarkerSymbolLayerV2::clone() const
m->setOffset( mOffset );
m->setOffsetUnit( mOffsetUnit );
m->setSizeUnit( mSizeUnit );
m->setHorizontalAnchorPoint( mHorizontalAnchorPoint );
m->setVerticalAnchorPoint( mVerticalAnchorPoint );
return m;
}

Expand Down
82 changes: 81 additions & 1 deletion src/core/symbology-ng/qgssymbollayerv2.cpp
Expand Up @@ -152,7 +152,8 @@ void QgsSymbolLayerV2::copyDataDefinedProperties( QgsSymbolLayerV2* destLayer )


QgsMarkerSymbolLayerV2::QgsMarkerSymbolLayerV2( bool locked )
: QgsSymbolLayerV2( QgsSymbolV2::Marker, locked ), mSizeUnit( QgsSymbolV2::MM ), mOffsetUnit( QgsSymbolV2::MM )
: QgsSymbolLayerV2( QgsSymbolV2::Marker, locked ), mSizeUnit( QgsSymbolV2::MM ), mOffsetUnit( QgsSymbolV2::MM ),
mHorizontalAnchorPoint( HCenter ), mVerticalAnchorPoint( VCenter )
{
}

Expand Down Expand Up @@ -180,6 +181,13 @@ void QgsMarkerSymbolLayerV2::setOutputUnit( QgsSymbolV2::OutputUnit unit )
}

void QgsMarkerSymbolLayerV2::markerOffset( QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY )
{
markerOffset( context, mSize, mSize, mSizeUnit, mSizeUnit, offsetX, offsetY );
}

void QgsMarkerSymbolLayerV2::markerOffset( QgsSymbolV2RenderContext& context, double width, double height,
QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
double& offsetX, double& offsetY )
{
offsetX = mOffset.x();
offsetY = mOffset.y();
Expand All @@ -194,6 +202,46 @@ void QgsMarkerSymbolLayerV2::markerOffset( QgsSymbolV2RenderContext& context, do

offsetX *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );
offsetY *= QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), mOffsetUnit );

HorizontalAnchorPoint horizontalAnchorPoint = mHorizontalAnchorPoint;
VerticalAnchorPoint verticalAnchorPoint = mVerticalAnchorPoint;
QgsExpression* horizontalAnchorExpression = expression( "horizontal_anchor_point" );
if ( horizontalAnchorExpression )
{
horizontalAnchorPoint = decodeHorizontalAnchorPoint( horizontalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
}
QgsExpression* verticalAnchorExpression = expression( "vertical_anchor_point" );
if ( verticalAnchorExpression )
{
verticalAnchorPoint = decodeVerticalAnchorPoint( verticalAnchorExpression->evaluate( const_cast<QgsFeature*>( context.feature() ) ).toString() );
}

//correct horizontal position according to anchor point
if ( horizontalAnchorPoint == HCenter && verticalAnchorPoint == VCenter )
{
return;
}

double anchorPointCorrectionX = width * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), widthUnit ) / 2.0;
double anchorPointCorrectionY = height * QgsSymbolLayerV2Utils::lineWidthScaleFactor( context.renderContext(), heightUnit ) / 2.0;
if ( horizontalAnchorPoint == Left )
{
offsetX += anchorPointCorrectionX;
}
else if ( horizontalAnchorPoint == Right )
{
offsetX -= anchorPointCorrectionX;
}

//correct vertical position according to anchor point
if ( verticalAnchorPoint == Top )
{
offsetY += anchorPointCorrectionY;
}
else if ( verticalAnchorPoint == Bottom )
{
offsetY -= anchorPointCorrectionY;
}
}

QPointF QgsMarkerSymbolLayerV2::_rotatedOffset( const QPointF& offset, double angle )
Expand All @@ -203,6 +251,38 @@ QPointF QgsMarkerSymbolLayerV2::_rotatedOffset( const QPointF& offset, double an
return QPointF( offset.x() * c - offset.y() * s, offset.x() * s + offset.y() * c );
}

QgsMarkerSymbolLayerV2::HorizontalAnchorPoint QgsMarkerSymbolLayerV2::decodeHorizontalAnchorPoint( const QString& str )
{
if ( str.compare( "left", Qt::CaseInsensitive ) == 0 )
{
return QgsMarkerSymbolLayerV2::Left;
}
else if ( str.compare( "right", Qt::CaseInsensitive ) == 0 )
{
return QgsMarkerSymbolLayerV2::Right;
}
else
{
return QgsMarkerSymbolLayerV2::HCenter;
}
}

QgsMarkerSymbolLayerV2::VerticalAnchorPoint QgsMarkerSymbolLayerV2::decodeVerticalAnchorPoint( const QString& str )
{
if ( str.compare( "top", Qt::CaseInsensitive ) == 0 )
{
return QgsMarkerSymbolLayerV2::Top;
}
else if ( str.compare( "bottom", Qt::CaseInsensitive ) == 0 )
{
return QgsMarkerSymbolLayerV2::Bottom;
}
else
{
return QgsMarkerSymbolLayerV2::VCenter;
}
}

QgsSymbolV2::OutputUnit QgsMarkerSymbolLayerV2::outputUnit() const
{
QgsSymbolV2::OutputUnit unit = mSizeUnit;
Expand Down
31 changes: 31 additions & 0 deletions src/core/symbology-ng/qgssymbollayerv2.h
Expand Up @@ -121,6 +121,21 @@ class CORE_EXPORT QgsSymbolLayerV2
class CORE_EXPORT QgsMarkerSymbolLayerV2 : public QgsSymbolLayerV2
{
public:

enum HorizontalAnchorPoint
{
Left,
HCenter,
Right
};

enum VerticalAnchorPoint
{
Top,
VCenter,
Bottom
};

virtual void renderPoint( const QPointF& point, QgsSymbolV2RenderContext& context ) = 0;

void drawPreviewIcon( QgsSymbolV2RenderContext& context, QSize size );
Expand Down Expand Up @@ -151,9 +166,19 @@ class CORE_EXPORT QgsMarkerSymbolLayerV2 : public QgsSymbolLayerV2
virtual void setOutputUnit( QgsSymbolV2::OutputUnit unit );
virtual QgsSymbolV2::OutputUnit outputUnit() const;

void setHorizontalAnchorPoint( HorizontalAnchorPoint h ) { mHorizontalAnchorPoint = h; }
HorizontalAnchorPoint horizontalAnchorPoint() const { return mHorizontalAnchorPoint; }

void setVerticalAnchorPoint( VerticalAnchorPoint v ) { mVerticalAnchorPoint = v; }
VerticalAnchorPoint verticalAnchorPoint() const { return mVerticalAnchorPoint; }

protected:
QgsMarkerSymbolLayerV2( bool locked = false );
//handles marker offset and anchor point shift together
void markerOffset( QgsSymbolV2RenderContext& context, double& offsetX, double& offsetY );
void markerOffset( QgsSymbolV2RenderContext& context, double width, double height,
QgsSymbolV2::OutputUnit widthUnit, QgsSymbolV2::OutputUnit heightUnit,
double& offsetX, double& offsetY );
static QPointF _rotatedOffset( const QPointF& offset, double angle );

double mAngle;
Expand All @@ -162,6 +187,12 @@ class CORE_EXPORT QgsMarkerSymbolLayerV2 : public QgsSymbolLayerV2
QPointF mOffset;
QgsSymbolV2::OutputUnit mOffsetUnit;
QgsSymbolV2::ScaleMethod mScaleMethod;
HorizontalAnchorPoint mHorizontalAnchorPoint;
VerticalAnchorPoint mVerticalAnchorPoint;

private:
static QgsMarkerSymbolLayerV2::HorizontalAnchorPoint decodeHorizontalAnchorPoint( const QString& str );
static QgsMarkerSymbolLayerV2::VerticalAnchorPoint decodeVerticalAnchorPoint( const QString& str );
};

class CORE_EXPORT QgsLineSymbolLayerV2 : public QgsSymbolLayerV2
Expand Down
10 changes: 10 additions & 0 deletions src/gui/symbology-ng/qgsdatadefinedsymboldialog.cpp
Expand Up @@ -182,3 +182,13 @@ QString QgsDataDefinedSymbolDialog::fileNameHelpText()
{
return tr( "'<filename>'" );
}

QString QgsDataDefinedSymbolDialog::horizontalAnchorHelpText()
{
return tr( "'left'|'center'|'right'" );
}

QString QgsDataDefinedSymbolDialog::verticalAnchorHelpText()
{
return tr( "'top'|'center'|'bottom'" );
}

0 comments on commit 8a94505

Please sign in to comment.