49 #include <QLinkedList> 
   59   mGeos = 
const_cast<GEOSGeometry *
>( geom );
 
   65   for ( 
int i = 0; i < 
mHoles.count(); i++ )
 
   67     mHoles.at( i )->holeOf = 
this;
 
   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   for ( 
int i = 0; i < 
nbPoints; ++i )
 
  141 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
  142     GEOSCoordSeq_getXY_r( geosctxt, coordSeq, i, &
x[i], &
y[i] );
 
  144     GEOSCoordSeq_getX_r( geosctxt, coordSeq, i, &
x[i] );
 
  145     GEOSCoordSeq_getY_r( geosctxt, coordSeq, i, &
y[i] );
 
  173   if ( mCachedMaxLineCandidates > 0 )
 
  174     return mCachedMaxLineCandidates;
 
  176   const double l = 
length();
 
  181     if ( maxForLayer == 0 )
 
  182       mCachedMaxLineCandidates = candidatesForLineLength;
 
  184       mCachedMaxLineCandidates = std::min( candidatesForLineLength, maxForLayer );
 
  188     mCachedMaxLineCandidates = 1;
 
  190   return mCachedMaxLineCandidates;
 
  195   if ( mCachedMaxPolygonCandidates > 0 )
 
  196     return mCachedMaxPolygonCandidates;
 
  198   const double a = 
area();
 
  203     if ( maxForLayer == 0 )
 
  204       mCachedMaxPolygonCandidates = candidatesForArea;
 
  206       mCachedMaxPolygonCandidates = std::min( candidatesForArea, maxForLayer );
 
  210     mCachedMaxPolygonCandidates = 1;
 
  212   return mCachedMaxPolygonCandidates;
 
  234   qreal quadOffsetX = quadOffset.x(), quadOffsetY = quadOffset.y();
 
  236   if ( quadOffsetX < 0 )
 
  238     if ( quadOffsetY < 0 )
 
  242     else if ( quadOffsetY > 0 )
 
  251   else  if ( quadOffsetX > 0 )
 
  253     if ( quadOffsetY < 0 )
 
  257     else if ( quadOffsetY > 0 )
 
  268     if ( quadOffsetY < 0 )
 
  272     else if ( quadOffsetY > 0 )
 
  285   return mTotalRepeats;
 
  299   double cost = 0.00005;
 
  300   int id = lPos.size();
 
  302   double xdiff = -labelW / 2.0;
 
  303   double ydiff = -labelH / 2.0;
 
  307   double lx = 
x + xdiff;
 
  308   double ly = 
y + ydiff;
 
  328   double cost = 0.0001;
 
  329   int id = lPos.size();
 
  331   double xdiff = -labelW / 2.0;
 
  332   double ydiff = -labelH / 2.0;
 
  349       double xd = xdiff * std::cos( 
angle ) - ydiff * std::sin( 
angle );
 
  350       double yd = xdiff * std::sin( 
angle ) + ydiff * std::cos( 
angle );
 
  386   double lx = 
x + xdiff;
 
  387   double ly = 
y + ydiff;
 
  397   lPos.emplace_back( std::make_unique< LabelPosition >( 
id, lx, ly, labelW, labelH, 
angle, cost, 
this, 
false, quadrantFromOffset() ) );
 
  410       const GEOSCoordSequence *coordSeq = GEOSGeom_getCoordSeq_r( geosctxt, pointGeom.get() );
 
  411 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
  412       unsigned int nPoints = 0;
 
  413       GEOSCoordSeq_getSize_r( geosctxt, coordSeq, &nPoints );
 
  416       GEOSCoordSeq_getXY_r( geosctxt, coordSeq, 0, &px, &py );
 
  418       GEOSCoordSeq_getX_r( geosctxt, coordSeq, 0, &px );
 
  419       GEOSCoordSeq_getY_r( geosctxt, coordSeq, 0, &py );
 
  423   catch ( GEOSException &e )
 
  425     qWarning( 
"GEOS exception: %s", e.what() );
 
  433 void createCandidateAtOrderedPositionOverPoint( 
double &labelX, 
double &labelY, 
LabelPosition::Quadrant &quadrant, 
double x, 
double y, 
double labelWidth, 
double labelHeight, 
QgsPalLayerSettings::PredefinedPointPosition position, 
double distanceToLabel, 
const QgsMargins &visualMargin, 
double symbolWidthOffset, 
double symbolHeightOffset )
 
  443       deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  444       deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  450       deltaX = -labelWidth / 4.0 - visualMargin.
left();
 
  451       deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  457       deltaX = -labelWidth / 2.0;
 
  458       deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  464       deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
 
  465       deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  471       deltaX = - visualMargin.
left() + symbolWidthOffset;
 
  472       deltaY = -visualMargin.
bottom() + symbolHeightOffset;
 
  478       deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  479       deltaY = -labelHeight / 2.0;
 
  485       deltaX = -visualMargin.
left() + symbolWidthOffset;
 
  486       deltaY = -labelHeight / 2.0;
 
  492       deltaX = -labelWidth + visualMargin.
right() - symbolWidthOffset;
 
  493       deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  499       deltaX = -labelWidth / 4.0 - visualMargin.
left();
 
  500       deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  506       deltaX = -labelWidth / 2.0;
 
  507       deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  513       deltaX = -labelWidth * 3.0 / 4.0 + visualMargin.
right();
 
  514       deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  520       deltaX = -visualMargin.
left() + symbolWidthOffset;
 
  521       deltaY = -labelHeight + visualMargin.
