57  mGeos = 
const_cast<GEOSGeometry *
>( geom );
 
   63  for ( 
int i = 0; i < 
mHoles.count(); i++ )
 
   65    mHoles.at( i )->holeOf = 
this;
 
   77    mHoles.last()->holeOf = 
this;
 
   91  const GEOSCoordSequence *coordSeq = 
nullptr;
 
   94  type = GEOSGeomTypeId_r( geosctxt, geom );
 
   96  if ( 
type == GEOS_POLYGON )
 
   98    if ( GEOSGetNumInteriorRings_r( geosctxt, geom ) > 0 )
 
  100      int numHoles = GEOSGetNumInteriorRings_r( geosctxt, geom );
 
  102      for ( 
int i = 0; i < numHoles; ++i )
 
  104        const GEOSGeometry *interior = GEOSGetInteriorRingN_r( geosctxt, geom, i );
 
  116    geom = GEOSGetExteriorRing_r( geosctxt, geom );
 
  125  nbPoints = GEOSGetNumCoordinates_r( geosctxt, geom );
 
  126  coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, geom );
 
  129  xmin = 
ymin = std::numeric_limits<double>::max();
 
  130  xmax = 
ymax = std::numeric_limits<double>::lowest();
 
  137#if GEOS_VERSION_MAJOR>3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR>=10 ) 
  138  GEOSCoordSeq_copyToArrays_r( geosctxt, coordSeq, 
x.data(), 
y.data(), 
nullptr, 
nullptr );
 
  139  auto xminmax = std::minmax_element( 
x.begin(), 
x.end() );
 
  140  xmin = *xminmax.first;
 
  141  xmax = *xminmax.second;
 
  142  auto yminmax = std::minmax_element( 
y.begin(), 
y.end() );
 
  143  ymin = *yminmax.first;
 
  144  ymax = *yminmax.second;
 
  146  for ( 
int i = 0; i < 
nbPoints; ++i )
 
  148    GEOSCoordSeq_getXY_r( geosctxt, coordSeq, i, &
x[i], &
y[i] );
 
  176  if ( mCachedMaxLineCandidates > 0 )
 
  177    return mCachedMaxLineCandidates;
 
  179  const double l = 
length();
 
  184    if ( maxForLayer == 0 )
 
  185      mCachedMaxLineCandidates = candidatesForLineLength;
 
  187      mCachedMaxLineCandidates = std::min( candidatesForLineLength, maxForLayer );
 
  191    mCachedMaxLineCandidates = 1;
 
  193  return mCachedMaxLineCandidates;
 
  198  if ( mCachedMaxPolygonCandidates > 0 )
 
  199    return mCachedMaxPolygonCandidates;
 
  201  const double a = 
area();
 
  206    if ( maxForLayer == 0 )
 
  207      mCachedMaxPolygonCandidates = candidatesForArea;
 
  209      mCachedMaxPolygonCandidates = std::min( candidatesForArea, maxForLayer );
 
  213    mCachedMaxPolygonCandidates = 1;
 
  215  return mCachedMaxPolygonCandidates;
 
  237  qreal quadOffsetX = quadOffset.x(), quadOffsetY = quadOffset.y();
 
  239  if ( quadOffsetX < 0 )
 
  241    if ( quadOffsetY < 0 )
 
  245    else if ( quadOffsetY > 0 )
 
  254  else  if ( quadOffsetX > 0 )
 
  256    if ( quadOffsetY < 0 )
 
  260    else if ( quadOffsetY > 0 )
 
  271    if ( quadOffsetY < 0 )
 
  275    else if ( quadOffsetY > 0 )
 
  288  return mTotalRepeats;
 
  302  double cost = 0.00005;
 
  303  int id = lPos.size();
 
  305  double xdiff = -labelW / 2.0;
 
  306  double ydiff = -labelH / 2.0;
 
  310  double lx = 
x + xdiff;
 
  311  double ly = 
y + ydiff;
 
  331  double cost = 0.0001;
 
  332  int id = lPos.size();
 
  334  double xdiff = -labelW / 2.0;
 
  335  double ydiff = -labelH / 2.0;
 
  352      double xd = xdiff * std::cos( 
angle ) - ydiff * std::sin( 
angle );
 
  353      double yd = xdiff * std::sin( 
angle ) + ydiff * std::cos( 
angle );
 
  389  double lx = 
x + xdiff;
 
  390  double ly = 
y + ydiff;
 
  400  lPos.emplace_back( std::make_unique< LabelPosition >( 
id, lx, ly, labelW, labelH, 
angle, cost, 
this, 
false, quadrantFromOffset() ) );
 
  413      const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, pointGeom.get() );
 
  414      unsigned int nPoints = 0;
 
  415      GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
 
  418      GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
 
  421  catch ( GEOSException &e )
 
  423    qWarning( 
"GEOS exception: %s", e.what() );
 
  431void createCandidateAtOrderedPositionOverPoint( 
double &labelX, 
double &labelY, 
LabelPosition::Quadrant &quadrant, 
double x, 
double y, 
double labelWidth, 
double labelHeight, 
Qgis::LabelPredefinedPointPosition position, 
double distanceToLabel, 
const QgsMargins &visualMargin, 
double symbolWidthOffset, 
double symbolHeightOffset, 
double angle )
 
  442      deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  443      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  449      deltaX = -labelWidth / 4.0 - visualMargin.
left();
 
  450      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  456      deltaX = -labelWidth / 2.0;
 
  457      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  463      deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
 
  464      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  470      deltaX = - visualMargin.
left() + symbolWidthOffset;
 
  471      deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  477      deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  478      deltaY = -labelHeight / 2.0;
 
  484      deltaX = -visualMargin.
left() + symbolWidthOffset;
 
  485      deltaY = -labelHeight / 2.0;
 
  491      deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  492      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  498      deltaX = -labelWidth / 4.0 - visualMargin.
left();
 
  499      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  505      deltaX = -labelWidth / 2.0;
 
  506      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  512      deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
 
  513      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  519      deltaX = -visualMargin.
