44 #include <QLinkedList>    54   mGeos = 
const_cast<GEOSGeometry *
>( geom );
    60   for ( 
int i = 0; i < 
mHoles.count(); i++ )
    62     mHoles.at( i )->holeOf = 
this;
    74     mHoles.last()->holeOf = 
this;
    88   const GEOSCoordSequence *coordSeq = 
nullptr;
    91   type = GEOSGeomTypeId_r( geosctxt, geom );
    93   if ( 
type == GEOS_POLYGON )
    95     if ( GEOSGetNumInteriorRings_r( geosctxt, geom ) > 0 )
    97       int numHoles = GEOSGetNumInteriorRings_r( geosctxt, geom );
    99       for ( 
int i = 0; i < numHoles; ++i )
   101         const GEOSGeometry *interior = GEOSGetInteriorRingN_r( geosctxt, geom, i );
   113     geom = GEOSGetExteriorRing_r( geosctxt, geom );
   122   nbPoints = GEOSGetNumCoordinates_r( geosctxt, geom );
   123   coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, geom );
   126   xmin = 
ymin = std::numeric_limits<double>::max();
   127   xmax = 
ymax = std::numeric_limits<double>::lowest();
   134   for ( 
int i = 0; i < 
nbPoints; ++i )
   136 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8   137     GEOSCoordSeq_getXY_r( geosctxt, coordSeq, i, &
x[i], &
y[i] );
   139     GEOSCoordSeq_getX_r( geosctxt, coordSeq, i, &
x[i] );
   140     GEOSCoordSeq_getY_r( geosctxt, coordSeq, i, &
y[i] );
   168   if ( mCachedMaxLineCandidates > 0 )
   169     return mCachedMaxLineCandidates;
   171   const double l = 
length();
   176     if ( maxForLayer == 0 )
   177       mCachedMaxLineCandidates = candidatesForLineLength;
   179       mCachedMaxLineCandidates = std::min( candidatesForLineLength, maxForLayer );
   183     mCachedMaxLineCandidates = 1;
   185   return mCachedMaxLineCandidates;
   190   if ( mCachedMaxPolygonCandidates > 0 )
   191     return mCachedMaxPolygonCandidates;
   193   const double a = 
area();
   198     if ( maxForLayer == 0 )
   199       mCachedMaxPolygonCandidates = candidatesForArea;
   201       mCachedMaxPolygonCandidates = std::min( candidatesForArea, maxForLayer );
   205     mCachedMaxPolygonCandidates = 1;
   207   return mCachedMaxPolygonCandidates;
   229   qreal quadOffsetX = quadOffset.x(), quadOffsetY = quadOffset.y();
   231   if ( quadOffsetX < 0 )
   233     if ( quadOffsetY < 0 )
   237     else if ( quadOffsetY > 0 )
   246   else  if ( quadOffsetX > 0 )
   248     if ( quadOffsetY < 0 )
   252     else if ( quadOffsetY > 0 )
   263     if ( quadOffsetY < 0 )
   267     else if ( quadOffsetY > 0 )
   280   return mTotalRepeats;
   294   double cost = 0.00005;
   295   int id = lPos.size();
   297   double xdiff = -labelW / 2.0;
   298   double ydiff = -labelH / 2.0;
   302   double lx = x + xdiff;
   303   double ly = y + ydiff;
   313   lPos.emplace_back( qgis::make_unique< LabelPosition >( 
id, lx, ly, labelW, labelH, angle, cost, 
this, 
false, 
LabelPosition::QuadrantOver ) );
   323   double cost = 0.0001;
   324   int id = lPos.size();
   326   double xdiff = -labelW / 2.0;
   327   double ydiff = -labelH / 2.0;
   344       double xd = xdiff * std::cos( angle ) - ydiff * std::sin( angle );
   345       double yd = xdiff * std::sin( angle ) + ydiff * std::cos( angle );
   381   double lx = x + xdiff;
   382   double ly = y + ydiff;
   392   lPos.emplace_back( qgis::make_unique< LabelPosition >( 
id, lx, ly, labelW, labelH, angle, cost, 
this, 
false, quadrantFromOffset() ) );
   405       const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, pointGeom.get() );
   406 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8   407       GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
   409       GEOSCoordSeq_getX_r( geosctxt, coordSeq, 0, &px );
   410       GEOSCoordSeq_getY_r( geosctxt, coordSeq, 0, &py );
   414   catch ( GEOSException &e )
   434   double cost = 0.0001;
   449         deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
   450         deltaY = -visualMargin.
bottom() + symbolHeightOffset;
   456         deltaX = -labelWidth / 4.0 - visualMargin.
left();
   457         deltaY = -visualMargin.
bottom() + symbolHeightOffset;
   463         deltaX = -labelWidth / 2.0;
   464         deltaY = -visualMargin.
bottom() + symbolHeightOffset;
   470         deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
   471         deltaY = -visualMargin.
bottom() + symbolHeightOffset;
   477         deltaX = - visualMargin.
left() + symbolWidthOffset;
   478         deltaY = -visualMargin.
bottom() + symbolHeightOffset;
   484         deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
   485         deltaY = -labelHeight / 2.0;
   491         deltaX = -visualMargin.
left() + symbolWidthOffset;
   492         deltaY = -labelHeight / 2.0;
   498         deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
   499         deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
   505         deltaX = -labelWidth / 4.0 - visualMargin.
left();
   506         deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
   512         deltaX = -labelWidth / 2.0;
   513         deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
   519         deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
   520         deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
   526         deltaX = -visualMargin.
