62  for ( 
int i = 0; i < 
mHoles.count(); i++ )
 
 
   72  , mTotalRepeats( other.mTotalRepeats )
 
   73  , mCachedMaxLineCandidates( other.mCachedMaxLineCandidates )
 
   74  , mCachedMaxPolygonCandidates( other.mCachedMaxPolygonCandidates )
 
   79    mHoles.last()->holeOf = 
this;
 
 
   93  const GEOSCoordSequence *coordSeq = 
nullptr;
 
   96  type = GEOSGeomTypeId_r( geosctxt, geom );
 
   98  if ( 
type == GEOS_POLYGON )
 
  100    if ( GEOSGetNumInteriorRings_r( geosctxt, geom ) > 0 )
 
  102      int numHoles = GEOSGetNumInteriorRings_r( geosctxt, geom );
 
  104      for ( 
int i = 0; i < numHoles; ++i )
 
  106        const GEOSGeometry *interior = GEOSGetInteriorRingN_r( geosctxt, geom, i );
 
  118    geom = GEOSGetExteriorRing_r( geosctxt, geom );
 
  127  nbPoints = GEOSGetNumCoordinates_r( geosctxt, geom );
 
  128  coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, geom );
 
  131  xmin = 
ymin = std::numeric_limits<double>::max();
 
  132  xmax = 
ymax = std::numeric_limits<double>::lowest();
 
  139#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
  140  GEOSCoordSeq_copyToArrays_r( geosctxt, coordSeq, 
x.data(), 
y.data(), 
nullptr, 
nullptr );
 
  141  auto xminmax = std::minmax_element( 
x.begin(), 
x.end() );
 
  142  xmin = *xminmax.first;
 
  143  xmax = *xminmax.second;
 
  144  auto yminmax = std::minmax_element( 
y.begin(), 
y.end() );
 
  145  ymin = *yminmax.first;
 
  146  ymax = *yminmax.second;
 
  148  for ( 
int i = 0; i < 
nbPoints; ++i )
 
  150    GEOSCoordSeq_getXY_r( geosctxt, coordSeq, i, &
x[i], &
y[i] );
 
 
  178  if ( mCachedMaxLineCandidates > 0 )
 
  179    return mCachedMaxLineCandidates;
 
  181  const double l = 
length();
 
  186    if ( maxForLayer == 0 )
 
  187      mCachedMaxLineCandidates = candidatesForLineLength;
 
  189      mCachedMaxLineCandidates = std::min( candidatesForLineLength, maxForLayer );
 
  193    mCachedMaxLineCandidates = 1;
 
  195  return mCachedMaxLineCandidates;
 
 
  200  if ( mCachedMaxPolygonCandidates > 0 )
 
  201    return mCachedMaxPolygonCandidates;
 
  203  const double a = 
area();
 
  208    if ( maxForLayer == 0 )
 
  209      mCachedMaxPolygonCandidates = candidatesForArea;
 
  211      mCachedMaxPolygonCandidates = std::min( candidatesForArea, maxForLayer );
 
  215    mCachedMaxPolygonCandidates = 1;
 
  217  return mCachedMaxPolygonCandidates;
 
 
  239  qreal quadOffsetX = quadOffset.x(), quadOffsetY = quadOffset.y();
 
  241  if ( quadOffsetX < 0 )
 
  243    if ( quadOffsetY < 0 )
 
  247    else if ( quadOffsetY > 0 )
 
  256  else  if ( quadOffsetX > 0 )
 
  258    if ( quadOffsetY < 0 )
 
  262    else if ( quadOffsetY > 0 )
 
  273    if ( quadOffsetY < 0 )
 
  277    else if ( quadOffsetY > 0 )
 
  290  return mTotalRepeats;
 
 
  304  double cost = 0.00005;
 
  305  int id = lPos.size();
 
  307  double xdiff = -labelW / 2.0;
 
  308  double ydiff = -labelH / 2.0;
 
  312  double lx = 
x + xdiff;
 
  313  double ly = 
y + ydiff;
 
 
  333  double cost = 0.0001;
 
  334  int id = lPos.size();
 
  336  double xdiff = -labelW / 2.0;
 
  337  double ydiff = -labelH / 2.0;
 
  354      double xd = xdiff * std::cos( angle ) - ydiff * std::sin( angle );
 
  355      double yd = xdiff * std::sin( angle ) + ydiff * std::cos( angle );
 
  391  double lx = 
x + xdiff;
 
  392  double ly = 
y + ydiff;
 
 
  412    geos::unique_ptr pointGeom( GEOSPointOnSurface_r( geosctxt, mapShape->
geos() ) );
 
  415      const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, pointGeom.get() );
 
  416      unsigned int nPoints = 0;
 
  417      GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
 
  420      GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
 
  423  catch ( QgsGeosException &e )
 
  425    qWarning( 
"GEOS exception: %s", e.what() );
 
 
  433void createCandidateAtOrderedPositionOverPoint( 
double &labelX, 
double &labelY, 
Qgis::LabelQuadrantPosition &quadrant, 
double x, 
double y, 
double labelWidth, 
double labelHeight, 
Qgis::LabelPredefinedPointPosition position, 
double distanceToLabel, 
const QgsMargins &visualMargin, 
double symbolWidthOffset, 
double symbolHeightOffset, 
double angle )
 
  444      deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  445      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  451      deltaX = -labelWidth / 4.0 - visualMargin.
left();
 
  452      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  458      deltaX = -labelWidth / 2.0;
 
  459      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  465      deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
 
  466      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  472      deltaX = - visualMargin.
left() + symbolWidthOffset;
 
  473      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  479      deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  480      deltaY = -labelHeight / 2.0;
 
  486      deltaX = -visualMargin.
left() + symbolWidthOffset;
 
  487      deltaY = -labelHeight / 2.0;
 
  493      deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  494      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  500      deltaX = -labelWidth / 4.0 - visualMargin.
left();
 
  501      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  507      deltaX = -labelWidth / 2.0;
 
  508      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  514      deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
 
  515      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  521      deltaX = -visualMargin.
left() + symbolWidthOffset;
 
  522      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  529      deltaX = -labelWidth / 2.0;
 
  530      deltaY = -labelHeight / 2.0;
 
  536  QTransform transformRotation;
 
  537  transformRotation.rotate( angle * 180 / M_PI );
 
  538  transformRotation.map( deltaX, deltaY, &deltaX, &deltaY );
 
  541  double referenceX = std::cos( alpha ) * distanceToLabel + x;
 
  542  double referenceY = std::sin( alpha ) * distanceToLabel + y;
 
  544  labelX = referenceX + deltaX;
 
  545  labelY = referenceY + deltaY;
 
 
  558  double symbolWidthOffset{ 0 };
 
  559  double symbolHeightOffset{ 0 };
 
  567      symbolWidthOffset = ( 
mLF->
symbolSize().width() - geom.boundingBox().width() ) / 2.0;
 
  568      symbolHeightOffset = ( 
mLF->
symbolSize().height() - geom.boundingBox().height() ) / 2.0;
 
  577  int candidatesPerPosition = 1;
 
  578  double distanceStep = 0;
 
  579  if ( maximumDistanceToLabel > distanceToLabel && !
qgsDoubleNear( maximumDistanceToLabel, 0 ) )
 
  583    const double rayLength = maximumDistanceToLabel - distanceToLabel;
 
  587    distanceStep = rayLength / ( candidatesPerPosition - 1 );
 
  590  double cost = 0.0001;
 
  591  std::size_t i = lPos.size();
 
  595  std::size_t created = 0;
 
  597  auto addCandidate = [
this, 
x, 
y, labelWidth, labelHeight, angle, visualMargin, symbolWidthOffset, symbolHeightOffset, &created, &cost, &lPos, &i, maxNumberCandidates]( 
Qgis::LabelPredefinedPointPosition position, 
double distance ) -> 
bool 
  603    createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, 
