Skip to content
Permalink
Browse files
Fix calculation of point symbol bounds using data defined rotation or…
… offset

(cherry-picked from a67853f)
  • Loading branch information
nyalldawson committed Apr 29, 2016
1 parent 80102b1 commit c230c23
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 11 deletions.
@@ -476,11 +476,16 @@ class QgsMarkerSymbolV2 : QgsSymbolV2
void renderPoint( QPointF point, const QgsFeature* f, QgsRenderContext& context, int layer = -1, bool selected = false );

/** Returns the approximate bounding box of the marker symbol, which includes the bounding box
* of all symbol layers for the symbol.
* of all symbol layers for the symbol. It is recommended to use this method only between startRender()
* and stopRender() calls, or data defined rotation and offset will not be correctly calculated.
* @param point location of rendered point in painter units
* @param context render context
* @param feature feature being rendered at point (optional). If not specified, the bounds calculation will not
* include data defined parameters such as offset and rotation
* @returns approximate symbol bounds, in painter units
* @note added in QGIS 2.14
*/
QRectF bounds( QPointF point, QgsRenderContext& context ) const;
*/
QRectF bounds(QPointF point, QgsRenderContext& context, const QgsFeature &feature = QgsFeature() ) const;

virtual QgsMarkerSymbolV2* clone() const /Factory/;
};
@@ -353,9 +353,9 @@ QgsGeometry* QgsVectorLayerLabelProvider::getPointObstacleGeometry( QgsFeature&
if ( symbol->type() == QgsSymbolV2::Marker )
{
if ( bounds.isValid() )
bounds = bounds.united( static_cast< QgsMarkerSymbolV2* >( symbol )->bounds( pt, context ) );
bounds = bounds.united( static_cast< QgsMarkerSymbolV2* >( symbol )->bounds( pt, context, fet ) );
else
bounds = static_cast< QgsMarkerSymbolV2* >( symbol )->bounds( pt, context );
bounds = static_cast< QgsMarkerSymbolV2* >( symbol )->bounds( pt, context, fet );
}
}

@@ -758,7 +758,7 @@ void QgsSymbolV2::renderFeature( const QgsFeature& feature, QgsRenderContext& co
//draw debugging rect
context.painter()->setPen( Qt::red );
context.painter()->setBrush( QColor( 255, 0, 0, 100 ) );
context.painter()->drawRect( static_cast<QgsMarkerSymbolV2*>( this )->bounds( pt, context ) );
context.painter()->drawRect( static_cast<QgsMarkerSymbolV2*>( this )->bounds( pt, context, feature ) );
}
}
break;
@@ -1422,9 +1422,9 @@ void QgsMarkerSymbolV2::renderPoint( QPointF point, const QgsFeature* f, QgsRend
}
}

QRectF QgsMarkerSymbolV2::bounds( QPointF point, QgsRenderContext& context ) const
QRectF QgsMarkerSymbolV2::bounds( QPointF point, QgsRenderContext& context, const QgsFeature& feature ) const
{
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, nullptr, nullptr, mapUnitScale() );
QgsSymbolV2RenderContext symbolContext( context, outputUnit(), mAlpha, false, mRenderHints, &feature, feature.fields(), mapUnitScale() );

QRectF bound;
Q_FOREACH ( QgsSymbolLayerV2* layer, mLayers )
@@ -545,10 +545,16 @@ class CORE_EXPORT QgsMarkerSymbolV2 : public QgsSymbolV2
void renderPoint( QPointF point, const QgsFeature* f, QgsRenderContext& context, int layer = -1, bool selected = false );

/** Returns the approximate bounding box of the marker symbol, which includes the bounding box
* of all symbol layers for the symbol.
* of all symbol layers for the symbol. It is recommended to use this method only between startRender()
* and stopRender() calls, or data defined rotation and offset will not be correctly calculated.
* @param point location of rendered point in painter units
* @param context render context
* @param feature feature being rendered at point (optional). If not specified, the bounds calculation will not
* include data defined parameters such as offset and rotation
* @returns approximate symbol bounds, in painter units
* @note added in QGIS 2.14 */
QRectF bounds( QPointF point, QgsRenderContext& context ) const;
* @note added in QGIS 2.14
*/
QRectF bounds( QPointF point, QgsRenderContext& context, const QgsFeature &feature = QgsFeature() ) const;