left() + symbolWidthOffset;
   527         deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
   532     double referenceX = std::cos( alpha ) * distanceToLabel + 
x;
   533     double referenceY = std::sin( alpha ) * distanceToLabel + 
y;
   535     double labelX = referenceX + deltaX;
   536     double labelY = referenceY + deltaY;
   540       lPos.emplace_back( qgis::make_unique< LabelPosition >( i, labelX, labelY, labelWidth, labelHeight, angle, cost, 
this, 
false, quadrant ) );
   543       if ( maxNumberCandidates > 0 && lPos.size() >= maxNumberCandidates )
   559   if ( maxNumberCandidates == 0 )
   560     maxNumberCandidates = 16;
   564   int id = lPos.size();
   566   double candidateAngleIncrement = 2 * M_PI / maxNumberCandidates; 
   571   double a270 = a180 + a90;
   572   double a360 = 2 * M_PI;
   574   double gamma1, gamma2;
   576   if ( distanceToLabel > 0 )
   578     gamma1 = std::atan2( labelHeight / 2, distanceToLabel + labelWidth / 2 );
   579     gamma2 = std::atan2( labelWidth / 2, distanceToLabel + labelHeight / 2 );
   583     gamma1 = gamma2 = a90 / 3.0;
   586   if ( gamma1 > a90 / 3.0 )
   589   if ( gamma2 > a90 / 3.0 )
   592   std::size_t numberCandidatesGenerated = 0;
   595   double angleToCandidate;
   596   for ( i = 0, angleToCandidate = M_PI_4; i < maxNumberCandidates; i++, angleToCandidate += candidateAngleIncrement )
   601     if ( angleToCandidate > a360 )
   602       angleToCandidate -= a360;
   606     if ( angleToCandidate < gamma1 || angleToCandidate > a360 - gamma1 )  
   608       labelX += distanceToLabel;
   609       double iota = ( angleToCandidate + gamma1 );
   610       if ( iota > a360 - gamma1 )
   614       labelY += -labelHeight + labelHeight * iota / ( 2 * gamma1 );
   618     else if ( angleToCandidate < a90 - gamma2 )  
   620       labelX += distanceToLabel * std::cos( angleToCandidate );
   621       labelY += distanceToLabel * std::sin( angleToCandidate );
   624     else if ( angleToCandidate < a90 + gamma2 ) 
   627       labelX += -labelWidth * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
   628       labelY += distanceToLabel;
   631     else if ( angleToCandidate < a180 - gamma1 )  
   633       labelX += distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
   634       labelY += distanceToLabel * std::sin( angleToCandidate );
   637     else if ( angleToCandidate < a180 + gamma1 ) 
   639       labelX += -distanceToLabel - labelWidth;
   641       labelY += - ( angleToCandidate - a180 + gamma1 ) * labelHeight / ( 2 * gamma1 );
   644     else if ( angleToCandidate < a270 - gamma2 ) 
   646       labelX += distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
   647       labelY += distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
   650     else if ( angleToCandidate < a270 + gamma2 ) 
   652       labelY += -distanceToLabel - labelHeight;
   654       labelX += -labelWidth + ( angleToCandidate - a270 + gamma2 ) * labelWidth / ( 2 * gamma2 );
   657     else if ( angleToCandidate < a360 ) 
   659       labelX += distanceToLabel * std::cos( angleToCandidate );
   660       labelY += distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
   666     if ( maxNumberCandidates == 1 )
   669       cost = 0.0001 + 0.0020 * double( icost ) / double( maxNumberCandidates - 1 );
   680     lPos.emplace_back( qgis::make_unique< LabelPosition >( 
id + i, labelX, labelY, labelWidth, labelHeight, angle, cost, 
this, 
false, quadrant ) );
   681     numberCandidatesGenerated++;
   685     if ( icost == static_cast< int >( maxNumberCandidates ) )
   687       icost = 
static_cast< int >( maxNumberCandidates ) - 1;
   690     else if ( icost > static_cast< int >( maxNumberCandidates ) )
   692       icost = 
static_cast< int >( maxNumberCandidates ) - 2;
   698   return numberCandidatesGenerated;
   705     double shapeLength = mapShape->
length();
   719   if ( candidates < candidateTargetCount )
   734   std::vector< double > &
x = line->
x;
   735   std::vector< double > &
y = line->
y;
   737   std::vector< double > segmentLengths( nbPoints - 1 ); 
   738   std::vector< double >distanceToSegment( nbPoints ); 
   740   double totalLineLength = 0.0; 
   741   for ( 
int i = 0; i < line->
nbPoints - 1; i++ )
   744       distanceToSegment[i] = 0;
   746       distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
   749     totalLineLength += segmentLengths[i];
   751   distanceToSegment[line->
nbPoints - 1] = totalLineLength;
   754   const double lineStepDistance = totalLineLength / ( candidateTargetCount + 1 ); 
   755   double currentDistanceAlongLine = lineStepDistance;
   757   double candidateCenterX, candidateCenterY;
   759   while ( currentDistanceAlongLine < totalLineLength )
   766     line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateCenterX, &candidateCenterY );
   769     double cost = std::fabs( totalLineLength / 2 - currentDistanceAlongLine ) / totalLineLength; 
   772     lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateCenterX - labelWidth / 2, candidateCenterY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this ) );
   774     currentDistanceAlongLine += lineStepDistance;
   778     if ( lineStepDistance < 0 )
   795   QVector< int > extremeAngleNodes;
   798   std::vector< double > &
