Move class, method out of QgsPalLabeling to central location

This commit is contained in:
Nyall Dawson 2024-12-02 12:13:58 +10:00
parent f041077a36
commit 7670fbe362
No known key found for this signature in database
GPG Key ID: 4C61673F0BF197FC
15 changed files with 260 additions and 211 deletions

View File

@ -0,0 +1,5 @@
# The following has been generated automatically from src/core/labeling/qgslabelingengine.h
try:
QgsLabelCandidate.__group__ = ['labeling']
except NameError:
pass

View File

@ -521,7 +521,3 @@ try:
QgsPalLabeling.__group__ = ['labeling']
except NameError:
pass
try:
QgsLabelCandidate.__group__ = ['labeling']
except NameError:
pass

View File

@ -0,0 +1,38 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/labeling/qgslabelingengine.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.py again *
************************************************************************/
class QgsLabelCandidate
{
%Docstring(signature="appended")
Represents a label candidate.
%End
%TypeHeaderCode
#include "qgslabelingengine.h"
%End
public:
QgsLabelCandidate( const QRectF &r, double c );
QRectF rect;
double cost;
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/labeling/qgslabelingengine.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.py again *
************************************************************************/

View File

@ -620,21 +620,6 @@ Sets the layer's unplaced label ``visibility``.
};
class QgsLabelCandidate
{
%Docstring(signature="appended")
Represents a label candidate.
%End
%TypeHeaderCode
#include "qgspallabeling.h"
%End
public:
QgsLabelCandidate( const QRectF &r, double c );
QRectF rect;
double cost;
};
class QgsPalLabeling
{
@ -652,7 +637,6 @@ PAL labeling utilities.
Called to find out whether a specified ``layer`` is used for labeling.
%End
static QgsGeometry prepareGeometry( const QgsGeometry &geometry, QgsRenderContext &context, const QgsCoordinateTransform &ct, const QgsGeometry &clipGeometry = QgsGeometry(), bool mergeLines = false ) /Factory/;
%Docstring
Prepares a geometry for registration with PAL. Handles reprojection, rotation, clipping, etc.

View File

@ -384,6 +384,7 @@
%Include auto_generated/gps/qgsvectorlayergpslogger.sip
%Include auto_generated/labeling/qgscalloutposition.sip
%Include auto_generated/labeling/qgslabeling.sip
%Include auto_generated/labeling/qgslabelingengine.sip
%Include auto_generated/labeling/qgslabelingenginesettings.sip
%Include auto_generated/labeling/qgslabelingresults.sip
%Include auto_generated/labeling/qgslabellinesettings.sip

View File

@ -0,0 +1,5 @@
# The following has been generated automatically from src/core/labeling/qgslabelingengine.h
try:
QgsLabelCandidate.__group__ = ['labeling']
except NameError:
pass

View File

@ -521,7 +521,3 @@ try:
QgsPalLabeling.__group__ = ['labeling']
except NameError:
pass
try:
QgsLabelCandidate.__group__ = ['labeling']
except NameError:
pass

View File

@ -0,0 +1,38 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/labeling/qgslabelingengine.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.py again *
************************************************************************/
class QgsLabelCandidate
{
%Docstring(signature="appended")
Represents a label candidate.
%End
%TypeHeaderCode
#include "qgslabelingengine.h"
%End
public:
QgsLabelCandidate( const QRectF &r, double c );
QRectF rect;
double cost;
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/labeling/qgslabelingengine.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.py again *
************************************************************************/

View File

@ -620,21 +620,6 @@ Sets the layer's unplaced label ``visibility``.
};
class QgsLabelCandidate
{
%Docstring(signature="appended")
Represents a label candidate.
%End
%TypeHeaderCode
#include "qgspallabeling.h"
%End
public:
QgsLabelCandidate( const QRectF &r, double c );
QRectF rect;
double cost;
};
class QgsPalLabeling
{
@ -652,7 +637,6 @@ PAL labeling utilities.
Called to find out whether a specified ``layer`` is used for labeling.
%End
static QgsGeometry prepareGeometry( const QgsGeometry &geometry, QgsRenderContext &context, const QgsCoordinateTransform &ct, const QgsGeometry &clipGeometry = QgsGeometry(), bool mergeLines = false ) /Factory/;
%Docstring
Prepares a geometry for registration with PAL. Handles reprojection, rotation, clipping, etc.

View File

@ -384,6 +384,7 @@
%Include auto_generated/gps/qgsvectorlayergpslogger.sip
%Include auto_generated/labeling/qgscalloutposition.sip
%Include auto_generated/labeling/qgslabeling.sip
%Include auto_generated/labeling/qgslabelingengine.sip
%Include auto_generated/labeling/qgslabelingenginesettings.sip
%Include auto_generated/labeling/qgslabelingresults.sip
%Include auto_generated/labeling/qgslabellinesettings.sip

View File

@ -33,6 +33,7 @@
#include "qgsfillsymbol.h"
#include "qgsruntimeprofiler.h"
#include "qgslabelingenginerule.h"
#include "qgstextlabelfeature.h"
#include <QUuid>
@ -439,7 +440,7 @@ void QgsLabelingEngine::solve( QgsRenderContext &context )
{
pal::LabelPosition *lp = mProblem->featureCandidate( i, j );
QgsPalLabeling::drawLabelCandidateRect( lp, painter, &xform );
drawLabelCandidateRect( lp, context, &xform );
}
}
}
@ -604,6 +605,141 @@ QgsLabelingResults *QgsLabelingEngine::takeResults()
return mResults.release();
}
void QgsLabelingEngine::drawLabelCandidateRect( pal::LabelPosition *lp, QgsRenderContext &context, const QgsMapToPixel *xform, QList<QgsLabelCandidate> *candidates )
{
QPainter *painter = context.painter();
if ( !painter )
return;
QgsPointXY outPt = xform->transform( lp->getX(), lp->getY() );
painter->save();
QgsPointXY outPt2 = xform->transform( lp->getX() + lp->getWidth(), lp->getY() + lp->getHeight() );
QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
painter->translate( QPointF( outPt.x(), outPt.y() ) );
painter->rotate( -lp->getAlpha() * 180 / M_PI );
if ( lp->conflictsWithObstacle() )
{
painter->setPen( QColor( 255, 0, 0, 64 ) );
}
else
{
painter->setPen( QColor( 0, 0, 0, 64 ) );
}
painter->drawRect( rect );
painter->restore();
// save the rect
rect.moveTo( outPt.x(), outPt.y() );
if ( candidates )
candidates->append( QgsLabelCandidate( rect, lp->cost() * 1000 ) );
// show all parts of the multipart label
if ( lp->nextPart() )
drawLabelCandidateRect( lp->nextPart(), context, xform, candidates );
}
void QgsLabelingEngine::drawLabelMetrics( pal::LabelPosition *label, QgsMapToPixel xform, QgsRenderContext &context, const QPointF &renderPoint )
{
QPainter *painter = context.painter();
if ( !painter )
return;
QgsPointXY outPt2 = xform.transform( label->getX() + label->getWidth(), label->getY() + label->getHeight() );
QRectF rect( 0, 0, outPt2.x() - renderPoint.x(), outPt2.y() - renderPoint.y() );
painter->save();
painter->setRenderHint( QPainter::Antialiasing, false );
painter->translate( QPointF( renderPoint.x(), renderPoint.y() ) );
painter->rotate( -label->getAlpha() * 180 / M_PI );
painter->setBrush( Qt::NoBrush );
painter->setPen( QColor( 255, 0, 0, 220 ) );
painter->drawRect( rect );
painter->setPen( QColor( 0, 0, 0, 60 ) );
const QgsMargins &margins = label->getFeaturePart()->feature()->visualMargin();
if ( margins.top() > 0 )
{
const double topMargin = margins.top() / context.mapToPixel().mapUnitsPerPixel();
painter->drawLine( QPointF( rect.left(), rect.top() - topMargin ), QPointF( rect.right(), rect.top() - topMargin ) );
}
if ( margins.bottom() > 0 )
{
const double bottomMargin = margins.top() / context.mapToPixel().mapUnitsPerPixel();
painter->drawLine( QPointF( rect.left(), rect.bottom() + bottomMargin ), QPointF( rect.right(), rect.bottom() + bottomMargin ) );
}
const QRectF outerBounds = label->getFeaturePart()->feature()->outerBounds();
if ( !outerBounds.isNull() )
{
const QRectF mapOuterBounds = QRectF( label->getX() + outerBounds.left(),
label->getY() + outerBounds.top(),
outerBounds.width(), outerBounds.height() );
QgsPointXY outerBoundsPt1 = xform.transform( mapOuterBounds.left(), mapOuterBounds.top() );
QgsPointXY outerBoundsPt2 = xform.transform( mapOuterBounds.right(), mapOuterBounds.bottom() );
const QRectF outerBoundsPixel( outerBoundsPt1.x() - renderPoint.x(),
outerBoundsPt1.y() - renderPoint.y(),
outerBoundsPt2.x() - outerBoundsPt1.x(),
outerBoundsPt2.y() - outerBoundsPt1.y() );
QPen pen( QColor( 255, 0, 255, 140 ) );
pen.setCosmetic( true );
pen.setWidth( 1 );
painter->setPen( pen );
painter->drawRect( outerBoundsPixel );
}
if ( QgsTextLabelFeature *textFeature = dynamic_cast< QgsTextLabelFeature * >( label->getFeaturePart()->feature() ) )
{
const QgsTextDocumentMetrics &metrics = textFeature->documentMetrics();
const QgsTextDocument &document = textFeature->document();
const int blockCount = document.size();
double prevBlockBaseline = rect.bottom() - rect.top();
const double verticalAlignOffset = -metrics.blockVerticalMargin( document.size() - 1 );
// draw block baselines
for ( int blockIndex = 0; blockIndex < blockCount; ++blockIndex )
{
const double blockBaseLine = metrics.baselineOffset( blockIndex, Qgis::TextLayoutMode::Labeling );
const QgsTextBlock &block = document.at( blockIndex );
const int fragmentCount = block.size();
double left = metrics.blockLeftMargin( blockIndex );
for ( int fragmentIndex = 0; fragmentIndex < fragmentCount; ++fragmentIndex )
{
const double fragmentVerticalOffset = metrics.fragmentVerticalOffset( blockIndex, fragmentIndex, Qgis::TextLayoutMode::Labeling );
const double right = left + metrics.fragmentHorizontalAdvance( blockIndex, fragmentIndex, Qgis::TextLayoutMode::Labeling );
if ( fragmentIndex > 0 )
{
QPen pen( QColor( 0, 0, 255, 220 ) );
pen.setStyle( Qt::PenStyle::DashLine );
painter->setPen( pen );
painter->drawLine( QPointF( rect.left() + left, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ),
QPointF( rect.left() + left, rect.top() + prevBlockBaseline + verticalAlignOffset ) );
}
painter->setPen( QColor( 0, 0, 255, 220 ) );
painter->drawLine( QPointF( rect.left() + left, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ),
QPointF( rect.left() + right, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ) );
left = right;
}
prevBlockBaseline = blockBaseLine;
}
}
painter->restore();
}
//
// QgsDefaultLabelingEngine

