@@ -968,7 +968,7 @@ int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition*>& l
968
968
}
969
969
970
970
971
- LabelPosition* FeaturePart::curvedPlacementAtOffset ( PointSet* path_positions, double * path_distances, int orientation, int index, double distance )
971
+ LabelPosition* FeaturePart::curvedPlacementAtOffset ( PointSet* path_positions, double * path_distances, int & orientation, int index, double distance, bool & flip )
972
972
{
973
973
// Check that the given distance is on the given index and find the correct index and distance if not
974
974
while ( distance < 0 && index > 1 )
@@ -995,10 +995,6 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d
995
995
996
996
LabelInfo* li = mLF ->curvedLabelInfo ();
997
997
998
- // Keep track of the initial index,distance incase we need to re-call get_placement_offset
999
- int initial_index = index;
1000
- double initial_distance = distance;
1001
-
1002
998
double string_height = li->label_height ;
1003
999
double old_x = path_positions->x [index-1 ];
1004
1000
double old_y = path_positions->y [index-1 ];
@@ -1018,14 +1014,18 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d
1018
1014
1019
1015
LabelPosition* slp = nullptr ;
1020
1016
LabelPosition* slp_tmp = nullptr ;
1021
- // current_placement = placement_result()
1022
1017
double angle = atan2 ( -dy, dx );
1023
1018
1024
1019
bool orientation_forced = ( orientation != 0 ); // Whether the orientation was set by the caller
1025
1020
if ( !orientation_forced )
1026
1021
orientation = ( angle > 0.55 * M_PI || angle < -0.45 * M_PI ? -1 : 1 );
1027
1022
1028
- int upside_down_char_count = 0 ; // Count of characters that are placed upside down.
1023
+ if ( !isUprightLabel () )
1024
+ {
1025
+ if ( orientation != 1 )
1026
+ flip = true ; // Report to the caller, that the orientation is flipped
1027
+ orientation = 1 ;
1028
+ }
1029
1029
1030
1030
for ( int i = 0 ; i < li->char_num ; i++ )
1031
1031
{
@@ -1086,7 +1086,6 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d
1086
1086
1087
1087
// Calculate angle from the start of the character to the end based on start_/end_ position
1088
1088
angle = atan2 ( start_y - end_y, end_x - start_x );
1089
- // angle = atan2(end_y-start_y, end_x-start_x);
1090
1089
1091
1090
// Test last_character_angle vs angle
1092
1091
// since our rendering angle has changed then check against our
@@ -1108,7 +1107,10 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d
1108
1107
// and we're calculating the mean line here
1109
1108
double dist = 0.9 * li->label_height / 2 ;
1110
1109
if ( orientation < 0 )
1110
+ {
1111
1111
dist = -dist;
1112
+ flip = true ;
1113
+ }
1112
1114
start_x += dist * cos ( angle + M_PI_2 );
1113
1115
start_y -= dist * sin ( angle + M_PI_2 );
1114
1116
@@ -1137,36 +1139,15 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d
1137
1139
slp_tmp->setNextPart ( tmp );
1138
1140
slp_tmp = tmp;
1139
1141
1140
- // current_placement.add_node(ci.character,render_x, -render_y, render_angle);
1141
- // current_placement.add_node(ci.character,render_x - current_placement.starting_x, render_y - current_placement.starting_y, render_angle)
1142
-
1143
1142
// Normalise to 0 <= angle < 2PI
1144
- while ( render_angle >= 2 * M_PI ) render_angle -= 2 * M_PI;
1143
+ while ( render_angle >= 2 * M_PI ) render_angle -= 2 * M_PI;
1145
1144
while ( render_angle < 0 ) render_angle += 2 * M_PI;
1146
1145
1147
- if ( render_angle > M_PI / 2 && render_angle < 1.5 * M_PI )
1148
- upside_down_char_count++ ;
1146
+ if ( render_angle > M_PI / 2 && render_angle < 1.5 * M_PI )
1147
+ slp-> incrementUpsideDownCharCount () ;
1149
1148
}
1150
1149
// END FOR
1151
1150
1152
- // If we placed too many characters upside down
1153
- if ( upside_down_char_count >= li->char_num / 2.0 )
1154
- {
1155
- // if we auto-detected the orientation then retry with the opposite orientation
1156
- if ( !orientation_forced )
1157
- {
1158
- orientation = -orientation;
1159
- delete slp;
1160
- slp = curvedPlacementAtOffset ( path_positions, path_distances, orientation, initial_index, initial_distance );
1161
- }
1162
- else
1163
- {
1164
- // Otherwise we have failed to find a placement
1165
- delete slp;
1166
- return nullptr ;
1167
- }
1168
- }
1169
-
1170
1151
return slp;
1171
1152
}
1172
1153
@@ -1231,99 +1212,120 @@ int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition* >& lPos,
1231
1212
flags = FLAG_ON_LINE; // default flag
1232
1213
// placements may need to be reversed if using line position dependent orientation
1233
1214
// and the line has right-to-left direction
1234
- bool reversed = ( ! ( flags & FLAG_MAP_ORIENTATION ) ? isRightToLeft : false );
1215
+ bool reversed = (( flags & FLAG_MAP_ORIENTATION ) ? isRightToLeft : false );
1235
1216
1236
1217
// an orientation of 0 means try both orientations and choose the best
1237
1218
int orientation = 0 ;
1238
- if ( !( flags & FLAG_MAP_ORIENTATION )
1239
- && mLF ->layer ()->arrangement () == QgsPalLayerSettings::PerimeterCurved )
1219
+ if ( !( flags & FLAG_MAP_ORIENTATION ) )
1240
1220
{
1241
- // ... but if we are labeling the perimeter of a polygon and using line orientation flags,
1242
- // then we can only accept a single orientation, as we need to ensure that the labels fall
1243
- // inside or outside the polygon (and not mixed)
1221
+ // ... but if we are using line orientation flags, then we can only accept a single orientation,
1222
+ // as we need to ensure that the labels fall inside or outside the polyline or polygon (and not mixed)
1244
1223
orientation = reversed ? -1 : 1 ;
1245
1224
}
1246
1225
1247
1226
// generate curved labels
1248
1227
for ( int i = 0 ; i*delta < total_distance; i++ )
1249
1228
{
1250
- LabelPosition* slp = curvedPlacementAtOffset ( mapShape, path_distances, orientation, 1 , i * delta );
1229
+ bool flip = false ;
1230
+ bool orientation_forced = ( orientation != 0 ); // Whether the orientation was set by the caller
1231
+ LabelPosition* slp = curvedPlacementAtOffset ( mapShape, path_distances, orientation, 1 , i * delta, flip );
1232
+ if ( slp == nullptr )
1233
+ continue ;
1251
1234
1252
- if ( slp )
1235
+ // If we placed too many characters upside down
1236
+ if ( slp->upsideDownCharCount () >= li->char_num / 2.0 )
1253
1237
{
1254
- // evaluate cost
1255
- double angle_diff = 0.0 , angle_last = 0.0 , diff;
1256
- LabelPosition* tmp = slp;
1257
- double sin_avg = 0 , cos_avg = 0 ;
1258
- while ( tmp )
1238
+ // if we auto-detected the orientation then retry with the opposite orientation
1239
+ if ( !orientation_forced )
1259
1240
{
1260
- if ( tmp != slp ) // not first?
1261
- {
1262
- diff = fabs ( tmp->getAlpha () - angle_last );
1263
- if ( diff > 2 *M_PI ) diff -= 2 * M_PI;
1264
- diff = qMin ( diff, 2 * M_PI - diff ); // difference 350 deg is actually just 10 deg...
1265
- angle_diff += diff;
1266
- }
1241
+ orientation = -orientation;
1242
+ delete slp;
1243
+ slp = curvedPlacementAtOffset ( mapShape, path_distances, orientation, 1 , i * delta, flip );
1244
+ }
1245
+ else if ( isUprightLabel () && !flip )
1246
+ {
1247
+ // Retry with the opposite orientation
1248
+ orientation = -orientation;
1249
+ delete slp;
1250
+ slp = curvedPlacementAtOffset ( mapShape, path_distances, orientation, 1 , i * delta, flip );
1251
+ }
1252
+ }
1253
+ if ( slp == nullptr )
1254
+ continue ;
1267
1255
1268
- sin_avg += sin ( tmp->getAlpha () );
1269
- cos_avg += cos ( tmp->getAlpha () );
1270
- angle_last = tmp->getAlpha ();
1271
- tmp = tmp->getNextPart ();
1256
+ // evaluate cost
1257
+ double angle_diff = 0.0 , angle_last = 0.0 , diff;
1258
+ LabelPosition* tmp = slp;
1259
+ double sin_avg = 0 , cos_avg = 0 ;
1260
+ while ( tmp )
1261
+ {
1262
+ if ( tmp != slp ) // not first?
1263
+ {
1264
+ diff = fabs ( tmp->getAlpha () - angle_last );
1265
+ if ( diff > 2 *M_PI ) diff -= 2 * M_PI;
1266
+ diff = qMin ( diff, 2 * M_PI - diff ); // difference 350 deg is actually just 10 deg...
1267
+ angle_diff += diff;
1272
1268
}
1273
1269
1274
- double angle_diff_avg = li->char_num > 1 ? ( angle_diff / ( li->char_num - 1 ) ) : 0 ; // <0, pi> but pi/8 is much already
1275
- double cost = angle_diff_avg / 100 ; // <0, 0.031 > but usually <0, 0.003 >
1276
- if ( cost < 0.0001 ) cost = 0.0001 ;
1270
+ sin_avg += sin ( tmp->getAlpha () );
1271
+ cos_avg += cos ( tmp->getAlpha () );
1272
+ angle_last = tmp->getAlpha ();
1273
+ tmp = tmp->getNextPart ();
1274
+ }
1275
+
1276
+ double angle_diff_avg = li->char_num > 1 ? ( angle_diff / ( li->char_num - 1 ) ) : 0 ; // <0, pi> but pi/8 is much already
1277
+ double cost = angle_diff_avg / 100 ; // <0, 0.031 > but usually <0, 0.003 >
1278
+ if ( cost < 0.0001 ) cost = 0.0001 ;
1277
1279
1278
- // penalize positions which are further from the line's midpoint
1279
- double labelCenter = ( i * delta ) + getLabelWidth () / 2 ;
1280
- double costCenter = qAbs ( total_distance / 2 - labelCenter ) / total_distance; // <0, 0.5>
1281
- cost += costCenter / 1000 ; // < 0, 0.0005 >
1282
- slp->setCost ( cost );
1280
+ // penalize positions which are further from the line's midpoint
1281
+ double labelCenter = ( i * delta ) + getLabelWidth () / 2 ;
1282
+ double costCenter = qAbs ( total_distance / 2 - labelCenter ) / total_distance; // <0, 0.5>
1283
+ cost += costCenter / 1000 ; // < 0, 0.0005 >
1284
+ slp->setCost ( cost );
1283
1285
1284
- // average angle is calculated with respect to periodicity of angles
1285
- double angle_avg = atan2 ( sin_avg / li->char_num , cos_avg / li->char_num );
1286
- // displacement - we loop through 3 times, generating above, online then below line placements successively
1287
- for ( int i = 0 ; i <= 2 ; ++i )
1286
+ // average angle is calculated with respect to periodicity of angles
1287
+ double angle_avg = atan2 ( sin_avg / li->char_num , cos_avg / li->char_num );
1288
+ bool localreversed = flip ? !reversed : reversed;
1289
+ // displacement - we loop through 3 times, generating above, online then below line placements successively
1290
+ for ( int i = 0 ; i <= 2 ; ++i )
1291
+ {
1292
+ LabelPosition* p = nullptr ;
1293
+ if ( i == 0 && (( !localreversed && ( flags & FLAG_ABOVE_LINE ) ) || ( localreversed && ( flags & FLAG_BELOW_LINE ) ) ) )
1294
+ p = _createCurvedCandidate ( slp, angle_avg, mLF ->distLabel () + li->label_height / 2 );
1295
+ if ( i == 1 && flags & FLAG_ON_LINE )
1288
1296
{
1289
- LabelPosition* p = nullptr ;
1290
- if ( i == 0 && (( !reversed && ( flags & FLAG_ABOVE_LINE ) ) || ( reversed && ( flags & FLAG_BELOW_LINE ) ) ) )
1291
- p = _createCurvedCandidate ( slp, angle_avg, mLF ->distLabel () + li->label_height / 2 );
1292
- if ( i == 1 && flags & FLAG_ON_LINE )
1293
- {
1294
- p = _createCurvedCandidate ( slp, angle_avg, 0 );
1295
- p->setCost ( p->cost () + 0.002 );
1296
- }
1297
- if ( i == 2 && (( !reversed && ( flags & FLAG_BELOW_LINE ) ) || ( reversed && ( flags & FLAG_ABOVE_LINE ) ) ) )
1297
+ p = _createCurvedCandidate ( slp, angle_avg, 0 );
1298
+ p->setCost ( p->cost () + 0.002 );
1299
+ }
1300
+ if ( i == 2 && (( !localreversed && ( flags & FLAG_BELOW_LINE ) ) || ( localreversed && ( flags & FLAG_ABOVE_LINE ) ) ) )
1301
+ {
1302
+ p = _createCurvedCandidate ( slp, angle_avg, -li->label_height / 2 - mLF ->distLabel () );
1303
+ p->setCost ( p->cost () + 0.001 );
1304
+ }
1305
+
1306
+ if ( p && mLF ->permissibleZonePrepared () )
1307
+ {
1308
+ bool within = true ;
1309
+ LabelPosition* currentPos = p;
1310
+ while ( within && currentPos )
1298
1311
{
1299
- p = _createCurvedCandidate ( slp, angle_avg, -li-> label_height / 2 - mLF -> distLabel () );
1300
- p-> setCost ( p-> cost () + 0.001 );
1312
+ within = GeomFunction::containsCandidate ( mLF -> permissibleZonePrepared (), currentPos-> getX (), currentPos-> getY (), currentPos-> getWidth (), currentPos-> getHeight (), currentPos-> getAlpha () );
1313
+ currentPos = currentPos-> getNextPart ( );
1301
1314
}
1302
-
1303
- if ( p && mLF ->permissibleZonePrepared () )
1315
+ if ( !within )
1304
1316
{
1305
- bool within = true ;
1306
- LabelPosition* currentPos = p;
1307
- while ( within && currentPos )
1308
- {
1309
- within = GeomFunction::containsCandidate ( mLF ->permissibleZonePrepared (), currentPos->getX (), currentPos->getY (), currentPos->getWidth (), currentPos->getHeight (), currentPos->getAlpha () );
1310
- currentPos = currentPos->getNextPart ();
1311
- }
1312
- if ( !within )
1313
- {
1314
- delete p;
1315
- p = nullptr ;
1316
- }
1317
+ delete p;
1318
+ p = nullptr ;
1317
1319
}
1318
-
1319
- if ( p )
1320
- positions.append ( p );
1321
1320
}
1322
- // delete original candidate
1323
- delete slp;
1321
+
1322
+ if ( p )
1323
+ positions.append ( p );
1324
1324
}
1325
- }
1326
1325
1326
+ // delete original candidate
1327
+ delete slp;
1328
+ }
1327
1329
1328
1330
int nbp = positions.size ();
1329
1331
for ( int i = 0 ; i < nbp; i++ )
@@ -1336,9 +1338,6 @@ int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition* >& lPos,
1336
1338
return nbp;
1337
1339
}
1338
1340
1339
-
1340
-
1341
-
1342
1341
/*
1343
1342
* seg 2
1344
1343
* pt3 ____________pt2
@@ -1588,9 +1587,7 @@ int FeaturePart::createCandidates( QList< LabelPosition*>& lPos,
1588
1587
createCandidatesAroundPoint ( x[0 ], y[0 ], lPos, angle );
1589
1588
break ;
1590
1589
case GEOS_LINESTRING:
1591
- if ( mLF ->layer ()->arrangement () == QgsPalLayerSettings::Curved )
1592
- createCurvedCandidatesAlongLine ( lPos, mapShape );
1593
- else if ( mLF ->layer ()->arrangement () == QgsPalLayerSettings::PerimeterCurved )
1590
+ if ( mLF ->layer ()->isCurved () )
1594
1591
createCurvedCandidatesAlongLine ( lPos, mapShape );
1595
1592
else
1596
1593
createCandidatesAlongLine ( lPos, mapShape );
@@ -1774,3 +1771,28 @@ double FeaturePart::calculatePriority() const
1774
1771
1775
1772
return mLF ->priority () >= 0 ? mLF ->priority () : mLF ->layer ()->priority ();
1776
1773
}
1774
+
1775
+ bool FeaturePart::isUprightLabel () const
1776
+ {
1777
+ bool uprightLabel = false ;
1778
+
1779
+ switch ( mLF ->layer ()->upsidedownLabels () )
1780
+ {
1781
+ case Layer::Upright:
1782
+ uprightLabel = true ;
1783
+ break ;
1784
+ case Layer::ShowDefined:
1785
+ // upright only dynamic labels
1786
+ if ( !hasFixedRotation () || ( !hasFixedPosition () && fixedAngle () == 0.0 ) )
1787
+ {
1788
+ uprightLabel = true ;
1789
+ }
1790
+ break ;
1791
+ case Layer::ShowAll:
1792
+ break ;
1793
+ default :
1794
+ uprightLabel = true ;
1795
+ }
1796
+ return uprightLabel;
1797
+ }
1798
+
0 commit comments