left() + symbolWidthOffset;
 
  520      deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  526  QTransform transformRotation;
 
  527  transformRotation.rotate( 
angle * 180 / M_PI );
 
  528  transformRotation.map( deltaX, deltaY, &deltaX, &deltaY );
 
  531  double referenceX = std::cos( alpha ) * distanceToLabel + x;
 
  532  double referenceY = std::sin( alpha ) * distanceToLabel + y;
 
  534  labelX = referenceX + deltaX;
 
  535  labelY = referenceY + deltaY;
 
  549  double cost = 0.0001;
 
  550  std::size_t i = lPos.size();
 
  553  std::size_t created = 0;
 
  560    createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, 
x, 
y, labelWidth, labelHeight, position, distanceToLabel, visualMargin, symbolWidthOffset, symbolHeightOffset, 
angle );
 
  564      lPos.emplace_back( std::make_unique< LabelPosition >( i, labelX, labelY, labelWidth, labelHeight, 
angle, cost, 
this, 
false, quadrant ) );
 
  568      if ( maxNumberCandidates > 0 && created >= maxNumberCandidates )
 
  584  if ( maxNumberCandidates == 0 )
 
  585    maxNumberCandidates = 16;
 
  589  int id = lPos.size();
 
  591  double candidateAngleIncrement = 2 * M_PI / maxNumberCandidates; 
 
  596  double a270 = a180 + a90;
 
  597  double a360 = 2 * M_PI;
 
  599  double gamma1, gamma2;
 
  601  if ( distanceToLabel > 0 )
 
  603    gamma1 = std::atan2( labelHeight / 2, distanceToLabel + labelWidth / 2 );
 
  604    gamma2 = std::atan2( labelWidth / 2, distanceToLabel + labelHeight / 2 );
 
  608    gamma1 = gamma2 = a90 / 3.0;
 
  611  if ( gamma1 > a90 / 3.0 )
 
  614  if ( gamma2 > a90 / 3.0 )
 
  617  std::size_t numberCandidatesGenerated = 0;
 
  620  double angleToCandidate;
 
  621  for ( i = 0, angleToCandidate = M_PI_4; i < maxNumberCandidates; i++, angleToCandidate += candidateAngleIncrement )
 
  626    if ( angleToCandidate > a360 )
 
  627      angleToCandidate -= a360;
 
  631    if ( angleToCandidate < gamma1 || angleToCandidate > a360 - gamma1 )  
 
  633      deltaX = distanceToLabel;
 
  634      double iota = ( angleToCandidate + gamma1 );
 
  635      if ( iota > a360 - gamma1 )
 
  639      deltaY = -labelHeight + labelHeight * iota / ( 2 * gamma1 );
 
  643    else if ( angleToCandidate < a90 - gamma2 )  
 
  645      deltaX = distanceToLabel * std::cos( angleToCandidate );
 
  646      deltaY = distanceToLabel * std::sin( angleToCandidate );
 
  649    else if ( angleToCandidate < a90 + gamma2 ) 
 
  652      deltaX = -labelWidth * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
 
  653      deltaY = distanceToLabel;
 
  656    else if ( angleToCandidate < a180 - gamma1 )  
 
  658      deltaX = distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
 
  659      deltaY = distanceToLabel * std::sin( angleToCandidate );
 
  662    else if ( angleToCandidate < a180 + gamma1 ) 
 
  664      deltaX = -distanceToLabel - labelWidth;
 
  666      deltaY = - ( angleToCandidate - a180 + gamma1 ) * labelHeight / ( 2 * gamma1 );
 
  669    else if ( angleToCandidate < a270 - gamma2 ) 
 
  671      deltaX = distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
 
  672      deltaY = distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
 
  675    else if ( angleToCandidate < a270 + gamma2 ) 
 
  677      deltaY = -distanceToLabel - labelHeight;
 
  679      deltaX = -labelWidth + ( angleToCandidate - a270 + gamma2 ) * labelWidth / ( 2 * gamma2 );
 
  682    else if ( angleToCandidate < a360 ) 
 
  684      deltaX = distanceToLabel * std::cos( angleToCandidate );
 
  685      deltaY = distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
 
  691    QTransform transformRotation;
 
  692    transformRotation.rotate( 
angle * 180 / M_PI );
 
  693    transformRotation.map( deltaX, deltaY, &deltaX, &deltaY );
 
  695    double labelX = 
x + deltaX;
 
  696    double labelY = 
y + deltaY;
 
  700    if ( maxNumberCandidates == 1 )
 
  703      cost = 0.0001 + 0.0020 * double( icost ) / double( maxNumberCandidates - 1 );
 
  714    lPos.emplace_back( std::make_unique< LabelPosition >( 
id + i, labelX, labelY, labelWidth, labelHeight, 
angle, cost, 
this, 
false, quadrant ) );
 
  715    numberCandidatesGenerated++;
 
  719    if ( icost == 
static_cast< int >( maxNumberCandidates ) )
 
  721      icost = 
static_cast< int >( maxNumberCandidates ) - 1;
 
  724    else if ( icost > 
static_cast< int >( maxNumberCandidates ) )
 
  726      icost = 
static_cast< int >( maxNumberCandidates ) - 2;
 
  732  return numberCandidatesGenerated;
 
  739    double shapeLength = mapShape->
length();
 
  750  std::size_t candidates = 0;
 
  756  if ( candidates < candidateTargetCount )
 
  771  std::vector< double > &
x = line->
x;
 
  772  std::vector< double > &
y = line->
y;
 
  774  std::vector< double > segmentLengths( 
nbPoints - 1 ); 
 
  775  std::vector< double >distanceToSegment( 
nbPoints ); 
 
  777  double totalLineLength = 0.0; 
 
  778  for ( 
int i = 0; i < line->
nbPoints - 1; i++ )
 
  781      distanceToSegment[i] = 0;
 
  783      distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
  786    totalLineLength += segmentLengths[i];
 
  788  distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
  791  double lineStepDistance = 0;
 
  794  double currentDistanceAlongLine = lineStepDistance;
 
  798      lineStepDistance = totalLineLength / ( candidateTargetCount + 1 ); 
 
  802      currentDistanceAlongLine = lineAnchorPoint;
 
  803      lineStepDistance = -1;
 
  809  double candidateCenterX, candidateCenterY;
 
  811  while ( currentDistanceAlongLine <= totalLineLength )
 
  813    if ( 
pal->isCanceled() )
 
  818    line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateCenterX, &candidateCenterY );
 
  821    double cost = std::fabs( lineAnchorPoint - currentDistanceAlongLine ) / totalLineLength; 
 
  828        labelX = candidateCenterX;
 
  831        labelX = candidateCenterX - labelWidth / 2;
 
  834        labelX = candidateCenterX - labelWidth;
 
  840    lPos.emplace_back( std::make_unique< LabelPosition >( i, labelX, candidateCenterY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this, 
false, 
LabelPosition::QuadrantOver ) );
 
  842    currentDistanceAlongLine += lineStepDistance;
 
  846    if ( lineStepDistance < 0 )
 
  860    flags = QgsLabeling::LinePlacementFlag::OnLine; 
 
  863  QVector< int > extremeAngleNodes;
 
  866  std::vector< double > &