View File

@ -16,8 +16,6 @@
#ifndef QGSLABELINGENGINE_H
#define QGSLABELINGENGINE_H
#define SIP_NO_FILE
#include "qgis_core.h"
#include "qgsmapsettings.h"
@ -29,12 +27,30 @@ class QgsLabelingResults;
class QgsLabelFeature;
class QgsLabelingEngineSettings;
#ifndef SIP_RUN
namespace pal
{
class Problem;
class Pal;
class LabelPosition;
}
#endif
/**
* \ingroup core
* \brief Represents a label candidate.
*/
class CORE_EXPORT QgsLabelCandidate
{
public:
QgsLabelCandidate( const QRectF &r, double c ): rect( r ), cost( c ) {}
QRectF rect;
double cost;
};
#ifndef SIP_RUN
/**
* \ingroup core
@ -411,6 +427,20 @@ class CORE_EXPORT QgsLabelingEngine
//! For internal use by the providers
QgsLabelingResults *results() const { return mResults.get(); }
/**
* Draws label candidate rectangles.
*
* \see drawLabelMetrics()
*/
static void drawLabelCandidateRect( pal::LabelPosition *lp, QgsRenderContext &context, const QgsMapToPixel *xform, QList<QgsLabelCandidate> *candidates = nullptr );
/**
* Draws label metrics.
*
* \see drawLabelCandidateRect()
*/
static void drawLabelMetrics( pal::LabelPosition *label, QgsMapToPixel xform, QgsRenderContext &context, const QPointF &renderPoint );
protected:
void processProvider( QgsAbstractLabelProvider *provider, QgsRenderContext &context, pal::Pal &p );
@ -576,4 +606,6 @@ class CORE_EXPORT QgsLabelingUtils
};
#endif
#endif // QGSLABELINGENGINE_H