x, 
y, labelWidth, labelHeight, position, distance, visualMargin, symbolWidthOffset, symbolHeightOffset, angle );
 
  612      if ( maxNumberCandidates > 0 && created >= maxNumberCandidates )
 
  618  switch ( prioritization )
 
  626        double currentDistance = distanceToLabel;
 
  627        for ( 
int distanceIndex = 0; distanceIndex < candidatesPerPosition; ++distanceIndex, currentDistance += distanceStep )
 
  629          if ( !addCandidate( position, currentDistance ) )
 
  638      double currentDistance = distanceToLabel;
 
  639      for ( 
int distanceIndex = 0; distanceIndex < candidatesPerPosition; ++distanceIndex, currentDistance += distanceStep )
 
  643          if ( !addCandidate( position, currentDistance ) )
 
 
  662  QTransform transformRotation;
 
  663  transformRotation.rotate( angle * 180 / M_PI );
 
  669  int candidatesPerRay = 0;
 
  670  double rayStepDelta = 0;
 
  671  if ( maximumDistanceToLabel > distanceToLabel && !
qgsDoubleNear( maximumDistanceToLabel, 0 ) )
 
  675    const double rayLength = maximumDistanceToLabel - distanceToLabel;
 
  679    rayStepDelta = rayLength / ( candidatesPerRay - 1 );
 
  683    candidatesPerRay = 1;
 
  686  int id = 
static_cast< int >( lPos.size() );
 
  688  const double candidateAngleIncrement = 2 * M_PI / 
static_cast< double >( rayCount ); 
 
  691  constexpr double a90  = M_PI_2;
 
  692  constexpr double a180 = M_PI;
 
  693  constexpr double a270 = a180 + a90;
 
  694  constexpr double a360 = 2 * M_PI;
 
  696  double gamma1, gamma2;
 
  698  if ( distanceToLabel > 0 )
 
  700    gamma1 = std::atan2( labelHeight / 2, distanceToLabel + labelWidth / 2 );
 
  701    gamma2 = std::atan2( labelWidth / 2, distanceToLabel + labelHeight / 2 );
 
  705    gamma1 = gamma2 = a90 / 3.0;
 
  708  if ( gamma1 > a90 / 3.0 )
 
  711  if ( gamma2 > a90 / 3.0 )
 
  714  std::size_t numberCandidatesGenerated = 0;
 
  716  double angleToCandidate = M_PI_4;
 
  718  int integerRayCost = 0;
 
  719  int integerRayCostIncrement = 2;
 
  721  for ( 
int rayIndex = 0; rayIndex < rayCount; ++rayIndex, angleToCandidate += candidateAngleIncrement )
 
  726    if ( angleToCandidate > a360 )
 
  727      angleToCandidate -= a360;
 
  729    double rayDistance = distanceToLabel;
 
  731    constexpr double RAY_ANGLE_COST_FACTOR = 0.0020;
 
  735    const double scaledRayAngleCost = RAY_ANGLE_COST_FACTOR * 
static_cast< double >( integerRayCost )
 
  736                                      / 
static_cast< double >( rayCount - 1 );
 
  738    for ( 
int j = 0; j < candidatesPerRay; ++j, rayDistance += rayStepDelta )
 
  742      if ( angleToCandidate < gamma1 || angleToCandidate > a360 - gamma1 )  
 
  744        deltaX = rayDistance;
 
  745        double iota = ( angleToCandidate + gamma1 );
 
  746        if ( iota > a360 - gamma1 )
 
  749        deltaY = -labelHeight + labelHeight * iota / ( 2 * gamma1 );
 
  753      else if ( angleToCandidate < a90 - gamma2 )  
 
  755        deltaX = rayDistance * std::cos( angleToCandidate );
 
  756        deltaY = rayDistance * std::sin( angleToCandidate );
 
  759      else if ( angleToCandidate < a90 + gamma2 ) 
 
  761        deltaX = -labelWidth * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
 
  762        deltaY = rayDistance;
 
  765      else if ( angleToCandidate < a180 - gamma1 )  
 
  767        deltaX = rayDistance * std::cos( angleToCandidate ) - labelWidth;
 
  768        deltaY = rayDistance * std::sin( angleToCandidate );
 
  771      else if ( angleToCandidate < a180 + gamma1 ) 
 
  773        deltaX = -rayDistance - labelWidth;
 
  774        deltaY = - ( angleToCandidate - a180 + gamma1 ) * labelHeight / ( 2 * gamma1 );
 
  777      else if ( angleToCandidate < a270 - gamma2 ) 
 
  779        deltaX = rayDistance * std::cos( angleToCandidate ) - labelWidth;
 
  780        deltaY = rayDistance * std::sin( angleToCandidate ) - labelHeight;
 
  783      else if ( angleToCandidate < a270 + gamma2 ) 
 
  785        deltaY = -rayDistance - labelHeight;
 
  786        deltaX = -labelWidth + ( angleToCandidate - a270 + gamma2 ) * labelWidth / ( 2 * gamma2 );
 
  789      else if ( angleToCandidate < a360 ) 
 
  791        deltaX = rayDistance * std::cos( angleToCandidate );
 
  792        deltaY = rayDistance * std::sin( angleToCandidate ) - labelHeight;
 
  796      transformRotation.map( deltaX, deltaY, &deltaX, &deltaY );
 
  798      double labelX = 
x + deltaX;
 
  799      double labelY = 
y + deltaY;
 
  806        cost = 0.0001 + scaledRayAngleCost;
 
  813        cost += j * RAY_ANGLE_COST_FACTOR + RAY_ANGLE_COST_FACTOR / rayCount;
 
  826      numberCandidatesGenerated++;
 
  829    integerRayCost += integerRayCostIncrement;
 
  831    if ( integerRayCost == 
static_cast< int >( rayCount ) )
 
  833      integerRayCost = 
static_cast< int >( rayCount ) - 1;
 
  834      integerRayCostIncrement = -2;
 
  836    else if ( integerRayCost > 
static_cast< int >( rayCount ) )
 
  838      integerRayCost = 
static_cast< int >( rayCount ) - 2;
 
  839      integerRayCostIncrement = -2;
 
  843  return numberCandidatesGenerated;
 
 
  850    double shapeLength = mapShape->
length();
 
  861  std::size_t candidates = 0;
 
  867  if ( candidates < candidateTargetCount )
 
 
  882  std::vector< double > &
x = line->
x;
 
  883  std::vector< double > &