x = line->
x;
 
  867  std::vector< double > &
y = line->
y;
 
  871  for ( 
int i = 1; i <= numberNodes - ( closedLine ? 1 : 2 ); ++i )
 
  873    double x1 = 
x[i - 1];
 
  875    double x3 = 
x[ i == numberNodes - 1 ? 1 : i + 1]; 
 
  876    double y1 = 
y[i - 1];
 
  878    double y3 = 
y[ i == numberNodes - 1 ? 1 : i + 1]; 
 
  883    double vertexAngle = M_PI - ( std::atan2( y3 - y2, x3 - x2 ) - std::atan2( y2 - y1, x2 - x1 ) );
 
  887    if ( vertexAngle < M_PI * 135.0 / 180.0 || vertexAngle > M_PI * 225.0 / 180.0 )
 
  888      extremeAngleNodes << i;
 
  890  extremeAngleNodes << numberNodes - 1;
 
  892  if ( extremeAngleNodes.isEmpty() )
 
  899  std::vector< double > segmentLengths( numberNodes - 1 ); 
 
  900  std::vector< double > distanceToSegment( numberNodes ); 
 
  901  double totalLineLength = 0.0;
 
  902  QVector< double > straightSegmentLengths;
 
  903  QVector< double > straightSegmentAngles;
 
  904  straightSegmentLengths.reserve( extremeAngleNodes.size() + 1 );
 
  905  straightSegmentAngles.reserve( extremeAngleNodes.size() + 1 );
 
  906  double currentStraightSegmentLength = 0;
 
  907  double longestSegmentLength = 0;
 
  908  int segmentIndex = 0;
 
  909  double segmentStartX = 
x[0];
 
  910  double segmentStartY = 
y[0];
 
  911  for ( 
int i = 0; i < numberNodes - 1; i++ )
 
  914      distanceToSegment[i] = 0;
 
  916      distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
  919    totalLineLength += segmentLengths[i];
 
  920    if ( extremeAngleNodes.contains( i ) )
 
  923      straightSegmentLengths << currentStraightSegmentLength;
 
  925      longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
 
  927      currentStraightSegmentLength = 0;
 
  928      segmentStartX = 
x[i];
 
  929      segmentStartY = 
y[i];
 
  931    currentStraightSegmentLength += segmentLengths[i];
 
  933  distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
  934  straightSegmentLengths << currentStraightSegmentLength;
 
  936  longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
 
  939  if ( totalLineLength < labelWidth )
 
  947  double lineStepDistance = ( totalLineLength - labelWidth ); 
 
  948  lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
 
  950  double distanceToEndOfSegment = 0.0;
 
  951  int lastNodeInSegment = 0;
 
  953  for ( 
int i = 0; i < straightSegmentLengths.count(); ++i )
 
  955    currentStraightSegmentLength = straightSegmentLengths.at( i );
 
  956    double currentSegmentAngle = straightSegmentAngles.at( i );
 
  957    lastNodeInSegment = extremeAngleNodes.at( i );
 
  958    double distanceToStartOfSegment = distanceToEndOfSegment;
 
  959    distanceToEndOfSegment = distanceToSegment[ lastNodeInSegment ];
 
  960    double distanceToCenterOfSegment = 0.5 * ( distanceToEndOfSegment + distanceToStartOfSegment );
 
  962    if ( currentStraightSegmentLength < labelWidth )
 
  966    double currentDistanceAlongLine = distanceToStartOfSegment;
 
  967    double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
 
  968    double candidateLength = 0.0;
 
  974    double segmentCost = 1.0 - ( distanceToEndOfSegment - distanceToStartOfSegment ) / longestSegmentLength; 
 
  975    double segmentAngleCost = 1 - std::fabs( std::fmod( currentSegmentAngle, M_PI ) - M_PI_2 ) / M_PI_2; 
 
  977    while ( currentDistanceAlongLine + labelWidth < distanceToEndOfSegment )
 
  979      if ( 
pal->isCanceled() )
 
  985      line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateStartX, &candidateStartY );
 
  986      line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
 
  988      candidateLength = std::sqrt( ( candidateEndX - candidateStartX ) * ( candidateEndX - candidateStartX ) + ( candidateEndY - candidateStartY ) * ( candidateEndY - candidateStartY ) );
 
  994      cost = candidateLength / labelWidth;
 
 1000        cost = ( 1 - cost ) / 100; 
 
 1003      const double labelCenter = currentDistanceAlongLine + labelWidth / 2.0;
 
 1004      double labelTextAnchor = 0;
 
 1005      switch ( textPoint )
 
 1008          labelTextAnchor = currentDistanceAlongLine;
 
 1011          labelTextAnchor = currentDistanceAlongLine + labelWidth / 2.0;
 
 1014          labelTextAnchor = currentDistanceAlongLine + labelWidth;
 
 1023      if ( placementIsFlexible )
 
 1026        double costCenter = 2 * std::fabs( labelCenter - distanceToCenterOfSegment ) / ( distanceToEndOfSegment - distanceToStartOfSegment ); 
 
 1027        cost += costCenter * 0.0005;  
 
 1035        double costLineCenter = 2 * std::fabs( labelTextAnchor - lineAnchorPoint ) / totalLineLength;  
 
 1036        cost += costLineCenter * 0.0005;  
 
 1039      if ( placementIsFlexible )
 
 1041        cost += segmentCost * 0.0005; 
 
 1042        cost += segmentAngleCost * 0.0001; 
 
 1050        angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
 
 1054      beta = 
