Skip to content

Commit 5f33991

Browse files
committedJul 27, 2016
[FEATURE] Label polygons using curved labels along perimeter
This adds a new mode for labeling polygons, where the perimeter of the polygon is labeled using curved labeling.
1 parent c0b1684 commit 5f33991

File tree

6 files changed

+549
-94
lines changed

6 files changed

+549
-94
lines changed
 

‎src/app/qgslabelinggui.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,7 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas,
219219
mPlacePolygonBtnGrp->addButton( radPolygonHorizontal, ( int )QgsPalLayerSettings::Horizontal );
220220
mPlacePolygonBtnGrp->addButton( radPolygonFree, ( int )QgsPalLayerSettings::Free );
221221
mPlacePolygonBtnGrp->addButton( radPolygonPerimeter, ( int )QgsPalLayerSettings::Line );
222+
mPlacePolygonBtnGrp->addButton( radPolygonPerimeterCurved, ( int )QgsPalLayerSettings::PerimeterCurved );
222223
mPlacePolygonBtnGrp->setExclusive( true );
223224
connect( mPlacePolygonBtnGrp, SIGNAL( buttonClicked( int ) ), this, SLOT( updatePlacementWidgets() ) );
224225

@@ -464,6 +465,7 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas,
464465
<< radPolygonFree
465466
<< radPolygonHorizontal
466467
<< radPolygonPerimeter
468+
<< radPolygonPerimeterCurved
467469
<< radPredefinedOrder
468470
<< mFieldExpressionWidget;
469471
connectValueChanged( widgets, SLOT( updatePreview() ) );
@@ -671,6 +673,9 @@ void QgsLabelingGui::init()
671673
case QgsPalLayerSettings::Free:
672674
radPolygonFree->setChecked( true );
673675
break;
676+
case QgsPalLayerSettings::PerimeterCurved:
677+
radPolygonPerimeterCurved->setChecked( true );
678+
break;
674679
}
675680

676681
// Label repeat distance
@@ -961,11 +966,17 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
961966
lyr.placement = QgsPalLayerSettings::OrderedPositionsAroundPoint;
962967
}
963968
else if (( curPlacementWdgt == pageLine && radLineParallel->isChecked() )
964-
|| ( curPlacementWdgt == pagePolygon && radPolygonPerimeter->isChecked() )
965-
|| ( curPlacementWdgt == pageLine && radLineCurved->isChecked() ) )
969+
|| ( curPlacementWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) )
970+
{
971+
lyr.placement = QgsPalLayerSettings::Line;
972+
}
973+
else if ( curPlacementWdgt == pageLine && radLineCurved->isChecked() )
974+
{
975+
lyr.placement = QgsPalLayerSettings::Curved;
976+
}
977+
else if ( curPlacementWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() )
966978
{
967-
bool curved = ( curPlacementWdgt == pageLine && radLineCurved->isChecked() );
968-
lyr.placement = ( curved ? QgsPalLayerSettings::Curved : QgsPalLayerSettings::Line );
979+
lyr.placement = QgsPalLayerSettings::PerimeterCurved;
969980
}
970981
else if (( curPlacementWdgt == pageLine && radLineHorizontal->isChecked() )
971982
|| ( curPlacementWdgt == pagePolygon && radPolygonHorizontal->isChecked() ) )
@@ -1706,7 +1717,8 @@ void QgsLabelingGui::updatePlacementWidgets()
17061717
}
17071718
else if (( curWdgt == pageLine && radLineParallel->isChecked() )
17081719
|| ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() )
1709-
|| ( curWdgt == pageLine && radLineCurved->isChecked() ) )
1720+
|| ( curWdgt == pageLine && radLineCurved->isChecked() )
1721+
|| ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() ) )
17101722
{
17111723
showLineFrame = true;
17121724
showDistanceFrame = true;
@@ -1716,9 +1728,11 @@ void QgsLabelingGui::updatePlacementWidgets()
17161728
chkLineOrientationDependent->setEnabled( offline );
17171729
mPlacementDistanceFrame->setEnabled( offline );
17181730

1719-
showMaxCharAngleFrame = ( curWdgt == pageLine && radLineCurved->isChecked() );
1731+
bool isCurved = ( curWdgt == pageLine && radLineCurved->isChecked() )
1732+
|| ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() );
1733+
showMaxCharAngleFrame = isCurved;
17201734
// TODO: enable mMultiLinesFrame when supported for curved labels
1721-
enableMultiLinesFrame = !( curWdgt == pageLine && radLineCurved->isChecked() );
1735+
enableMultiLinesFrame = !isCurved;
17221736
}
17231737

17241738
mPlacementLineFrame->setVisible( showLineFrame );
@@ -1730,7 +1744,8 @@ void QgsLabelingGui::updatePlacementWidgets()
17301744
mPlacementDistanceFrame->setVisible( showDistanceFrame );
17311745
mPlacementOffsetTypeFrame->setVisible( showOffsetTypeFrame );
17321746
mPlacementRotationFrame->setVisible( showRotationFrame );
1733-
mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) );
1747+
mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon &&
1748+
( radPolygonPerimeter->isChecked() || radPolygonPerimeterCurved->isChecked() ) ) );
17341749
mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame );
17351750

17361751
mMultiLinesFrame->setEnabled( enableMultiLinesFrame );

‎src/core/pal/feature.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,10 +1008,21 @@ int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition* >& lPos,
10081008
// and the line has right-to-left direction
10091009
bool reversed = ( !( flags & FLAG_MAP_ORIENTATION ) ? isRightToLeft : false );
10101010

