43 #include <QLinkedList> 53 mGeos =
const_cast<GEOSGeometry *
>( geom );
59 for (
int i = 0; i <
mHoles.count(); i++ )
61 mHoles.at( i )->holeOf =
this;
73 mHoles.last()->holeOf =
this;
87 const GEOSCoordSequence *coordSeq =
nullptr;
90 type = GEOSGeomTypeId_r( geosctxt, geom );
92 if (
type == GEOS_POLYGON )
94 if ( GEOSGetNumInteriorRings_r( geosctxt, geom ) > 0 )
96 int numHoles = GEOSGetNumInteriorRings_r( geosctxt, geom );
98 for (
int i = 0; i < numHoles; ++i )
100 const GEOSGeometry *interior = GEOSGetInteriorRingN_r( geosctxt, geom, i );
112 geom = GEOSGetExteriorRing_r( geosctxt, geom );
121 nbPoints = GEOSGetNumCoordinates_r( geosctxt, geom );
122 coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, geom );
133 for (
int i = 0; i <
nbPoints; ++i )
135 GEOSCoordSeq_getX_r( geosctxt, coordSeq, i, &
x[i] );
136 GEOSCoordSeq_getY_r( geosctxt, coordSeq, i, &
y[i] );
175 qreal quadOffsetX = quadOffset.x(), quadOffsetY = quadOffset.y();
177 if ( quadOffsetX < 0 )
179 if ( quadOffsetY < 0 )
183 else if ( quadOffsetY > 0 )
192 else if ( quadOffsetX > 0 )
194 if ( quadOffsetY < 0 )
198 else if ( quadOffsetY > 0 )
209 if ( quadOffsetY < 0 )
213 else if ( quadOffsetY > 0 )
232 double cost = 0.0001;
235 double xdiff = -labelW / 2.0;
236 double ydiff = -labelH / 2.0;
251 double xd = xdiff * std::cos( angle ) - ydiff * std::sin( angle );
252 double yd = xdiff * std::sin( angle ) + ydiff * std::cos( angle );
288 double lx = x + xdiff;
289 double ly = y + ydiff;
299 lPos <<
new LabelPosition(
id, lx, ly, labelW, labelH, angle, cost,
this,
false, quadrantFromOffset() );
314 double cost = 0.0001;
327 deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
328 deltaY = -visualMargin.
bottom() + symbolHeightOffset;
334 deltaX = -labelWidth / 4.0 - visualMargin.
left();
335 deltaY = -visualMargin.
bottom() + symbolHeightOffset;
341 deltaX = -labelWidth / 2.0;
342 deltaY = -visualMargin.
bottom() + symbolHeightOffset;
348 deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
349 deltaY = -visualMargin.
bottom() + symbolHeightOffset;
355 deltaX = - visualMargin.
left() + symbolWidthOffset;
356 deltaY = -visualMargin.
bottom() + symbolHeightOffset;
362 deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
363 deltaY = -labelHeight / 2.0;
369 deltaX = -visualMargin.
left() + symbolWidthOffset;
370 deltaY = -labelHeight / 2.0;
376 deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
377 deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
383 deltaX = -labelWidth / 4.0 - visualMargin.
left();
384 deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
390 deltaX = -labelWidth / 2.0;
391 deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
397 deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
398 deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
404 deltaX = -visualMargin.
left() + symbolWidthOffset;
405 deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
410 double referenceX = std::cos( alpha ) * distanceToLabel +
x;
411 double referenceY = std::sin( alpha ) * distanceToLabel +
y;
413 double labelX = referenceX + deltaX;
414 double labelY = referenceY + deltaY;
418 lPos <<
new LabelPosition( i, labelX, labelY, labelWidth, labelHeight, angle, cost,
this,
false, quadrant );
440 double candidateAngleIncrement = 2 * M_PI / numberCandidates;
445 double a270 = a180 + a90;
446 double a360 = 2 * M_PI;
448 double gamma1, gamma2;
450 if ( distanceToLabel > 0 )
452 gamma1 = std::atan2( labelHeight / 2, distanceToLabel + labelWidth / 2 );
453 gamma2 = std::atan2( labelWidth / 2, distanceToLabel + labelHeight / 2 );
457 gamma1 = gamma2 = a90 / 3.0;
460 if ( gamma1 > a90 / 3.0 )
463 if ( gamma2 > a90 / 3.0 )
466 QList< LabelPosition * > candidates;
469 double angleToCandidate;
470 for ( i = 0, angleToCandidate = M_PI_4; i < numberCandidates; i++, angleToCandidate += candidateAngleIncrement )
475 if ( angleToCandidate > a360 )
476 angleToCandidate -= a360;
480 if ( angleToCandidate < gamma1 || angleToCandidate > a360 - gamma1 )
482 labelX += distanceToLabel;
483 double iota = ( angleToCandidate + gamma1 );
484 if ( iota > a360 - gamma1 )
488 labelY += -labelHeight + labelHeight * iota / ( 2 * gamma1 );
492 else if ( angleToCandidate < a90 - gamma2 )
494 labelX += distanceToLabel * std::cos( angleToCandidate );
495 labelY += distanceToLabel * std::sin( angleToCandidate );
498 else if ( angleToCandidate < a90 + gamma2 )
501 labelX += -labelWidth * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
502 labelY += distanceToLabel;
505 else if ( angleToCandidate < a180 - gamma1 )
507 labelX += distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
508 labelY += distanceToLabel * std::sin( angleToCandidate );
511 else if ( angleToCandidate < a180 + gamma1 )
513 labelX += -distanceToLabel - labelWidth;
515 labelY += - ( angleToCandidate - a180 + gamma1 ) * labelHeight / ( 2 * gamma1 );
518 else if ( angleToCandidate < a270 - gamma2 )
520 labelX += distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
521 labelY += distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
524 else if ( angleToCandidate < a270 + gamma2 )
526 labelY += -distanceToLabel - labelHeight;
528 labelX += -labelWidth + ( angleToCandidate - a270 + gamma2 ) * labelWidth / ( 2 * gamma2 );
531 else if ( angleToCandidate < a360 )
533 labelX += distanceToLabel * std::cos( angleToCandidate );
534 labelY += distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
540 if ( numberCandidates == 1 )
543 cost = 0.0001 + 0.0020 * double( icost ) / double( numberCandidates - 1 );
554 candidates <<
new LabelPosition( i, labelX, labelY, labelWidth, labelHeight, angle, cost,
this,
false, quadrant );
558 if ( icost == numberCandidates )
560 icost = numberCandidates - 1;
563 else if ( icost > numberCandidates )
565 icost = numberCandidates - 2;
571 if ( !candidates.isEmpty() )
573 for (
int i = 0; i < candidates.count(); ++i )
575 lPos << candidates.at( i );
579 return candidates.count();
587 if ( candidates < mLF->
layer()->
pal->line_p )
605 QVector< int > extremeAngleNodes;
613 for (
int i = 1; i <= numberNodes - ( closedLine ? 1 : 2 ); ++i )
615 double x1 = x[i - 1];
617 double x3 = x[ i == numberNodes - 1 ? 1 : i + 1];
618 double y1 = y[i - 1];
620 double y3 = y[ i == numberNodes - 1 ? 1 : i + 1];
625 double vertexAngle = M_PI - ( std::atan2( y3 - y2, x3 - x2 ) - std::atan2( y2 - y1, x2 - x1 ) );
629 if ( vertexAngle < M_PI * 135.0 / 180.0 || vertexAngle > M_PI * 225.0 / 180.0 )
630 extremeAngleNodes << i;
632 extremeAngleNodes << numberNodes - 1;
634 if ( extremeAngleNodes.isEmpty() )
641 double *segmentLengths =
new double[ numberNodes - 1 ];
642 double *distanceToSegment =
new double[ numberNodes ];
643 double totalLineLength = 0.0;
644 QVector< double > straightSegmentLengths;
645 QVector< double > straightSegmentAngles;
646 straightSegmentLengths.reserve( extremeAngleNodes.size() + 1 );
647 straightSegmentAngles.reserve( extremeAngleNodes.size() + 1 );
648 double currentStraightSegmentLength = 0;
649 double longestSegmentLength = 0;
650 int segmentIndex = 0;
651 double segmentStartX = x[0];
652 double segmentStartY = y[0];
653 for (
int i = 0; i < numberNodes - 1; i++ )
656 distanceToSegment[i] = 0;
658 distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
661 totalLineLength += segmentLengths[i];
662 if ( extremeAngleNodes.contains( i ) )
665 straightSegmentLengths << currentStraightSegmentLength;
667 longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
669 currentStraightSegmentLength = 0;
670 segmentStartX = x[i];
671 segmentStartY = y[i];
673 currentStraightSegmentLength += segmentLengths[i];
675 distanceToSegment[line->
nbPoints - 1] = totalLineLength;
676 straightSegmentLengths << currentStraightSegmentLength;
678 longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
679 double middleOfLine = totalLineLength / 2.0;
681 if ( totalLineLength < labelWidth )
683 delete[] segmentLengths;
684 delete[] distanceToSegment;
688 double lineStepDistance = ( totalLineLength - labelWidth );
689 lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance /
mLF->
layer()->
pal->line_p );
691 double distanceToEndOfSegment = 0.0;
692 int lastNodeInSegment = 0;
694 for (
int i = 0; i < straightSegmentLengths.count(); ++i )
696 currentStraightSegmentLength = straightSegmentLengths.at( i );
697 double currentSegmentAngle = straightSegmentAngles.at( i );
698 lastNodeInSegment = extremeAngleNodes.at( i );
699 double distanceToStartOfSegment = distanceToEndOfSegment;
700 distanceToEndOfSegment = distanceToSegment[ lastNodeInSegment ];
701 double distanceToCenterOfSegment = 0.5 * ( distanceToEndOfSegment + distanceToStartOfSegment );
703 if ( currentStraightSegmentLength < labelWidth )
707 double currentDistanceAlongLine = distanceToStartOfSegment;
708 double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
709 double candidateLength = 0.0;
715 double segmentCost = 1.0 - ( distanceToEndOfSegment - distanceToStartOfSegment ) / longestSegmentLength;
716 double segmentAngleCost = 1 - std::fabs( std::fmod( currentSegmentAngle, M_PI ) - M_PI_2 ) / M_PI_2;
718 while ( currentDistanceAlongLine + labelWidth < distanceToEndOfSegment )
721 line->
getPointByDistance( segmentLengths, distanceToSegment, currentDistanceAlongLine, &candidateStartX, &candidateStartY );
722 line->
getPointByDistance( segmentLengths, distanceToSegment, currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
724 candidateLength = std::sqrt( ( candidateEndX - candidateStartX ) * ( candidateEndX - candidateStartX ) + ( candidateEndY - candidateStartY ) * ( candidateEndY - candidateStartY ) );
730 cost = candidateLength / labelWidth;
736 cost = ( 1 - cost ) / 100;
740 double labelCenter = currentDistanceAlongLine + labelWidth / 2.0;
741 double costCenter = 2 * std::fabs( labelCenter - distanceToCenterOfSegment ) / ( distanceToEndOfSegment - distanceToStartOfSegment );
742 cost += costCenter * 0.0005;
749 double costLineCenter = 2 * std::fabs( labelCenter - middleOfLine ) / totalLineLength;
750 cost += costLineCenter * 0.0005;
753 cost += segmentCost * 0.0005;
754 cost += segmentAngleCost * 0.0001;
761 angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
763 beta = angle + M_PI_2;
768 bool isRightToLeft = ( angle > M_PI_2 || angle <= -M_PI_2 );
774 double placementCost = 0.0;
779 lPos.append(
new LabelPosition( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle, cost + placementCost,
this, isRightToLeft ) );
780 placementCost += 0.001;
787 lPos.append(
new LabelPosition( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle, cost + placementCost,
this, isRightToLeft ) );
788 placementCost += 0.001;
794 lPos.append(
new LabelPosition( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle, cost + placementCost,
this, isRightToLeft ) );
799 lPos.append(
new LabelPosition( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost,
this ) );
806 currentDistanceAlongLine += lineStepDistance;
810 delete[] segmentLengths;
811 delete[] distanceToSegment;
829 QList<LabelPosition *> positions;
836 double *segmentLengths =
new double[nbPoints - 1];
837 double *distanceToSegment =
new double[
nbPoints];
839 double totalLineLength = 0.0;
840 for (
int i = 0; i < line->
nbPoints - 1; i++ )
843 distanceToSegment[i] = 0;
845 distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
848 totalLineLength += segmentLengths[i];
850 distanceToSegment[line->
nbPoints - 1] = totalLineLength;
852 double lineStepDistance = ( totalLineLength - labelWidth );
853 double currentDistanceAlongLine = 0;
855 if ( totalLineLength > labelWidth )
857 lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance /
mLF->
layer()->
pal->line_p );
861 currentDistanceAlongLine = - ( labelWidth - totalLineLength ) / 2.0;
862 lineStepDistance = -1;
863 totalLineLength = labelWidth;
868 currentDistanceAlongLine = std::numeric_limits< double >::max();
871 double candidateLength;
873 double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
875 while ( currentDistanceAlongLine < totalLineLength - labelWidth )
878 line->
getPointByDistance( segmentLengths, distanceToSegment, currentDistanceAlongLine, &candidateStartX, &candidateStartY );
879 line->
getPointByDistance( segmentLengths, distanceToSegment, currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
881 if ( currentDistanceAlongLine < 0 )
884 candidateLength = std::sqrt( ( x[nbPoints - 1] - x[0] ) * ( x[nbPoints - 1] - x[0] )
885 + ( y[nbPoints - 1] - y[0] ) * ( y[nbPoints - 1] - y[0] ) );
889 candidateLength = std::sqrt( ( candidateEndX - candidateStartX ) * ( candidateEndX - candidateStartX ) + ( candidateEndY - candidateStartY ) * ( candidateEndY - candidateStartY ) );
892 cost = candidateLength / labelWidth;
898 cost = ( 1 - cost ) / 100;
902 double costCenter = std::fabs( totalLineLength / 2 - ( currentDistanceAlongLine + labelWidth / 2 ) ) / totalLineLength;
903 cost += costCenter / 1000;
911 angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
913 beta = angle + M_PI_2;
918 bool isRightToLeft = ( angle > M_PI_2 || angle <= -M_PI_2 );
927 positions.append(
new LabelPosition( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle, cost,
this, isRightToLeft ) );
932 positions.append(
new LabelPosition( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle, cost,
this, isRightToLeft ) );
937 positions.append(
new LabelPosition( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle, cost,
this, isRightToLeft ) );
942 positions.append(
new LabelPosition( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost,
this ) );
949 currentDistanceAlongLine += lineStepDistance;
953 if ( lineStepDistance < 0 )
959 delete[] segmentLengths;
960 delete[] distanceToSegment;
962 lPos.append( positions );
970 while ( distance < 0 && index > 1 )
973 distance += path_distances[index];
976 if ( index <= 1 && distance < 0 )
982 while ( index < path_positions->
nbPoints && distance > path_distances[index] )
984 distance -= path_distances[index];
987 if ( index >= path_positions->
nbPoints )
996 double segment_length = path_distances[index];
1003 if ( orientation == 0 )
1007 double _distance = distance;
1008 int endindex = index;
1010 for (
int i = 0; i < li->
char_num; i++ )
1013 double start_x, start_y, end_x, end_y;
1014 if ( !
nextCharPosition( ci.
width, path_distances[index], path_positions, endindex, _distance, start_x, start_y, end_x, end_y ) )
1021 double dx = path_positions->
x[endindex] - path_positions->
x[index];
1022 double dy = path_positions->
y[endindex] - path_positions->
y[index];
1023 double line_angle = std::atan2( -dy, dx );
1025 bool isRightToLeft = ( line_angle > 0.55 * M_PI || line_angle < -0.45 * M_PI );
1026 reversed = isRightToLeft;
1027 orientation = isRightToLeft ? -1 : 1;
1032 if ( orientation < 0 )
1035 reversed = !reversed;
1043 double old_x = path_positions->
x[index - 1];
1044 double old_y = path_positions->
y[index - 1];
1046 double new_x = path_positions->
x[index];
1047 double new_y = path_positions->
y[index];
1049 double dx = new_x - old_x;
1050 double dy = new_y - old_y;
1052 double angle = std::atan2( -dy, dx );
1054 for (
int i = 0; i < li->
char_num; i++ )
1056 double last_character_angle =
angle;
1064 double start_x, start_y, end_x, end_y;
1065 if ( !
nextCharPosition( ci.
width, path_distances[index], path_positions, index, distance, start_x, start_y, end_x, end_y ) )
1072 angle = std::atan2( start_y - end_y, end_x - start_x );
1077 double angle_delta = last_character_angle -
angle;
1079 while ( angle_delta > M_PI ) angle_delta -= 2 * M_PI;
1080 while ( angle_delta < -M_PI ) angle_delta += 2 * M_PI;
1084 && angle_delta < li->max_char_angle_outside * ( M_PI / 180 ) ) )
1093 if ( orientation < 0 )
1098 start_x += dist * std::cos( angle + M_PI_2 );
1099 start_y -= dist * std::sin( angle + M_PI_2 );
1101 double render_angle =
angle;
1103 double render_x = start_x;
1104 double render_y = start_y;
1110 if ( orientation < 0 )
1113 render_x += ci.
width * std::cos( render_angle );
1114 render_y -= ci.
width * std::sin( render_angle );
1115 render_angle += M_PI;
1127 while ( render_angle >= 2 * M_PI ) render_angle -= 2 * M_PI;
1128 while ( render_angle < 0 ) render_angle += 2 * M_PI;
1130 if ( render_angle > M_PI_2 && render_angle < 1.5 * M_PI )
1154 double *path_distances =
new double[mapShape->
nbPoints];
1155 double total_distance = 0;
1156 double old_x = -1.0, old_y = -1.0;
1157 for (
int i = 0; i < mapShape->
nbPoints; i++ )
1160 path_distances[i] = 0;
1162 path_distances[i] = std::sqrt( std::pow( old_x - mapShape->
x[i], 2 ) + std::pow( old_y - mapShape->
y[i], 2 ) );
1163 old_x = mapShape->
x[i];
1164 old_y = mapShape->
y[i];
1166 total_distance += path_distances[i];
1171 delete[] path_distances;
1175 QLinkedList<LabelPosition *> positions;
1183 for (
double i = 0; i < total_distance; i += delta )
1187 bool reversed =
false;
1190 int orientation = 0;
1209 orientation = -orientation;
1217 double angle_diff = 0.0, angle_last = 0.0, diff;
1219 double sin_avg = 0, cos_avg = 0;
1224 diff = std::fabs( tmp->
getAlpha() - angle_last );
1225 if ( diff > 2 * M_PI ) diff -= 2 * M_PI;
1226 diff = std::min( diff, 2 * M_PI - diff );
1230 sin_avg += std::sin( tmp->
getAlpha() );
1231 cos_avg += std::cos( tmp->
getAlpha() );
1236 double angle_diff_avg = li->
char_num > 1 ? ( angle_diff / ( li->
char_num - 1 ) ) : 0;
1237 double cost = angle_diff_avg / 100;
1238 if ( cost < 0.0001 ) cost = 0.0001;
1242 double costCenter = std::fabs( total_distance / 2 - labelCenter ) / total_distance;
1243 cost += costCenter / 1000;
1247 double angle_avg = std::atan2( sin_avg / li->
char_num, cos_avg / li->
char_num );
1248 bool localreversed = flip ? !reversed : reversed;
1250 for (
int i = 0; i <= 2; ++i )
1257 p = _createCurvedCandidate( slp, angle_avg, 0 );
1260 if ( i == 2 && ( ( !localreversed && ( flags & FLAG_BELOW_LINE ) ) || ( localreversed && ( flags & FLAG_ABOVE_LINE ) ) ) )
1270 while ( within && currentPos )
1283 positions.append( p );
1290 int nbp = positions.size();
1291 for (
int i = 0; i < nbp; i++ )
1293 lPos << positions.takeFirst();
1296 delete[] path_distances;
1321 QLinkedList<PointSet *> shapes_toProcess;
1322 QLinkedList<PointSet *> shapes_final;
1324 mapShape->
parent =
nullptr;
1326 shapes_toProcess.append( mapShape );
1328 splitPolygons( shapes_toProcess, shapes_final, labelWidth, labelHeight );
1332 if ( !shapes_final.isEmpty() )
1334 QLinkedList<LabelPosition *> positions;
1344 double diago = std::sqrt( labelWidth * labelWidth / 4.0 + labelHeight * labelHeight / 4 );
1350 while ( !shapes_final.isEmpty() )
1352 PointSet *shape = shapes_final.takeFirst();
1362 dx = labelWidth / 2.0;
1363 dy = labelHeight / 2.0;
1373 for ( bbid = 0; bbid < j; bbid++ )
1394 bool enoughPlace =
false;
1398 px = ( box->
x[0] + box->
x[2] ) / 2 - labelWidth;
1399 py = ( box->
y[0] + box->
y[2] ) / 2 - labelHeight;
1405 for ( rx = px, i = 0; i < 2; rx = rx + 2 * labelWidth, i++ )
1407 for ( ry = py, j = 0; j < 2; ry = ry + 2 * labelHeight, j++ )
1411 enoughPlace =
false;
1427 else if ( box->
length > 1.5 * labelWidth && box->
width > 1.5 * labelWidth )
1429 if ( box->
alpha <= M_PI_4 )
1435 alpha = box->
alpha - M_PI_2;
1440 alpha = box->
alpha - M_PI_2;
1447 beta = std::atan2( labelHeight, labelWidth ) + alpha;
1453 dlx = std::cos( beta ) * diago;
1454 dly = std::sin( beta ) * diago;
1458 px0 = box->
width / 2.0;
1461 px0 -= std::ceil( px0 / dx ) * dx;
1462 py0 -= std::ceil( py0 / dy ) * dy;
1464 for ( px = px0; px <= box->
width; px += dx )
1466 for ( py = py0; py <= box->
length; py += dy )
1469 rx = std::cos( box->
alpha ) * px + std::cos( box->
alpha - M_PI_2 ) * py;
1470 ry = std::sin( box->
alpha ) * px + std::sin( box->
alpha - M_PI_2 ) * py;
1478 if ( candidateAcceptable )
1481 positions.append(
new LabelPosition(
id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001,
this ) );
1487 nbp = positions.size();
1495 while ( nbp == 0 && numTry < maxTry );
1497 nbp = positions.size();
1499 for ( i = 0; i < nbp; i++ )
1501 lPos << positions.takeFirst();
1504 for ( bbid = 0; bbid < j; bbid++ )
1520 const GEOSPreparedGeometry *mapBoundary,
1521 PointSet *mapShape, RTree<LabelPosition *, double, 2, double> *candidates )
1541 case GEOS_LINESTRING:
1575 QMutableListIterator< LabelPosition *> i( lPos );
1576 while ( i.hasNext() )
1579 bool outside =
false;
1584 outside = !pos->
within( mapBoundary );
1597 return lPos.count();
1606 int geomType = GEOSGeomTypeId_r( ctxt,
mGeos );
1608 double sizeCost = 0;
1609 if ( geomType == GEOS_LINESTRING )
1614 if ( GEOSLength_r( ctxt,
mGeos, &length ) != 1 )
1617 catch ( GEOSException &e )
1622 double bbox_length = std::max( bbx[2] - bbx[0], bby[2] - bby[0] );
1623 if ( length >= bbox_length / 4 )
1626 sizeCost = 1 - ( length / ( bbox_length / 4 ) );
1628 else if ( geomType == GEOS_POLYGON )
1633 if ( GEOSArea_r( ctxt,
mGeos, &area ) != 1 )
1636 catch ( GEOSException &e )
1641 double bbox_area = ( bbx[2] - bbx[0] ) * ( bby[2] - bby[0] );
1642 if ( area >= bbox_area / 16 )
1645 sizeCost = 1 - ( area / ( bbox_area / 16 ) );
1651 for (
int i = 0; i < nbp; i++ )
1653 lPos.at( i )->setCost( lPos.at( i )->cost() + sizeCost / 100 );
1666 catch ( GEOSException &e )
1677 if ( !other->
mGeos )
1683 GEOSGeometry *g1 = GEOSGeom_clone_r( ctxt,
mGeos );
1684 GEOSGeometry *g2 = GEOSGeom_clone_r( ctxt, other->
mGeos );
1685 GEOSGeometry *geoms[2] = { g1, g2 };
1686 geos::unique_ptr g( GEOSGeom_createCollection_r( ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
1689 if ( GEOSGeomTypeId_r( ctxt, gTmp.get() ) != GEOS_LINESTRING )
1697 mGeos = gTmp.release();
1706 catch ( GEOSException &e )
1728 bool uprightLabel =
false;
1733 uprightLabel =
true;
1739 uprightLabel =
true;
1745 uprightLabel =
true;
1747 return uprightLabel;
1751 double &start_x,
double &start_y,
double &end_x,
double &end_y )
const 1760 double old_x = path_positions->
x[index - 1];
1761 double old_y = path_positions->
y[index - 1];
1763 double new_x = path_positions->
x[index];
1764 double new_y = path_positions->
y[index];
1766 double dx = new_x - old_x;
1767 double dy = new_y - old_y;
1769 start_x = old_x + dx * distance / segment_length;
1770 start_y = old_y + dy * distance / segment_length;
1776 if ( segment_length - distance >= charWidth )
1779 distance += charWidth;
1780 end_x = old_x + dx * distance / segment_length;
1781 end_y = old_y + dy * distance / segment_length;
1792 if ( index >= path_positions->
nbPoints )
1796 new_x = path_positions->
x[index];
1797 new_y = path_positions->
y[index];
1801 while ( std::sqrt( std::pow( start_x - new_x, 2 ) + std::pow( start_y - new_y, 2 ) ) < charWidth );
1807 distance = std::sqrt( std::pow( old_x - end_x, 2 ) + std::pow( old_y - end_y, 2 ) );
Label below point, slightly right of center.
double right() const
Returns the right margin.
bool centroidInside() const
Returns whether labels placed at the centroid of features within the layer are forced to be placed in...
Label on bottom-left of point.
int createCandidatesForPolygon(QList< LabelPosition *> &lPos, PointSet *mapShape)
Generate candidates for polygon features.
double distLabel() const
Applies to "around point" placement strategy or linestring features.
bool containsPoint(double x, double y) const
Tests whether point set contains a specified point.
double fixedAngle() const
Returns the fixed angle for the feature's label.
QgsFeatureId featureId() const
Returns the unique ID of the feature.
QgsFeatureId id() const
Identifier of the label (unique within the parent label provider)
static bool candidateSortGrow(const LabelPosition *c1, const LabelPosition *c2)
Sorts label candidates in ascending order of cost.
double max_char_angle_outside
double priority() const
Returns the feature's labeling priority.
bool alwaysShow() const
Whether label should be always shown (sets very high label priority)
Label on top-left of point.
void setCost(double newCost)
Sets the candidate label position's geographical cost.
int incrementUpsideDownCharCount()
Increases the count of upside down characters for this label position.
bool hasFixedRotation() const
Returns true if the feature's label has a fixed rotation.
double getY(int i=0) const
get the down-left y coordinate
A set of features which influence the labeling process.
PredefinedPointPosition
Positions for labels when using the QgsPalLabeling::OrderedPositionsAroundPoint placement mode...
void offsetPosition(double xOffset, double yOffset)
Shift the label by specified offset.
int createCandidatesAlongLineNearStraightSegments(QList< LabelPosition *> &lPos, PointSet *mapShape)
Generate candidates for line feature, by trying to place candidates towards the middle of the longest...
void createGeosGeom() const
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
friend class LabelPosition
const GEOSPreparedGeometry * permissibleZonePrepared() const
Returns a GEOS prepared geometry representing the label's permissibleZone().
static void findLineCircleIntersection(double cx, double cy, double radius, double x1, double y1, double x2, double y2, double &xRes, double &yRes)
Label on top of point, slightly right of center.
const QSizeF & symbolSize() const
Returns the size of the rendered symbol associated with this feature, if applicable.
bool isClosed() const
Returns true if pointset is closed.
bool mergeWithFeaturePart(FeaturePart *other)
Merge other (connected) part with this one and save the result in this part (other is unchanged)...
UpsideDownLabels upsidedownLabels() const
Returns how upside down labels are handled within the layer.
bool isConnected(FeaturePart *p2)
Check whether this part is connected with some other part.
const QgsMargins & visualMargin() const
Returns the visual margin for the label feature.
double getLabelDistance() const
int createCandidatesAtOrderedPositionsOverPoint(double x, double y, QList< LabelPosition *> &lPos, double angle)
Generates candidates following a prioritized list of predefined positions around a point...
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning)
add a message to the instance (and create it if necessary)
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
QgsPointXY positionOffset() const
Applies only to "offset from point" placement strategy.
Arranges candidates following the curvature of a line feature. Applies to line layers only...
CharacterInfo * char_info
int createCandidatesAroundPoint(double x, double y, QList< LabelPosition *> &lPos, double angle)
Generate candidates for point feature, located around a specified point.
double priority() const
Returns the layer's priority, between 0 and 1.
LabelPosition * curvedPlacementAtOffset(PointSet *path_positions, double *path_distances, int &orientation, int index, double distance, bool &reversed, bool &flip)
Returns the label position for a curved label at a specific offset along a path.
double cost() const
Returns the candidate label position's geographical cost.
pal::LabelInfo * curvedLabelInfo() const
Get additional infor required for curved label placement. Returns null if not set.
bool hasFixedQuadrant() const
Returns whether the quadrant for the label is fixed.
static bool containsCandidate(const GEOSPreparedGeometry *geom, double x, double y, double width, double height, double alpha)
Returns true if a GEOS prepared geometry totally contains a label candidate.
QgsGeometry permissibleZone() const
Returns the label's permissible zone geometry.
bool nextCharPosition(double charWidth, double segment_length, PointSet *path_positions, int &index, double &distance, double &start_x, double &start_y, double &end_x, double &end_y) const
Returns true if the next char position is found. The referenced parameters are updated.
bool getShowPartial()
Get flag show partial label.
void getPointByDistance(double *d, double *ad, double dl, double *px, double *py)
Get a point a set distance along a line geometry.
void addSizePenalty(int nbp, QList< LabelPosition *> &lPos, double bbx[4], double bby[4])
double bottom() const
Returns the bottom margin.
double width() const
Returns the width of the rectangle.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
LabelPosition * getNextPart() const
Optional additional info about label (for curved labels)
Layer * layer()
Returns the layer that feature belongs to.
double calculatePriority() const
Calculates the priority for the feature.
QgsPalLayerSettings::Placement arrangement() const
Returns the layer's arrangement policy.
bool hasFixedAngle() const
Whether the label should use a fixed angle instead of using angle from automatic placement.
double top() const
Returns the top margin.
void insertIntoIndex(RTree< LabelPosition *, double, 2, double > *index)
int createCandidates(QList< LabelPosition *> &lPos, const GEOSPreparedGeometry *mapBoundary, PointSet *mapShape, RTree< LabelPosition *, double, 2, double > *candidates)
Generic method to generate label candidates for the feature.
static double dist_euc2d(double x1, double y1, double x2, double y2)
pal::Layer * layer() const
Get PAL layer of the label feature. Should be only used internally in PAL.
int createCandidatesAlongLine(QList< LabelPosition *> &lPos, PointSet *mapShape)
Generate candidates for line feature.
GEOSContextHandle_t geosContext()
Get GEOS context handle to be used in all GEOS library calls with reentrant API.
double fixedAngle() const
Angle in degrees of the fixed angle (relevant only if hasFixedAngle() returns true) ...
double getLabelHeight() const
static double normalizedAngle(double angle)
Ensures that an angle is in the range 0 <= angle < 2 pi.
Main class to handle feature.
int upsideDownCharCount() const
Returns the number of upside down characters for this label position.
Offset distance applies from rendered symbol bounds.
bool hasFixedPosition() const
Returns true if the feature's label has a fixed position.
int createCandidatesOverPoint(double x, double y, QList< LabelPosition *> &lPos, double angle)
Generate one candidate over or offset the specified point.
QPointF quadOffset() const
Applies to "offset from point" placement strategy and "around point" (in case hasFixedQuadrant() retu...
void setNextPart(LabelPosition *next)
CHullBox * compute_chull_bbox()
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point...
bool hasFixedPosition() const
Whether the label should use a fixed position instead of being automatically placed.
The QgsLabelFeature class describes a feature that should be used within the labeling engine...
bool hasSameLabelFeatureAs(FeaturePart *part) const
Tests whether this feature part belongs to the same QgsLabelFeature as another feature part...
double getAlpha() const
get alpha
double length() const
Returns length of line geometry.
QgsPalLayerSettings::OffsetType offsetType() const
Returns the offset type, which determines how offsets and distance to label behaves.
~FeaturePart() override
Delete the feature.
QList< FeaturePart * > mHoles
double getX(int i=0) const
get the down-left x coordinate
double max_char_angle_inside
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
int createCandidatesAlongLineNearMidpoint(QList< LabelPosition *> &lPos, PointSet *mapShape, double initialCost=0.0)
Generate candidates for line feature, by trying to place candidates as close as possible to the line'...
Label below point, slightly left of center.
void extractCoords(const GEOSGeometry *geom)
read coordinates from a GEOS geom
QString name() const
Returns the layer's name.
double getLabelWidth() const
LabelPosition is a candidate feature label position.
Label on top of point, slightly left of center.
Quadrant
Position of label candidate relative to feature.
const GEOSPreparedGeometry * preparedGeom() const
LineArrangementFlags arrangementFlags() const
Returns the layer's arrangement flags.
static int reorderPolygon(int nbPoints, double *x, double *y)
Reorder points to have cross prod ((x,y)[i], (x,y)[i+1), point) > 0 when point is outside...
FeaturePart(QgsLabelFeature *lf, const GEOSGeometry *geom)
Creates a new generic feature.
bool within(const GEOSPreparedGeometry *geometry)
Returns true if the label position is within a geometry.
QgsPointXY fixedPosition() const
Coordinates of the fixed position (relevant only if hasFixedPosition() returns true) ...
QVector< QgsPalLayerSettings::PredefinedPointPosition > predefinedPositionOrder() const
Returns the priority ordered list of predefined positions for label candidates.
bool intersects(const GEOSPreparedGeometry *geometry)
Returns true if the label position intersects a geometry.
void getCentroid(double &px, double &py, bool forceInside=false) const
static void splitPolygons(QLinkedList< PointSet *> &shapes_toProcess, QLinkedList< PointSet *> &shapes_final, double xrm, double yrm)
Split a concave shape into several convex shapes.
double left() const
Returns the left margin.
bool isCurved() const
Returns true if the layer has curved labels.
bool showUprightLabels() const
Returns true if feature's label must be displayed upright.
The QgsMargins class defines the four margins of a rectangle.
double height() const
Returns the height of the rectangle.
int connectedFeatureId(QgsFeatureId featureId) const
Returns the connected feature ID for a label feature ID, which is unique for all features which have ...
int createCurvedCandidatesAlongLine(QList< LabelPosition *> &lPos, PointSet *mapShape)
Generate curved candidates for line features.
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...