angle + M_PI_2;
 
 1059        bool isRightToLeft = ( 
angle > M_PI_2 || 
angle <= -M_PI_2 );
 
 1061        bool reversed = ( ( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ? isRightToLeft : 
false );
 
 1062        bool aboveLine = ( !reversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) ) || ( reversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) );
 
 1063        bool belowLine = ( !reversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) ) || ( reversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) );
 
 1069            const double candidateCost = cost + ( reversed ? 0 : 0.001 );
 
 1070            lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, 
angle, candidateCost, 
this, isRightToLeft, 
LabelPosition::QuadrantOver ) ); 
 
 1077            const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); 
 
 1078            lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, 
angle, candidateCost, 
this, isRightToLeft, 
LabelPosition::QuadrantOver ) ); 
 
 1081        if ( flags & QgsLabeling::LinePlacementFlag::OnLine )
 
 1085            const double candidateCost = cost + 0.002;
 
 1086            lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, 
angle, candidateCost, 
this, isRightToLeft, 
LabelPosition::QuadrantOver ) ); 
 
 1092        lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this, 
false, 
LabelPosition::QuadrantOver ) ); 
 
 1099      currentDistanceAlongLine += lineStepDistance;
 
 1118    flags = QgsLabeling::LinePlacementFlag::OnLine; 
 
 1122  std::vector< double > &
x = line->
x;
 
 1123  std::vector< double > &
y = line->
y;
 
 1125  std::vector< double > segmentLengths( 
nbPoints - 1 ); 
 
 1126  std::vector< double >distanceToSegment( 
nbPoints ); 
 
 1128  double totalLineLength = 0.0; 
 
 1129  for ( 
int i = 0; i < line->
nbPoints - 1; i++ )
 
 1132      distanceToSegment[i] = 0;
 
 1134      distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
 1137    totalLineLength += segmentLengths[i];
 
 1139  distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
 1141  double lineStepDistance = ( totalLineLength - labelWidth ); 
 
 1142  double currentDistanceAlongLine = 0;
 
 1148  if ( totalLineLength > labelWidth )
 
 1150    lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
 
 1154    currentDistanceAlongLine = - ( labelWidth - totalLineLength ) / 2.0;
 
 1155    lineStepDistance = -1;
 
 1156    totalLineLength = labelWidth;
 
 1161    currentDistanceAlongLine = std::numeric_limits< double >::max();
 
 1172      switch ( textPoint )
 
 1175          currentDistanceAlongLine = std::min( lineAnchorPoint, totalLineLength * 0.99 - labelWidth );
 
 1178          currentDistanceAlongLine = std::min( lineAnchorPoint - labelWidth / 2, totalLineLength * 0.99 - labelWidth );
 
 1181          currentDistanceAlongLine = std::min( lineAnchorPoint - labelWidth, totalLineLength * 0.99 - labelWidth );
 
 1187      lineStepDistance = -1;
 
 1191  double candidateLength;
 
 1193  double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
 
 1197    if ( 
pal->isCanceled() )
 
 1203    line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateStartX, &candidateStartY );
 
 1204    line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
 
 1206    if ( currentDistanceAlongLine < 0 )
 
 1214      candidateLength = std::sqrt( ( candidateEndX - candidateStartX ) * ( candidateEndX - candidateStartX ) + ( candidateEndY - candidateStartY ) * ( candidateEndY - candidateStartY ) );
 
 1217    cost = candidateLength / labelWidth;
 
 1223      cost = ( 1 - cost ) / 100; 
 
 1227    double textAnchorPoint = 0;
 
 1228    switch ( textPoint )
 
 1231        textAnchorPoint = currentDistanceAlongLine;
 
 1234        textAnchorPoint = currentDistanceAlongLine + labelWidth / 2;
 
 1237        textAnchorPoint = currentDistanceAlongLine + labelWidth;
 
 1243    double costCenter = std::fabs( lineAnchorPoint - textAnchorPoint ) / totalLineLength; 
 
 1244    cost += costCenter / 1000;  
 
 1245    cost += initialCost;
 
 1252      angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
 
 1256    beta = 
angle + M_PI_2;
 
 1261      bool isRightToLeft = ( 
angle > M_PI_2 || 
angle <= -M_PI_2 );
 
 1263      bool reversed = ( ( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ? isRightToLeft : 
false );
 
 1264      bool aboveLine = ( !reversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) ) || ( reversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) );
 
 1265      bool belowLine = ( !reversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) ) || ( reversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) );
 
 1271          const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); 
 
 1272          lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX + std::cos( beta ) *distanceLineToLabel, candidateStartY + std::sin( beta ) *distanceLineToLabel, labelWidth, labelHeight, 
angle, candidateCost, 
this, isRightToLeft, 
LabelPosition::QuadrantOver ) ); 
 
 1279          const double candidateCost = cost + ( !reversed ? 0.001 : 0 );
 
 1280          lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX - std::cos( beta ) * ( distanceLineToLabel + labelHeight ), candidateStartY - std::sin( beta ) * ( distanceLineToLabel + labelHeight ), labelWidth, labelHeight, 
angle, candidateCost, 
this, isRightToLeft, 
LabelPosition::QuadrantOver ) ); 
 
 1283      if ( flags & QgsLabeling::LinePlacementFlag::OnLine )
 
 1287          const double candidateCost = cost + 0.002;
 
 1288          lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX - labelHeight * std::cos( beta ) / 2, candidateStartY - labelHeight * std::sin( beta ) / 2, labelWidth, labelHeight, 
angle, candidateCost, 
this, isRightToLeft, 
LabelPosition::QuadrantOver ) ); 
 
 1294      lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this, 
