Skip to content

Commit 2ab1e02

Browse files
committed
Fix labeling hide partial labels setting when map is rotated
Previously partially hidden labels would be shown when a map is rotated, even if the project was set to hide partial labels. To achieve this pal has been refactored to allow an arbitrary QgsGeometry specifying the map boundary (instead of the previous rectangular only extents). The good news is that this paves the way for a future release to have non-rectangular layout map items, where the actual map item shape will be correctly handled by the labeling engine...
1 parent 2d71309 commit 2ab1e02

File tree

5 files changed

+37
-30
lines changed

5 files changed

+37
-30
lines changed

src/core/pal/feature.cpp

+4-10
Original file line numberDiff line numberDiff line change
@@ -1512,16 +1512,9 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition *> &lPos, Poin
15121512
}
15131513

15141514
int FeaturePart::createCandidates( QList< LabelPosition *> &lPos,
1515-
double bboxMin[2], double bboxMax[2],
1515+
const GEOSPreparedGeometry *mapBoundary,
15161516
PointSet *mapShape, RTree<LabelPosition *, double, 2, double> *candidates )
15171517
{
1518-
double bbox[4];
1519-
1520-
bbox[0] = bboxMin[0];
1521-
bbox[1] = bboxMin[1];
1522-
bbox[2] = bboxMax[0];
1523-
bbox[3] = bboxMax[1];
1524-
15251518
double angle = mLF->hasFixedAngle() ? mLF->fixedAngle() : 0.0;
15261519

15271520
if ( mLF->hasFixedPosition() )
@@ -1579,10 +1572,11 @@ int FeaturePart::createCandidates( QList< LabelPosition *> &lPos,
15791572
{
15801573
LabelPosition *pos = i.next();
15811574
bool outside = false;
1575+
15821576
if ( mLF->layer()->pal->getShowPartial() )
1583-
outside = !pos->isIntersect( bbox );
1577+
outside = !pos->intersects( mapBoundary );
15841578
else
1585-
outside = !pos->isInside( bbox );
1579+
outside = !pos->within( mapBoundary );
15861580
if ( outside )
15871581
{
15881582
i.remove();

src/core/pal/feature.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -130,13 +130,12 @@ namespace pal
130130
/**
131131
* Generic method to generate label candidates for the feature.
132132
* \param lPos pointer to an array of candidates, will be filled by generated candidates
133-
* \param bboxMin min values of the map extent
134-
* \param bboxMax max values of the map extent
133+
* \param mapBoundary map boundary geometry
135134
* \param mapShape generate candidates for this spatial entity
136135
* \param candidates index for candidates
137136
* \returns the number of candidates generated in lPos
138137
*/
139-
int createCandidates( QList<LabelPosition *> &lPos, double bboxMin[2], double bboxMax[2], PointSet *mapShape, RTree<LabelPosition *, double, 2, double> *candidates );
138+
int createCandidates( QList<LabelPosition *> &lPos, const GEOSPreparedGeometry *mapBoundary, PointSet *mapShape, RTree<LabelPosition *, double, 2, double> *candidates );
140139

141140
/**
142141
* Generate candidates for point feature, located around a specified point.

src/core/pal/pal.cpp

+14-13
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,7 @@ typedef struct _featCbackCtx
124124
QLinkedList<Feats *> *fFeats;
125125
RTree<FeaturePart *, double, 2, double> *obstacles;
126126
RTree<LabelPosition *, double, 2, double> *candidates;
127-
double bbox_min[2];
128-
double bbox_max[2];
127+
const GEOSPreparedGeometry *mapBoundary = nullptr;
129128
} FeatCallBackCtx;
130129

131130

@@ -154,7 +153,7 @@ bool extractFeatCallback( FeaturePart *ft_ptr, void *ctx )
154153

155154
// generate candidates for the feature part
156155
QList< LabelPosition * > lPos;
157-
if ( ft_ptr->createCandidates( lPos, context->bbox_min, context->bbox_max, ft_ptr, context->candidates ) )
156+
if ( ft_ptr->createCandidates( lPos, context->mapBoundary, ft_ptr, context->candidates ) )
158157
{
159158
// valid features are added to fFeats
160159
Feats *ft = new Feats();
@@ -241,23 +240,25 @@ std::unique_ptr<Problem> Pal::extract( const QgsRectangle &extent, const QgsGeom
241240

242241
LabelPosition *lp = nullptr;
243242

244-
bbx[0] = bbx[3] = amin[0] = prob->bbox[0] = lambda_min;
245-
bby[0] = bby[1] = amin[1] = prob->bbox[1] = phi_min;
246-
bbx[1] = bbx[2] = amax[0] = prob->bbox[2] = lambda_max;
247-
bby[2] = bby[3] = amax[1] = prob->bbox[3] = phi_max;
243+
bbx[0] = bbx[3] = amin[0] = prob->bbox[0] = extent.xMinimum();
244+
bby[0] = bby[1] = amin[1] = prob->bbox[1] = extent.yMinimum();
245+
bbx[1] = bbx[2] = amax[0] = prob->bbox[2] = extent.xMaximum();
246+
bby[2] = bby[3] = amax[1] = prob->bbox[3] = extent.yMaximum();
248247

249248
prob->pal = this;
250249

251250
QLinkedList<Feats *> *fFeats = new QLinkedList<Feats *>;
252251

253252
FeatCallBackCtx context;
253+
254+
// prepare map boundary
255+
geos::unique_ptr mapBoundaryGeos( mapBoundary.exportToGeos() );
256+
geos::prepared_unique_ptr mapBoundaryPrepared( GEOSPrepare_r( geosContext(), mapBoundaryGeos.get() ) );
257+
254258
context.fFeats = fFeats;
255259
context.obstacles = obstacles;
256260
context.candidates = prob->candidates;
257-
context.bbox_min[0] = amin[0];
258-
context.bbox_min[1] = amin[1];
259-
context.bbox_max[0] = amax[0];
260-
context.bbox_max[1] = amax[1];
261+
context.mapBoundary = mapBoundaryPrepared.get();
261262

262263
ObstacleCallBackCtx obstacleContext;
263264
obstacleContext.obstacles = obstacles;
@@ -451,9 +452,9 @@ void Pal::registerCancelationCallback( Pal::FnIsCanceled fnCanceled, void *conte
451452
fnIsCanceledContext = context;
452453
}
453454

454-
Problem *Pal::extractProblem( double bbox[4] )
455+
std::unique_ptr<Problem> Pal::extractProblem( const QgsRectangle &extent, const QgsGeometry &mapBoundary )
455456
{
456-
return extract( bbox[0], bbox[1], bbox[2], bbox[3] );
457+
return extract( extent, mapBoundary );
457458
}
458459

459460
QList<LabelPosition *> Pal::solveProblem( Problem *prob, bool displayAll )

src/core/pal/pal.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,14 @@ namespace pal
138138
//! Check whether the job has been canceled
139139
inline bool isCanceled() { return fnIsCanceled ? fnIsCanceled( fnIsCanceledContext ) : false; }
140140

141-
Problem *extractProblem( double bbox[4] );
141+
/**
142+
* Extracts the labeling problem for the specified map \a extent - only features within this
143+
* extent will be considered. The \a mapBoundary argument specifies the actual geometry of the map
144+
* boundary, which will be used to detect whether a label is visible (or partially visible) in
145+
* the rendered map. This may differ from \a extent in the case of rotated or non-rectangular
146+
* maps.
147+
*/
148+
std::unique_ptr< Problem > extractProblem( const QgsRectangle &extent, const QgsGeometry &mapBoundary );
142149

143150
QList<LabelPosition *> solveProblem( Problem *prob, bool displayAll );
144151

@@ -266,8 +273,7 @@ namespace pal
266273
* \param lambda_max xMax bounding-box
267274
* \param phi_max yMax bounding-box
268275
*/
269-
Problem *extract( double lambda_min, double phi_min,
270-
double lambda_max, double phi_max );
276+
std::unique_ptr< Problem > extract( const QgsRectangle &extent, const QgsGeometry &mapBoundary );
271277

272278

273279
/**

src/core/qgslabelingengine.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,21 @@ void QgsLabelingEngine::run( QgsRenderContext &context )
242242
QPainter *painter = context.painter();
243243

244244
QgsGeometry extentGeom = QgsGeometry::fromRect( mMapSettings.visibleExtent() );
245+
QPolygonF visiblePoly = mMapSettings.visiblePolygon();
246+
visiblePoly.append( visiblePoly.at( 0 ) ); //close polygon
247+
QgsGeometry mapBoundaryGeom = QgsGeometry::fromQPolygonF( visiblePoly );
248+
245249
if ( !qgsDoubleNear( mMapSettings.rotation(), 0.0 ) )
246250
{
247251
//PAL features are prerotated, so extent also needs to be unrotated
248252
extentGeom.rotate( -mMapSettings.rotation(), mMapSettings.visibleExtent().center() );
253+
// yes - this is rotated in the opposite direction... phew, this is confusing!
254+
mapBoundaryGeom.rotate( mMapSettings.rotation(), mMapSettings.visibleExtent().center() );
249255
}
250256

251257
QgsRectangle extent = extentGeom.boundingBox();
252258

259+
253260
p.registerCancelationCallback( &_palIsCanceled, reinterpret_cast< void * >( &context ) );
254261

255262
QTime t;
@@ -259,7 +266,7 @@ void QgsLabelingEngine::run( QgsRenderContext &context )
259266
std::unique_ptr< pal::Problem > problem;
260267
try
261268
{
262-
problem = p.extractProblem( bbox );
269+
problem = p.extractProblem( extent, mapBoundaryGeom );
263270
}
264271
catch ( std::exception &e )
265272
{

0 commit comments

Comments
 (0)