x = line->
x;
   799   std::vector< double > &
y = line->
y;
   803   for ( 
int i = 1; i <= numberNodes - ( closedLine ? 1 : 2 ); ++i )
   805     double x1 = x[i - 1];
   807     double x3 = x[ i == numberNodes - 1 ? 1 : i + 1]; 
   808     double y1 = y[i - 1];
   810     double y3 = y[ i == numberNodes - 1 ? 1 : i + 1]; 
   815     double vertexAngle = M_PI - ( std::atan2( y3 - y2, x3 - x2 ) - std::atan2( y2 - y1, x2 - x1 ) );
   819     if ( vertexAngle < M_PI * 135.0 / 180.0 || vertexAngle > M_PI * 225.0 / 180.0 )
   820       extremeAngleNodes << i;
   822   extremeAngleNodes << numberNodes - 1;
   824   if ( extremeAngleNodes.isEmpty() )
   831   std::vector< double > segmentLengths( numberNodes - 1 ); 
   832   std::vector< double > distanceToSegment( numberNodes ); 
   833   double totalLineLength = 0.0;
   834   QVector< double > straightSegmentLengths;
   835   QVector< double > straightSegmentAngles;
   836   straightSegmentLengths.reserve( extremeAngleNodes.size() + 1 );
   837   straightSegmentAngles.reserve( extremeAngleNodes.size() + 1 );
   838   double currentStraightSegmentLength = 0;
   839   double longestSegmentLength = 0;
   840   int segmentIndex = 0;
   841   double segmentStartX = x[0];
   842   double segmentStartY = y[0];
   843   for ( 
int i = 0; i < numberNodes - 1; i++ )
   846       distanceToSegment[i] = 0;
   848       distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
   851     totalLineLength += segmentLengths[i];
   852     if ( extremeAngleNodes.contains( i ) )
   855       straightSegmentLengths << currentStraightSegmentLength;
   857       longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
   859       currentStraightSegmentLength = 0;
   860       segmentStartX = x[i];
   861       segmentStartY = y[i];
   863     currentStraightSegmentLength += segmentLengths[i];
   865   distanceToSegment[line->
nbPoints - 1] = totalLineLength;
   866   straightSegmentLengths << currentStraightSegmentLength;
   868   longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
   869   double middleOfLine = totalLineLength / 2.0;
   871   if ( totalLineLength < labelWidth )
   877   double lineStepDistance = ( totalLineLength - labelWidth ); 
   878   lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
   880   double distanceToEndOfSegment = 0.0;
   881   int lastNodeInSegment = 0;
   883   for ( 
int i = 0; i < straightSegmentLengths.count(); ++i )
   885     currentStraightSegmentLength = straightSegmentLengths.at( i );
   886     double currentSegmentAngle = straightSegmentAngles.at( i );
   887     lastNodeInSegment = extremeAngleNodes.at( i );
   888     double distanceToStartOfSegment = distanceToEndOfSegment;
   889     distanceToEndOfSegment = distanceToSegment[ lastNodeInSegment ];
   890     double distanceToCenterOfSegment = 0.5 * ( distanceToEndOfSegment + distanceToStartOfSegment );
   892     if ( currentStraightSegmentLength < labelWidth )
   896     double currentDistanceAlongLine = distanceToStartOfSegment;
   897     double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
   898     double candidateLength = 0.0;
   904     double segmentCost = 1.0 - ( distanceToEndOfSegment - distanceToStartOfSegment ) / longestSegmentLength; 
   905     double segmentAngleCost = 1 - std::fabs( std::fmod( currentSegmentAngle, M_PI ) - M_PI_2 ) / M_PI_2; 
   907     while ( currentDistanceAlongLine + labelWidth < distanceToEndOfSegment )
   915       line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateStartX, &candidateStartY );
   916       line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
   918       candidateLength = std::sqrt( ( candidateEndX - candidateStartX ) * ( candidateEndX - candidateStartX ) + ( candidateEndY - candidateStartY ) * ( candidateEndY - candidateStartY ) );
   924       cost = candidateLength / labelWidth;
   930         cost = ( 1 - cost ) / 100; 
   934       double labelCenter = currentDistanceAlongLine + labelWidth / 2.0;
   935       double costCenter = 2 * std::fabs( labelCenter - distanceToCenterOfSegment ) / ( distanceToEndOfSegment - distanceToStartOfSegment ); 
   936       cost += costCenter * 0.0005;  
   943         double costLineCenter = 2 * std::fabs( labelCenter - middleOfLine ) / totalLineLength; 
   944         cost += costLineCenter * 0.0005;  
   947       cost += segmentCost * 0.0005; 
   948       cost += segmentAngleCost * 0.0001; 
   955         angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
   959       beta = angle + M_PI_2;
   964         bool isRightToLeft = ( angle > M_PI_2 || angle <= -M_PI_2 );
   974             const double candidateCost = cost + ( reversed ? 0 : 0.001 );
   975             lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle, candidateCost, 
this, isRightToLeft ) ); 
   982             const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); 
   983             lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle, candidateCost, 
this, isRightToLeft ) ); 
   990             const double candidateCost = cost + 0.002;
   991             lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle, candidateCost, 
this, isRightToLeft ) ); 
   997         lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this ) ); 
  1004       currentDistanceAlongLine += lineStepDistance;
  1027   std::vector< double > &
x = line->
x;
  1028   std::vector< double > &