top() - symbolHeightOffset;
 
  526   double referenceX = std::cos( alpha ) * distanceToLabel + x;
 
  527   double referenceY = std::sin( alpha ) * distanceToLabel + y;
 
  529   labelX = referenceX + deltaX;
 
  530   labelY = referenceY + deltaY;
 
  544   double cost = 0.0001;
 
  545   std::size_t i = lPos.size();
 
  548   std::size_t created = 0;
 
  555     createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, 
x, 
y, labelWidth, labelHeight, position, distanceToLabel, visualMargin, symbolWidthOffset, symbolHeightOffset );
 
  559       lPos.emplace_back( std::make_unique< LabelPosition >( i, labelX, labelY, labelWidth, labelHeight, 
angle, cost, 
this, 
false, quadrant ) );
 
  563       if ( maxNumberCandidates > 0 && created >= maxNumberCandidates )
 
  579   if ( maxNumberCandidates == 0 )
 
  580     maxNumberCandidates = 16;
 
  584   int id = lPos.size();
 
  586   double candidateAngleIncrement = 2 * M_PI / maxNumberCandidates; 
 
  591   double a270 = a180 + a90;
 
  592   double a360 = 2 * M_PI;
 
  594   double gamma1, gamma2;
 
  596   if ( distanceToLabel > 0 )
 
  598     gamma1 = std::atan2( labelHeight / 2, distanceToLabel + labelWidth / 2 );
 
  599     gamma2 = std::atan2( labelWidth / 2, distanceToLabel + labelHeight / 2 );
 
  603     gamma1 = gamma2 = a90 / 3.0;
 
  606   if ( gamma1 > a90 / 3.0 )
 
  609   if ( gamma2 > a90 / 3.0 )
 
  612   std::size_t numberCandidatesGenerated = 0;
 
  615   double angleToCandidate;
 
  616   for ( i = 0, angleToCandidate = M_PI_4; i < maxNumberCandidates; i++, angleToCandidate += candidateAngleIncrement )
 
  621     if ( angleToCandidate > a360 )
 
  622       angleToCandidate -= a360;
 
  626     if ( angleToCandidate < gamma1 || angleToCandidate > a360 - gamma1 )  
 
  628       labelX += distanceToLabel;
 
  629       double iota = ( angleToCandidate + gamma1 );
 
  630       if ( iota > a360 - gamma1 )
 
  634       labelY += -labelHeight + labelHeight * iota / ( 2 * gamma1 );
 
  638     else if ( angleToCandidate < a90 - gamma2 )  
 
  640       labelX += distanceToLabel * std::cos( angleToCandidate );
 
  641       labelY += distanceToLabel * std::sin( angleToCandidate );
 
  644     else if ( angleToCandidate < a90 + gamma2 ) 
 
  647       labelX += -labelWidth * ( angleToCandidate - a90 + gamma2 ) / ( 2 * gamma2 );
 
  648       labelY += distanceToLabel;
 
  651     else if ( angleToCandidate < a180 - gamma1 )  
 
  653       labelX += distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
 
  654       labelY += distanceToLabel * std::sin( angleToCandidate );
 
  657     else if ( angleToCandidate < a180 + gamma1 ) 
 
  659       labelX += -distanceToLabel - labelWidth;
 
  661       labelY += - ( angleToCandidate - a180 + gamma1 ) * labelHeight / ( 2 * gamma1 );
 
  664     else if ( angleToCandidate < a270 - gamma2 ) 
 
  666       labelX += distanceToLabel * std::cos( angleToCandidate ) - labelWidth;
 
  667       labelY += distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
 
  670     else if ( angleToCandidate < a270 + gamma2 ) 
 
  672       labelY += -distanceToLabel - labelHeight;
 
  674       labelX += -labelWidth + ( angleToCandidate - a270 + gamma2 ) * labelWidth / ( 2 * gamma2 );
 
  677     else if ( angleToCandidate < a360 ) 
 
  679       labelX += distanceToLabel * std::cos( angleToCandidate );
 
  680       labelY += distanceToLabel * std::sin( angleToCandidate ) - labelHeight;
 
  686     if ( maxNumberCandidates == 1 )
 
  689       cost = 0.0001 + 0.0020 * double( icost ) / double( maxNumberCandidates - 1 );
 
  700     lPos.emplace_back( std::make_unique< LabelPosition >( 
id + i, labelX, labelY, labelWidth, labelHeight, 
angle, cost, 
this, 
false, quadrant ) );
 
  701     numberCandidatesGenerated++;
 
  705     if ( icost == 
static_cast< int >( maxNumberCandidates ) )
 
  707       icost = 
static_cast< int >( maxNumberCandidates ) - 1;
 
  710     else if ( icost > 
static_cast< int >( maxNumberCandidates ) )
 
  712       icost = 
static_cast< int >( maxNumberCandidates ) - 2;
 
  718   return numberCandidatesGenerated;
 
  725     double shapeLength = mapShape->
length();
 
  736   std::size_t candidates = 0;
 
  742   if ( candidates < candidateTargetCount )
 
  757   std::vector< double > &
x = line->
x;
 
  758   std::vector< double > &
y = line->
y;
 
  760   std::vector< double > segmentLengths( 
nbPoints - 1 ); 
 
  761   std::vector< double >distanceToSegment( 
nbPoints ); 
 
  763   double totalLineLength = 0.0; 
 
  764   for ( 
int i = 0; i < line->
nbPoints - 1; i++ )
 
  767       distanceToSegment[i] = 0;
 
  769       distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
  772     totalLineLength += segmentLengths[i];
 
  774   distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
  777   double lineStepDistance = 0;
 
  780   double currentDistanceAlongLine = lineStepDistance;
 
  784       lineStepDistance = totalLineLength / ( candidateTargetCount + 1 ); 
 
  788       currentDistanceAlongLine = lineAnchorPoint;
 
  789       lineStepDistance = -1;
 
  793   double candidateCenterX, candidateCenterY;
 
  795   while ( currentDistanceAlongLine <= totalLineLength )
 
  797     if ( 
pal->isCanceled() )
 
  802     line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateCenterX, &candidateCenterY );
 
  805     double cost = std::fabs( lineAnchorPoint - currentDistanceAlongLine ) / totalLineLength; 
 
  808     lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateCenterX - labelWidth / 2, candidateCenterY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this, 