View File

@ -25,8 +25,6 @@
#include "qgstextrenderer.h"
#include "qgsscaleutils.h"
#include "pal/labelposition.h"
#include <cmath>
#include <QApplication>
@ -4831,62 +4829,3 @@ void QgsPalLabeling::dataDefinedDropShadow( QgsPalLayerSettings &tmpLyr,
tmpLyr.setFormat( format );
}
}
void QgsPalLabeling::drawLabelCandidateRect( pal::LabelPosition *lp, QPainter *painter, const QgsMapToPixel *xform, QList<QgsLabelCandidate> *candidates )
{
QgsPointXY outPt = xform->transform( lp->getX(), lp->getY() );
painter->save();
#if 0 // TODO: generalize some of this
double w = lp->getWidth();
double h = lp->getHeight();
double cx = lp->getX() + w / 2.0;
double cy = lp->getY() + h / 2.0;
double scale = 1.0 / xform->mapUnitsPerPixel();
double rotation = xform->mapRotation();
double sw = w * scale;
double sh = h * scale;
QRectF rect( -sw / 2, -sh / 2, sw, sh );
painter->translate( xform->transform( QPointF( cx, cy ) ).toQPointF() );
if ( rotation )
{
// Only if not horizontal
if ( lp->getFeaturePart()->getLayer()->getArrangement() != P_POINT &&
lp->getFeaturePart()->getLayer()->getArrangement() != P_POINT_OVER &&
lp->getFeaturePart()->getLayer()->getArrangement() != P_HORIZ )
{
painter->rotate( rotation );
}
}
painter->translate( rect.bottomLeft() );
painter->rotate( -lp->getAlpha() * 180 / M_PI );
painter->translate( -rect.bottomLeft() );
#else
QgsPointXY outPt2 = xform->transform( lp->getX() + lp->getWidth(), lp->getY() + lp->getHeight() );
QRectF rect( 0, 0, outPt2.x() - outPt.x(), outPt2.y() - outPt.y() );
painter->translate( QPointF( outPt.x(), outPt.y() ) );
painter->rotate( -lp->getAlpha() * 180 / M_PI );
#endif
if ( lp->conflictsWithObstacle() )
{
painter->setPen( QColor( 255, 0, 0, 64 ) );
}
else
{
painter->setPen( QColor( 0, 0, 0, 64 ) );
}
painter->drawRect( rect );
painter->restore();
// save the rect
rect.moveTo( outPt.x(), outPt.y() );
if ( candidates )
candidates->append( QgsLabelCandidate( rect, lp->cost() * 1000 ) );
// show all parts of the multipart label
if ( lp->nextPart() )
drawLabelCandidateRect( lp->nextPart(), painter, xform, candidates );
}