false, 
LabelPosition::QuadrantOver ) ); 
 
 1301    currentDistanceAlongLine += lineStepDistance;
 
 1305    if ( lineStepDistance < 0 )
 
 1315  Q_ASSERT( metrics );
 
 1317  const double maximumCharacterAngleInside = applyAngleConstraints ? std::fabs( qgis::down_cast< QgsTextLabelFeature *>( 
mLF )->maximumCharacterAngleInside() ) : -1;
 
 1318  const double maximumCharacterAngleOutside = applyAngleConstraints ? std::fabs( qgis::down_cast< QgsTextLabelFeature *>( 
mLF )->maximumCharacterAngleOutside() ) : -1;
 
 1320  std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > placement(
 
 1324  labeledLineSegmentIsRightToLeft = !uprightOnly ? placement->labeledLineSegmentIsRightToLeft : placement->flippedCharacterPlacementToGetUprightLabels;
 
 1326  if ( placement->graphemePlacement.empty() )
 
 1329  auto it = placement->graphemePlacement.constBegin();
 
 1330  std::unique_ptr< LabelPosition > firstPosition = std::make_unique< LabelPosition >( 0, it->x, it->y, it->width, it->height, it->angle, 0.0001, 
this, 
false, 
LabelPosition::QuadrantOver );
 
 1331  firstPosition->setUpsideDownCharCount( placement->upsideDownCharCount );
 
 1332  firstPosition->setPartId( it->graphemeIndex );
 
 1335  while ( it != placement->graphemePlacement.constEnd() )
 
 1337    std::unique_ptr< LabelPosition > position = std::make_unique< LabelPosition >( 0, it->x, it->y, it->width, it->height, it->angle, 0.0001, 
this, 
false, 
LabelPosition::QuadrantOver );
 
 1338    position->setPartId( it->graphemeIndex );
 
 1341    previousPosition->
setNextPart( std::move( position ) );
 
 1342    previousPosition = nextPosition;
 
 1346  return firstPosition;
 
 1358  const int characterCount = li->
count();
 
 1359  if ( characterCount == 0 )
 
 1365  double totalCharacterWidth = 0;
 
 1366  for ( 
int i = 0; i < characterCount; ++i )
 
 1369  std::unique_ptr< PointSet > expanded;
 
 1370  double shapeLength = mapShape->
length();
 
 1373    allowOverrun = 
false;
 
 1391  if ( totalCharacterWidth > shapeLength )
 
 1393    if ( !allowOverrun || shapeLength < totalCharacterWidth - 2 * overrun )
 
 1404  if ( allowOverrun && overrun > 0 )
 
 1407    expanded = mapShape->
clone();
 
 1409    mapShape = expanded.get();
 
 1410    shapeLength += 2 * overrun;
 
 1415    flags = QgsLabeling::LinePlacementFlag::OnLine; 
 
 1416  const bool hasAboveBelowLinePlacement = flags & QgsLabeling::LinePlacementFlag::AboveLine || flags & QgsLabeling::LinePlacementFlag::BelowLine;
 
 1418  std::unique_ptr< PointSet > mapShapeOffsetPositive;
 
 1419  bool positiveShapeHasNegativeDistance = 
false;
 
 1420  std::unique_ptr< PointSet > mapShapeOffsetNegative;
 
 1421  bool negativeShapeHasNegativeDistance = 
false;
 
 1422  if ( hasAboveBelowLinePlacement && !
qgsDoubleNear( offsetDistance, 0 ) )
 
 1425    if ( ( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) || ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) )
 
 1426      mapShapeOffsetPositive = mapShape->
clone();
 
 1427    if ( ( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) || ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) )
 
 1428      mapShapeOffsetNegative = mapShape->
clone();
 
 1429    if ( offsetDistance >= 0.0 || !( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) )
 
 1431      if ( mapShapeOffsetPositive )
 
 1432        mapShapeOffsetPositive->offsetCurveByDistance( offsetDistance );
 
 1433      positiveShapeHasNegativeDistance = offsetDistance < 0;
 
 1434      if ( mapShapeOffsetNegative )
 
 1435        mapShapeOffsetNegative->offsetCurveByDistance( offsetDistance * -1 );
 
 1436      negativeShapeHasNegativeDistance = offsetDistance > 0;
 
 1441      if ( flags & QgsLabeling::LinePlacementFlag::AboveLine
 
 1442           && !( flags & QgsLabeling::LinePlacementFlag::BelowLine ) )
 
 1445        flags |= QgsLabeling::LinePlacementFlag::BelowLine;
 
 1447      else if ( flags & QgsLabeling::LinePlacementFlag::BelowLine
 
 1448                && !( flags & QgsLabeling::LinePlacementFlag::AboveLine ) )
 
 1451        flags |= QgsLabeling::LinePlacementFlag::AboveLine;
 
 1453      if ( mapShapeOffsetPositive )
 
 1454        mapShapeOffsetPositive->offsetCurveByDistance( offsetDistance * -1 );
 
 1455      positiveShapeHasNegativeDistance = offsetDistance > 0;
 
 1456      if ( mapShapeOffsetNegative )
 
 1457        mapShapeOffsetNegative->offsetCurveByDistance( offsetDistance );
 
 1458      negativeShapeHasNegativeDistance = offsetDistance < 0;
 
 1464  std::vector< std::unique_ptr< LabelPosition >> positions;
 
 1465  std::unique_ptr< LabelPosition > backupPlacement;
 
 1468    PointSet *currentMapShape = 
nullptr;
 
 1471      currentMapShape = mapShapeOffsetPositive.get();
 
 1473    if ( offset == 
NoOffset && flags & QgsLabeling::LinePlacementFlag::OnLine )
 
 1475      currentMapShape = mapShape;
 
 1479      currentMapShape = mapShapeOffsetNegative.get();
 
 1481    if ( !currentMapShape )
 
 1485    const auto [ pathDistances, totalDistance ] = currentMapShape->
edgeDistances();
 
 1489    double lineAnchorPoint = 0;
 
 1490    if ( originalPoint && offset != 
NoOffset )
 
 1495      lineAnchorPoint = currentMapShape->
lineLocatePoint( originalPoint.get() );
 
 1501        lineAnchorPoint = totalDistance - lineAnchorPoint;
 
 1504    if ( 
pal->isCanceled() )
 
 1508    double delta = std::max( li->
characterHeight( 0 ) / 6, totalDistance / candidateTargetCount );
 
 1511    double distanceAlongLineToStartCandidate = 0;
 
 1512    bool singleCandidateOnly = 
false;
 
 1519        switch ( textPoint )
 
 1522            distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint, 0.0, totalDistance * 0.999 );
 
 1525            distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - 