y = line->
y;
 
  885  std::vector< double > segmentLengths( 
nbPoints - 1 ); 
 
  886  std::vector< double >distanceToSegment( 
nbPoints ); 
 
  888  double totalLineLength = 0.0; 
 
  889  for ( 
int i = 0; i < line->
nbPoints - 1; i++ )
 
  892      distanceToSegment[i] = 0;
 
  894      distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
  897    totalLineLength += segmentLengths[i];
 
  899  distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
  902  double lineStepDistance = 0;
 
  905  double currentDistanceAlongLine = lineStepDistance;
 
  909      lineStepDistance = totalLineLength / ( candidateTargetCount + 1 ); 
 
  913      currentDistanceAlongLine = lineAnchorPoint;
 
  914      lineStepDistance = -1;
 
  920  double candidateCenterX, candidateCenterY;
 
  922  while ( currentDistanceAlongLine <= totalLineLength )
 
  924    if ( 
pal->isCanceled() )
 
  929    line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateCenterX, &candidateCenterY );
 
  932    double cost = std::fabs( lineAnchorPoint - currentDistanceAlongLine ) / totalLineLength; 
 
  939        labelX = candidateCenterX;
 
  942        labelX = candidateCenterX - labelWidth / 2;
 
  945        labelX = candidateCenterX - labelWidth;
 
  953    currentDistanceAlongLine += lineStepDistance;
 
  957    if ( lineStepDistance < 0 )
 
 
  974  QVector< int > extremeAngleNodes;
 
  977  std::vector< double > &
x = line->
x;
 
  978  std::vector< double > &
y = line->
y;
 
  982  for ( 
int i = 1; i <= numberNodes - ( closedLine ? 1 : 2 ); ++i )
 
  984    double x1 = 
x[i - 1];
 
  986    double x3 = 
x[ i == numberNodes - 1 ? 1 : i + 1]; 
 
  987    double y1 = 
y[i - 1];
 
  989    double y3 = 
y[ i == numberNodes - 1 ? 1 : i + 1]; 
 
  994    double vertexAngle = M_PI - ( std::atan2( y3 - y2, x3 - x2 ) - std::atan2( y2 - y1, x2 - x1 ) );
 
  998    if ( vertexAngle < M_PI * 135.0 / 180.0 || vertexAngle > M_PI * 225.0 / 180.0 )
 
  999      extremeAngleNodes << i;
 
 1001  extremeAngleNodes << numberNodes - 1;
 
 1003  if ( extremeAngleNodes.isEmpty() )
 
 1010  std::vector< double > segmentLengths( numberNodes - 1 ); 
 
 1011  std::vector< double > distanceToSegment( numberNodes ); 
 
 1012  double totalLineLength = 0.0;
 
 1013  QVector< double > straightSegmentLengths;
 
 1014  QVector< double > straightSegmentAngles;
 
 1015  straightSegmentLengths.reserve( extremeAngleNodes.size() + 1 );
 
 1016  straightSegmentAngles.reserve( extremeAngleNodes.size() + 1 );
 
 1017  double currentStraightSegmentLength = 0;
 
 1018  double longestSegmentLength = 0;
 
 1019  double segmentStartX = 
x[0];
 
 1020  double segmentStartY = 
y[0];
 
 1021  for ( 
int i = 0; i < numberNodes - 1; i++ )
 
 1024      distanceToSegment[i] = 0;
 
 1026      distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
 1029    totalLineLength += segmentLengths[i];
 
 1030    if ( extremeAngleNodes.contains( i ) )
 
 1033      straightSegmentLengths << currentStraightSegmentLength;
 
 1035      longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
 
 1036      currentStraightSegmentLength = 0;
 
 1037      segmentStartX = 
x[i];
 
 1038      segmentStartY = 
y[i];
 
 1040    currentStraightSegmentLength += segmentLengths[i];
 
 1042  distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
 1043  straightSegmentLengths << currentStraightSegmentLength;
 
 1045  longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
 
 1048  if ( totalLineLength < labelWidth )
 
 1056  double lineStepDistance = ( totalLineLength - labelWidth ); 
 
 1057  lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
 
 1059  double distanceToEndOfSegment = 0.0;
 
 1060  int lastNodeInSegment = 0;
 
 1062  for ( 
int i = 0; i < straightSegmentLengths.count(); ++i )
 
 1064    currentStraightSegmentLength = straightSegmentLengths.at( i );
 
 1065    double currentSegmentAngle = straightSegmentAngles.at( i );
 
 1066    lastNodeInSegment = extremeAngleNodes.at( i );
 
 1067    double distanceToStartOfSegment = distanceToEndOfSegment;
 
 1068    distanceToEndOfSegment = distanceToSegment[ lastNodeInSegment ];
 
 1069    double distanceToCenterOfSegment = 0.5 * ( distanceToEndOfSegment + distanceToStartOfSegment );
 
 1071    if ( currentStraightSegmentLength < labelWidth )
 
 1075    double currentDistanceAlongLine = distanceToStartOfSegment;
 
 1076    double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
 
 1077    double candidateLength = 0.0;
 
 1083    double segmentCost = 1.0 - ( distanceToEndOfSegment - distanceToStartOfSegment ) / longestSegmentLength; 
 
 1084    double segmentAngleCost = 1 - std::fabs( std::fmod( currentSegmentAngle, M_PI ) - M_PI_2 ) / M_PI_2; 
 
 1086    while ( currentDistanceAlongLine + labelWidth < distanceToEndOfSegment )
 
 1088      if ( 
pal->isCanceled() )
 
 1094      line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateStartX, &candidateStartY );
 
 1095      line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
 
 1103      cost = candidateLength / labelWidth;
 
 1109        cost = ( 1 - cost ) / 100; 
 
 1112      const double labelCenter = currentDistanceAlongLine + labelWidth / 2.0;
 
 1113      double labelTextAnchor = 0;
 
 1114      switch ( textPoint )
 
 1117          labelTextAnchor = currentDistanceAlongLine;
 
 1120          labelTextAnchor = currentDistanceAlongLine + labelWidth / 2.0;
 
 1123          labelTextAnchor = currentDistanceAlongLine + labelWidth;
 
 1132      if ( placementIsFlexible )
 
 1135        double costCenter = 2 * std::fabs( labelCenter - distanceToCenterOfSegment ) / ( distanceToEndOfSegment - distanceToStartOfSegment ); 
 
 1136        cost += costCenter * 0.0005;  
 
 1144        double costLineCenter = 2 * std::fabs( labelTextAnchor - lineAnchorPoint ) / totalLineLength;  
 
 1145        cost += costLineCenter * 0.0005;  
 
 1148      if ( placementIsFlexible )
 
 1150        cost += segmentCost * 0.0005; 
 
 1151        cost += segmentAngleCost * 0.0001; 
 
 1159        angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
 
 1163      beta = angle + M_PI_2;
 
 1168        bool isRightToLeft = ( angle > M_PI_2 || angle <= -M_PI_2 );
 
 1178            const double candidateCost = cost + ( reversed ? 0 : 0.001 );
 
 1186            const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); 
 
 1194            const double candidateCost = cost + 0.002;
 
 1208      currentDistanceAlongLine += lineStepDistance;
 
 
 1231  std::vector< double > &
x = line->
x;
 
 1232  std::vector< double > &