false, 
LabelPosition::QuadrantOver ) );
 
  810     currentDistanceAlongLine += lineStepDistance;
 
  814     if ( lineStepDistance < 0 )
 
  828     flags = QgsLabeling::LinePlacementFlag::OnLine; 
 
  831   QVector< int > extremeAngleNodes;
 
  834   std::vector< double > &
x = line->
x;
 
  835   std::vector< double > &
y = line->
y;
 
  839   for ( 
int i = 1; i <= numberNodes - ( closedLine ? 1 : 2 ); ++i )
 
  841     double x1 = 
x[i - 1];
 
  843     double x3 = 
x[ i == numberNodes - 1 ? 1 : i + 1]; 
 
  844     double y1 = 
y[i - 1];
 
  846     double y3 = 
y[ i == numberNodes - 1 ? 1 : i + 1]; 
 
  851     double vertexAngle = M_PI - ( std::atan2( y3 - y2, x3 - x2 ) - std::atan2( y2 - y1, x2 - x1 ) );
 
  855     if ( vertexAngle < M_PI * 135.0 / 180.0 || vertexAngle > M_PI * 225.0 / 180.0 )
 
  856       extremeAngleNodes << i;
 
  858   extremeAngleNodes << numberNodes - 1;
 
  860   if ( extremeAngleNodes.isEmpty() )
 
  867   std::vector< double > segmentLengths( numberNodes - 1 ); 
 
  868   std::vector< double > distanceToSegment( numberNodes ); 
 
  869   double totalLineLength = 0.0;
 
  870   QVector< double > straightSegmentLengths;
 
  871   QVector< double > straightSegmentAngles;
 
  872   straightSegmentLengths.reserve( extremeAngleNodes.size() + 1 );
 
  873   straightSegmentAngles.reserve( extremeAngleNodes.size() + 1 );
 
  874   double currentStraightSegmentLength = 0;
 
  875   double longestSegmentLength = 0;
 
  876   int segmentIndex = 0;
 
  877   double segmentStartX = 
x[0];
 
  878   double segmentStartY = 
y[0];
 
  879   for ( 
int i = 0; i < numberNodes - 1; i++ )
 
  882       distanceToSegment[i] = 0;
 
  884       distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
  887     totalLineLength += segmentLengths[i];
 
  888     if ( extremeAngleNodes.contains( i ) )
 
  891       straightSegmentLengths << currentStraightSegmentLength;
 
  893       longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
 
  895       currentStraightSegmentLength = 0;
 
  896       segmentStartX = 
x[i];
 
  897       segmentStartY = 
y[i];
 
  899     currentStraightSegmentLength += segmentLengths[i];
 
  901   distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
  902   straightSegmentLengths << currentStraightSegmentLength;
 
  904   longestSegmentLength = std::max( longestSegmentLength, currentStraightSegmentLength );
 
  907   if ( totalLineLength < labelWidth )
 
  913   double lineStepDistance = ( totalLineLength - labelWidth ); 
 
  914   lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
 
  916   double distanceToEndOfSegment = 0.0;
 
  917   int lastNodeInSegment = 0;
 
  919   for ( 
int i = 0; i < straightSegmentLengths.count(); ++i )
 
  921     currentStraightSegmentLength = straightSegmentLengths.at( i );
 
  922     double currentSegmentAngle = straightSegmentAngles.at( i );
 
  923     lastNodeInSegment = extremeAngleNodes.at( i );
 
  924     double distanceToStartOfSegment = distanceToEndOfSegment;
 
  925     distanceToEndOfSegment = distanceToSegment[ lastNodeInSegment ];
 
  926     double distanceToCenterOfSegment = 0.5 * ( distanceToEndOfSegment + distanceToStartOfSegment );
 
  928     if ( currentStraightSegmentLength < labelWidth )
 
  932     double currentDistanceAlongLine = distanceToStartOfSegment;
 
  933     double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
 
  934     double candidateLength = 0.0;
 
  940     double segmentCost = 1.0 - ( distanceToEndOfSegment - distanceToStartOfSegment ) / longestSegmentLength; 
 
  941     double segmentAngleCost = 1 - std::fabs( std::fmod( currentSegmentAngle, M_PI ) - M_PI_2 ) / M_PI_2; 
 
  943     while ( currentDistanceAlongLine + labelWidth < distanceToEndOfSegment )
 
  945       if ( 
pal->isCanceled() )
 
  951       line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateStartX, &candidateStartY );
 
  952       line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
 
  954       candidateLength = std::sqrt( ( candidateEndX - candidateStartX ) * ( candidateEndX - candidateStartX ) + ( candidateEndY - candidateStartY ) * ( candidateEndY - candidateStartY ) );
 
  960       cost = candidateLength / labelWidth;
 
  966         cost = ( 1 - cost ) / 100; 
 
  970       double labelCenter = currentDistanceAlongLine + labelWidth / 2.0;
 
  972       if ( placementIsFlexible )
 
  975         double costCenter = 2 * std::fabs( labelCenter - distanceToCenterOfSegment ) / ( distanceToEndOfSegment - distanceToStartOfSegment ); 
 
  976         cost += costCenter * 0.0005;  
 
  984         double costLineCenter = 2 * std::fabs( labelCenter - lineAnchorPoint ) / totalLineLength;  
 
  985         cost += costLineCenter * 0.0005;  
 
  988       if ( placementIsFlexible )
 
  990         cost += segmentCost * 0.0005; 
 
  991         cost += segmentAngleCost * 0.0001; 
 
  999         angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
 
 1003       beta = 