View File

@ -1026,18 +1026,6 @@ class CORE_EXPORT QgsPalLayerSettings
static void initPropertyDefinitions();
};
/**
* \ingroup core
* \brief Represents a label candidate.
*/
class CORE_EXPORT QgsLabelCandidate
{
public:
QgsLabelCandidate( const QRectF &r, double c ): rect( r ), cost( c ) {}
QRectF rect;
double cost;
};
/**
* \ingroup core
@ -1053,9 +1041,6 @@ class CORE_EXPORT QgsPalLabeling
*/
static bool staticWillUseLayer( const QgsMapLayer *layer );
//! \note not available in Python bindings
static void drawLabelCandidateRect( pal::LabelPosition *lp, QPainter *painter, const QgsMapToPixel *xform, QList<QgsLabelCandidate> *candidates = nullptr ) SIP_SKIP;
/**
* Prepares a geometry for registration with PAL. Handles reprojection, rotation, clipping, etc.
* \param geometry geometry to prepare

View File

@ -560,98 +560,7 @@ void QgsVectorLayerLabelProvider::drawLabelPrivate( pal::LabelPosition *label, Q
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 );
painter->setBrush( Qt::NoBrush );
painter->setPen( QColor( 255, 0, 0, 220 ) );
painter->drawRect( rect );
painter->setPen( QColor( 0, 0, 0, 60 ) );
const QgsMargins &margins = label->getFeaturePart()->feature()->visualMargin();
if ( margins.top() > 0 )
{
const double topMargin = margins.top() / context.mapToPixel().mapUnitsPerPixel();
painter->drawLine( QPointF( rect.left(), rect.top() - topMargin ), QPointF( rect.right(), rect.top() - topMargin ) );
}
if ( margins.bottom() > 0 )
{
const double bottomMargin = margins.top() / context.mapToPixel().mapUnitsPerPixel();
painter->drawLine( QPointF( rect.left(), rect.bottom() + bottomMargin ), QPointF( rect.right(), rect.bottom() + bottomMargin ) );
}
const QRectF outerBounds = label->getFeaturePart()->feature()->outerBounds();
if ( !outerBounds.isNull() )
{
const QRectF mapOuterBounds = QRectF( label->getX() + outerBounds.left(),
label->getY() + outerBounds.top(),
outerBounds.width(), outerBounds.height() );
QgsPointXY outerBoundsPt1 = xform.transform( mapOuterBounds.left(), mapOuterBounds.top() );
QgsPointXY outerBoundsPt2 = xform.transform( mapOuterBounds.right(), mapOuterBounds.bottom() );
const QRectF outerBoundsPixel( outerBoundsPt1.x() - outPt.x(),
outerBoundsPt1.y() - outPt.y(),
outerBoundsPt2.x() - outerBoundsPt1.x(),
outerBoundsPt2.y() - outerBoundsPt1.y() );
QPen pen( QColor( 255, 0, 255, 140 ) );
pen.setCosmetic( true );
pen.setWidth( 1 );
painter->setPen( pen );
painter->drawRect( outerBoundsPixel );
}
if ( QgsTextLabelFeature *textFeature = dynamic_cast< QgsTextLabelFeature * >( label->getFeaturePart()->feature() ) )
{
const QgsTextDocumentMetrics &metrics = textFeature->documentMetrics();
const QgsTextDocument &document = textFeature->document();
const int blockCount = document.size();
double prevBlockBaseline = rect.bottom() - rect.top();
const double verticalAlignOffset = -metrics.blockVerticalMargin( document.size() - 1 );
// draw block baselines
for ( int blockIndex = 0; blockIndex < blockCount; ++blockIndex )
{
const double blockBaseLine = metrics.baselineOffset( blockIndex, Qgis::TextLayoutMode::Labeling );
const QgsTextBlock &block = document.at( blockIndex );
const int fragmentCount = block.size();
double left = metrics.blockLeftMargin( blockIndex );
for ( int fragmentIndex = 0; fragmentIndex < fragmentCount; ++fragmentIndex )
{
const double fragmentVerticalOffset = metrics.fragmentVerticalOffset( blockIndex, fragmentIndex, Qgis::TextLayoutMode::Labeling );
const double right = left + metrics.fragmentHorizontalAdvance( blockIndex, fragmentIndex, Qgis::TextLayoutMode::Labeling );
if ( fragmentIndex > 0 )
{
QPen pen( QColor( 0, 0, 255, 220 ) );
pen.setStyle( Qt::PenStyle::DashLine );
painter->setPen( pen );
painter->drawLine( QPointF( rect.left() + left, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ),
QPointF( rect.left() + left, rect.top() + prevBlockBaseline + verticalAlignOffset ) );
}
painter->setPen( QColor( 0, 0, 255, 220 ) );
painter->drawLine( QPointF( rect.left() + left, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ),
QPointF( rect.left() + right, rect.top() + blockBaseLine + fragmentVerticalOffset + verticalAlignOffset ) );
left = right;
}
prevBlockBaseline = blockBaseLine;
}
}
painter->restore();
QgsLabelingEngine::drawLabelMetrics( label, xform, context, outPt );
}
QgsTextRenderer::Component component;