y = line->
y;
 
 1234  std::vector< double > segmentLengths( 
nbPoints - 1 ); 
 
 1235  std::vector< double >distanceToSegment( 
nbPoints ); 
 
 1237  double totalLineLength = 0.0; 
 
 1238  for ( 
int i = 0; i < line->
nbPoints - 1; i++ )
 
 1241      distanceToSegment[i] = 0;
 
 1243      distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
 1246    totalLineLength += segmentLengths[i];
 
 1248  distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
 1250  double lineStepDistance = ( totalLineLength - labelWidth ); 
 
 1251  double currentDistanceAlongLine = 0;
 
 1257  if ( totalLineLength > labelWidth )
 
 1259    lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
 
 1263    currentDistanceAlongLine = - ( labelWidth - totalLineLength ) / 2.0;
 
 1264    lineStepDistance = -1;
 
 1265    totalLineLength = labelWidth;
 
 1270    currentDistanceAlongLine = std::numeric_limits< double >::max();
 
 1281      switch ( textPoint )
 
 1284          currentDistanceAlongLine = std::min( lineAnchorPoint, totalLineLength * 0.99 - labelWidth );
 
 1287          currentDistanceAlongLine = std::min( lineAnchorPoint - labelWidth / 2, totalLineLength * 0.99 - labelWidth );
 
 1290          currentDistanceAlongLine = std::min( lineAnchorPoint - labelWidth, totalLineLength * 0.99 - labelWidth );
 
 1296      lineStepDistance = -1;
 
 1300  double candidateLength;
 
 1302  double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
 
 1306    if ( 
pal->isCanceled() )
 
 1312    line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateStartX, &candidateStartY );
 
 1313    line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
 
 1315    if ( currentDistanceAlongLine < 0 )
 
 1325    cost = candidateLength / labelWidth;
 
 1331      cost = ( 1 - cost ) / 100; 
 
 1335    double textAnchorPoint = 0;
 
 1336    switch ( textPoint )
 
 1339        textAnchorPoint = currentDistanceAlongLine;
 
 1342        textAnchorPoint = currentDistanceAlongLine + labelWidth / 2;
 
 1345        textAnchorPoint = currentDistanceAlongLine + labelWidth;
 
 1351    double costCenter = std::fabs( lineAnchorPoint - textAnchorPoint ) / totalLineLength; 
 
 1352    cost += costCenter / 1000;  
 
 1353    cost += initialCost;
 
 1360      angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
 
 1364    beta = angle + M_PI_2;
 
 1369      bool isRightToLeft = ( angle > M_PI_2 || angle <= -M_PI_2 );
 
 1379          const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); 
 
 1387          const double candidateCost = cost + ( !reversed ? 0.001 : 0 );
 
 1395          const double candidateCost = cost + 0.002;
 
 1409    currentDistanceAlongLine += lineStepDistance;
 
 1413    if ( lineStepDistance < 0 )
 
 
 1423  Q_ASSERT( metrics );
 
 1425  const double maximumCharacterAngleInside = applyAngleConstraints ? std::fabs( qgis::down_cast< QgsTextLabelFeature *>( 
mLF )->maximumCharacterAngleInside() ) : -1;
 
 1426  const double maximumCharacterAngleOutside = applyAngleConstraints ? std::fabs( qgis::down_cast< QgsTextLabelFeature *>( 
mLF )->maximumCharacterAngleOutside() ) : -1;
 
 1428  std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > placement(
 
 1434  if ( placement->graphemePlacement.empty() )
 
 1437  auto it = placement->graphemePlacement.constBegin();
 
 1439  firstPosition->setUpsideDownCharCount( placement->upsideDownCharCount );
 
 1440  firstPosition->setPartId( it->graphemeIndex );
 
 1443  while ( it != placement->graphemePlacement.constEnd() )
 
 1446    position->setPartId( it->graphemeIndex );
 
 1449    previousPosition->
setNextPart( std::move( position ) );
 
 1450    previousPosition = nextPosition;
 
 1454  return firstPosition;
 
 
 1466  const int characterCount = li->
count();
 
 1467  if ( characterCount == 0 )
 
 1473  double totalCharacterWidth = 0;
 
 1474  for ( 
int i = 0; i < characterCount; ++i )
 
 1477  std::unique_ptr< PointSet > expanded;
 
 1478  double shapeLength = mapShape->
length();
 
 1481    allowOverrun = 
false;
 
 1499  if ( totalCharacterWidth > shapeLength )
 
 1501    if ( !allowOverrun || shapeLength < totalCharacterWidth - 2 * overrun )
 
 1512  if ( allowOverrun && overrun > 0 )
 
 1515    expanded = mapShape->
clone();
 
 1517    mapShape = expanded.get();
 
 1518    shapeLength += 2 * overrun;
 
 1526  std::unique_ptr< PointSet > mapShapeOffsetPositive;
 
 1527  bool positiveShapeHasNegativeDistance = 
false;
 
 1528  std::unique_ptr< PointSet > mapShapeOffsetNegative;
 
 1529  bool negativeShapeHasNegativeDistance = 
false;
 
 1530  if ( hasAboveBelowLinePlacement && !
qgsDoubleNear( offsetDistance, 0 ) )
 
 1534      mapShapeOffsetPositive = mapShape->
clone();
 
 1536      mapShapeOffsetNegative = mapShape->
clone();
 
 1539      if ( mapShapeOffsetPositive )
 
 1540        mapShapeOffsetPositive->offsetCurveByDistance( offsetDistance );
 
 1541      positiveShapeHasNegativeDistance = offsetDistance < 0;
 
 1542      if ( mapShapeOffsetNegative )
 
 1543        mapShapeOffsetNegative->offsetCurveByDistance( offsetDistance * -1 );
 
 1544      negativeShapeHasNegativeDistance = offsetDistance > 0;
 
 1561      if ( mapShapeOffsetPositive )
 
 1562        mapShapeOffsetPositive->offsetCurveByDistance( offsetDistance * -1 );
 
 1563      positiveShapeHasNegativeDistance = offsetDistance > 0;
 
 1564      if ( mapShapeOffsetNegative )
 
 1565        mapShapeOffsetNegative->offsetCurveByDistance( offsetDistance );
 
 1566      negativeShapeHasNegativeDistance = offsetDistance < 0;
 
 1572  std::vector< std::unique_ptr< LabelPosition >> positions;
 
 1573  std::unique_ptr< LabelPosition > backupPlacement;
 
 1576    PointSet *currentMapShape = 
nullptr;
 
 1579      currentMapShape = mapShapeOffsetPositive.get();
 
 1583      currentMapShape = mapShape;
 
 1587      currentMapShape = mapShapeOffsetNegative.get();
 
 1589    if ( !currentMapShape )
 
 1593    const auto [ pathDistances, totalDistance ] = currentMapShape->
edgeDistances();
 
 1597    double lineAnchorPoint = 0;
 
 1598    if ( originalPoint && offset != 
NoOffset )
 
 1603      lineAnchorPoint = currentMapShape->
lineLocatePoint( originalPoint.get() );
 
 1609        lineAnchorPoint = totalDistance - lineAnchorPoint;
 
 1612    if ( 
pal->isCanceled() )
 
 1616    double delta = std::max( li->
characterHeight( 0 ) / 6, totalDistance / candidateTargetCount );
 
 1619    double distanceAlongLineToStartCandidate = 0;
 
 1620    bool singleCandidateOnly = 
false;
 
 1627        switch ( textPoint )
 
 1630            distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint, 0.0, totalDistance * 0.999 );
 
 1633            distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - 
getLabelWidth() / 2, 0.0, totalDistance * 0.999 - 
getLabelWidth() / 2 );
 
 1636            distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - 
getLabelWidth(), 0.0, totalDistance * 0.999 - 
getLabelWidth() ) ;
 
 1642        singleCandidateOnly = 
true;
 
 1646    bool hasTestedFirstPlacement = 
false;
 
 1647    for ( ; distanceAlongLineToStartCandidate <= totalDistance; distanceAlongLineToStartCandidate += delta )
 
 1649      if ( singleCandidateOnly && hasTestedFirstPlacement )
 
 1652      if ( 
pal->isCanceled() )
 
 1655      hasTestedFirstPlacement = 