angle + M_PI_2;
 
 1008         bool isRightToLeft = ( 
angle > M_PI_2 || 
angle <= -M_PI_2 );
 
 1010         bool reversed = ( ( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ? isRightToLeft : 
false );
 
 1011         bool aboveLine = ( !reversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) ) || ( reversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) );
 
 1012         bool belowLine = ( !reversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) ) || ( reversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) );
 
 1018             const double candidateCost = cost + ( reversed ? 0 : 0.001 );
 
 1019             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 ) ); 
 
 1026             const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); 
 
 1027             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 ) ); 
 
 1030         if ( flags & QgsLabeling::LinePlacementFlag::OnLine )
 
 1034             const double candidateCost = cost + 0.002;
 
 1035             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 ) ); 
 
 1041         lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this, 
false, 
LabelPosition::QuadrantOver ) ); 
 
 1048       currentDistanceAlongLine += lineStepDistance;
 
 1067     flags = QgsLabeling::LinePlacementFlag::OnLine; 
 
 1071   std::vector< double > &
x = line->
x;
 
 1072   std::vector< double > &
y = line->
y;
 
 1074   std::vector< double > segmentLengths( 
nbPoints - 1 ); 
 
 1075   std::vector< double >distanceToSegment( 
nbPoints ); 
 
 1077   double totalLineLength = 0.0; 
 
 1078   for ( 
int i = 0; i < line->
nbPoints - 1; i++ )
 
 1081       distanceToSegment[i] = 0;
 
 1083       distanceToSegment[i] = distanceToSegment[i - 1] + segmentLengths[i - 1];
 
 1086     totalLineLength += segmentLengths[i];
 
 1088   distanceToSegment[line->
nbPoints - 1] = totalLineLength;
 
 1090   double lineStepDistance = ( totalLineLength - labelWidth ); 
 
 1091   double currentDistanceAlongLine = 0;
 
 1095   if ( totalLineLength > labelWidth )
 
 1097     lineStepDistance = std::min( std::min( labelHeight, labelWidth ), lineStepDistance / candidateTargetCount );
 
 1101     currentDistanceAlongLine = - ( labelWidth - totalLineLength ) / 2.0;
 
 1102     lineStepDistance = -1;
 
 1103     totalLineLength = labelWidth;
 
 1108     currentDistanceAlongLine = std::numeric_limits< double >::max();
 
 1119       currentDistanceAlongLine = std::min( lineAnchorPoint, totalLineLength * 0.99 - labelWidth );
 
 1120       lineStepDistance = -1;
 
 1124   double candidateLength;
 
 1126   double candidateStartX, candidateStartY, candidateEndX, candidateEndY;
 
 1130     if ( 
pal->isCanceled() )
 
 1136     line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine, &candidateStartX, &candidateStartY );
 
 1137     line->
getPointByDistance( segmentLengths.data(), distanceToSegment.data(), currentDistanceAlongLine + labelWidth, &candidateEndX, &candidateEndY );
 
 1139     if ( currentDistanceAlongLine < 0 )
 
 1147       candidateLength = std::sqrt( ( candidateEndX - candidateStartX ) * ( candidateEndX - candidateStartX ) + ( candidateEndY - candidateStartY ) * ( candidateEndY - candidateStartY ) );
 
 1150     cost = candidateLength / labelWidth;
 
 1156       cost = ( 1 - cost ) / 100; 
 
 1160     double costCenter = std::fabs( lineAnchorPoint - ( currentDistanceAlongLine + labelWidth / 2 ) ) / totalLineLength; 
 
 1161     cost += costCenter / 1000;  
 
 1162     cost += initialCost;
 
 1169       angle = std::atan2( candidateEndY - candidateStartY, candidateEndX - candidateStartX );
 
 1173     beta = 
angle + M_PI_2;
 
 1178       bool isRightToLeft = ( 
angle > M_PI_2 || 
angle <= -M_PI_2 );
 
 1180       bool reversed = ( ( flags & QgsLabeling::LinePlacementFlag::MapOrientation ) ? isRightToLeft : 
false );
 
 1181       bool aboveLine = ( !reversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) ) || ( reversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) );
 
 1182       bool belowLine = ( !reversed && ( flags & QgsLabeling::LinePlacementFlag::BelowLine ) ) || ( reversed && ( flags & QgsLabeling::LinePlacementFlag::AboveLine ) );
 
 1188           const double candidateCost = cost + ( !reversed ? 0 : 0.001 ); 
 
 1189           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 ) ); 
 
 1196           const double candidateCost = cost + ( !reversed ? 0.001 : 0 );
 
 1197           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 ) ); 
 
 1200       if ( flags & QgsLabeling::LinePlacementFlag::OnLine )
 
 1204           const double candidateCost = cost + 0.002;
 
 1205           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 ) ); 
 
 1211       lPos.emplace_back( std::make_unique< LabelPosition >( i, candidateStartX - labelWidth / 2, candidateStartY - labelHeight / 2, labelWidth, labelHeight, 0, cost, 
this, 
false, 
LabelPosition::QuadrantOver ) ); 
 
 1218     currentDistanceAlongLine += lineStepDistance;
 
 1222     if ( lineStepDistance < 0 )
 
 1232   Q_ASSERT( metrics );
 
 1235   const double maximumCharacterAngleInside = applyAngleConstraints ? std::fabs( qgis::down_cast< QgsTextLabelFeature *>( 
mLF )->maximumCharacterAngleInside() ) : -1;
 
 1236   const double maximumCharacterAngleOutside = applyAngleConstraints ? std::fabs( qgis::down_cast< QgsTextLabelFeature *>( 
mLF )->maximumCharacterAngleOutside() ) : -1;
 
 1238   std::unique_ptr< QgsTextRendererUtils::CurvePlacementProperties > placement(
 
 1242   labeledLineSegmentIsRightToLeft = placement->flippedCharacterPlacementToGetUprightLabels;
 
 1244   if ( placement->graphemePlacement.empty() )
 
 1247   auto it = placement->graphemePlacement.constBegin();
 
 1248   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 );
 
 1249   firstPosition->setUpsideDownCharCount( placement->upsideDownCharCount );
 
 1250   firstPosition->setPartId( it->graphemeIndex );
 
 1253   while ( it != placement->graphemePlacement.constEnd() )
 
 1255     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 );
 
 1256     position->setPartId( it->graphemeIndex );
 
 1259     previousPosition->