getLabelWidth() / 2, 0.0, totalDistance * 0.999 - 
getLabelWidth() / 2 );
 
 1528            distanceAlongLineToStartCandidate = std::clamp( lineAnchorPoint - 
getLabelWidth(), 0.0, totalDistance * 0.999 - 
getLabelWidth() ) ;
 
 1534        singleCandidateOnly = 
true;
 
 1538    bool hasTestedFirstPlacement = 
false;
 
 1539    for ( ; distanceAlongLineToStartCandidate <= totalDistance; distanceAlongLineToStartCandidate += delta )
 
 1541      if ( singleCandidateOnly && hasTestedFirstPlacement )
 
 1544      if ( 
pal->isCanceled() )
 
 1547      hasTestedFirstPlacement = 
true;
 
 1549      bool labeledLineSegmentIsRightToLeft = 
false;
 
 1551      std::unique_ptr< LabelPosition > labelPosition = 
curvedPlacementAtOffset( currentMapShape, pathDistances, direction, distanceAlongLineToStartCandidate, labeledLineSegmentIsRightToLeft, !singleCandidateOnly,
 
 1552          onlyShowUprightLabels() && ( !singleCandidateOnly || !( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ) );
 
 1554      if ( !labelPosition )
 
 1560      bool isBackupPlacementOnly = 
false;
 
 1561      if ( flags & QgsLabeling::LinePlacementFlag::MapOrientation )
 
 1563        if ( ( currentMapShape == mapShapeOffsetPositive.get() && positiveShapeHasNegativeDistance )
 
 1564             || ( currentMapShape == mapShapeOffsetNegative.get() && negativeShapeHasNegativeDistance ) )
 
 1566          labeledLineSegmentIsRightToLeft = !labeledLineSegmentIsRightToLeft;
 
 1569        if ( ( offset != 
NoOffset ) && !labeledLineSegmentIsRightToLeft && !( flags & QgsLabeling::LinePlacementFlag::AboveLine ) )
 
 1572            isBackupPlacementOnly = 
true;
 
 1576        if ( ( offset != 
NoOffset ) && labeledLineSegmentIsRightToLeft && !( flags & QgsLabeling::LinePlacementFlag::BelowLine ) )
 
 1579            isBackupPlacementOnly = 
true;
 
 1585      backupPlacement.reset();
 
 1588      const double angleDiff = labelPosition->angleDifferential();
 
 1589      const double angleDiffAvg = characterCount > 1 ? ( angleDiff / ( characterCount - 1 ) ) : 0; 
 
 1594      double cost = angleDiffAvg / 100; 
 
 1595      if ( cost < 0.0001 )
 
 1599      double labelTextAnchor = 0;
 
 1600      switch ( textPoint )
 
 1603          labelTextAnchor = distanceAlongLineToStartCandidate;
 
 1606          labelTextAnchor = distanceAlongLineToStartCandidate + 
getLabelWidth() / 2;
 
 1609          labelTextAnchor = distanceAlongLineToStartCandidate + 
getLabelWidth();
 
 1615      double costCenter = std::fabs( lineAnchorPoint - labelTextAnchor ) / totalDistance; 
 
 1616      cost += costCenter / ( anchorIsFlexiblePlacement ? 100 : 10 );  
 
 1618      const bool isBelow = ( offset != 
NoOffset ) && labeledLineSegmentIsRightToLeft;
 
 1630      labelPosition->setCost( cost );
 
 1632      std::unique_ptr< LabelPosition > p = std::make_unique< LabelPosition >( *labelPosition );
 
 1637        while ( within && currentPos )
 
 1640          currentPos = currentPos->
nextPart();
 
 1650        if ( isBackupPlacementOnly )
 
 1651          backupPlacement = std::move( p );
 
 1653          positions.emplace_back( std::move( p ) );
 
 1658  for ( std::unique_ptr< LabelPosition > &pos : positions )
 
 1660    lPos.emplace_back( std::move( pos ) );
 
 1663  if ( backupPlacement )
 
 1664    lPos.emplace_back( std::move( backupPlacement ) );
 
 1666  return positions.size();
 
 1690  const double totalArea = 
area();
 
 1692  mapShape->
parent = 
nullptr;
 
 1694  if ( 
pal->isCanceled() )
 
 1697  QLinkedList<PointSet *> shapes_final = 
splitPolygons( mapShape, labelWidth, labelHeight );
 
 1699  QgsDebugMsg( QStringLiteral( 
"PAL split polygons resulted in:" ) );
 
 1700  for ( 
PointSet *ps : shapes_final )
 
 1706  std::size_t nbp = 0;
 
 1708  if ( !shapes_final.isEmpty() )
 
 1716    double diago = std::sqrt( labelWidth * labelWidth / 4.0 + labelHeight * labelHeight / 4 );
 
 1718    std::vector< OrientedConvexHullBoundingBox > boxes;
 
 1719    boxes.reserve( shapes_final.size() );
 
 1722    while ( !shapes_final.isEmpty() )
 
 1724      PointSet *shape = shapes_final.takeFirst();
 
 1728        boxes.emplace_back( box );
 
 1734    if ( 
pal->isCanceled() )
 
 1738    double densityY = densityX;
 
 1745    std::size_t numberCandidatesGenerated = 0;
 
 1760        double dx = densityX;
 
 1761        double dy = densityY;
 
 1762        if ( numTry == 0 && maxPolygonCandidates > 0 )
 
 1765          const double boxArea = box.width * box.length;
 
 1766          double maxThisBox = targetPolygonCandidates * boxArea / totalArea;
 
 1767          dx = std::max( dx, std::sqrt( boxArea / maxThisBox ) * 0.8 );
 
 1771        if ( 
pal->isCanceled() )
 
 1772          return numberCandidatesGenerated;
 
 1791        bool enoughPlace = 
false;
 
 1795          px = ( box.x[0] + box.x[2] ) / 2 - labelWidth;
 
 1796          py = ( box.y[0] + box.y[2] ) / 2 - labelHeight;
 
 1802          for ( rx = px, i = 0; i < 2; rx = rx + 2 * labelWidth, i++ )
 
 1804            for ( ry = py, j = 0; j < 2; ry = ry + 2 * labelHeight, j++ )
 
 1808                enoughPlace = 
false;
 
 1824        else if ( box.length > 1.5 * labelWidth && box.width > 1.5 * labelWidth )
 
 1826          if ( box.alpha <= M_PI_4 )
 
 1832            alpha = box.alpha - M_PI_2;
 
 1835        else if ( box.length > box.width )
 
 1837          alpha = box.alpha - M_PI_2;
 
 1844        beta  = std::atan2( labelHeight, labelWidth ) + alpha;
 
 1850        dlx = std::cos( beta ) * diago;
 
 1851        dly = std::sin( beta ) * diago;
 
 1853        double px0 = box.width / 2.0;
 
 1854        double py0 = box.length / 2.0;
 
 1856        px0 -= std::ceil( px0 / dx ) * dx;
 
 1857        py0 -= std::ceil( py0 / dy ) * dy;
 
 1859        for ( px = px0; px <= box.width; px += dx )
 
 1861          if ( 
pal->isCanceled() )
 
 1864          for ( py = py0; py <= box.length; py += dy )
 
 1867            rx = std::cos( box.alpha ) * px + std::cos( box.alpha - M_PI_2 ) * py;
 
 1868            ry = std::sin( box.alpha ) * px + std::sin( box.alpha - M_PI_2 ) * py;
 
 1878                lPos.emplace_back( std::make_unique< LabelPosition >( 
id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, 
this, 
false, 
LabelPosition::QuadrantOver ) );
 
 1879                numberCandidatesGenerated++;
 
 1890                std::unique_ptr< LabelPosition > potentialCandidate = std::make_unique< LabelPosition >( 
id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, 
this, 
false, 
LabelPosition::QuadrantOver );
 
 1892                lPos.emplace_back( std::move( potentialCandidate ) );
 
 1893                numberCandidatesGenerated++;
 
 1900      nbp = numberCandidatesGenerated;
 
 1901      if ( maxPolygonCandidates > 0 && nbp < targetPolygonCandidates )
 
 1912    while ( numTry < maxTry );
 
 1914    nbp = numberCandidatesGenerated;
 
 1928  std::size_t candidatesCreated = 0;
 
 1988  const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( gg.get() );
 
 1990    return candidatesCreated;
 
 1994    return candidatesCreated;
 
 1998  const double ringLength = ring->
length();
 
 1999  const double circleArea = std::pow( ringLength, 2 ) / ( 4 * M_PI );
 
 2001  const std::size_t targetPolygonCandidates = std::max( 
static_cast< std::size_t 
>( 16 ), maxPolygonCandidates > 0 ? std::min( maxPolygonCandidates,  candidatesForArea ) : candidatesForArea );
 
 2004  const double delta = ringLength / targetPolygonCandidates;
 
 2007  const double maxDistCentroidToLabelX = std::max( 
xmax - cx, cx - 
xmin ) + distanceToLabel;
 
 2008  const double maxDistCentroidToLabelY = std::max( 
ymax - cy, cy - 
ymin ) + distanceToLabel;
 
 2009  const double estimateOfMaxPossibleDistanceCentroidToLabel = std::sqrt( maxDistCentroidToLabelX * maxDistCentroidToLabelX + maxDistCentroidToLabelY * maxDistCentroidToLabelY );
 
 2012  const double labelAngle = 0;
 
 2014  std::size_t i = lPos.size();
 
 2022    createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, 
x, 
y, labelWidth, labelHeight, position, distanceToLabel * 0.5, visualMargin, 0, 0, labelAngle );
 
 2024    std::unique_ptr< LabelPosition > candidate = std::make_unique< LabelPosition >( i, labelX, labelY, labelWidth, labelHeight, labelAngle, 0, 
this, 
false, quadrant );
 
 2025    if ( candidate->intersects( preparedBuffer.get() ) )
 
 2043    const double centroidDistance = candidate->getDistanceToPoint( cx, cy );
 
 2044    const double centroidCost = centroidDistance / estimateOfMaxPossibleDistanceCentroidToLabel;
 
 2045    candidate->setCost( centroidCost );
 
 2047    lPos.emplace_back( std::move( candidate ) );
 
 2048    candidatesCreated++;
 
 2053                                      double startSegmentX, 
