Skip to content

Commit 5ab62a9

Browse files
committedAug 9, 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. (cherry-picked from 5f33991)
1 parent 8c6f5fd commit 5ab62a9

File tree

6 files changed

+548
-93
lines changed

6 files changed

+548
-93
lines changed
 

‎src/app/qgslabelinggui.cpp

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

@@ -465,6 +466,7 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer* layer, QgsMapCanvas* mapCanvas,
465466
<< radPolygonFree
466467
<< radPolygonHorizontal
467468
<< radPolygonPerimeter
469+
<< radPolygonPerimeterCurved
468470
<< radPredefinedOrder
469471
<< mFieldExpressionWidget;
470472
connectValueChanged( widgets, SLOT( updatePreview() ) );
@@ -672,6 +674,9 @@ void QgsLabelingGui::init()
672674
case QgsPalLayerSettings::Free:
673675
radPolygonFree->setChecked( true );
674676
break;
677+
case QgsPalLayerSettings::PerimeterCurved:
678+
radPolygonPerimeterCurved->setChecked( true );
679+
break;
675680
}
676681

677682
// Label repeat distance
@@ -962,11 +967,17 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
962967
lyr.placement = QgsPalLayerSettings::OrderedPositionsAroundPoint;
963968
}
964969
else if (( curPlacementWdgt == pageLine && radLineParallel->isChecked() )
965-
|| ( curPlacementWdgt == pagePolygon && radPolygonPerimeter->isChecked() )
966-
|| ( curPlacementWdgt == pageLine && radLineCurved->isChecked() ) )
970+
|| ( curPlacementWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) )
971+
{
972+
lyr.placement = QgsPalLayerSettings::Line;
973+
}
974+
else if ( curPlacementWdgt == pageLine && radLineCurved->isChecked() )
975+
{
976+
lyr.placement = QgsPalLayerSettings::Curved;
977+
}
978+
else if ( curPlacementWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() )
967979
{
968-
bool curved = ( curPlacementWdgt == pageLine && radLineCurved->isChecked() );
969-
lyr.placement = ( curved ? QgsPalLayerSettings::Curved : QgsPalLayerSettings::Line );
980+
lyr.placement = QgsPalLayerSettings::PerimeterCurved;
970981
}
971982
else if (( curPlacementWdgt == pageLine && radLineHorizontal->isChecked() )
972983
|| ( curPlacementWdgt == pagePolygon && radPolygonHorizontal->isChecked() ) )
@@ -1707,7 +1718,8 @@ void QgsLabelingGui::updatePlacementWidgets()
17071718
}
17081719
else if (( curWdgt == pageLine && radLineParallel->isChecked() )
17091720
|| ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() )
1710-
|| ( curWdgt == pageLine && radLineCurved->isChecked() ) )
1721+
|| ( curWdgt == pageLine && radLineCurved->isChecked() )
1722+
|| ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() ) )
17111723
{
17121724
showLineFrame = true;
17131725
showDistanceFrame = true;
@@ -1717,9 +1729,11 @@ void QgsLabelingGui::updatePlacementWidgets()
17171729
chkLineOrientationDependent->setEnabled( offline );
17181730
mPlacementDistanceFrame->setEnabled( offline );
17191731

1720-
showMaxCharAngleFrame = ( curWdgt == pageLine && radLineCurved->isChecked() );
1732+
bool isCurved = ( curWdgt == pageLine && radLineCurved->isChecked() )
1733+
|| ( curWdgt == pagePolygon && radPolygonPerimeterCurved->isChecked() );
1734+
showMaxCharAngleFrame = isCurved;
17211735
// TODO: enable mMultiLinesFrame when supported for curved labels
1722-
enableMultiLinesFrame = !( curWdgt == pageLine && radLineCurved->isChecked() );
1736+
enableMultiLinesFrame = !isCurved;
17231737
}
17241738

17251739
mPlacementLineFrame->setVisible( showLineFrame );
@@ -1731,7 +1745,8 @@ void QgsLabelingGui::updatePlacementWidgets()
17311745
mPlacementDistanceFrame->setVisible( showDistanceFrame );
17321746
mPlacementOffsetTypeFrame->setVisible( showOffsetTypeFrame );
17331747
mPlacementRotationFrame->setVisible( showRotationFrame );
1734-
mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) );
1748+
mPlacementRepeatDistanceFrame->setVisible( curWdgt == pageLine || ( curWdgt == pagePolygon &&
1749+
( radPolygonPerimeter->isChecked() || radPolygonPerimeterCurved->isChecked() ) ) );
17351750
mPlacementMaxCharAngleFrame->setVisible( showMaxCharAngleFrame );
17361751

17371752
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: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,7 +2374,7 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
23742374
double maxcharanglein = 20.0; // range 20.0-60.0
23752375
double maxcharangleout = -20.0; // range 20.0-95.0
23762376

2377-
if ( placement == QgsPalLayerSettings::Curved )
2377+
if ( placement == QgsPalLayerSettings::Curved || placement == QgsPalLayerSettings::PerimeterCurved )
23782378
{
23792379
maxcharanglein = maxCurvedCharAngleIn;
23802380
maxcharangleout = maxCurvedCharAngleOut;
@@ -2518,7 +2518,7 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
25182518

25192519
GEOSGeometry* geos_geom_clone;
25202520
GEOSGeomTypes geomType = ( GEOSGeomTypes ) GEOSGeomTypeId_r( QgsGeometry::getGEOSHandler(), geos_geom );
2521-
if (( geomType == GEOS_POLYGON || geomType == GEOS_MULTIPOLYGON ) && repeatDistance > 0 && placement == Line )
2521+
if (( geomType == GEOS_POLYGON || geomType == GEOS_MULTIPOLYGON ) && repeatDistance > 0 && ( placement == Line || placement == PerimeterCurved ) )
25222522
{
25232523
geos_geom_clone = GEOSBoundary_r( QgsGeometry::getGEOSHandler(), geos_geom );
25242524
}
@@ -2879,7 +2879,8 @@ void QgsPalLayerSettings::registerFeature( QgsFeature& f, QgsRenderContext &cont
28792879

28802880
// TODO: only for placement which needs character info
28812881
// account for any data defined font metrics adjustments
2882-
lf->calculateInfo( placement == QgsPalLayerSettings::Curved, labelFontMetrics.data(), xform, rasterCompressFactor, maxcharanglein, maxcharangleout );
2882+
lf->calculateInfo( placement == QgsPalLayerSettings::Curved || placement == QgsPalLayerSettings::PerimeterCurved,
2883+
labelFontMetrics.data(), xform, rasterCompressFactor, maxcharanglein, maxcharangleout );
28832884
// for labelFeature the LabelInfo is passed to feat when it is registered
28842885

28852886
// 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
@@ -89,6 +89,7 @@ class CORE_EXPORT QgsPalLayerSettings
8989
Horizontal, /**< Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only.*/
9090
Free, /**< Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the polygon's orientation. Applies to polygon layers only.*/
9191
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.*/
92+
PerimeterCurved, /** Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.*/
9293
};
9394

9495
//! 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)
Please sign in to comment.