setNextPart( std::move( position ) );
 
 1260     previousPosition = nextPosition;
 
 1264   return firstPosition;
 
 1276   const int characterCount = li->
count();
 
 1277   if ( characterCount == 0 )
 
 1283   double totalCharacterWidth = 0;
 
 1284   for ( 
int i = 0; i < characterCount; ++i )
 
 1287   std::unique_ptr< PointSet > expanded;
 
 1288   double shapeLength = mapShape->
length();
 
 1291     allowOverrun = 
false;
 
 1297   if ( totalCharacterWidth > shapeLength )
 
 1299     if ( !allowOverrun || shapeLength < totalCharacterWidth - 2 * overrun )
 
 1306   if ( allowOverrun && overrun > 0 )
 
 1309     expanded = mapShape->
clone();
 
 1311     mapShape = expanded.get();
 
 1316     flags = QgsLabeling::LinePlacementFlag::OnLine; 
 
 1317   const bool hasAboveBelowLinePlacement = flags & QgsLabeling::LinePlacementFlag::AboveLine || flags & QgsLabeling::LinePlacementFlag::BelowLine;
 
 1319   std::unique_ptr< PointSet > mapShapeOffsetPositive;
 
 1320   std::unique_ptr< PointSet > mapShapeOffsetNegative;
 
 1321   if ( hasAboveBelowLinePlacement && !
qgsDoubleNear( offsetDistance, 0 ) )
 
 1324     mapShapeOffsetPositive = mapShape->
clone();
 
 1325     mapShapeOffsetNegative = mapShape->
clone();
 
 1326     if ( offsetDistance >= 0.0 )
 
 1328       mapShapeOffsetPositive->offsetCurveByDistance( offsetDistance );
 
 1329       mapShapeOffsetNegative->offsetCurveByDistance( offsetDistance * -1 );
 
 1334       if ( flags & QgsLabeling::LinePlacementFlag::AboveLine
 
 1335            && !( flags & QgsLabeling::LinePlacementFlag::BelowLine ) )
 
 1337         flags &= ~
QgsLabeling::LinePlacementFlag::AboveLine;
 
 1338         flags |= QgsLabeling::LinePlacementFlag::BelowLine;
 
 1340       else if ( flags & QgsLabeling::LinePlacementFlag::BelowLine
 
 1341                 && !( flags & QgsLabeling::LinePlacementFlag::AboveLine ) )
 
 1343         flags &= ~
QgsLabeling::LinePlacementFlag::BelowLine;
 
 1344         flags |= QgsLabeling::LinePlacementFlag::AboveLine;
 
 1346       mapShapeOffsetPositive->offsetCurveByDistance( offsetDistance * -1 );
 
 1347       mapShapeOffsetNegative->offsetCurveByDistance( offsetDistance );
 
 1351   std::vector< std::unique_ptr< LabelPosition >> positions;
 
 1354     PointSet *currentMapShape = 
nullptr;
 
 1357       currentMapShape = mapShapeOffsetPositive.get();
 
 1359     if ( offset == 
NoOffset && flags & QgsLabeling::LinePlacementFlag::OnLine )
 
 1361       currentMapShape = mapShape;
 
 1365       currentMapShape = mapShapeOffsetNegative.get();
 
 1367     if ( !currentMapShape )
 
 1371     const auto [ pathDistances, totalDistance ] = currentMapShape->
edgeDistances();
 
 1377     if ( 
pal->isCanceled() )
 
 1381     double delta = std::max( li->
characterHeight() / 6, totalDistance / candidateTargetCount );
 
 1384     double distanceAlongLineToStartCandidate = 0;
 
 1385     bool singleCandidateOnly = 
false;
 
 1392         distanceAlongLineToStartCandidate = std::min( lineAnchorPoint, totalDistance * 0.99 - 
getLabelWidth() );
 
 1393         singleCandidateOnly = 
true;
 
 1397     for ( ; distanceAlongLineToStartCandidate <= totalDistance; distanceAlongLineToStartCandidate += delta )
 
 1399       if ( 
pal->isCanceled() )
 
 1403       bool labeledLineSegmentIsRightToLeft = 
false;
 
 1405       std::unique_ptr< LabelPosition > labelPosition = 
