Skip to content

Commit

Permalink
Move responsibility for drawing label metrics, rects to labeling engine
Browse files Browse the repository at this point in the history
Fixes a TODO
  • Loading branch information
nyalldawson committed Dec 2, 2024
1 parent 18b36cb commit a1e0177
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 66 deletions.
119 changes: 95 additions & 24 deletions src/core/labeling/qgslabelingengine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -517,41 +517,82 @@ void QgsLabelingEngine::drawLabels( QgsRenderContext &context, const QString &la
lf->provider()->drawLabelBackground( context, label );
}

// draw the labels
for ( pal::LabelPosition *label : std::as_const( mLabels ) )
if ( engineSettings().testFlag( Qgis::LabelingFlag::DrawLabelRectOnly ) )
{
if ( context.renderingStopped() )
break;

QgsLabelFeature *lf = label->getFeaturePart()->feature();
if ( !lf )
// features are pre-rotated but not scaled/translated,
// so we only disable rotation here. Ideally, they'd be
// also pre-scaled/translated, as suggested here:
// https://github.com/qgis/QGIS/issues/20071
QgsMapToPixel xform = context.mapToPixel();
xform.setMapRotation( 0, 0, 0 );

std::function<void( pal::LabelPosition * )> drawLabelRect;
drawLabelRect = [&xform, painter, &drawLabelRect]( pal::LabelPosition * label )
{
continue;
}
QPointF outPt = xform.transform( label->getX(), label->getY() ).toQPointF();

if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
continue;
QgsPointXY outPt2 = xform.transform( label->getX() + label->getWidth(), label->getY() + label->getHeight() );
QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
painter->save();
painter->setRenderHint( QPainter::Antialiasing, false );
painter->translate( QPointF( outPt.x(), outPt.y() ) );
painter->rotate( -label->getAlpha() * 180 / M_PI );

context.expressionContext().setFeature( lf->feature() );
context.expressionContext().setFields( lf->feature().fields() );
if ( label->conflictsWithObstacle() )
{
painter->setBrush( QColor( 255, 0, 0, 100 ) );
painter->setPen( QColor( 255, 0, 0, 150 ) );
}
else
{
painter->setBrush( QColor( 0, 255, 0, 100 ) );
painter->setPen( QColor( 0, 255, 0, 150 ) );
}

QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, lf->provider()->layerReferenceScale() );
if ( lf->symbol() )
painter->drawRect( rect );
painter->restore();

if ( pal::LabelPosition *nextPart = label->nextPart() )
drawLabelRect( nextPart );
};

for ( pal::LabelPosition *label : std::as_const( mLabels ) )
{
symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
drawLabelRect( label );
}
lf->provider()->drawLabel( context, label );
// finished with symbol -- we can't keep it around after this, it may be deleted
lf->setSymbol( nullptr );
}

