Skip to content

Commit fe42b00

Browse files
committed
Merge pull request #1238 from ahuarte47/Issue_9480
Fix bug #9480: Labels for polygon centroids should always originate inside a polygon
2 parents 34f3378 + 6cb4cbb commit fe42b00

20 files changed

+178
-14
lines changed

python/core/qgsgeometry.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,9 @@ class QgsGeometry
322322
* and for point based geometries, the point itself is returned */
323323
QgsGeometry* centroid() /Factory/;
324324

325+
/** Returns a point within a geometry */
326+
QgsGeometry* pointOnSurface() /Factory/;
327+
325328
/** Returns the smallest convex polygon that contains all the points in the geometry. */
326329
QgsGeometry* convexHull() /Factory/;
327330

python/core/qgspallabeling.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ class QgsPalLayerSettings
394394
unsigned int placementFlags;
395395

396396
bool centroidWhole; // whether centroid calculated from whole or visible polygon
397+
bool centroidInside; // whether centroid-point calculated must be inside polygon
397398
double dist; // distance from the feature (in mm)
398399
bool distInMapUnits; //true if distance is in map units (otherwise in mm)
399400
QgsMapUnitScale distMapUnitScale;

src/app/qgslabelinggui.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ void QgsLabelingGui::init()
259259