double startSegmentY, 
double, 
double,
 
 2054                                      double endSegmentX, 
double endSegmentY, 
double, 
double )
 
 2057    float angle = atan2( 
static_cast< float >( endSegmentY - startSegmentY ), 
static_cast< float >( endSegmentX - startSegmentX ) ) * 180 / M_PI;
 
 2067    else if ( 
angle <= 85 )
 
 2071    else if ( 
angle <= 90 )
 
 2077    else if ( 
angle <= 95 )
 
 2082    else if ( 
angle <= 175 )
 
 2086    else if ( 
angle <= 180 )
 
 2092    else if ( 
angle <= 185 )
 
 2097    else if ( 
angle <= 265 )
 
 2101    else if ( 
angle <= 270 )
 
 2106    else if ( 
angle <= 275 )
 
 2111    else if ( 
angle <= 355 )
 
 2121    return !
pal->isCanceled();
 
 2124  return candidatesCreated;
 
 2129  std::vector< std::unique_ptr< LabelPosition > > lPos;
 
 2149      case GEOS_LINESTRING:
 
 2163        const bool allowOutside = 
mLF->
polygonPlacementFlags() & QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
 
 2164        const bool allowInside =  
mLF->
polygonPlacementFlags() & QgsLabeling::PolygonPlacementFlag::AllowPlacementInsideOfPolygon;
 
 2172        else if ( allowOutside && ( std::fabs( 
xmax - 
xmin ) < labelWidth ||
 
 2173                                    std::fabs( 
ymax - 
ymin ) < labelHeight ) )
 
 2180          std::size_t created = 0;
 
 2238  int geomType = GEOSGeomTypeId_r( ctxt, 
mGeos );
 
 2240  double sizeCost = 0;
 
 2241  if ( geomType == GEOS_LINESTRING )
 
 2243    const double l = 
length();
 
 2246    double bbox_length = std::max( bbx[2] - bbx[0], bby[2] - bby[0] );
 
 2247    if ( l >= bbox_length / 4 )
 
 2250    sizeCost = 1 - ( l / ( bbox_length / 4 ) ); 
 
 2252  else if ( geomType == GEOS_POLYGON )
 
 2254    const double a = 