y = line->
y;
  1030   std::vector< double > segmentLengths( nbPoints - 1 ); 
  1031   std::vector< double >distanceToSegment( nbPoints ); 
  1033   double totalLineLength = 0.0; 
  1034   for ( 
int i = 0; i < line->
nbPoints - 1; i++ )
  1037       distanceToSegment[i] = 0;
  1039       distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
  1042     totalLineLength += segmentLengths[i];
  1044   distanceToSegment[line->
nbPoints - 1] = totalLineLength;
  1046   double lineStepDistance = ( totalLineLength - labelWidth ); 
  1047   double currentDistanceAlongLine = 0;
  1051   if ( totalLineLength > labelWidth )
  1053     lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
  1057     currentDistanceAlongLine = - ( labelWidth - totalLineLength ) / 2.0;
  1058     lineStepDistance = -1;
  1059     totalLineLength = labelWidth;
  1064     currentDistanceAlongLine = std::numeric_limits< double >::max();
  1067   double candidateLength;
  1069   double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
  1071   while ( currentDistanceAlongLine < totalLineLength - labelWidth )
  1079     line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateStartX, &candidateStartY );
  1080     line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
  1082     if ( currentDistanceAlongLine < 0 )
  1085       candidateLength = std::sqrt( ( x[nbPoints - 1] - x[0] ) * ( x[nbPoints - 1] - x[0] )
  1086                                    + ( y[nbPoints - 1] - y[0] ) * ( y[nbPoints - 1] - y[0] ) );
  1090       candidateLength = std::sqrt( ( candidateEndX - candidateStartX ) * ( candidateEndX - candidateStartX ) + ( candidateEndY - candidateStartY ) * ( candidateEndY - candidateStartY ) );
  1093     cost = candidateLength / labelWidth;
  1099       cost = ( 1 - cost ) / 100; 
  1103     double costCenter = std::fabs( totalLineLength / 2 - ( currentDistanceAlongLine + labelWidth / 2 ) ) / totalLineLength; 
  1104     cost += costCenter / 1000;  
  1105     cost += initialCost;
  1112       angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
  1116     beta = angle + M_PI_2;
  1121       bool isRightToLeft = ( angle > M_PI_2 || angle <= -M_PI_2 );
  1131           const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); 
  1132           lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, angle, candidateCost, 
this, isRightToLeft ) ); 
  1139           const double candidateCost = cost + ( !reversed ? 0.001 : 0 );
  1140           lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, angle, candidateCost, 
this, isRightToLeft ) ); 
  1147           const double candidateCost = cost + 0.002;
  1148           lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, angle, candidateCost, 
this, isRightToLeft ) ); 
  1154       lPos.emplace_back( qgis::make_unique< LabelPosition >( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this ) ); 
  1161     currentDistanceAlongLine += lineStepDistance;
  1165     if ( lineStepDistance < 0 )
  1175   double offsetAlongSegment = offsetAlongLine;
  1178   while ( index < path_positions->
nbPoints && offsetAlongSegment > path_distances[index] )
  1180     offsetAlongSegment -= path_distances[index];
  1183   if ( index >= path_positions->
nbPoints )
  1192   const double segment_length = path_distances[index];
  1199   if ( orientation == 0 )       
  1203     double _distance = offsetAlongSegment;
  1204     int endindex = index;
  1206     double startLabelX = 0;
  1207     double startLabelY = 0;
  1208     double endLabelX = 0;
  1209     double endLabelY = 0;
  1210     for ( 
int i = 0; i < li->
char_num; i++ )
  1213       double characterStartX, characterStartY;
  1214       if ( !
nextCharPosition( ci.
width, path_distances[endindex], path_positions, endindex, _distance, characterStartX, characterStartY, endLabelX, endLabelY ) )
  1220         startLabelX = characterStartX;
  1221         startLabelY = characterStartY;
  1226     double dx = endLabelX - startLabelX;
  1227     double dy = endLabelY - startLabelY;
  1228     const double lineAngle = std::atan2( -dy, dx ) * 180 / M_PI;
  1230     bool isRightToLeft = ( lineAngle > 90 || lineAngle < -90 );
  1231     reversed = isRightToLeft;
  1232     orientation = isRightToLeft ? -1 : 1;
  1237     if ( orientation < 0 )
  1240       reversed = !reversed;
  1245   std::unique_ptr< LabelPosition > slp;
  1248   double old_x = path_positions->
x[index - 1];
  1249   double old_y = path_positions->
y[index - 1];
  1251   double new_x = path_positions->
x[index];
  1252   double new_y = path_positions->
y[index];
  1254   double dx = new_x - old_x;
  1255   double dy = new_y - old_y;
  1257   double angle = std::atan2( -dy, dx );
  1259   for ( 
int i = 0; i < li->
char_num; i++ )
  1261     double last_character_angle = 
angle;
  1269     double start_x, start_y, end_x, end_y;
  1270     if ( !
nextCharPosition( ci.
width, path_distances[index], path_positions, index, offsetAlongSegment, start_x, start_y, end_x, end_y ) )
  1276     angle = std::atan2( start_y - end_y, end_x - start_x );
  1281     double angle_delta = last_character_angle - 
angle;
  1283     while ( angle_delta > M_PI ) angle_delta -= 2 * M_PI;
  1284     while ( angle_delta < -M_PI ) angle_delta += 2 * M_PI;
  1288               && angle_delta < li->max_char_angle_outside * ( M_PI / 180 ) ) )
  1296     if ( orientation < 0 )
  1301     start_x += dist * std::cos( angle + M_PI_2 );
  1302     start_y -= dist * std::sin( angle + M_PI_2 );
  1304     double render_angle = 