// draw unplaced labels. These are always rendered on top
if ( settings.testFlag( Qgis::LabelingFlag::DrawUnplacedLabels ) || settings.testFlag( Qgis::LabelingFlag::CollectUnplacedLabels ) )
else
{
for ( pal::LabelPosition *label : std::as_const( mUnlabeled ) )
if ( engineSettings().testFlag( Qgis::LabelingFlag::DrawLabelMetrics ) )
{
// features are pre-rotated but not scaled/translated,
// so we only disable rotation here. Ideally, they'd be
// also pre-scaled/translated, as suggested here:
// https://github.com/qgis/QGIS/issues/20071
QgsMapToPixel xform = context.mapToPixel();
xform.setMapRotation( 0, 0, 0 );

std::function<void( pal::LabelPosition * )> drawLabelMetricsRecursive;
drawLabelMetricsRecursive = [&xform, &context, &drawLabelMetricsRecursive]( pal::LabelPosition * label )
{
QPointF outPt = xform.transform( label->getX(), label->getY() ).toQPointF();
QgsLabelingEngine::drawLabelMetrics( label, xform, context, outPt );
if ( pal::LabelPosition *nextPart = label->nextPart() )
drawLabelMetricsRecursive( nextPart );
};

for ( pal::LabelPosition *label : std::as_const( mLabels ) )
{
drawLabelMetricsRecursive( label );
}
}

// draw the labels
for ( pal::LabelPosition *label : std::as_const( mLabels ) )
{
if ( context.renderingStopped() )
break;

QgsLabelFeature *lf = label->getFeaturePart()->feature();
if ( !lf )
{
Expand All @@ -569,10 +610,40 @@ void QgsLabelingEngine::drawLabels( QgsRenderContext &context, const QString &la
{
symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
}
lf->provider()->drawUnplacedLabel( context, label );
lf->provider()->drawLabel( context, label );
// finished with symbol -- we can't keep it around after this, it may be deleted
lf->setSymbol( nullptr );
}

// draw unplaced labels. These are always rendered on top
if ( settings.testFlag( Qgis::LabelingFlag::DrawUnplacedLabels ) || settings.testFlag( Qgis::LabelingFlag::CollectUnplacedLabels ) )
{
for ( pal::LabelPosition *label : std::as_const( mUnlabeled ) )
{
if ( context.renderingStopped() )
break;
QgsLabelFeature *lf = label->getFeaturePart()->feature();
if ( !lf )
{
continue;
}

if ( !layerId.isEmpty() && lf->provider()->layerId() != layerId )
continue;

context.expressionContext().setFeature( lf->feature() );
context.expressionContext().setFields( lf->feature().fields() );

QgsScopedRenderContextReferenceScaleOverride referenceScaleOverride( context, lf->provider()->layerReferenceScale() );
if ( lf->symbol() )
{
symbolScope = QgsExpressionContextUtils::updateSymbolScope( lf->symbol(), symbolScope );
}
lf->provider()->drawUnplacedLabel( context, label );
// finished with symbol -- we can't keep it around after this, it may be deleted
lf->setSymbol( nullptr );
}
}
}

symbolScopePopper.reset();
Expand Down
42 changes: 0 additions & 42 deletions src/core/labeling/qgsvectorlayerlabelprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,6 @@ void QgsVectorLayerLabelProvider::drawUnplacedLabel( QgsRenderContext &context,
void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition *label, QgsRenderContext &context, QgsPalLayerSettings &tmpLyr, Qgis::TextComponent drawType, double dpiRatio ) const
{
// NOTE: this is repeatedly called for multi-part labels
QPainter *painter = context.painter();

Qgis::TextComponents components;
switch ( drawType )
{
Expand All @@ -523,46 +521,6 @@ void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition *label, Q

QPointF outPt = xform.transform( label->getX(), label->getY() ).toQPointF();

if ( mEngine->engineSettings().testFlag( Qgis::LabelingFlag::DrawLabelRectOnly ) ) // TODO: this should get directly to labeling engine
{
//debugging rect
if ( drawType != Qgis::TextComponent::Text )
return;

QgsPointXY outPt2 = xform.transform( label->getX() + label->getWidth(), label->getY() + label->getHeight() );
QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
painter->save();
painter->setRenderHint( QPainter::Antialiasing, false );
painter->translate( QPointF( outPt.x(), outPt.y() ) );
painter->rotate( -label->getAlpha() * 180 / M_PI );

if ( label->conflictsWithObstacle() )
{
painter->setBrush( QColor( 255, 0, 0, 100 ) );
painter->setPen( QColor( 255, 0, 0, 150 ) );
}
else
{
painter->setBrush( QColor( 0, 255, 0, 100 ) );
painter->setPen( QColor( 0, 255, 0, 150 ) );
}

painter->drawRect( rect );
painter->restore();

if ( label->nextPart() )
drawLabelPrivate( label->nextPart(), context, tmpLyr, drawType, dpiRatio );

return;
}
if ( mEngine->engineSettings().testFlag( Qgis::LabelingFlag::DrawLabelMetrics ) )
{
if ( drawType != Qgis::TextComponent::Text )
return;

QgsLabelingEngine::drawLabelMetrics( label, xform, context, outPt );
}

QgsTextRenderer::Component component;
component.dpiRatio = dpiRatio;
component.origin = outPt;
Expand Down

0 comments on commit a1e0177

Please sign in to comment.