virtual QgsMarkerSymbolV2* clone() const override;

@@ -60,6 +60,9 @@ class TestQgsSimpleMarkerSymbol : public QObject

void simpleMarkerSymbol();
void bounds();
void boundsWithOffset();
void boundsWithRotation();
void boundsWithRotationAndOffset();

private:
bool mTestHasError;
@@ -152,6 +155,57 @@ void TestQgsSimpleMarkerSymbol::bounds()
mMapSettings.setFlag( QgsMapSettings::DrawSymbolBounds, true );
bool result = imageCheck( "simplemarker_bounds" );
mMapSettings.setFlag( QgsMapSettings::DrawSymbolBounds, false );
mSimpleMarkerLayer->removeDataDefinedProperty( "size" );
QVERIFY( result );
}

void TestQgsSimpleMarkerSymbol::boundsWithOffset()
{
mSimpleMarkerLayer->setColor( QColor( 200, 200, 200 ) );
mSimpleMarkerLayer->setBorderColor( QColor( 0, 0, 0 ) );
mSimpleMarkerLayer->setName( "circle" );
mSimpleMarkerLayer->setSize( 5 );
mSimpleMarkerLayer->setDataDefinedProperty( "offset", new QgsDataDefined( true, true, "if(importance > 2, '5,10', '10, 5')" ) );
mSimpleMarkerLayer->setOutlineWidth( 0.5 );

mMapSettings.setFlag( QgsMapSettings::DrawSymbolBounds, true );
bool result = imageCheck( "simplemarker_boundsoffset" );
mMapSettings.setFlag( QgsMapSettings::DrawSymbolBounds, false );
mSimpleMarkerLayer->removeDataDefinedProperty( "offset" );
QVERIFY( result );
}

void TestQgsSimpleMarkerSymbol::boundsWithRotation()
{
mSimpleMarkerLayer->setColor( QColor( 200, 200, 200 ) );
mSimpleMarkerLayer->setBorderColor( QColor( 0, 0, 0 ) );
mSimpleMarkerLayer->setName( "square" );
mSimpleMarkerLayer->setSize( 5 );
mSimpleMarkerLayer->setDataDefinedProperty( "angle", new QgsDataDefined( true, true, "importance * 20" ) );
mSimpleMarkerLayer->setOutlineWidth( 0.5 );

mMapSettings.setFlag( QgsMapSettings::DrawSymbolBounds, true );
bool result = imageCheck( "simplemarker_boundsrotation" );
mMapSettings.setFlag( QgsMapSettings::DrawSymbolBounds, false );
mSimpleMarkerLayer->removeDataDefinedProperty( "angle" );
QVERIFY( result );
}

void TestQgsSimpleMarkerSymbol::boundsWithRotationAndOffset()
{
mSimpleMarkerLayer->setColor( QColor( 200, 200, 200 ) );
mSimpleMarkerLayer->setBorderColor( QColor( 0, 0, 0 ) );
mSimpleMarkerLayer->setName( "square" );
mSimpleMarkerLayer->setSize( 5 );
mSimpleMarkerLayer->setDataDefinedProperty( "offset", new QgsDataDefined( true, true, "if(importance > 2, '5,10', '10, 5')" ) );
mSimpleMarkerLayer->setDataDefinedProperty( "angle", new QgsDataDefined( true, false, QString(), "heading" ) );
mSimpleMarkerLayer->setOutlineWidth( 0.5 );

mMapSettings.setFlag( QgsMapSettings::DrawSymbolBounds, true );
bool result = imageCheck( "simplemarker_boundsrotationoffset" );
mMapSettings.setFlag( QgsMapSettings::DrawSymbolBounds, false );
mSimpleMarkerLayer->removeDataDefinedProperty( "offset" );
mSimpleMarkerLayer->removeDataDefinedProperty( "angle" );
QVERIFY( result );
}

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.
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 c230c23

Please sign in to comment.