angle;
  1306     double render_x = start_x;
  1307     double render_y = start_y;
  1313     if ( orientation < 0 )
  1316       render_x += ci.
width * std::cos( render_angle ); 
  1317       render_y -= ci.
width * std::sin( render_angle ); 
  1318       render_angle += M_PI;
  1321     std::unique_ptr< LabelPosition > tmp = qgis::make_unique< LabelPosition >( 0, render_x , render_y , ci.
width, string_height, -render_angle, 0.0001, this );
  1322     tmp->setPartId( orientation > 0 ? i : li->
char_num - i - 1 );
  1325       slp = std::move( tmp );
  1331     while ( render_angle >= 2 * M_PI ) render_angle -= 2 * M_PI;
  1332     while ( render_angle < 0 ) render_angle += 2 * M_PI;
  1334     if ( render_angle > M_PI_2 && render_angle < 1.5 * M_PI )
  1341 static std::unique_ptr< LabelPosition > _createCurvedCandidate( 
LabelPosition *lp, 
double angle, 
double dist )
  1343   std::unique_ptr< LabelPosition > newLp = qgis::make_unique< LabelPosition >( *lp );
  1344   newLp->offsetPosition( dist * std::cos( 
angle + M_PI_2 ), dist * std::sin( 
angle + M_PI_2 ) );
  1359   double totalCharacterWidth = 0;
  1360   for ( 
int i = 0; i < li->
char_num; ++i )
  1363   std::unique_ptr< PointSet > expanded;
  1364   double shapeLength = mapShape->
length();
  1367     allowOverrun = 
false;
  1373   if ( totalCharacterWidth > shapeLength )
  1375     if ( !allowOverrun || shapeLength < totalCharacterWidth - 2 * overrun )
  1382   if ( allowOverrun && overrun > 0 )
  1385     expanded = mapShape->
clone();
  1387     mapShape = expanded.get();
  1388     shapeLength = mapShape->
length();
  1392   std::unique_ptr< double [] > path_distances = qgis::make_unique<double[]>( mapShape->
nbPoints );
  1393   double total_distance = 0;
  1394   double old_x = -1.0, old_y = -1.0;
  1395   for ( 
int i = 0; i < mapShape->
nbPoints; i++ )
  1398       path_distances[i] = 0;
  1400       path_distances[i] = std::sqrt( std::pow( old_x - mapShape->
x[i], 2 ) + std::pow( old_y - mapShape->
y[i], 2 ) );
  1401     old_x = mapShape->
x[i];
  1402     old_y = mapShape->
y[i];
  1404     total_distance += path_distances[i];
  1415   std::vector< std::unique_ptr< LabelPosition >> positions;
  1417   double delta = std::max( li->
label_height / 6, total_distance / candidateTargetCount );
  1424   for ( 
double distanceAlongLineToStartCandidate = 0; distanceAlongLineToStartCandidate < total_distance; distanceAlongLineToStartCandidate += delta )
  1428     bool reversed = 
false;
  1434     int orientation = 0;
  1442     std::unique_ptr< LabelPosition > slp = 
curvedPlacementAtOffset( mapShape, path_distances.get(), orientation, distanceAlongLineToStartCandidate, reversed, flip );
  1447     if ( slp->upsideDownCharCount() >= li->
char_num / 2.0 )
  1452         orientation = -orientation;
  1453         slp = 
curvedPlacementAtOffset( mapShape, path_distances.get(), orientation, distanceAlongLineToStartCandidate, reversed, flip );
  1460     double angle_diff = 0.0, angle_last = 0.0, diff;
  1462     double sin_avg = 0, cos_avg = 0;
  1465       if ( tmp != slp.get() ) 
  1467         diff = std::fabs( tmp->
getAlpha() - angle_last );
  1468         if ( diff > 2 * M_PI ) diff -= 2 * M_PI;
  1469         diff = std::min( diff, 2 * M_PI - diff ); 
  1473       sin_avg += std::sin( tmp->
getAlpha() );
  1474       cos_avg += std::cos( tmp->
getAlpha() );
  1479     double angle_diff_avg = li->
char_num > 1 ? ( angle_diff / ( li->
char_num - 1 ) ) : 0; 
  1480     double cost = angle_diff_avg / 100; 
  1481     if ( cost < 0.0001 ) cost = 0.0001;
  1484     double labelCenter = distanceAlongLineToStartCandidate + 
getLabelWidth() / 2;
  1485     double costCenter = std::fabs( total_distance / 2 - labelCenter ) / total_distance; 
  1486     cost += costCenter / 100;  
  1487     slp->setCost( cost );
  1490     double angle_avg = std::atan2( sin_avg / li->
char_num, cos_avg / li->
char_num );
  1491     bool localreversed = flip ? !reversed : reversed;
  1493     for ( 
int i = 0; i <= 2; ++i )
  1495       std::unique_ptr< LabelPosition > p;
  1500         p = _createCurvedCandidate( slp.get(), angle_avg, 0 );
  1501         p->setCost( p->cost() + 0.002 );
  1503       if ( i == 2 && ( ( !localreversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) ) || ( localreversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) ) ) )
  1506         p->setCost( p->cost() + 0.001 );
  1513         while ( within && currentPos )
  1516           currentPos = currentPos->
nextPart();
  1525         positions.emplace_back( std::move( p ) );
  1529   for ( std::unique_ptr< LabelPosition > &pos : positions )
  1531     lPos.emplace_back( std::move( pos ) );
  1534   return positions.size();
  1558   QLinkedList<PointSet *> shapes_toProcess;
  1559   QLinkedList<PointSet *> shapes_final;
  1560   const double totalArea = 