260260
// populate placement options
261261
mCentroidRadioWhole->setChecked( lyr.centroidWhole );
262+
mCentroidInsideCheckBox->setChecked( lyr.centroidInside );
262263
switch ( lyr.placement )
263264
{
264265
case QgsPalLayerSettings::AroundPoint:
@@ -545,6 +546,7 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
545546

546547
QWidget* curPlacementWdgt = stackedPlacement->currentWidget();
547548
lyr.centroidWhole = mCentroidRadioWhole->isChecked();
549+
lyr.centroidInside = mCentroidInsideCheckBox->isChecked();
548550
if (( curPlacementWdgt == pagePoint && radAroundPoint->isChecked() )
549551
|| ( curPlacementWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
550552
{

src/core/pal/feature.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1344,7 +1344,7 @@ namespace pal
13441344
case P_POINT:
13451345
case P_POINT_OVER:
13461346
double cx, cy;
1347-
mapShape->getCentroid( cx, cy );
1347+
mapShape->getCentroid( cx, cy, f->layer->getCentroidInside() );
13481348
if ( f->layer->getArrangement() == P_POINT_OVER )
13491349
nbp = setPositionOverPoint( cx, cy, scale, lPos, delta, angle );
13501350
else

src/core/pal/layer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ namespace pal
6161

6262
Layer::Layer( const char *lyrName, double min_scale, double max_scale, Arrangement arrangement, Units label_unit, double defaultPriority, bool obstacle, bool active, bool toLabel, Pal *pal, bool displayAll )
6363
: pal( pal ), obstacle( obstacle ), active( active ),
64-
toLabel( toLabel ), displayAll( displayAll ), label_unit( label_unit ),
64+
toLabel( toLabel ), displayAll( displayAll ), centroidInside( false ), label_unit( label_unit ),
6565
min_scale( min_scale ), max_scale( max_scale ),
6666
arrangement( arrangement ), arrangementFlags( 0 ), mode( LabelPerFeature ), mergeLines( false )
6767
{

src/core/pal/layer.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ namespace pal
101101
bool active;
102102
bool toLabel;
103103
bool displayAll;
104+
bool centroidInside;
104105

105106
Units label_unit;
106107

@@ -291,6 +292,9 @@ namespace pal
291292
void setUpsidedownLabels( UpsideDownLabels ud ) { upsidedownLabels = ud; }
292293
UpsideDownLabels getUpsidedownLabels() const { return upsidedownLabels; }
293294

295+
void setCentroidInside( bool forceInside ) { centroidInside = forceInside; }
296+
bool getCentroidInside() const { return centroidInside; }
297+
294298
/**
295299
* \brief register a feature in the layer
296300
*

src/core/pal/pointset.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -956,7 +956,7 @@ namespace pal
956956

957957

958958

959-
void PointSet::getCentroid( double &px, double &py )
959+
void PointSet::getCentroid( double &px, double &py, bool forceInside )
960960
{
961961
// for explanation see this page:
962962
// http://local.wasp.uwa.edu.au/~pbourke/geometry/polyarea/
@@ -984,6 +984,35 @@ namespace pal
984984
px = cx / ( 3 * A ) + x[0];
985985
py = cy / ( 3 * A ) + y[0];
986986
}
987+
988+
// check if centroid inside in polygon
989+
if ( forceInside && !isPointInPolygon( nbPoints, x, y, px, py ) )
990+
{
991+
GEOSCoordSequence *coord = GEOSCoordSeq_create( nbPoints, 2 );
992+
993+
for ( int i = 0; i < nbPoints; ++i )
994+
{
995+
GEOSCoordSeq_setX( coord, i, x[i] );
996+
GEOSCoordSeq_setY( coord, i, y[i] );
997+
}
998+
999+
GEOSGeometry *geom = GEOSGeom_createPolygon( GEOSGeom_createLinearRing( coord ), 0, 0 );
1000+
1001+
if ( geom )
1002+
{
1003+
GEOSGeometry *pointGeom = GEOSPointOnSurface( geom );
1004+
1005+
if ( pointGeom )
1006+
{
1007+
const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq( pointGeom );
1008+
GEOSCoordSeq_getX( coordSeq, 0, &px );
1009+
GEOSCoordSeq_getY( coordSeq, 0, &py );
1010+
1011+
GEOSGeom_destroy( pointGeom );
1012+
}
1013+
GEOSGeom_destroy( geom );
1014+
}
1015+
}
9871016
}
9881017

9891018
} // end namespace

src/core/pal/pointset.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ namespace pal
160160

161161
//double getDistInside(double px, double py);
162162

163-
void getCentroid( double &px, double &py );
163+
void getCentroid( double &px, double &py, bool forceInside = false );
164164

165165

166166
int getGeosType() const { return type; }

src/core/qgsgeometry.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ static GEOSInit geosinit;
145145
#define GEOSArea(g, a) GEOSArea( (GEOSGeometry*) g, a )
146146
#define GEOSTopologyPreserveSimplify(g, t) GEOSTopologyPreserveSimplify( (GEOSGeometry*) g, t )
147147
#define GEOSGetCentroid(g) GEOSGetCentroid( (GEOSGeometry*) g )
148+
#define GEOSPointOnSurface(g) GEOSPointOnSurface( (GEOSGeometry*) g )
148149

149150
#define GEOSCoordSeq_getSize(cs,n) GEOSCoordSeq_getSize( (GEOSCoordSequence *) cs, n )
150151
#define GEOSCoordSeq_getX(cs,i,x) GEOSCoordSeq_getX( (GEOSCoordSequence *)cs, i, x )
@@ -5623,6 +5624,21 @@ QgsGeometry* QgsGeometry::centroid()
56235624
CATCH_GEOS( 0 )
56245625
}
56255626

5627+
QgsGeometry* QgsGeometry::pointOnSurface()
5628+
{
5629+
if ( mDirtyGeos )
5630+
exportWkbToGeos();
5631+
5632+
if ( !mGeos )
5633+
return 0;
5634+
5635+
try
5636+
{
5637+
return fromGeosGeom( GEOSPointOnSurface( mGeos ) );
5638+
}
5639+
CATCH_GEOS( 0 )
5640+
}
5641+
56265642
QgsGeometry* QgsGeometry::convexHull()
56275643
{
56285644
if ( mDirtyGeos )

src/core/qgsgeometry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,9 @@ class CORE_EXPORT QgsGeometry
363363
* and for point based geometries, the point itself is returned */
364364
QgsGeometry* centroid();
365365

366+
/** Returns a point within a geometry */
367+
QgsGeometry* pointOnSurface();
368+
366369
/** Returns the smallest convex polygon that contains all the points in the geometry. */
367370
QgsGeometry* convexHull();
368371

0 commit comments

Comments
 (0)