true;
 
 1657      bool labeledLineSegmentIsRightToLeft = 
false;
 
 1663      std::unique_ptr< LabelPosition > labelPosition = 
curvedPlacementAtOffset( currentMapShape, pathDistances, direction, distanceAlongLineToStartCandidate, labeledLineSegmentIsRightToLeft, !singleCandidateOnly, curvedTextFlags );
 
 1664      if ( !labelPosition )
 
 1670      bool isBackupPlacementOnly = 
false;
 
 1673        if ( ( currentMapShape == mapShapeOffsetPositive.get() && positiveShapeHasNegativeDistance )
 
 1674             || ( currentMapShape == mapShapeOffsetNegative.get() && negativeShapeHasNegativeDistance ) )
 
 1676          labeledLineSegmentIsRightToLeft = !labeledLineSegmentIsRightToLeft;
 
 1682            isBackupPlacementOnly = 
true;
 
 1689            isBackupPlacementOnly = 
true;
 
 1695      backupPlacement.reset();
 
 1698      const double angleDiff = labelPosition->angleDifferential();
 
 1699      const double angleDiffAvg = characterCount > 1 ? ( angleDiff / ( characterCount - 1 ) ) : 0; 
 
 1704      double cost = angleDiffAvg / 100; 
 
 1705      if ( cost < 0.0001 )
 
 1709      double labelTextAnchor = 0;
 
 1710      switch ( textPoint )
 
 1713          labelTextAnchor = distanceAlongLineToStartCandidate;
 
 1716          labelTextAnchor = distanceAlongLineToStartCandidate + 
getLabelWidth() / 2;
 
 1719          labelTextAnchor = distanceAlongLineToStartCandidate + 
getLabelWidth();
 
 1725      double costCenter = std::fabs( lineAnchorPoint - labelTextAnchor ) / totalDistance; 
 
 1726      cost += costCenter / ( anchorIsFlexiblePlacement ? 100 : 10 );  
 
 1728      const bool isBelow = ( offset != 
NoOffset ) && labeledLineSegmentIsRightToLeft;
 
 1740      labelPosition->setCost( cost );
 
 1742      auto p = std::make_unique< LabelPosition >( *labelPosition );
 
 1747        while ( within && currentPos )
 
 1750          currentPos = currentPos->
nextPart();
 
 1760        if ( isBackupPlacementOnly )
 
 1761          backupPlacement = std::move( p );
 
 1763          positions.emplace_back( std::move( p ) );
 
 1768  for ( std::unique_ptr< LabelPosition > &pos : positions )
 
 1770    lPos.emplace_back( std::move( pos ) );
 
 1773  if ( backupPlacement )
 
 1774    lPos.emplace_back( std::move( backupPlacement ) );
 
 1776  return positions.size();
 
 
 1800  const double totalArea = 
area();
 
 1802  mapShape->
parent = 
nullptr;
 
 1804  if ( 
pal->isCanceled() )
 
 1807  QLinkedList<PointSet *> shapes_final = 
splitPolygons( mapShape, labelWidth, labelHeight );
 
 1809  QgsDebugMsgLevel( QStringLiteral( 
"PAL split polygons resulted in:" ), 2 );
 
 1810  for ( 
PointSet *ps : shapes_final )
 
 1816  std::size_t nbp = 0;
 
 1818  if ( !shapes_final.isEmpty() )
 
 1826    double diago = std::sqrt( labelWidth * labelWidth / 4.0 + labelHeight * labelHeight / 4 );
 
 1828    std::vector< OrientedConvexHullBoundingBox > boxes;
 
 1829    boxes.reserve( shapes_final.size() );
 
 1832    while ( !shapes_final.isEmpty() )
 
 1834      PointSet *shape = shapes_final.takeFirst();
 
 1838        boxes.emplace_back( box );
 
 1844    if ( 
pal->isCanceled() )
 
 1848    double densityY = densityX;
 
 1855    std::size_t numberCandidatesGenerated = 0;
 
 1870        double dx = densityX;
 
 1871        double dy = densityY;
 
 1872        if ( numTry == 0 && maxPolygonCandidates > 0 )
 
 1875          const double boxArea = box.width * box.length;
 
 1876          double maxThisBox = targetPolygonCandidates * boxArea / totalArea;
 
 1877          dx = std::max( dx, std::sqrt( boxArea / maxThisBox ) * 0.8 );
 
 1881        if ( 
pal->isCanceled() )
 
 1882          return numberCandidatesGenerated;
 
 1901        bool enoughPlace = 
false;
 
 1905          px = ( box.x[0] + box.x[2] ) / 2 - labelWidth;
 
 1906          py = ( box.y[0] + box.y[2] ) / 2 - labelHeight;
 
 1912          for ( rx = px, i = 0; i < 2; rx = rx + 2 * labelWidth, i++ )
 
 1914            for ( ry = py, j = 0; j < 2; ry = ry + 2 * labelHeight, j++ )
 
 1918                enoughPlace = 
false;
 
 1934        else if ( box.length > 1.5 * labelWidth && box.width > 1.5 * labelWidth )
 
 1936          if ( box.alpha <= M_PI_4 )
 
 1942            alpha = box.alpha - M_PI_2;
 
 1945        else if ( box.length > box.width )
 
 1947          alpha = box.alpha - M_PI_2;
 
 1954        beta  = std::atan2( labelHeight, labelWidth ) + alpha;
 
 1960        dlx = std::cos( beta ) * diago;
 
 1961        dly = std::sin( beta ) * diago;
 
 1963        double px0 = box.width / 2.0;
 
 1964        double py0 = box.length / 2.0;
 
 1966        px0 -= std::ceil( px0 / dx ) * dx;
 
 1967        py0 -= std::ceil( py0 / dy ) * dy;
 
 1969        for ( px = px0; px <= box.width; px += dx )
 
 1971          if ( 
pal->isCanceled() )
 
 1974          for ( py = py0; py <= box.length; py += dy )
 
 1977            rx = std::cos( box.alpha ) * px + std::cos( box.alpha - M_PI_2 ) * py;
 
 1978            ry = std::sin( box.alpha ) * px + std::sin( box.alpha - M_PI_2 ) * py;
 
 1989                numberCandidatesGenerated++;
 
 2002                lPos.emplace_back( std::move( potentialCandidate ) );
 
 2003                numberCandidatesGenerated++;
 
 2010      nbp = numberCandidatesGenerated;
 
 2011      if ( maxPolygonCandidates > 0 && nbp < targetPolygonCandidates )
 
 2022    while ( numTry < maxTry );
 
 2024    nbp = numberCandidatesGenerated;
 
 
 2038  std::size_t candidatesCreated = 0;
 
 2093  geos::unique_ptr buffer( GEOSBuffer_r( ctxt, 
geos(), distanceToLabel * 0.5, 1 ) );
 
 2096  geos::prepared_unique_ptr preparedBuffer( GEOSPrepare_r( ctxt, buffer.get() ) );
 
 2098  const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( gg.get() );
 
 2100    return candidatesCreated;
 
 2104    return candidatesCreated;
 
 2108  const double ringLength = ring->