area();
  1562   mapShape->
parent = 
nullptr;
  1567   shapes_toProcess.append( mapShape );
  1569   splitPolygons( shapes_toProcess, shapes_final, labelWidth, labelHeight );
  1571   std::size_t nbp = 0;
  1573   if ( !shapes_final.isEmpty() )
  1581     double diago = std::sqrt( labelWidth * labelWidth / 4.0 + labelHeight * labelHeight / 4 );
  1583     std::vector< CHullBox > boxes;
  1584     boxes.reserve( shapes_final.size() );
  1587     while ( !shapes_final.isEmpty() )
  1589       PointSet *shape = shapes_final.takeFirst();
  1600     double densityY = densityX;
  1607     std::size_t numberCandidatesGenerated = 0;
  1622         double dx = densityX;
  1623         double dy = densityY;
  1624         if ( numTry == 0 && maxPolygonCandidates > 0 )
  1627           const double boxArea = box.width * box.length;
  1628           double maxThisBox = targetPolygonCandidates * boxArea / totalArea;
  1629           dx = std::max( dx, std::sqrt( boxArea / maxThisBox ) * 0.8 );
  1634           return numberCandidatesGenerated;
  1653         bool enoughPlace = 
false;
  1657           px = ( box.x[0] + box.x[2] ) / 2 - labelWidth;
  1658           py = ( box.y[0] + box.y[2] ) / 2 - labelHeight;
  1664           for ( rx = px, i = 0; i < 2; rx = rx + 2 * labelWidth, i++ )
  1666             for ( ry = py, j = 0; j < 2; ry = ry + 2 * labelHeight, j++ )
  1670                 enoughPlace = 
false;
  1686         else if ( box.length > 1.5 * labelWidth && box.width > 1.5 * labelWidth )
  1688           if ( box.alpha <= M_PI_4 )
  1694             alpha = box.alpha - M_PI_2;
  1697         else if ( box.length > box.width )
  1699           alpha = box.alpha - M_PI_2;
  1706         beta  = std::atan2( labelHeight, labelWidth ) + alpha;
  1712         dlx = std::cos( beta ) * diago;
  1713         dly = std::sin( beta ) * diago;
  1715         double px0 = box.width / 2.0;
  1716         double py0 = box.length / 2.0;
  1718         px0 -= std::ceil( px0 / dx ) * dx;
  1719         py0 -= std::ceil( py0 / dy ) * dy;
  1721         for ( px = px0; px <= box.width; px += dx )
  1726           for ( py = py0; py <= box.length; py += dy )
  1729             rx = std::cos( box.alpha ) * px + std::cos( box.alpha - M_PI_2 ) * py;
  1730             ry = std::sin( box.alpha ) * px + std::sin( box.alpha - M_PI_2 ) * py;
  1740                 lPos.emplace_back( qgis::make_unique< LabelPosition >( 
id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, 
this ) );
  1741                 numberCandidatesGenerated++;
  1752                 std::unique_ptr< LabelPosition > potentialCandidate = qgis::make_unique< LabelPosition >( 
id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, this );
  1754                 lPos.emplace_back( std::move( potentialCandidate ) );
  1755                 numberCandidatesGenerated++;
  1762       nbp = numberCandidatesGenerated;
  1763       if ( maxPolygonCandidates > 0 && nbp < targetPolygonCandidates )
  1774     while ( numTry < maxTry );
  1776     nbp = numberCandidatesGenerated;
  1788   std::vector< std::unique_ptr< LabelPosition > > lPos;
  1808       case GEOS_LINESTRING:
  1858   int geomType = GEOSGeomTypeId_r( ctxt, 
mGeos );
  1860   double sizeCost = 0;
  1861   if ( geomType == GEOS_LINESTRING )
  1863     const double l = 
length();
  1866     double bbox_length = std::max( bbx[2] - bbx[0], bby[2] - bby[0] );
  1867     if ( l >= bbox_length / 4 )
  1870     sizeCost = 1 - ( l / ( bbox_length / 4 ) ); 
  1872   else if ( geomType == GEOS_POLYGON )
  1874     const double a = 
