@@ -773,8 +773,7 @@ int FeaturePart::createCandidatesAlongLineNearStraightSegments( QList<LabelPosit
773
773
{
774
774
// find out whether the line direction for this candidate is from right to left
775
775
bool isRightToLeft = ( angle > M_PI / 2 || angle <= -M_PI / 2 );
776
- // meaning of above/below may be reversed if using line position dependent orientation
777
- // and the line has right-to-left direction
776
+ // meaning of above/below may be reversed if using map orientation and the line has right-to-left direction
778
777
bool reversed = (( flags & FLAG_MAP_ORIENTATION ) ? isRightToLeft : false );
779
778
bool aboveLine = ( !reversed && ( flags & FLAG_ABOVE_LINE ) ) || ( reversed && ( flags & FLAG_BELOW_LINE ) );
780
779
bool belowLine = ( !reversed && ( flags & FLAG_BELOW_LINE ) ) || ( reversed && ( flags & FLAG_ABOVE_LINE ) );
@@ -919,8 +918,7 @@ int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition*>& l
919
918
{
920
919
// find out whether the line direction for this candidate is from right to left
921
920
bool isRightToLeft = ( angle > M_PI / 2 || angle <= -M_PI / 2 );
922
- // meaning of above/below may be reversed if using line position dependent orientation
923
- // and the line has right-to-left direction
921
+ // meaning of above/below may be reversed if using map orientation and the line has right-to-left direction
924
922
bool reversed = (( flags & FLAG_MAP_ORIENTATION ) ? isRightToLeft : false );
925
923
bool aboveLine = ( !reversed && ( flags & FLAG_ABOVE_LINE ) ) || ( reversed && ( flags & FLAG_BELOW_LINE ) );
926
924
bool belowLine = ( !reversed && ( flags & FLAG_BELOW_LINE ) ) || ( reversed && ( flags & FLAG_ABOVE_LINE ) );
@@ -968,7 +966,7 @@ int FeaturePart::createCandidatesAlongLineNearMidpoint( QList<LabelPosition*>& l
968
966
}
969
967
970
968
971
- LabelPosition* FeaturePart::curvedPlacementAtOffset ( PointSet* path_positions, double * path_distances, int & orientation, int index, double distance, bool & flip )
969
+ LabelPosition* FeaturePart::curvedPlacementAtOffset ( PointSet* path_positions, double * path_distances, int & orientation, int index, double distance, bool & reversed, bool & flip )
972
970
{
973
971
// Check that the given distance is on the given index and find the correct index and distance if not
974
972
while ( distance < 0 && index > 1 )
@@ -996,14 +994,6 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d
996
994
LabelInfo* li = mLF ->curvedLabelInfo ();
997
995
998
996
double string_height = li->label_height ;
999
- double old_x = path_positions->x [index-1 ];
1000
- double old_y = path_positions->y [index-1 ];
1001
-
1002
- double new_x = path_positions->x [index];
1003
- double new_y = path_positions->y [index];
1004
-
1005
- double dx = new_x - old_x;
1006
- double dy = new_y - old_y;
1007
997
1008
998
double segment_length = path_distances[index];
1009
999
if ( qgsDoubleNear ( segment_length, 0.0 ) )
@@ -1012,78 +1002,70 @@ LabelPosition* FeaturePart::curvedPlacementAtOffset( PointSet* path_positions, d
1012
1002
return nullptr ;
1013
1003
}
1014
1004
1015
- LabelPosition* slp = nullptr ;
1016
- LabelPosition* slp_tmp = nullptr ;
1017
- double angle = atan2 ( -dy, dx );
1005
+ if ( orientation == 0 ) // Must be map orientation
1006
+ {
1007
+ // Calculate the orientation based on the angle of the path segment under consideration
1018
1008
1019
- bool orientation_forced = ( orientation != 0 ); // Whether the orientation was set by the caller
1020
- if ( !orientation_forced )
1021
- orientation = ( angle > 0.55 * M_PI || angle < -0.45 * M_PI ? -1 : 1 );
1009
+ double _distance = distance;
1010
+ int endindex = index;
1022
1011
1023
- if ( !isUprightLabel () )
1012
+ for ( int i = 0 ; i < li->char_num ; i++ )
1013
+ {
1014
+ LabelInfo::CharacterInfo& ci = li->char_info [i];
1015
+ double start_x, start_y, end_x, end_y;
1016
+ if ( nextCharPosition ( ci.width , path_distances[index], path_positions, endindex, _distance, start_x, start_y, end_x, end_y ) == false )
1017
+ {
1018
+ return nullptr ;
1019
+ }
1020
+ }
1021
+
1022
+ // Determine the angle of the path segment under consideration
1023
+ double dx = path_positions->x [endindex] - path_positions->x [index];
1024
+ double dy = path_positions->y [endindex] - path_positions->y [index];
1025
+ double line_angle = atan2 ( -dy, dx );
1026
+
1027
+ bool isRightToLeft = ( line_angle > 0.55 * M_PI || line_angle < -0.45 * M_PI );
1028
+ reversed = isRightToLeft;
1029
+ orientation = isRightToLeft ? -1 : 1 ;
1030
+ }
1031
+
1032
+ if ( !showUprightLabels () )
1024
1033
{
1025
- if ( orientation != 1 )
1034
+ if ( orientation < 0 )
1035
+ {
1026
1036
flip = true ; // Report to the caller, that the orientation is flipped
1027
- orientation = 1 ;
1037
+ reversed = !reversed;
1038
+ orientation = 1 ;
1039
+ }
1028
1040
}
1029
1041
1042
+ LabelPosition* slp = nullptr ;
1043
+ LabelPosition* slp_tmp = nullptr ;
1044
+
1045
+ double old_x = path_positions->x [index-1 ];
1046
+ double old_y = path_positions->y [index-1 ];
1047
+
1048
+ double new_x = path_positions->x [index];
1049
+ double new_y = path_positions->y [index];
1050
+
1051
+ double dx = new_x - old_x;
1052
+ double dy = new_y - old_y;
1053
+
1054
+ double angle = atan2 ( -dy, dx );
1055
+
1030
1056
for ( int i = 0 ; i < li->char_num ; i++ )
1031
1057
{
1032
1058
double last_character_angle = angle;
1033
1059
1034
1060
// grab the next character according to the orientation
1035
1061
LabelInfo::CharacterInfo& ci = ( orientation > 0 ? li->char_info [i] : li->char_info [li->char_num -i-1 ] );
1036
-
1037
- // Coordinates this character will start at
1038
- if ( qgsDoubleNear ( segment_length, 0.0 ) )
1062
+ double start_x, start_y, end_x, end_y;
1063
+ if ( nextCharPosition ( ci.width , path_distances[index], path_positions, index, distance, start_x, start_y, end_x, end_y ) == false )
1039
1064
{
1040
- // Not allowed to place across on 0 length segments or discontinuities
1041
1065
delete slp;
1042
1066
return nullptr ;
1043
1067
}
1044
1068
1045
- double start_x = old_x + dx * distance / segment_length;
1046
- double start_y = old_y + dy * distance / segment_length;
1047
- // Coordinates this character ends at, calculated below
1048
- double end_x = 0 ;
1049
- double end_y = 0 ;
1050
-
1051
- if ( segment_length - distance >= ci.width )
1052
- {
1053
- // if the distance remaining in this segment is enough, we just go further along the segment
1054
- distance += ci.width ;
1055
- end_x = old_x + dx * distance / segment_length;
1056
- end_y = old_y + dy * distance / segment_length;
1057
- }
1058
- else
1059
- {
1060
- // If there isn't enough distance left on this segment
1061
- // then we need to search until we find the line segment that ends further than ci.width away
1062
- do
1063
- {
1064
- old_x = new_x;
1065
- old_y = new_y;
1066
- index++;
1067
- if ( index >= path_positions->nbPoints ) // Bail out if we run off the end of the shape
1068
- {
1069
- delete slp;
1070
- return nullptr ;
1071
- }
1072
- new_x = path_positions->x [index];
1073
- new_y = path_positions->y [index];
1074
- dx = new_x - old_x;
1075
- dy = new_y - old_y;
1076
- segment_length = path_distances[index];
1077
- }
1078
- while ( sqrt ( pow ( start_x - new_x, 2 ) + pow ( start_y - new_y, 2 ) ) < ci.width ); // Distance from start_ to new_
1079
-
1080
- // Calculate the position to place the end of the character on
1081
- GeomFunction::findLineCircleIntersection ( start_x, start_y, ci.width , old_x, old_y, new_x, new_y, end_x, end_y );
1082
-
1083
- // Need to calculate distance on the new segment
1084
- distance = sqrt ( pow ( old_x - end_x, 2 ) + pow ( old_y - end_y, 2 ) );
1085
- }
1086
-
1087
1069
// Calculate angle from the start of the character to the end based on start_/end_ position
1088
1070
angle = atan2 ( start_y - end_y, end_x - start_x );
1089
1071
@@ -1201,53 +1183,42 @@ int FeaturePart::createCurvedCandidatesAlongLine( QList< LabelPosition* >& lPos,
1201
1183
else
1202
1184
lineAngle = atan2 ( ey - by, ex - bx );
1203
1185
1204
- // find out whether the line direction for this candidate is from right to left
1205
- bool isRightToLeft = ( lineAngle > M_PI / 2 || lineAngle <= -M_PI / 2 );
1206
-
1207
1186
QLinkedList<LabelPosition*> positions;
1208
1187
double delta = qMax ( li->label_height , total_distance / mLF ->layer ()->pal ->line_p );
1209
1188
1210
1189
unsigned long flags = mLF ->layer ()->arrangementFlags ();
1211
1190
if ( flags == 0 )
1212
1191
flags = FLAG_ON_LINE; // default flag
1213
- // placements may need to be reversed if using line position dependent orientation
1214
- // and the line has right-to-left direction
1215
- bool reversed = (( flags & FLAG_MAP_ORIENTATION ) ? isRightToLeft : false );
1216
-
1217
- // an orientation of 0 means try both orientations and choose the best
1218
- int orientation = 0 ;
1219
- if ( !( flags & FLAG_MAP_ORIENTATION ) )
1220
- {
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)
1223
- orientation = reversed ? -1 : 1 ;
1224
- }
1225
1192
1226
1193
// generate curved labels
1227
- for ( int i = 0 ; i* delta < total_distance; i++ )
1194
+ for ( int i = 0 ; i * delta < total_distance; i++ )
1228
1195
{
1229
1196
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 );
1197
+ // placements may need to be reversed if using map orientation and the line has right-to-left direction
1198
+ bool reversed = false ;
1199
+
1200
+ // an orientation of 0 means try both orientations and choose the best
1201
+ int orientation = 0 ;
1202
+ if ( !( flags & FLAG_MAP_ORIENTATION ) )
1203
+ {
1204
+ // ... but if we are using line orientation flags, then we can only accept a single orientation,
1205
+ // as we need to ensure that the labels fall inside or outside the polyline or polygon (and not mixed)
1206
+ orientation = 1 ;
1207
+ }
1208
+
1209
+ LabelPosition* slp = curvedPlacementAtOffset ( mapShape, path_distances, orientation, 1 , i * delta, reversed, flip );
1232
1210
if ( slp == nullptr )
1233
1211
continue ;
1234
1212
1235
1213
// If we placed too many characters upside down
1236
1214
if ( slp->upsideDownCharCount () >= li->char_num / 2.0 )
1237
1215
{
1238
- // if we auto-detected the orientation then retry with the opposite orientation
1239
- if ( !orientation_forced )
1216
+ // if labels should be shown upright then retry with the opposite orientation
1217
+ if (( showUprightLabels () && !flip ) )
1240
1218
{
1241
- orientation = -orientation;
1242
1219
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
1220
orientation = -orientation;
1249
- delete slp;
1250
- slp = curvedPlacementAtOffset ( mapShape, path_distances, orientation, 1 , i * delta, flip );
1221
+ slp = curvedPlacementAtOffset ( mapShape, path_distances, orientation, 1 , i * delta, reversed, flip );
1251
1222
}
1252
1223
}
1253
1224
if ( slp == nullptr )
@@ -1402,7 +1373,6 @@ int FeaturePart::createCandidatesForPolygon( QList< LabelPosition*>& lPos, Point
1402
1373
dx = labelWidth / 2.0 ;
1403
1374
dy = labelHeight / 2.0 ;
1404
1375
1405
-
1406
1376
int numTry = 0 ;
1407
1377
1408
1378
// fit in polygon only mode slows down calculation a lot, so if it's enabled
@@ -1772,7 +1742,7 @@ double FeaturePart::calculatePriority() const
1772
1742
return mLF ->priority () >= 0 ? mLF ->priority () : mLF ->layer ()->priority ();
1773
1743
}
1774
1744
1775
- bool FeaturePart::isUprightLabel () const
1745
+ bool FeaturePart::showUprightLabels () const
1776
1746
{
1777
1747
bool uprightLabel = false ;
1778
1748
@@ -1796,3 +1766,64 @@ bool FeaturePart::isUprightLabel() const
1796
1766
return uprightLabel;
1797
1767
}
1798
1768
1769
+ bool FeaturePart::nextCharPosition ( int charWidth, double segment_length, PointSet* path_positions, int & index, double & distance,
1770
+ double & start_x, double & start_y, double & end_x, double & end_y ) const
1771
+ {
1772
+ // Coordinates this character will start at
1773
+ if ( qgsDoubleNear ( segment_length, 0.0 ) )
1774
+ {
1775
+ // Not allowed to place across on 0 length segments or discontinuities
1776
+ return false ;
1777
+ }
1778
+
1779
+ double old_x = path_positions->x [index-1 ];
1780
+ double old_y = path_positions->y [index-1 ];
1781
+
1782
+ double new_x = path_positions->x [index];
1783
+ double new_y = path_positions->y [index];
1784
+
1785
+ double dx = new_x - old_x;
1786
+ double dy = new_y - old_y;
1787
+
1788
+ start_x = old_x + dx * distance / segment_length;
1789
+ start_y = old_y + dy * distance / segment_length;
1790
+
1791
+ // Coordinates this character ends at, calculated below
1792
+ end_x = 0 ;
1793
+ end_y = 0 ;
1794
+
1795
+ if ( segment_length - distance >= charWidth )
1796
+ {
1797
+ // if the distance remaining in this segment is enough, we just go further along the segment
1798
+ distance += charWidth;
1799
+ end_x = old_x + dx * distance / segment_length;
1800
+ end_y = old_y + dy * distance / segment_length;
1801
+ }
1802
+ else
1803
+ {
1804
+ // If there isn't enough distance left on this segment
1805
+ // then we need to search until we find the line segment that ends further than ci.width away
1806
+ do
1807
+ {
1808
+ old_x = new_x;
1809
+ old_y = new_y;
1810
+ index++;
1811
+ if ( index >= path_positions->nbPoints ) // Bail out if we run off the end of the shape
1812
+ {
1813
+ return false ;
1814
+ }
1815
+ new_x = path_positions->x [index];
1816
+ new_y = path_positions->y [index];
1817
+ dx = new_x - old_x;
1818
+ dy = new_y - old_y;
1819
+ }
1820
+ while ( sqrt ( pow ( start_x - new_x, 2 ) + pow ( start_y - new_y, 2 ) ) < charWidth ); // Distance from start_ to new_
1821
+
1822
+ // Calculate the position to place the end of the character on
1823
+ GeomFunction::findLineCircleIntersection ( start_x, start_y, charWidth, old_x, old_y, new_x, new_y, end_x, end_y );
1824
+
1825
+ // Need to calculate distance on the new segment
1826
+ distance = sqrt ( pow ( old_x - end_x, 2 ) + pow ( old_y - end_y, 2 ) );
1827
+ }
1828
+ return true ;
1829
+ }
0 commit comments