curvedPlacementAtOffset( currentMapShape, pathDistances, direction, distanceAlongLineToStartCandidate, labeledLineSegmentIsRightToLeft, !singleCandidateOnly );
 
 1407       if ( !labelPosition )
 
 1409       if ( ( offset != 
NoOffset ) && !labeledLineSegmentIsRightToLeft && !( flags & QgsLabeling::LinePlacementFlag::AboveLine ) )
 
 1411       if ( ( offset != 
NoOffset ) && labeledLineSegmentIsRightToLeft && !( flags & QgsLabeling::LinePlacementFlag::BelowLine ) )
 
 1415       const double angleDiff = labelPosition->angleDifferential();
 
 1416       const double angleDiffAvg = characterCount > 1 ? ( angleDiff / ( characterCount - 1 ) ) : 0; 
 
 1421       double cost = angleDiffAvg / 100; 
 
 1422       if ( cost < 0.0001 )
 
 1426       double labelCenter = distanceAlongLineToStartCandidate + 
getLabelWidth() / 2;
 
 1427       double costCenter = std::fabs( lineAnchorPoint - labelCenter ) / totalDistance; 
 
 1428       cost += costCenter / ( anchorIsFlexiblePlacement ? 100 : 10 );  
 
 1430       const bool isBelow = ( offset != 
NoOffset ) && labeledLineSegmentIsRightToLeft;
 
 1442       labelPosition->setCost( cost );
 
 1444       std::unique_ptr< LabelPosition > p = std::make_unique< LabelPosition >( *labelPosition );
 
 1449         while ( within && currentPos )
 
 1452           currentPos = currentPos->
nextPart();
 
 1461         positions.emplace_back( std::move( p ) );
 
 1463       if ( singleCandidateOnly )
 
 1468   for ( std::unique_ptr< LabelPosition > &pos : positions )
 
 1470     lPos.emplace_back( std::move( pos ) );
 
 1473   return positions.size();
 
 1497   const double totalArea = 
area();
 
 1499   mapShape->
parent = 
nullptr;
 
 1501   if ( 
pal->isCanceled() )
 
 1504   QLinkedList<PointSet *> shapes_final = 
splitPolygons( mapShape, labelWidth, labelHeight );
 
 1506   QgsDebugMsg( QStringLiteral( 
"PAL split polygons resulted in:" ) );
 
 1507   for ( 
PointSet *ps : shapes_final )
 
 1513   std::size_t nbp = 0;
 
 1515   if ( !shapes_final.isEmpty() )
 
 1523     double diago = std::sqrt( labelWidth * labelWidth / 4.0 + labelHeight * labelHeight / 4 );
 
 1525     std::vector< OrientedConvexHullBoundingBox > boxes;
 
 1526     boxes.reserve( shapes_final.size() );
 
 1529     while ( !shapes_final.isEmpty() )
 
 1531       PointSet *shape = shapes_final.takeFirst();
 
 1535         boxes.emplace_back( box );
 
 1541     if ( 
pal->isCanceled() )
 
 1545     double densityY = densityX;
 
 1552     std::size_t numberCandidatesGenerated = 0;
 
 1567         double dx = densityX;
 
 1568         double dy = densityY;
 
 1569         if ( numTry == 0 && maxPolygonCandidates > 0 )
 
 1572           const double boxArea = box.width * box.length;
 
 1573           double maxThisBox = targetPolygonCandidates * boxArea / totalArea;
 
 1574           dx = std::max( dx, std::sqrt( boxArea / maxThisBox ) * 0.8 );
 
 1578         if ( 
pal->isCanceled() )
 
 1579           return numberCandidatesGenerated;
 
 1598         bool enoughPlace = 
false;
 
 1602           px = ( box.x[0] + box.x[2] ) / 2 - labelWidth;
 
 1603           py = ( box.y[0] + box.y[2] ) / 2 - labelHeight;
 
 1609           for ( rx = px, i = 0; i < 2; rx = rx + 2 * labelWidth, i++ )
 
 1611             for ( ry = py, j = 0; j < 2; ry = ry + 2 * labelHeight, j++ )
 
 1615                 enoughPlace = 
false;
 
 1631         else if ( box.length > 1.5 * labelWidth && box.width > 1.5 * labelWidth )
 
 1633           if ( box.alpha <= M_PI_4 )
 
 1639             alpha = box.alpha - M_PI_2;
 
 1642         else if ( box.length > box.width )
 
 1644           alpha = box.alpha - M_PI_2;
 
 1651         beta  = std::atan2( labelHeight, labelWidth ) + alpha;
 
 1657         dlx = std::cos( beta ) * diago;
 
 1658         dly = std::sin( beta ) * diago;
 
 1660         double px0 = box.width / 2.0;
 
 1661         double py0 = box.length / 2.0;
 
 1663         px0 -= std::ceil( px0 / dx ) * dx;
 
 1664         py0 -= std::ceil( py0 / dy ) * dy;
 
 1666         for ( px = px0; px <= box.width; px += dx )
 
 1668           if ( 
pal->isCanceled() )
 
 1671           for ( py = py0; py <= box.length; py += dy )
 
 1674             rx = std::cos( box.alpha ) * px + std::cos( box.alpha - M_PI_2 ) * py;
 
 1675             ry = std::sin( box.alpha ) * px + std::sin( box.alpha - M_PI_2 ) * py;
 
 1685                 lPos.emplace_back( std::make_unique< LabelPosition >( 
id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, 
this, 
false, 
LabelPosition::QuadrantOver ) );
 
 1686                 numberCandidatesGenerated++;
 
 1697                 std::unique_ptr< LabelPosition > potentialCandidate = std::make_unique< LabelPosition >( 
id++, rx - dlx, ry - dly, labelWidth, labelHeight, alpha, 0.0001, 
this, 
false, 
LabelPosition::QuadrantOver );
 
 1699                 lPos.emplace_back( std::move( potentialCandidate ) );
 
 1700                 numberCandidatesGenerated++;
 
 1707       nbp = numberCandidatesGenerated;
 
 1708       if ( maxPolygonCandidates > 0 && nbp < targetPolygonCandidates )
 
 1719     while ( numTry < maxTry );
 
 1721     nbp = numberCandidatesGenerated;
 
 1735   std::size_t candidatesCreated = 0;
 
 1795   const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( gg.get() );
 
 1797     return candidatesCreated;
 
 1801     return candidatesCreated;
 
 1805   const double ringLength = ring->