area();
  1877     double bbox_area = ( bbx[2] - bbx[0] ) * ( bby[2] - bby[0] );
  1878     if ( a >= bbox_area / 16 )
  1881     sizeCost = 1 - ( a / ( bbox_area / 16 ) ); 
  1887   for ( std::unique_ptr< LabelPosition > &pos : lPos )
  1889     pos->setCost( pos->cost() + sizeCost / 100 );
  1902   catch ( GEOSException &e )
  1913   if ( !other->
mGeos )
  1919     GEOSGeometry *g1 = GEOSGeom_clone_r( ctxt, 
mGeos );
  1920     GEOSGeometry *g2 = GEOSGeom_clone_r( ctxt, other->
mGeos );
  1921     GEOSGeometry *geoms[2] = { g1, g2 };
  1922     geos::unique_ptr g( GEOSGeom_createCollection_r( ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
  1925     if ( GEOSGeomTypeId_r( ctxt, gTmp.get() ) != GEOS_LINESTRING )
  1933     mGeos = gTmp.release();
  1942   catch ( GEOSException &e )
  1964   bool uprightLabel = 
false;
  1969       uprightLabel = 
true;
  1975         uprightLabel = 
true;
  1981       uprightLabel = 
true;
  1983   return uprightLabel;
  1987                                     double &characterStartX, 
double &characterStartY, 
double &characterEndX, 
double &characterEndY )
 const  1996   double segmentStartX = path_positions->
x[index - 1];
  1997   double segmentStartY = path_positions->
y[index - 1];
  1999   double segmentEndX = path_positions->
x[index];
  2000   double segmentEndY = path_positions->
y[index];
  2002   double segmentDx = segmentEndX - segmentStartX;
  2003   double segmentDy = segmentEndY - segmentStartY;
  2005   characterStartX = segmentStartX + segmentDx * currentDistanceAlongSegment / segmentLength;
  2006   characterStartY = segmentStartY + segmentDy * currentDistanceAlongSegment / segmentLength;
  2012   if ( segmentLength - currentDistanceAlongSegment >= charWidth )
  2015     currentDistanceAlongSegment += charWidth;
  2016     characterEndX = segmentStartX + segmentDx * currentDistanceAlongSegment / segmentLength;
  2017     characterEndY = segmentStartY + segmentDy * currentDistanceAlongSegment / segmentLength;
  2025       segmentStartX = segmentEndX;
  2026       segmentStartY = segmentEndY;
  2028       if ( index >= path_positions->
nbPoints ) 
  2032       segmentEndX = path_positions->
x[index];
  2033       segmentEndY = path_positions->
y[index];
  2035     while ( std::sqrt( std::pow( characterStartX - segmentEndX, 2 ) + std::pow( characterStartY - segmentEndY, 2 ) ) < charWidth ); 
  2041     currentDistanceAlongSegment = std::sqrt( std::pow( segmentStartX - characterEndX, 2 ) + std::pow( segmentStartY - characterEndY, 2 ) );
 Label on bottom right of point. 
 
QgsLabeling::LinePlacementFlags arrangementFlags() const
Returns the feature's arrangement flags. 
 
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...
 
LabelPosition * nextPart() const
Returns the next part of this label position (i.e. 
 
Label on bottom-left of point. 
 
Label on top of point, slightly left of center. 
 
CHullBox compute_chull_bbox()
Computes a con???? hull. 
 
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. 
 
std::size_t createCurvedCandidatesAlongLine(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal)
Generate curved candidates for line features. 
 
QgsFeatureId id() const
Identifier of the label (unique within the parent label provider) 
 
std::size_t maximumPointLabelCandidates() const
Returns the maximum number of point label candidates to generate for features in this layer...
 
double max_char_angle_outside
 
QgsLabelFeature * feature()
Returns the parent feature. 
 
double priority() const
Returns the feature's labeling priority. 
 
void setTotalRepeats(int repeats)
Returns the total number of repeating labels associated with this label. 
 
bool alwaysShow() const
Whether label should be always shown (sets very high label priority) 
 
Label on top-left of point. 
 
int incrementUpsideDownCharCount()
Increases the count of upside down characters for this label position. 
 
void addSizePenalty(std::vector< std::unique_ptr< LabelPosition > > &lPos, double bbx[4], double bby[4])
Increases the cost of the label candidates for this feature, based on the size of the feature...
 
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point...
 
bool hasFixedRotation() const
Returns true if the feature's label has a fixed rotation. 
 
double getY(int i=0) const
Returns 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...
 
A class to represent a 2D point. 
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference) 
 
void createGeosGeom() const
 
std::size_t maximumPolygonLabelCandidates() const
Returns the maximum number of polygon label candidates to generate for features in this layer...
 
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
 
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)
 
std::size_t maximumLineLabelCandidates() const
Returns the maximum number of line label candidates to generate for features in this layer...
 
Label on top-right of point. 
 
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
Returns the distance from the anchor point to the label. 
 
std::size_t createCandidatesForPolygon(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, Pal *pal)
Generate candidates for polygon features. 
 
Labels can be placed directly over a line feature. 
 
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) 
 
std::unique_ptr< LabelPosition > curvedPlacementAtOffset(PointSet *path_positions, double *path_distances, int &orientation, double distance, bool &reversed, bool &flip)
Returns the label position for a curved label at a specific offset along a path. 
 
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
 
static GEOSContextHandle_t getGEOSHandler()
 
QgsPointXY positionOffset() const
Applies only to "offset from point" placement strategy. 
 
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
 
CharacterInfo * char_info
 
double priority() const
Returns the layer's priority, between 0 and 1. 
 
pal::LabelInfo * curvedLabelInfo() const
Gets additional info required for curved label placement. Returns nullptr 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. 
 
std::unique_ptr< LabelPosition > createCandidatePointOnSurface(PointSet *mapShape)
Creates a single candidate using the "point on sruface" algorithm. 
 
void getPointByDistance(double *d, double *ad, double dl, double *px, double *py)
Gets a point a set distance along a line geometry. 
 
static void splitPolygons(QLinkedList< PointSet *> &inputShapes, QLinkedList< PointSet *> &outputShapes, double xrm, double yrm)
Split a concave shape into several convex shapes. 
 
bool nextCharPosition(double charWidth, double segmentLength, PointSet *path_positions, int &index, double ¤tDistanceAlongSegment, double &characterStartX, double &characterStartY, double &characterEndX, double &characterEndY) const
Returns true if the next char position is found. The referenced parameters are updated. 
 
std::size_t createCandidatesAlongLineNearMidpoint(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, double initialCost=0.0, Pal *pal=nullptr)
Generate candidates for line feature, by trying to place candidates as close as possible to the line'...
 
double bottom() const
Returns the bottom margin. 
 
double width() const
Returns the width of the rectangle. 
 
