Skip to content
Permalink
Browse files

[labeling] Avoid placing labels over ANY part of point symbols

  • Loading branch information
nyalldawson committed Nov 25, 2015
1 parent 3e61891 commit f45f688f6179dd1eb64cc4b4ba61543efd6c0734
@@ -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
@@ -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;
@@ -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 )
@@ -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 );

@@ -89,7 +89,8 @@ namespace pal
enum ObstacleType
{
PolygonInterior,
PolygonBoundary
PolygonBoundary,
PolygonWhole
};

/**
@@ -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
@@ -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
@@ -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() )
@@ -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 )
@@ -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;
}

@@ -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;

0 comments on commit f45f688

Please sign in to comment.
You can’t perform that action at this time.