length();
 
 1806   const double circleArea = std::pow( ringLength, 2 ) / ( 4 * M_PI );
 
 1808   const std::size_t targetPolygonCandidates = std::max( 
static_cast< std::size_t 
>( 16 ), maxPolygonCandidates > 0 ? std::min( maxPolygonCandidates,  candidatesForArea ) : candidatesForArea );
 
 1811   const double delta = ringLength / targetPolygonCandidates;
 
 1814   const double maxDistCentroidToLabelX = std::max( 
xmax - cx, cx - 
xmin ) + distanceToLabel;
 
 1815   const double maxDistCentroidToLabelY = std::max( 
ymax - cy, cy - 
ymin ) + distanceToLabel;
 
 1816   const double estimateOfMaxPossibleDistanceCentroidToLabel = std::sqrt( maxDistCentroidToLabelX * maxDistCentroidToLabelX + maxDistCentroidToLabelY * maxDistCentroidToLabelY );
 
 1819   const double labelAngle = 0;
 
 1821   std::size_t i = lPos.size();
 
 1829     createCandidateAtOrderedPositionOverPoint( labelX, labelY, quadrant, 
x, 
y, labelWidth, labelHeight, position, distanceToLabel * 0.5, visualMargin, 0, 0 );
 
 1831     std::unique_ptr< LabelPosition > candidate = std::make_unique< LabelPosition >( i, labelX, labelY, labelWidth, labelHeight, labelAngle, 0, 
this, 
false, quadrant );
 
 1832     if ( candidate->intersects( preparedBuffer.get() ) )
 
 1850     const double centroidDistance = candidate->getDistanceToPoint( cx, cy );
 
 1851     const double centroidCost = centroidDistance / estimateOfMaxPossibleDistanceCentroidToLabel;
 
 1852     candidate->setCost( centroidCost );
 
 1854     lPos.emplace_back( std::move( candidate ) );
 
 1855     candidatesCreated++;
 
 1860                                       double startSegmentX, 
double startSegmentY, 
double, 
double,
 
 1861                                       double endSegmentX, 
double endSegmentY, 
double, 
double )
 
 1864     float angle = atan2( 
static_cast< float >( endSegmentY - startSegmentY ), 
static_cast< float >( endSegmentX - startSegmentX ) ) * 180 / M_PI;
 
 1874     else if ( 
angle <= 85 )
 
 1878     else if ( 
angle <= 90 )
 
 1884     else if ( 
angle <= 95 )
 
 1889     else if ( 
angle <= 175 )
 
 1893     else if ( 
angle <= 180 )
 
 1899     else if ( 
angle <= 185 )
 
 1904     else if ( 
angle <= 265 )
 
 1908     else if ( 
angle <= 270 )
 
 1913     else if ( 
angle <= 275 )
 
 1918     else if ( 
angle <= 355 )
 
 1928     return !
pal->isCanceled();
 
 1931   return candidatesCreated;
 
 1936   std::vector< std::unique_ptr< LabelPosition > > lPos;
 
 1956       case GEOS_LINESTRING:
 
 1970         const bool allowOutside = 
mLF->
polygonPlacementFlags() & QgsLabeling::PolygonPlacementFlag::AllowPlacementOutsideOfPolygon;
 
 1971         const bool allowInside =  
mLF->
polygonPlacementFlags() & QgsLabeling::PolygonPlacementFlag::AllowPlacementInsideOfPolygon;
 
 1979         else if ( allowOutside && ( std::fabs( 
xmax - 
xmin ) < labelWidth ||
 
 1980                                     std::fabs( 
ymax - 
ymin ) < labelHeight ) )
 
 1987           std::size_t created = 0;
 
 2045   int geomType = GEOSGeomTypeId_r( ctxt, 
mGeos );
 
 2047   double sizeCost = 0;
 
 2048   if ( geomType == GEOS_LINESTRING )
 
 2050     const double l = 
length();
 
 2053     double bbox_length = std::max( bbx[2] - bbx[0], bby[2] - bby[0] );
 
 2054     if ( l >= bbox_length / 4 )
 
 2057     sizeCost = 1 - ( l / ( bbox_length / 4 ) ); 
 
 2059   else if ( geomType == GEOS_POLYGON )
 
 2061     const double a = 
area();
 
 2064     double bbox_area = ( bbx[2] - bbx[0] ) * ( bby[2] - bby[0] );
 
 2065     if ( a >= bbox_area / 16 )
 
 2068     sizeCost = 1 - ( a / ( bbox_area / 16 ) ); 
 
 2074   for ( std::unique_ptr< LabelPosition > &pos : lPos )
 
 2076     pos->setCost( pos->cost() + sizeCost / 100 );
 
 2087   const double x1first = 
x.front();
 
 2088   const double x1last = 
x.back();
 
 2089   const double x2first = p2->
x.front();
 
 2090   const double x2last = p2->
x.back();
 
 2091   const double y1first = 
y.front();
 
 2092   const double y1last = 
y.back();
 
 2093   const double y2first = p2->
y.front();
 
 2094   const double y2last = p2->