1011+
// an orientation of 0 means try both orientations and choose the best
1012+
int orientation = 0;
1013+
if ( !( flags & FLAG_MAP_ORIENTATION )
1014+
&& mLF->layer()->arrangement() == QgsPalLayerSettings::PerimeterCurved )
1015+
{
1016+
//... but if we are labeling the perimeter of a polygon and using line orientation flags,
1017+
// then we can only accept a single orientation, as we need to ensure that the labels fall
1018+
// inside or outside the polygon (and not mixed)
1019+
orientation = reversed ? -1 : 1;
1020+
}
1021+
10111022
// generate curved labels
10121023
for ( int i = 0; i*delta < total_distance; i++ )
10131024
{
1014-
LabelPosition* slp = curvedPlacementAtOffset( mapShape, path_distances, 0, 1, i * delta );
1025+
LabelPosition* slp = curvedPlacementAtOffset( mapShape, path_distances, orientation, 1, i * delta );
10151026

10161027
if ( slp )
10171028
{
@@ -1325,6 +1336,8 @@ int FeaturePart::createCandidates( QList< LabelPosition*>& lPos,
13251336
case GEOS_LINESTRING:
13261337
if ( mLF->layer()->arrangement() == QgsPalLayerSettings::Curved )
13271338
createCurvedCandidatesAlongLine( lPos, mapShape );
1339+
else if ( mLF->layer()->arrangement() == QgsPalLayerSettings::PerimeterCurved )
1340+
createCurvedCandidatesAlongLine( lPos, mapShape );
13281341
else
13291342
createCandidatesAlongLine( lPos, mapShape );
13301343
break;
@@ -1344,6 +1357,9 @@ int FeaturePart::createCandidates( QList< LabelPosition*>& lPos,
13441357
case QgsPalLayerSettings::Line:
13451358
createCandidatesAlongLine( lPos, mapShape );
13461359
break;
1360+
case QgsPalLayerSettings::PerimeterCurved:
1361+
createCurvedCandidatesAlongLine( lPos, mapShape );
1362+
break;
13471363
default:
13481364
createCandidatesForPolygon( lPos, mapShape );
13491365
break;

‎src/core/pal/labelposition.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ LabelPosition::LabelPosition( int id, double x1, double y1, double w, double h,
9999

100100
// upside down ? (curved labels are always correct)
101101
if ( feature->layer()->arrangement() != QgsPalLayerSettings::Curved &&
102+
feature->layer()->arrangement() != QgsPalLayerSettings::PerimeterCurved &&
102103
this->alpha > M_PI / 2 && this->alpha <= 3*M_PI / 2 )
103104
{
104105
bool uprightLabel = false;

‎src/core/qgspallabeling.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,7 +2371,7 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
23712371
double maxcharanglein = 20.0; // range 20.0-60.0
23722372
double maxcharangleout = -20.0; // range 20.0-95.0
23732373

2374-
if ( placement == QgsPalLayerSettings::Curved )
2374+
if ( placement == QgsPalLayerSettings::Curved || placement == QgsPalLayerSettings::PerimeterCurved )
23752375
{
23762376
maxcharanglein = maxCurvedCharAngleIn;
23772377
maxcharangleout = maxCurvedCharAngleOut;
@@ -2514,8 +2514,8 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
25142514
}
25152515

25162516
GEOSGeometry* geos_geom_clone;
2517-
GEOSGeomTypes geomType = (GEOSGeomTypes) GEOSGeomTypeId_r( QgsGeometry::getGEOSHandler(), geos_geom );
2518-
if ( (geomType == GEOS_POLYGON || geomType == GEOS_MULTIPOLYGON) && repeatDistance > 0 && placement == Line )
2517+
GEOSGeomTypes geomType = ( GEOSGeomTypes ) GEOSGeomTypeId_r( QgsGeometry::getGEOSHandler(), geos_geom );
2518+
if (( geomType == GEOS_POLYGON || geomType == GEOS_MULTIPOLYGON ) && repeatDistance > 0 && ( placement == Line || placement == PerimeterCurved ) )
25192519
{
25202520
geos_geom_clone = GEOSBoundary_r( QgsGeometry::getGEOSHandler(), geos_geom );
25212521
}
@@ -2876,7 +2876,8 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
28762876

28772877
// TODO: only for placement which needs character info
28782878
// account for any data defined font metrics adjustments
2879-
lf->calculateInfo( placement == QgsPalLayerSettings::Curved, labelFontMetrics.data(), xform, rasterCompressFactor, maxcharanglein, maxcharangleout );
2879+
lf->calculateInfo( placement == QgsPalLayerSettings::Curved || placement == QgsPalLayerSettings::PerimeterCurved,
2880+
labelFontMetrics.data(), xform, rasterCompressFactor, maxcharanglein, maxcharangleout );
28802881
// for labelFeature the LabelInfo is passed to feat when it is registered
28812882

28822883
// TODO: allow layer-wide feature dist in PAL...?

‎src/core/qgspallabeling.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class CORE_EXPORT QgsPalLayerSettings
194194
Horizontal, /**< Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only.*/
195195
Free, /**< Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the polygon's orientation. Applies to polygon layers only.*/
196196
OrderedPositionsAroundPoint, /**< Candidates are placed in predefined positions around a point. Peference is given to positions with greatest cartographic appeal, eg top right, bottom right, etc. Applies to point layers only.*/
197+
PerimeterCurved, /** Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.*/
197198
};
198199

199200
//! Positions for labels when using the QgsPalLabeling::OrderedPositionsAroundPoint placement mode

‎src/ui/qgslabelingguibase.ui

Lines changed: 502 additions & 81 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)