Skip to content

Commit f45f688

Browse files
committed
[labeling] Avoid placing labels over ANY part of point symbols
1 parent 3e61891 commit f45f688

9 files changed

+69
-4
lines changed

python/core/qgspallabeling.sip

+5-1
Original file line numberDiff line numberDiff line change
@@ -152,8 +152,12 @@ class QgsPalLayerSettings
152152
{
153153
PolygonInterior, /*!< avoid placing labels over interior of polygon (prefer placing labels totally
154154
outside or just slightly inside polygon) */
155-
PolygonBoundary /*!< avoid placing labels over boundary of polygon (prefer placing outside or
155+
PolygonBoundary, /*!< avoid placing labels over boundary of polygon (prefer placing outside or
156156
completely inside polygon) */
157+
PolygonWhole /*!< avoid placing labels over ANY part of polygon. Where PolygonInterior will prefer
158+
to place labels with the smallest area of intersection between the label and the polygon,
159+
PolygonWhole will penalise any label which intersects with the polygon by an equal amount, so that
160+
placing labels over any part of the polygon is avoided.*/
157161
};
158162

159163
enum ShapeType

src/core/pal/costcalculator.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ namespace pal
7777
// penalty may need tweaking, given that interior mode ranges up to 12
7878
n = ( lp->crossesBoundary( obstacle ) ? 6 : 0 );
7979
break;
80+
case PolygonWhole:
81+
// n is either 0 or 12
82+
n = ( lp->intersectsWithPolygon( obstacle ) ? 12 : 0 );
83+
break;
8084
}
8185

8286
break;

src/core/pal/labelposition.cpp

+31
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,37 @@ namespace pal
590590
return ceil( totalCost / n );
591591
}
592592

593+
bool LabelPosition::intersectsWithPolygon( PointSet* polygon ) const
594+
{
595+
if ( !mGeos )
596+
createGeosGeom();
597+
598+
if ( !polygon->mGeos )
599+
polygon->createGeosGeom();
600+
601+
GEOSContextHandle_t geosctxt = geosContext();
602+
try
603+
{
604+
if ( GEOSPreparedIntersects_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1 )
605+
{
606+
return true;
607+
}
608+
}
609+
catch ( GEOSException &e )
610+
{
611+
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
612+
}
613+
614+
if ( nextPart )
615+
{
616+
return nextPart->intersectsWithPolygon( polygon );
617+
}
618+
else
619+
{
620+
return false;
621+
}
622+
}
623+
593624
double LabelPosition::polygonIntersectionCostForParts( PointSet *polygon ) const
594625
{
595626
if ( !mGeos )

src/core/pal/labelposition.h

+4
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,10 @@ namespace pal
140140
*/
141141
int polygonIntersectionCost( PointSet* polygon ) const;
142142

143+
/** Returns true if if any intersection between polygon and position exists.
144+
*/
145+
bool intersectsWithPolygon( PointSet* polygon ) const;
146+
143147
/** Shift the label by specified offset */
144148
void offsetPosition( double xOffset, double yOffset );
145149

src/core/pal/pal.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ namespace pal
8989
enum ObstacleType
9090
{
9191
PolygonInterior,
92-
PolygonBoundary
92+
PolygonBoundary,
93+
PolygonWhole
9394
};
9495

9596
/**

src/core/qgslabelingenginev2.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ void QgsLabelingEngineV2::processProvider( QgsAbstractLabelProvider* provider, Q
110110
case QgsPalLayerSettings::PolygonBoundary:
111111
l->setObstacleType( pal::PolygonBoundary );
112112
break;
113+
case QgsPalLayerSettings::PolygonWhole:
114+
l->setObstacleType( pal::PolygonWhole );
115+
break;
113116
}
114117

115118
// set whether location of centroid must be inside of polygons

src/core/qgspallabeling.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,12 @@ class CORE_EXPORT QgsPalLayerSettings
134134
{
135135
PolygonInterior, /*!< avoid placing labels over interior of polygon (prefer placing labels totally
136136
outside or just slightly inside polygon) */
137-
PolygonBoundary /*!< avoid placing labels over boundary of polygon (prefer placing outside or
137+
PolygonBoundary, /*!< avoid placing labels over boundary of polygon (prefer placing outside or
138138
completely inside polygon) */
139+
PolygonWhole /*!< avoid placing labels over ANY part of polygon. Where PolygonInterior will prefer
140+
to place labels with the smallest area of intersection between the label and the polygon,
141+
PolygonWhole will penalise any label which intersects with the polygon by an equal amount, so that
142+
placing labels over any part of the polygon is avoided.*/
139143
};
140144

141145
enum ShapeType

src/core/qgsvectorlayerlabelprovider.cpp

+13-1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static void _fixQPictureDPI( QPainter* p )
5252
QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop, const QgsPalLayerSettings* settings, const QString& layerName )
5353
: mSettings( settings ? *settings : QgsPalLayerSettings::fromLayer( layer ) )
5454
, mLayerId( layer->id() )
55+
, mLayerGeometryType( layer->geometryType() )
5556
, mRenderer( layer->rendererV2() )
5657
, mFields( layer->fields() )
5758
, mCrs( layer->crs() )
@@ -80,6 +81,7 @@ QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( const QgsPalLayerSetti
8081
bool ownsSource, QgsFeatureRendererV2* renderer )
8182
: mSettings( settings )
8283
, mLayerId( layerId )
84+
, mLayerGeometryType( QGis::UnknownGeometry )
8385
, mRenderer( renderer )
8486
, mFields( fields )
8587
, mCrs( crs )
@@ -102,7 +104,17 @@ void QgsVectorLayerLabelProvider::init()
102104
if ( mSettings.fitInPolygonOnly ) mFlags |= FitInPolygonOnly;
103105
if ( mSettings.labelPerPart ) mFlags |= LabelPerFeaturePart;
104106
mPriority = 1 - mSettings.priority / 10.0; // convert 0..10 --> 1..0
105-
mObstacleType = mSettings.obstacleType;
107+
108+
if ( mLayerGeometryType == QGis::Point && mRenderer )
109+
{
110+
//override obstacle type to treat any intersection of a label with the point symbol as a high cost conflict
111+
mObstacleType = QgsPalLayerSettings::PolygonWhole;
112+
}
113+
else
114+
{
115+
mObstacleType = mSettings.obstacleType;
116+
}
117+
106118
mUpsidedownLabels = mSettings.upsidedownLabels;
107119
}
108120

src/core/qgsvectorlayerlabelprovider.h

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
9494
QgsPalLayerSettings mSettings;
9595
//! Layer's ID
9696
QString mLayerId;
97+
//! Geometry type of layer
98+
QGis::GeometryType mLayerGeometryType;
9799

98100
QgsFeatureRendererV2* mRenderer;
99101

0 commit comments

Comments
 (0)