y.back();
 
 2102   if ( ( !p2startTouches && !p2endTouches ) || ( p2startTouches && p2endTouches ) )
 
 2108   const double p2otherX = p2startTouches ? x2last : x2first;
 
 2109   const double p2otherY = p2startTouches ? y2last : y2first;
 
 2113   GEOSCoordSequence *coord = GEOSCoordSeq_create_r( geosctxt, 1, 2 );
 
 2114 #if GEOS_VERSION_MAJOR>3 || GEOS_VERSION_MINOR>=8 
 2115   GEOSCoordSeq_setXY_r( geosctxt, coord, 0, p2otherX, p2otherY );
 
 2117   GEOSCoordSeq_setX_r( geosctxt, coord, 0, p2otherX );
 
 2118   GEOSCoordSeq_setY_r( geosctxt, coord, 0, p2otherY );
 
 2124     return ( GEOSPreparedIntersects_r( geosctxt, 
preparedGeom(), p2OtherEnd.get() ) != 1 );
 
 2126   catch ( GEOSException &e )
 
 2128     qWarning( 
"GEOS exception: %s", e.what() );
 
 2138   if ( !other->
mGeos )
 
 2144     GEOSGeometry *g1 = GEOSGeom_clone_r( ctxt, 
mGeos );
 
 2145     GEOSGeometry *g2 = GEOSGeom_clone_r( ctxt, other->
mGeos );
 
 2146     GEOSGeometry *geoms[2] = { g1, g2 };
 
 2147     geos::unique_ptr g( GEOSGeom_createCollection_r( ctxt, GEOS_MULTILINESTRING, geoms, 2 ) );
 
 2150     if ( GEOSGeomTypeId_r( ctxt, gTmp.get() ) != GEOS_LINESTRING )
 
 2158     mGeos = gTmp.release();
 
 2167   catch ( GEOSException &e )
 
 2169     qWarning( 
"GEOS exception: %s", e.what() );
 
 2190   bool uprightLabel = 
false;
 
 2195       uprightLabel = 
true;
 
 2201         uprightLabel = 
true;
 
 2207       uprightLabel = 
true;
 
 2209   return uprightLabel;
 
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...
QVector< QgsPalLayerSettings::PredefinedPointPosition > predefinedPositionOrder() const
Returns the priority ordered list of predefined positions for label candidates.
pal::Layer * layer() const
Gets PAL layer of the label feature. Should be only used internally in PAL.
double fixedAngle() const
Angle in degrees of the fixed angle (relevant only if hasFixedAngle() returns true)
const QSizeF & symbolSize() const
Returns the size of the rendered symbol associated with this feature, if applicable.
QgsPalLayerSettings::OffsetType offsetType() const
Returns the offset type, which determines how offsets and distance to label behaves.
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.
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 QgsMargins & visualMargin() const
Returns the visual margin for the label feature.
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.
const GEOSPreparedGeometry * permissibleZonePrepared() const
Returns a GEOS prepared geometry representing the label's permissibleZone().
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...
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).
@ PerimeterCurved
Arranges candidates following the curvature of a polygon's boundary. Applies to polygon layers only.
@ Horizontal
Arranges horizontal candidates scattered throughout a polygon feature. Applies to polygon layers only...
@ Free
Arranges candidates scattered throughout a polygon feature. Candidates are rotated to respect the pol...
@ 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'...
@ OrderedPositionsAroundPoint
Candidates are placed in predefined positions around a point. Preference is given to positions with g...
@ OutsidePolygons
Candidates are placed outside of polygon boundaries. Applies to polygon layers only....
PredefinedPointPosition
Positions for labels when using the QgsPalLabeling::OrderedPositionsAroundPoint placement mode.
@ BottomSlightlyLeft
Label below point, slightly left of center.
@ BottomMiddle
Label directly below point.
@ BottomSlightlyRight
Label below point, slightly right of center.
@ MiddleLeft
Label on left of point.
@ TopSlightlyRight
Label on top of point, slightly right of center.
@ TopSlightlyLeft
Label on top of point, slightly left of center.
@ MiddleRight
Label on right of point.
@ TopMiddle
Label directly above point.
@ BottomRight
Label on bottom right of point.
@ BottomLeft
Label on bottom-left of point.
@ TopRight
Label on top-right of point.
@ TopLeft
Label on top-left of point.
@ FromSymbolBounds
Offset distance applies from rendered symbol bounds.
A class to represent a 2D point.
Contains precalculated properties regarding text metrics for text to be renderered at a later stage.
double characterHeight() const
Character height (actually font metrics height, not individual character height).
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 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.
void addSizePenalty(std::vector< std::unique_ptr< LabelPosition > > &lPos, double bbx[4], double bby[4])
Increases the cost of the label candidates for this feature, based on the size of the feature.
std::unique_ptr< LabelPosition > curvedPlacementAtOffset(PointSet *mapShape, const std::vector< double > &pathDistances, QgsTextRendererUtils::LabelLineDirection direction, double distance, bool &labeledLineSegmentIsRightToLeft, bool applyAngleConstraints)
Returns the label position for a curved label at a specific offset along a path.
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.
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 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.
QgsLabelFeature * feature()
Returns the parent feature.
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.
LabelPosition * nextPart() const
Returns 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.
A set of features which influence the labeling process.
QgsPalLayerSettings::Placement arrangement() const
Returns the layer's arrangement policy.
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 ...
std::size_t maximumPointLabelCandidates() const
Returns the maximum number of point label candidates to generate for features in this layer.
bool centroidInside() const
Returns whether labels placed at the centroid of features within the layer are forced to be placed in...
UpsideDownLabels upsidedownLabels() const
Returns how upside down labels are handled within the layer.
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.
std::unique_ptr< PointSet > clone() const
Returns a copy of the point set.
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 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 getPointByDistance(double *d, double *ad, double dl, double *px, double *py)
Gets a point a set distance along a line geometry.
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, QgsPalLayerSettings::PredefinedPointPosition position, double distanceToLabel, const QgsMargins &visualMargin, double symbolWidthOffset, double symbolHeightOffset)
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.