bool isCanceled()
Check whether the job has been canceled. 
 
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer. 
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary). 
 
std::size_t createHorizontalCandidatesAlongLine(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, Pal *pal)
Generate horizontal candidates for line feature. 
 
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
 
void setAnchorPosition(const QgsPointXY &anchorPosition)
In case of quadrand or aligned positioning, this is set to the anchor point. 
 
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. 
 
static double dist_euc2d(double x1, double y1, double x2, double y2)
 
pal::Layer * layer() const
Gets PAL layer of the label feature. Should be only used internally in PAL. 
 
double fixedAngle() const
Angle in degrees of the fixed angle (relevant only if hasFixedAngle() returns true) ...
 
Label below point, slightly right of center. 
 
static double normalizedAngle(double angle)
Ensures that an angle is in the range 0 <= angle < 2 pi. 
 
Main class to handle feature. 
 
Offset distance applies from rendered symbol bounds. 
 
std::size_t createCandidatesAlongLine(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal)
Generate candidates for line feature. 
 
bool hasFixedPosition() const
Returns true if the feature's label has a fixed position. 
 
double maximumLineCandidatesPerMapUnit() const
Returns the maximum number of line label candidate positions per map unit. 
 
std::size_t maximumLineCandidates() const
Returns the maximum number of line candidates to generate for this feature. 
 
QPointF quadOffset() const
Applies to "offset from point" placement strategy and "around point" (in case hasFixedQuadrant() retu...
 
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
 
double maximumPolygonCandidatesPerMapUnitSquared() const
Returns the maximum number of polygon label candidate positions per map unit squared. 
 
double area() const
Returns area of polygon geometry. 
 
void setNextPart(std::unique_ptr< LabelPosition > next)
Sets the next part of this label position (i.e. 
 
static int reorderPolygon(int nbPoints, std::vector< double > &x, std::vector< double > &y)
Reorder points to have cross prod ((x,y)[i], (x,y)[i+1), point) > 0 when point is outside...
 
Signifies that the AboveLine and BelowLine flags should respect the map's orientation rather than the...
 
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...
 
std::unique_ptr< PointSet > clone() const
Returns a copy of the point set. 
 
bool hasSameLabelFeatureAs(FeaturePart *part) const
Tests whether this feature part belongs to the same QgsLabelFeature as another feature part...
 
double getAlpha() const
Returns the angle to rotate text (in rad). 
 
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. 
 
Label below point, slightly left of center. 
 
~FeaturePart() override
Delete the feature. 
 
QList< FeaturePart * > mHoles
 
double getX(int i=0) const
Returns the down-left x coordinate. 
 
double max_char_angle_inside
 
Label on top of point, slightly right of center. 
 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry. 
 
Label directly below point. 
 
void extractCoords(const GEOSGeometry *geom)
read coordinates from a GEOS geom 
 
QString name() const
Returns the layer's name. 
 
LabelPosition is a candidate feature label position. 
 
std::size_t createCandidatesAtOrderedPositionsOverPoint(double x, double y, std::vector< std::unique_ptr< LabelPosition > > &lPos, double angle)
Generates candidates following a prioritized list of predefined positions around a point...
 
double overrunSmoothDistance() const
Returns the distance (in map units) with which the ends of linear features are averaged over when cal...
 
Label directly above point. 
 
std::size_t createCandidatesOverPoint(double x, double y, std::vector< std::unique_ptr< LabelPosition > > &lPos, double angle)
Generate one candidate over or offset the specified point. 
 
Quadrant
Position of label candidate relative to feature. 
 
const GEOSPreparedGeometry * preparedGeom() const
 
std::vector< std::unique_ptr< LabelPosition > > createCandidates(Pal *pal)
Generates a list of candidate positions for labels for this feature. 
 
FeaturePart(QgsLabelFeature *lf, const GEOSGeometry *geom)
Creates a new generic feature. 
 
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. 
 
std::size_t maximumPointCandidates() const
Returns the maximum number of point candidates to generate for this feature. 
 
void getCentroid(double &px, double &py, bool forceInside=false) const
 
std::size_t maximumPolygonCandidates() const
Returns the maximum number of polygon candidates to generate for this feature. 
 
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only...
 
const GEOSGeometry * geos() const
Returns the point set's GEOS geometry. 
 
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
 
std::size_t createCandidatesAroundPoint(double x, double y, std::vector< std::unique_ptr< LabelPosition > > &lPos, double angle)
Generate candidates for point feature, located around a specified point. 
 
double left() const
Returns the left margin. 
 
bool isCurved() const
Returns true if the layer has curved labels. 
 
double getLabelWidth(double angle=0.0) const
Returns the width of the label, optionally taking an angle into account. 
 
double overrunDistance() const
Returns the permissible distance (in map units) which labels are allowed to overrun the start or end ...
 
bool showUprightLabels() const
Returns true if feature's label must be displayed upright. 
 
double getLabelHeight(double angle=0.0) const
Returns the height of the label, optionally taking an angle into account. 
 
The QgsMargins class defines the four margins of a rectangle. 
 
std::size_t createCandidatesAlongLineNearStraightSegments(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, Pal *pal)
Generate candidates for line feature, by trying to place candidates towards the middle of the longest...
 
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 totalRepeats() const
Returns the total number of repeating labels associated with this label. 
 
std::size_t createCandidateCenteredOverPoint(double x, double y, std::vector< std::unique_ptr< LabelPosition > > &lPos, double angle)
Generate one candidate centered over the specified point. 
 
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...