length();
 
 2109  const double circleArea = std::pow( ringLength, 2 ) / ( 4 * M_PI );
 
 2111  const std::size_t targetPolygonCandidates = std::max( 
static_cast< std::size_t 
>( 16 ), maxPolygonCandidates > 0 ? std::min( maxPolygonCandidates,  candidatesForArea ) : candidatesForArea );
 
 2114  const double delta = ringLength / targetPolygonCandidates;
 
 2115  geos::unique_ptr geosPoint;
 
 2117  const double maxDistCentroidToLabelX = std::max( 
xmax - cx, cx - 
xmin ) + distanceToLabel;
 
 2118  const double maxDistCentroidToLabelY = std::max( 
ymax - cy, cy - 
ymin ) + distanceToLabel;
 
 2119  const double estimateOfMaxPossibleDistanceCentroidToLabel = std::sqrt( maxDistCentroidToLabelX * maxDistCentroidToLabelX + maxDistCentroidToLabelY * maxDistCentroidToLabelY );
 
 2122  const double labelAngle = 0;
 
 2124  std::size_t i = lPos.size();
 
 2132    createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, 
x, 
y, labelWidth, labelHeight, position, distanceToLabel * 0.5, visualMargin, 0, 0, labelAngle );
 
 2135    if ( candidate->intersects( preparedBuffer.get() ) )
 
 2153    const double centroidDistance = candidate->getDistanceToPoint( cx, cy, 
false );
 
 2154    const double centroidCost = centroidDistance / estimateOfMaxPossibleDistanceCentroidToLabel;
 
 2155    candidate->setCost( centroidCost );
 
 2157    lPos.emplace_back( std::move( candidate ) );
 
 2158    candidatesCreated++;
 
 2163                                      double startSegmentX, 
double startSegmentY, 
double, 
double,
 
 2164                                      double endSegmentX, 
double endSegmentY, 
double, 
double )
 
 2167    float angle = atan2( 
static_cast< float >( endSegmentY - startSegmentY ), 
static_cast< float >( endSegmentX - startSegmentX ) ) * 180 / M_PI;
 
 2172    if ( angle >= 0 && angle <= 5 )
 
 2177    else if ( angle <= 85 )
 
 2181    else if ( angle <= 90 )
 
 2187    else if ( angle <= 95 )
 
 2192    else if ( angle <= 175 )
 
 2196    else if ( angle <= 180 )
 
 2202    else if ( angle <= 185 )
 
 2207    else if ( angle <= 265 )
 
 2211    else if ( angle <= 270 )
 
 2216    else if ( angle <= 275 )
 
 2221    else if ( angle <= 355 )
 
 2231    return !
pal->isCanceled();
 
 2234  return candidatesCreated;
 
 
 2239  std::vector< std::unique_ptr< LabelPosition > > lPos;
 
 2259      case GEOS_LINESTRING:
 
 2282        else if ( allowOutside && ( std::fabs( 
xmax - 
xmin ) < labelWidth ||
 
 2283                                    std::fabs( 
ymax - 
ymin ) < labelHeight ) )
 
 2290          std::size_t created = 0;
 
 
 2348  int geomType = GEOSGeomTypeId_r( ctxt, 
mGeos );
 
 2350  double sizeCost = 0;
 
 2351  if ( geomType == GEOS_LINESTRING )
 
 2353    const double l = 
length();
 
 2356    double bbox_length = std::max( bbx[2] - bbx[0], bby[2] - bby[0] );
 
 2357    if ( l >= bbox_length / 4 )
 
 2360    sizeCost = 1 - ( l / ( bbox_length / 4 ) ); 
 
 2362  else if ( geomType == GEOS_POLYGON )
 
 2364    const double a = 
area();
 
 2367    double bbox_area = ( bbx[2] - bbx[0] ) * ( bby[2] - bby[0] );
 
 2368    if ( a >= bbox_area / 16 )
 
 2371    sizeCost = 1 - ( a / ( bbox_area / 16 ) ); 
 
 2377  for ( std::unique_ptr< LabelPosition > &pos : lPos )
 
 2379    pos->setCost( pos->cost() + sizeCost / 100 );
 
 
 2390  const double x1first = 
x.front();
 
 2391  const double x1last = 
x.back();
 
 2392  const double x2first = p2->
x.front();
 
 2393  const double x2last = p2->
x.back();
 
 2394  const double y1first = 
y.front();
 
 2395  const double y1last = 
y.back();
 
 2396  const double y2first = p2->
y.front();
 
 2397  const double y2last = p2->
