Skip to content

Commit

Permalink
[labeling] Avoid placing labels over ANY part of point symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 25, 2015
1 parent 3e61891 commit f45f688
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 4 deletions.
6 changes: 5 additions & 1 deletion python/core/qgspallabeling.sip
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,12 @@ class QgsPalLayerSettings
{
PolygonInterior, /*!< avoid placing labels over interior of polygon (prefer placing labels totally
outside or just slightly inside polygon) */
PolygonBoundary /*!< avoid placing labels over boundary of polygon (prefer placing outside or
PolygonBoundary, /*!< avoid placing labels over boundary of polygon (prefer placing outside or
completely inside polygon) */
PolygonWhole /*!< avoid placing labels over ANY part of polygon. Where PolygonInterior will prefer
to place labels with the smallest area of intersection between the label and the polygon,
PolygonWhole will penalise any label which intersects with the polygon by an equal amount, so that
placing labels over any part of the polygon is avoided.*/
};

enum ShapeType
Expand Down
4 changes: 4 additions & 0 deletions src/core/pal/costcalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ namespace pal
// penalty may need tweaking, given that interior mode ranges up to 12
n = ( lp->crossesBoundary( obstacle ) ? 6 : 0 );
break;
case PolygonWhole:
// n is either 0 or 12
n = ( lp->intersectsWithPolygon( obstacle ) ? 12 : 0 );
break;
}

break;
Expand Down
31 changes: 31 additions & 0 deletions src/core/pal/labelposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,37 @@ namespace pal
return ceil( totalCost / n );
}

bool LabelPosition::intersectsWithPolygon( PointSet* polygon ) const
{
if ( !mGeos )
createGeosGeom();

if ( !polygon->mGeos )
polygon->createGeosGeom();

GEOSContextHandle_t geosctxt = geosContext();
try
{
if ( GEOSPreparedIntersects_r( geosctxt, polygon->preparedGeom(), mGeos ) == 1 )
{
return true;
}
}
catch ( GEOSException &e )
{
QgsMessageLog::logMessage( QObject::tr( "Exception: %1" ).arg( e.what() ), QObject::tr( "GEOS" ) );
}

if ( nextPart )
{
return nextPart->intersectsWithPolygon( polygon );
}
else
{
return false;
}
}

double LabelPosition::polygonIntersectionCostForParts( PointSet *polygon ) const
{
if ( !mGeos )
Expand Down
4 changes: 4 additions & 0 deletions src/core/pal/labelposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ namespace pal
*/
int polygonIntersectionCost( PointSet* polygon ) const;

/** Returns true if if any intersection between polygon and position exists.
*/
bool intersectsWithPolygon( PointSet* polygon ) const;

/** Shift the label by specified offset */
void offsetPosition( double xOffset, double yOffset );

Expand Down
3 changes: 2 additions & 1 deletion src/core/pal/pal.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ namespace pal
enum ObstacleType
{
PolygonInterior,
PolygonBoundary
PolygonBoundary,
PolygonWhole
};

/**
Expand Down
3 changes: 3 additions & 0 deletions src/core/qgslabelingenginev2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ void QgsLabelingEngineV2::processProvider( QgsAbstractLabelProvider* provider, Q
case QgsPalLayerSettings::PolygonBoundary:
l->setObstacleType( pal::PolygonBoundary );
break;
case QgsPalLayerSettings::PolygonWhole:
l->setObstacleType( pal::PolygonWhole );
break;
}

// set whether location of centroid must be inside of polygons
Expand Down
6 changes: 5 additions & 1 deletion src/core/qgspallabeling.h
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,12 @@ class CORE_EXPORT QgsPalLayerSettings
{
PolygonInterior, /*!< avoid placing labels over interior of polygon (prefer placing labels totally
outside or just slightly inside polygon) */
PolygonBoundary /*!< avoid placing labels over boundary of polygon (prefer placing outside or
PolygonBoundary, /*!< avoid placing labels over boundary of polygon (prefer placing outside or
completely inside polygon) */
PolygonWhole /*!< avoid placing labels over ANY part of polygon. Where PolygonInterior will prefer
to place labels with the smallest area of intersection between the label and the polygon,
PolygonWhole will penalise any label which intersects with the polygon by an equal amount, so that
placing labels over any part of the polygon is avoided.*/
};

enum ShapeType
Expand Down
14 changes: 13 additions & 1 deletion src/core/qgsvectorlayerlabelprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ static void _fixQPictureDPI( QPainter* p )
QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( QgsVectorLayer* layer, bool withFeatureLoop, const QgsPalLayerSettings* settings, const QString& layerName )
: mSettings( settings ? *settings : QgsPalLayerSettings::fromLayer( layer ) )
, mLayerId( layer->id() )
, mLayerGeometryType( layer->geometryType() )
, mRenderer( layer->rendererV2() )
, mFields( layer->fields() )
, mCrs( layer->crs() )
Expand Down Expand Up @@ -80,6 +81,7 @@ QgsVectorLayerLabelProvider::QgsVectorLayerLabelProvider( const QgsPalLayerSetti
bool ownsSource, QgsFeatureRendererV2* renderer )
: mSettings( settings )
, mLayerId( layerId )
, mLayerGeometryType( QGis::UnknownGeometry )
, mRenderer( renderer )
, mFields( fields )
, mCrs( crs )
Expand All @@ -102,7 +104,17 @@ void QgsVectorLayerLabelProvider::init()
if ( mSettings.fitInPolygonOnly ) mFlags |= FitInPolygonOnly;
if ( mSettings.labelPerPart ) mFlags |= LabelPerFeaturePart;
mPriority = 1 - mSettings.priority / 10.0; // convert 0..10 --> 1..0
mObstacleType = mSettings.obstacleType;

if ( mLayerGeometryType == QGis::Point && mRenderer )
{
//override obstacle type to treat any intersection of a label with the point symbol as a high cost conflict
mObstacleType = QgsPalLayerSettings::PolygonWhole;
}
else
{
mObstacleType = mSettings.obstacleType;
}

mUpsidedownLabels = mSettings.upsidedownLabels;
}

Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsvectorlayerlabelprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ class CORE_EXPORT QgsVectorLayerLabelProvider : public QgsAbstractLabelProvider
QgsPalLayerSettings mSettings;
//! Layer's ID
QString mLayerId;
//! Geometry type of layer
QGis::GeometryType mLayerGeometryType;

QgsFeatureRendererV2* mRenderer;

Expand Down

0 comments on commit f45f688

Please sign in to comment.