area();
 
 2257    double bbox_area = ( bbx[2] - bbx[0] ) * ( bby[2] - bby[0] );
 
 2258    if ( a >= bbox_area / 16 )
 
 2261    sizeCost = 1 - ( a / ( bbox_area / 16 ) ); 
 
 2267  for ( std::unique_ptr< LabelPosition > &pos : lPos )
 
 2269    pos->setCost( pos->cost() + sizeCost / 100 );
 
 2280  const double x1first = 
x.front();
 
 2281  const double x1last = 
x.back();
 
 2282  const double x2first = p2->
x.front();
 
 2283  const double x2last = p2->
x.back();
 
 2284  const double y1first = 
y.front();
 
 2285  const double y1last = 
y.back();
 
 2286  const double y2first = p2->
y.front();
 
 2287  const double y2last = p2->
y.back();
 
 2295  if ( ( !p2startTouches && !p2endTouches ) || ( p2startTouches && p2endTouches ) )
 
 2301  const double p2otherX = p2startTouches ? x2last : x2first;
 
 2302  const double p2otherY = p2startTouches ? y2last : y2first;
 
 2306  GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
 
 2307  GEOSCoordSeq_setXY_r( geosctxt, coord, 0, p2otherX, p2otherY );
 
 2312    return ( GEOSPreparedIntersects_r( geosctxt, 
preparedGeom(), p2OtherEnd.get() ) != 1 );
 
 2314  catch ( GEOSException &e )
 
 2316    qWarning( 
"GEOS exception: %s", e.what() );
 
 2326  if ( !other->
mGeos )
 
 2332    GEOSGeometry *g1 = GEOSGeom_clone_r( ctxt, 
mGeos );
 
 2333    GEOSGeometry *g2 = GEOSGeom_clone_r( ctxt, other->
mGeos );
 
 2334    GEOSGeometry *geoms[2] = { g1, g2 };
 
 2335    geos::unique_ptr g( GEOSGeom_createCollection_r( ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
 
 2338    if ( GEOSGeomTypeId_r( ctxt, gTmp.get() ) != GEOS_LINESTRING )
 
 2346    mGeos = gTmp.release();
 
 2355  catch ( GEOSException &e )
 
 2357    qWarning( 
"GEOS exception: %s", e.what() );
 
 2378  bool result = 
false;
 
 2382    case Qgis::UpsideDownLabelHandling::FlipUpsideDownLabels:
 
 2385    case Qgis::UpsideDownLabelHandling::AllowUpsideDownWhenRotationIsDefined:
 
 2392    case Qgis::UpsideDownLabelHandling::AlwaysAllowUpsideDown:
 
@ FromSymbolBounds
Offset distance applies from rendered symbol bounds.
 
@ 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....
 
LabelPredefinedPointPosition
Positions for labels when using the Qgis::LabelPlacement::OrderedPositionsAroundPoint placement mode.
 
@ 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.
 
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
 
static double normalizedAngle(double angle) SIP_HOLDGIL
Ensures that an angle is in the range 0 <= angle < 2 pi.
 
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
 
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
 
static GEOSContextHandle_t getGEOSHandler()
 
The QgsLabelFeature class describes a feature that should be used within the labeling engine.
 
double overrunSmoothDistance() const
Returns the distance (in map units) with which the ends of linear features are averaged over when cal...
 
double fixedAngle() const
Angle in degrees 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.
 
QgsLabeling::PolygonPlacementFlags polygonPlacementFlags() const
Returns the polygon placement flags, which dictate how polygon labels can be placed.
 
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.
 
QgsLabeling::LinePlacementFlags arrangementFlags() const
Returns the feature's arrangement flags.
 
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.
 
QPointF quadOffset() const
Applies to "offset from point" placement strategy and "around point" (in case hasFixedQuadrant() retu...
 
void setAnchorPosition(const QgsPointXY &anchorPosition)
In case of quadrand or aligned positioning, this is set to the anchor point.
 
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::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...
 
Contains constants and enums relating to labeling.
 
Line string geometry type, with support for z-dimension and m-values.
 
double length() const override SIP_HOLDGIL
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.
 
The QgsMargins class 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)
Adds a message to the log instance (and creates it if necessary).
 
A class to represent a 2D point.
 
Contains precalculated properties regarding text metrics for text to be renderered 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...
 
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
 
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
 
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 ...
 
static CurvePlacementProperties * generateCurvedTextPlacement(const QgsPrecalculatedTextMetrics &metrics, const double *x, const double *y, int numPoints, const std::vector< double > &pathDistances, double offsetAlongLine, LabelLineDirection direction=RespectPainterOrientation, double maxConcaveAngle=-1, double maxConvexAngle=-1, bool uprightOnly=true)
Calculates curved text placement properties.
 
Main class to handle 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 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::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 into account.
 
QgsLabelFeature * feature()
Returns the parent feature.
 
std::unique_ptr< LabelPosition > curvedPlacementAtOffset(PointSet *mapShape, const std::vector< double > &pathDistances, QgsTextRendererUtils::LabelLineDirection direction, double distance, bool &labeledLineSegmentIsRightToLeft, bool applyAngleConstraints, bool uprightOnly)
Returns the label position for a curved label at a specific offset along a path.
 
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 double dist_euc2d(double x1, double y1, double x2, double y2)
 
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 rad).
 
Quadrant
Position of label candidate relative to feature.
 
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.
 
OrientedConvexHullBoundingBox computeConvexHullOrientedBoundingBox(bool &ok)
Computes an oriented bounding box for the shape's convex hull.
 
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
 
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, LabelPosition::Quadrant &quadrant, double x, double y, double labelWidth, double labelHeight, Qgis::LabelPredefinedPointPosition position, double distanceToLabel, const QgsMargins &visualMargin, double symbolWidthOffset, double symbolHeightOffset, double angle)
 
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< const GEOSPreparedGeometry, GeosDeleter > prepared_unique_ptr
Scoped GEOS prepared geometry pointer.
 
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
 
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
 
Represents the minimum area, oriented bounding box surrounding a convex hull.