y.back();
 
 2405  if ( ( !p2startTouches && !p2endTouches ) || ( p2startTouches && p2endTouches ) )
 
 2411  const double p2otherX = p2startTouches ? x2last : x2first;
 
 2412  const double p2otherY = p2startTouches ? y2last : y2first;
 
 2418#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=12 ) 
 2419    return ( GEOSPreparedIntersectsXY_r( geosctxt, 
preparedGeom(), p2otherX, p2otherY ) != 1 );
 
 2421    GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
 
 2422    GEOSCoordSeq_setXY_r( geosctxt, coord, 0, p2otherX, p2otherY );
 
 2423    geos::unique_ptr p2OtherEnd( GEOSGeom_createPoint_r( geosctxt, coord ) );
 
 2424    return ( GEOSPreparedIntersects_r( geosctxt, 
preparedGeom(), p2OtherEnd.get() ) != 1 );
 
 2427  catch ( QgsGeosException &e )
 
 2429    qWarning( 
"GEOS exception: %s", e.what() );
 
 
 2439  if ( !other->
mGeos )
 
 2448    geos::unique_ptr g( GEOSGeom_createCollection_r( ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
 
 2449    geos::unique_ptr gTmp( GEOSLineMerge_r( ctxt, g.get() ) );
 
 2451    if ( GEOSGeomTypeId_r( ctxt, gTmp.get() ) != GEOS_LINESTRING )
 
 2459    mGeos = gTmp.release();
 
 2468  catch ( QgsGeosException &e )
 
 2470    qWarning( 
"GEOS exception: %s", e.what() );
 
 
 2491  bool result = 
false;
 
 
@ BelowLine
Labels can be placed below a line feature. Unless MapOrientation is also specified this mode respects...
 
@ MapOrientation
Signifies that the AboveLine and BelowLine flags should respect the map's orientation rather than the...
 
@ OnLine
Labels can be placed directly over a line feature.
 
@ AboveLine
Labels can be placed above a line feature. Unless MapOrientation is also specified this mode respects...
 
@ FromSymbolBounds
Offset distance applies from rendered symbol bounds.
 
LabelPrioritization
Label prioritization.
 
@ PreferCloser
Prefer closer labels, falling back to alternate positions before larger distances.
 
@ PreferPositionOrdering
Prefer labels follow position ordering, falling back to more distance labels before alternate positio...
 
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
 
@ AroundPoint
Arranges candidates in a circle around a point (or centroid of a polygon). Applies to point or polygo...
 
@ Line
Arranges candidates parallel to a generalised line representing the feature or parallel to a polygon'...
 
@ Free
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
 
@ OrderedPositionsAroundPoint
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
 
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
 
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
 
@ OutsidePolygons
Candidates are placed outside of polygon boundaries. Applies to polygon layers only.
 
@ AllowPlacementInsideOfPolygon
Labels can be placed inside a polygon feature.
 
@ AllowPlacementOutsideOfPolygon
Labels can be placed outside of a polygon feature.
 
QFlags< LabelLinePlacementFlag > LabelLinePlacementFlags
Line placement flags, which control how candidates are generated for a linear feature.
 
LabelQuadrantPosition
Label quadrant positions.
 
LabelPredefinedPointPosition
Positions for labels when using the Qgis::LabelPlacement::OrderedPositionsAroundPoint placement mode.
 
@ OverPoint
Label directly centered over point.
 
@ MiddleLeft
Label on left of point.
 
@ TopRight
Label on top-right of point.
 
@ MiddleRight
Label on right of point.
 
@ TopSlightlyRight
Label on top of point, slightly right of center.
 
@ TopMiddle
Label directly above point.
 
@ BottomSlightlyLeft
Label below point, slightly left of center.
 
@ BottomRight
Label on bottom right of point.
 
@ BottomLeft
Label on bottom-left of point.
 
@ BottomSlightlyRight
Label below point, slightly right of center.
 
@ TopLeft
Label on top-left of point.
 
@ BottomMiddle
Label directly below point.
 
@ TopSlightlyLeft
Label on top of point, slightly left of center.
 
@ FlipUpsideDownLabels
Upside-down labels (90 <= angle < 270) are shown upright.
 
@ AlwaysAllowUpsideDown
Show upside down for all labels, including dynamic ones.
 
@ AllowUpsideDownWhenRotationIsDefined
Show upside down when rotation is layer- or data-defined.
 
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
 
bool hasNext() const
Find out whether there are more parts.
 
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
 
static double normalizedAngle(double angle)
Ensures that an angle is in the range 0 <= angle < 2 pi.
 
A geometry is the spatial representation of a feature.
 
QgsGeometryConstPartIterator constParts() const
Returns Java-style iterator for traversal of parts of the geometry.
 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
 
static GEOSContextHandle_t get()
Returns a thread local instance of a GEOS context, safe for use in the current thread.
 
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
 
Describes a feature that should be used within the labeling engine.
 
double maximumDistance() const
Returns the maximum distance which labels are allowed to be from their corresponding points.
 
double overrunSmoothDistance() const
Returns the distance (in map units) with which the ends of linear features are averaged over when cal...
 
Qgis::LabelPolygonPlacementFlags polygonPlacementFlags() const
Returns the polygon placement flags, which dictate how polygon labels can be placed.
 
double fixedAngle() const
Angle in radians of the fixed angle (relevant only if hasFixedAngle() returns true)
 
const QSizeF & symbolSize() const
Returns the size of the rendered symbol associated with this feature, if applicable.
 
QVector< Qgis::LabelPredefinedPointPosition > predefinedPositionOrder() const
Returns the priority ordered list of predefined positions for label candidates.
 
QgsPointXY positionOffset() const
Applies only to "offset from point" placement strategy.
 
bool hasFixedQuadrant() const
Returns whether the quadrant for the label is fixed.
 
bool hasFixedAngle() const
Whether the label should use a fixed angle instead of using angle from automatic placement.
 
pal::Layer * layer() const
Gets PAL layer of the label feature. Should be only used internally in PAL.
 
bool alwaysShow() const
Whether label should be always shown (sets very high label priority)
 
double lineAnchorPercent() const
Returns the percent along the line at which labels should be placed, for line labels only.
 
const GEOSPreparedGeometry * permissibleZonePrepared() const
Returns a GEOS prepared geometry representing the label's permissibleZone().
 
QgsLabelLineSettings::AnchorType lineAnchorType() const
Returns the line anchor type, which dictates how the lineAnchorPercent() setting is handled.
 
double distLabel() const
Applies to "around point" placement strategy or linestring features.
 
GEOSGeometry * geometry() const
Gets access to the associated geometry.
 
QPointF quadOffset() const
Applies to "offset from point" placement strategy and "around point" (in case hasFixedQuadrant() retu...
 
Qgis::LabelPrioritization prioritization() const
Returns the label prioritization technique.
 
void setAnchorPosition(const QgsPointXY &anchorPosition)
In case of quadrand or aligned positioning, this is set to the anchor point.
 
QgsFeature feature() const
Returns the original feature associated with this label.
 
QgsFeatureId id() const
Identifier of the label (unique within the parent label provider)
 
double overrunDistance() const
Returns the permissible distance (in map units) which labels are allowed to overrun the start or end ...
 
double priority() const
Returns the feature's labeling priority.
 
QgsGeometry permissibleZone() const
Returns the label's permissible zone geometry.
 
bool hasFixedPosition() const
Whether the label should use a fixed position instead of being automatically placed.
 
QgsLabelLineSettings::AnchorTextPoint lineAnchorTextPoint() const
Returns the line anchor text point, which dictates which part of the label text should be placed at t...
 
const QgsMargins & visualMargin() const
Returns the visual margin for the label feature.
 
Qgis::LabelLinePlacementFlags arrangementFlags() const
Returns the feature's arrangement flags.
 
Qgis::LabelOffsetType offsetType() const
Returns the offset type, which determines how offsets and distance to label behaves.
 
QgsPointXY fixedPosition() const
Coordinates of the fixed position (relevant only if hasFixedPosition() returns true)
 
@ Strict
Line anchor is a strict placement, and other placements are not permitted.
 
@ HintOnly
Line anchor is a hint for preferred placement only, but other placements close to the hint are permit...
 
AnchorTextPoint
Anchor point of label text.
 
@ EndOfText
Anchor using end of text.
 
@ StartOfText
Anchor using start of text.
 
@ CenterOfText
Anchor using center of text.
 
@ FollowPlacement
Automatically set the anchor point based on the lineAnchorPercent() value. Values <25% will use the s...
 
Line string geometry type, with support for z-dimension and m-values.
 
double length() const override
Returns the planar, 2-dimensional length of the geometry.
 
void visitPointsByRegularDistance(double distance, const std::function< bool(double x, double y, double z, double m, double startSegmentX, double startSegmentY, double startSegmentZ, double startSegmentM, double endSegmentX, double endSegmentY, double endSegmentZ, double endSegmentM) > &visitPoint) const
Visits regular points along the linestring, spaced by distance.
 
Defines the four margins of a rectangle.
 
double top() const
Returns the top margin.
 
double right() const
Returns the right margin.
 
double bottom() const
Returns the bottom margin.
 
double left() const
Returns the left margin.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
 
Contains precalculated properties regarding text metrics for text to be rendered at a later stage.
 
int count() const
Returns the total number of characters.
 
double characterWidth(int position) const
Returns the width of the character at the specified position.
 
double characterHeight(int position) const
Returns the character height of the character at the specified position (actually font metrics height...
 
LabelLineDirection
Controls behavior of curved text with respect to line directions.
 
@ FollowLineDirection
Curved text placement will respect the line direction and ignore painter orientation.
 
@ RespectPainterOrientation
Curved text will be placed respecting the painter orientation, and the actual line direction will be ...
 
@ UprightCharactersOnly
Permit upright characters only. If not present then upside down text placement is permitted.
 
QFlags< CurvedTextFlag > CurvedTextFlags
Flags controlling behavior of curved text generation.
 
static std::unique_ptr< CurvePlacementProperties > generateCurvedTextPlacement(const QgsPrecalculatedTextMetrics &metrics, const QPolygonF &line, double offsetAlongLine, LabelLineDirection direction=RespectPainterOrientation, double maxConcaveAngle=-1, double maxConvexAngle=-1, CurvedTextFlags flags=CurvedTextFlags())
Calculates curved text placement properties.
 
Represents a part of a label feature.
 
FeaturePart(QgsLabelFeature *lf, const GEOSGeometry *geom)
Creates a new generic feature.
 
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.
 
std::size_t createCandidatesOutsidePolygon(std::vector< std::unique_ptr< LabelPosition > > &lPos, Pal *pal)
Generate candidates outside of polygon features.
 
bool hasFixedRotation() const
Returns true if the feature's label has a fixed rotation.
 
double getLabelHeight(double angle=0.0) const
Returns the height of the label, optionally taking an angle (in radians) into account.
 
QList< FeaturePart * > mHoles
 
double getLabelDistance() const
Returns the distance from the anchor point to the label.
 
~FeaturePart() override
Deletes the feature.
 
bool hasFixedPosition() const
Returns true if the feature's label has a fixed position.
 
std::size_t createCandidatesForPolygon(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, Pal *pal)
Generate candidates for polygon features.
 
void setTotalRepeats(int repeats)
Returns the total number of repeating labels associated with this label.
 
std::size_t maximumPolygonCandidates() const
Returns the maximum number of polygon candidates to generate for this feature.
 
QgsFeatureId featureId() const
Returns the unique ID of the feature.
 
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...
 
bool hasSameLabelFeatureAs(FeaturePart *part) const
Tests whether this feature part belongs to the same QgsLabelFeature as another feature part.
 
double fixedAngle() const
Returns the fixed angle for the feature's label.
 
std::size_t maximumLineCandidates() const
Returns the maximum number of line candidates to generate for this feature.
 
std::size_t createHorizontalCandidatesAlongLine(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, Pal *pal)
Generate horizontal candidates for line feature.
 
std::unique_ptr< LabelPosition > curvedPlacementAtOffset(PointSet *mapShape, const std::vector< double > &pathDistances, QgsTextRendererUtils::LabelLineDirection direction, double distance, bool &labeledLineSegmentIsRightToLeft, bool applyAngleConstraints, QgsTextRendererUtils::CurvedTextFlags flags)
Returns the label position for a curved label at a specific offset along a path.
 
std::size_t createCandidatesAlongLine(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal)
Generate candidates for line feature.
 
bool mergeWithFeaturePart(FeaturePart *other)
Merge other (connected) part with this one and save the result in this part (other is unchanged).
 
std::size_t createCurvedCandidatesAlongLine(std::vector< std::unique_ptr< LabelPosition > > &lPos, PointSet *mapShape, bool allowOverrun, Pal *pal)
Generate curved candidates for line features.
 
bool onlyShowUprightLabels() const
Returns true if feature's label must be displayed upright.
 
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.
 
std::unique_ptr< LabelPosition > createCandidatePointOnSurface(PointSet *mapShape)
Creates a single candidate using the "point on sruface" algorithm.
 
double getLabelWidth(double angle=0.0) const
Returns the width of the label, optionally taking an angle (in radians) into account.
 
QgsLabelFeature * feature()
Returns the parent feature.
 
std::vector< std::unique_ptr< LabelPosition > > createCandidates(Pal *pal)
Generates a list of candidate positions for labels for this feature.
 
bool isConnected(FeaturePart *p2)
Check whether this part is connected with some other part.
 
Layer * layer()
Returns the layer that feature belongs to.
 
PathOffset
Path offset variances used in curved placement.
 
int totalRepeats() const
Returns the total number of repeating labels associated with this label.
 
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'...
 
void addSizePenalty(std::vector< std::unique_ptr< LabelPosition > > &lPos, double bbx[4], double bby[4]) const
Increases the cost of the label candidates for this feature, based on the size of the feature.
 
void extractCoords(const GEOSGeometry *geom)
read coordinates from a GEOS geom
 
double calculatePriority() const
Calculates the priority for the feature.
 
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.
 
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.
 
std::size_t maximumPointCandidates() const
Returns the maximum number of point candidates to generate for this feature.
 
static bool reorderPolygon(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.
 
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.
 
LabelPosition is a candidate feature label position.
 
double getAlpha() const
Returns the angle to rotate text (in radians).
 
void setNextPart(std::unique_ptr< LabelPosition > next)
Sets the next part of this label position (i.e.
 
double getX(int i=0) const
Returns the down-left x coordinate.
 
double getY(int i=0) const
Returns the down-left y coordinate.
 
LabelPosition * nextPart() const
Returns the next part of this label position (i.e.
 
A set of features which influence the labeling process.
 
QString name() const
Returns the layer's name.
 
std::size_t maximumPolygonLabelCandidates() const
Returns the maximum number of polygon label candidates to generate for features in this layer.
 
int connectedFeatureId(QgsFeatureId featureId) const
Returns the connected feature ID for a label feature ID, which is unique for all features which have ...
 
Qgis::LabelPlacement arrangement() const
Returns the layer's arrangement policy.
 
std::size_t maximumPointLabelCandidates() const
Returns the maximum number of point label candidates to generate for features in this layer.
 
Qgis::UpsideDownLabelHandling upsidedownLabels() const
Returns how upside down labels are handled within the layer.
 
bool centroidInside() const
Returns whether labels placed at the centroid of features within the layer are forced to be placed in...
 
bool isCurved() const
Returns true if the layer has curved labels.
 
double priority() const
Returns the layer's priority, between 0 and 1.
 
std::size_t maximumLineLabelCandidates() const
Returns the maximum number of line label candidates to generate for features in this layer.
 
double maximumLineCandidatesPerMapUnit() const
Returns the maximum number of line label candidate positions per map unit.
 
double maximumPolygonCandidatesPerMapUnitSquared() const
Returns the maximum number of polygon label candidate positions per map unit squared.
 
The underlying raw pal geometry class.
 
geos::unique_ptr interpolatePoint(double distance) const
Returns a GEOS geometry representing the point interpolated on the shape by distance.
 
std::unique_ptr< PointSet > clone() const
Returns a copy of the point set.
 
double lineLocatePoint(const GEOSGeometry *point) const
Returns the distance along the geometry closest to the specified GEOS point.
 
double length() const
Returns length of line geometry.
 
double area() const
Returns area of polygon geometry.
 
bool isClosed() const
Returns true if pointset is closed.
 
void createGeosGeom() const
 
void getPointByDistance(double *d, double *ad, double dl, double *px, double *py) const
Gets a point a set distance along a line geometry.
 
void getCentroid(double &px, double &py, bool forceInside=false) const
 
OrientedConvexHullBoundingBox computeConvexHullOrientedBoundingBox(bool &ok) const
Computes an oriented bounding box for the shape's convex hull.
 
const GEOSPreparedGeometry * preparedGeom() const
 
const GEOSGeometry * geos() const
Returns the point set's GEOS geometry.
 
void invalidateGeos() const
 
bool containsPoint(double x, double y) const
Tests whether point set contains a specified point.
 
std::tuple< std::vector< double >, double > edgeDistances() const
Returns a vector of edge distances as well as its total length.
 
static QLinkedList< PointSet * > splitPolygons(PointSet *inputShape, double labelWidth, double labelHeight)
Split a polygon using some random logic into some other polygons.
 
void createCandidateAtOrderedPositionOverPoint(double &labelX, double &labelY, Qgis::LabelQuadrantPosition &quadrant, double x, double y, double labelWidth, double labelHeight, Qgis::LabelPredefinedPointPosition position, double distanceToLabel, const QgsMargins &visualMargin, double symbolWidthOffset, double symbolHeightOffset, double angle)
 
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
 
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
 
#define QgsDebugMsgLevel(str, level)
 
Represents the minimum area, oriented bounding box surrounding a convex hull.
 
struct GEOSGeom_t GEOSGeometry