50    QgsLinearReferencingSymbolLayerLabelProvider()
 
   61    ~QgsLinearReferencingSymbolLayerLabelProvider()
 
   63      qDeleteAll( mLabels );
 
   66    void addLabel( 
const QPointF &painterPoint, 
double angleRadians, 
const QString &text, 
QgsRenderContext &context, 
const QgsTextFormat &format )
 
   77      auto feature = std::make_unique< QgsTextLabelFeatureWithFormat >( mLabels.size(),
 
   78                     QgsGeos::asGeos( &mapPoint ), QSizeF( size.width() * uPP, size.height() * uPP ), format );
 
   80      feature->setDocument( doc, documentMetrics );
 
   81      feature->setFixedAngle( angleRadians );
 
   82      feature->setHasFixedAngle( 
true );
 
   85      feature->setQuadOffset( QPointF( 1, 1 ) );
 
   87      mLabels.append( feature.release() );
 
  102      QgsTextLabelFeatureWithFormat *lf = qgis::down_cast<QgsTextLabelFeatureWithFormat *>( label->getFeaturePart()->feature() );
 
  109    QList<QgsLabelFeature *> mLabels;
 
  117  mNumericFormat = std::make_unique< QgsBasicNumericFormat >();
 
 
  124  auto res = std::make_unique< QgsLinearReferencingSymbolLayer >();
 
  128  const double interval = 
properties.value( QStringLiteral( 
"interval" ) ).toDouble( &ok );
 
  131  const double skipMultiples = 
properties.value( QStringLiteral( 
"skip_multiples" ) ).toDouble( &ok );
 
  133    res->setSkipMultiplesOf( skipMultiples );
 
  134  res->setRotateLabels( 
properties.value( QStringLiteral( 
"rotate" ), 
true ).toBool() );
 
  135  res->setShowMarker( 
properties.value( QStringLiteral( 
"show_marker" ), 
false ).toBool() );
 
  142  const QString textFormatXml = 
properties.value( QStringLiteral( 
"text_format" ) ).toString();
 
  143  if ( !textFormatXml.isEmpty() )
 
  147    doc.setContent( textFormatXml );
 
  148    elem = doc.documentElement();
 
  155  const QString numericFormatXml = 
properties.value( QStringLiteral( 
"numeric_format" ) ).toString();
 
  156  if ( !numericFormatXml.isEmpty() )
 
  159    doc.setContent( numericFormatXml );
 
  163  if ( 
properties.contains( QStringLiteral( 
"label_offset" ) ) )
 
  167  if ( 
properties.contains( QStringLiteral( 
"label_offset_unit" ) ) )
 
  171  if ( 
properties.contains( ( QStringLiteral( 
"label_offset_map_unit_scale" ) ) ) )
 
  175  if ( 
properties.contains( QStringLiteral( 
"average_angle_length" ) ) )
 
  177    res->setAverageAngleLength( 
properties[QStringLiteral( 
"average_angle_length" )].toDouble() );
 
  179  if ( 
properties.contains( QStringLiteral( 
"average_angle_unit" ) ) )
 
  183  if ( 
properties.contains( ( QStringLiteral( 
"average_angle_map_unit_scale" ) ) ) )
 
  188  return res.release();
 
 
  193  auto res = std::make_unique< QgsLinearReferencingSymbolLayer >();
 
  194  res->setPlacement( mPlacement );
 
  195  res->setLabelSource( mLabelSource );
 
  196  res->setInterval( mInterval );
 
  197  res->setSkipMultiplesOf( mSkipMultiplesOf );
 
  198  res->setRotateLabels( mRotateLabels );
 
  199  res->setLabelOffset( mLabelOffset );
 
  200  res->setLabelOffsetUnit( mLabelOffsetUnit );
 
  201  res->setLabelOffsetMapUnitScale( mLabelOffsetMapUnitScale );
 
  202  res->setShowMarker( mShowMarker );
 
  203  res->setAverageAngleLength( mAverageAngleLength );
 
  204  res->setAverageAngleUnit( mAverageAngleLengthUnit );
 
  205  res->setAverageAngleMapUnitScale( mAverageAngleLengthMapUnitScale );
 
  207  res->mTextFormat = mTextFormat;
 
  208  res->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
 
  209  if ( mNumericFormat )
 
  210    res->mNumericFormat.reset( mNumericFormat->clone() );
 
  215  return res.release();
 
 
  220  QDomDocument textFormatDoc;
 
  225  const QDomElement textElem = mTextFormat.
writeXml( textFormatDoc, rwContext );
 
  226  textFormatDoc.appendChild( textElem );
 
  228  QDomDocument numericFormatDoc;
 
  229  QDomElement numericFormatElem = numericFormatDoc.createElement( QStringLiteral( 
"numericFormat" ) );
 
  230  mNumericFormat->writeXml( numericFormatElem, numericFormatDoc, rwContext );
 
  231  numericFormatDoc.appendChild( numericFormatElem );
 
  242      QStringLiteral( 
"interval" ), mInterval
 
  245      QStringLiteral( 
"rotate" ), mRotateLabels
 
  248      QStringLiteral( 
"show_marker" ), mShowMarker
 
  251      QStringLiteral( 
"text_format" ), textFormatDoc.toString()
 
  254      QStringLiteral( 
"numeric_format" ), numericFormatDoc.toString()
 
  266      QStringLiteral( 
"average_angle_length" ), mAverageAngleLength
 
  276  if ( mSkipMultiplesOf >= 0 )
 
  278    res.insert( QStringLiteral( 
"skip_multiples" ), mSkipMultiplesOf );
 
 
  286  return QStringLiteral( 
"LinearReferencing" );
 
 
  297  return mShowMarker ? mMarkerSymbol.get() : 
nullptr;
 
 
  304    mMarkerSymbol.reset( qgis::down_cast<QgsMarkerSymbol *>( symbol ) );
 
 
  318    mMarkerSymbol->setRenderHints( hints );
 
  327    QgsLinearReferencingSymbolLayerLabelProvider *provider = 
new QgsLinearReferencingSymbolLayerLabelProvider();
 
  328    mLabelProviderId = labelingEngine->addProvider( provider );
 
 
  340void QgsLinearReferencingSymbolLayer::renderGeometryPart( 
QgsSymbolRenderContext &context, 
const QgsAbstractGeometry *geometry, 
double labelOffsetPainterUnitsX, 
double labelOffsetPainterUnitsY, 
double skipMultiples, 
double averageAngleDistancePainterUnits, 
bool showMarker )
 
  342  if ( 
const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( geometry ) )
 
  344    renderLineString( context, line, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits, 
showMarker );
 
  346  else if ( 
const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( geometry ) )
 
  348    renderLineString( context, qgsgeometry_cast< const QgsLineString *>( polygon->exteriorRing() ), labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits, 
showMarker );
 
  349    for ( 
int i = 0; i < polygon->numInteriorRings(); ++i )
 
  351      renderLineString( context, qgsgeometry_cast< const QgsLineString *>( polygon->interiorRing( i ) ), labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits, 
showMarker );
 
  356void QgsLinearReferencingSymbolLayer::renderLineString( 
QgsSymbolRenderContext &context, 
const QgsLineString *line, 
double labelOffsetPainterUnitsX, 
double labelOffsetPainterUnitsY, 
double skipMultiples, 
double averageAngleDistancePainterUnits, 
bool showMarker )
 
  361  switch ( mPlacement )
 
  366      renderPolylineInterval( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits, 
showMarker );
 
  370      renderPolylineVertex( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits, 
showMarker );
 
  390  double skipMultiples = mSkipMultiplesOf;
 
  397  double labelOffsetX = mLabelOffset.x();
 
  398  double labelOffsetY = mLabelOffset.y();
 
  400  double averageOver = mAverageAngleLength;
 
  416  const double averageAngleDistancePainterUnits = context.
renderContext().
convertToPainterUnits( averageOver, mAverageAngleLengthUnit, mAverageAngleLengthMapUnitScale ) / 2;
 
  420    renderGeometryPart( context, *partIt, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits, 
showMarker );
 
 
  426                               double averageAngleLengthPainterUnits, 
double prevXPainterUnits, 
double prevYPainterUnits,
 
  427                               double thisXPainterUnits, 
double thisYPainterUnits, 
const double *xPainterUnits,
 
  428                               const double *yPainterUnits, 
int totalPoints, 
int i )
 
  432  double painterDistRemaining = averageAngleLengthPainterUnits + targetPointDistanceAlongSegment;
 
  433  double startAverageSegmentX = prevXPainterUnits;
 
  434  double startAverageSegmentY = prevYPainterUnits;
 
  435  double endAverageSegmentX = thisXPainterUnits;
 
  436  double endAverageSegmentY = thisYPainterUnits;
 
  437  double averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
 
  438  const double *xAveragingData = xPainterUnits;
 
  439  const double *yAveragingData = yPainterUnits;
 
  442  while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
 
  444    if ( j >= totalPoints - 1 )
 
  447    painterDistRemaining -= averagingSegmentLengthPainterUnits;
 
  448    startAverageSegmentX = endAverageSegmentX;
 
  449    startAverageSegmentY = endAverageSegmentY;
 
  451    endAverageSegmentX = *xAveragingData++;
 
  452    endAverageSegmentY = *yAveragingData++;
 
  454    averagingSegmentLengthPainterUnits = 
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
 
  457  double endAverageXPainterUnits;
 
  458  double endAverageYPainterUnits;
 
  459  if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
 
  462        nullptr, 
nullptr, 
nullptr,
 
  463        nullptr, 
nullptr, 
nullptr );
 
  467    endAverageXPainterUnits = endAverageSegmentX;
 
  468    endAverageYPainterUnits = endAverageSegmentY;
 
  473  painterDistRemaining = ( segmentLengthPainterUnits - targetPointDistanceAlongSegment ) + averageAngleLengthPainterUnits;
 
  474  startAverageSegmentX = thisXPainterUnits;
 
  475  startAverageSegmentY = thisYPainterUnits;
 
  476  endAverageSegmentX = prevXPainterUnits;
 
  477  endAverageSegmentY = prevYPainterUnits;
 
  478  averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
 
  479  xAveragingData = xPainterUnits - 2;
 
  480  yAveragingData = yPainterUnits - 2;
 
  481  while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
 
  486    painterDistRemaining -= averagingSegmentLengthPainterUnits;
 
  487    startAverageSegmentX = endAverageSegmentX;
 
  488    startAverageSegmentY = endAverageSegmentY;
 
  490    endAverageSegmentX = *xAveragingData--;
 
  491    endAverageSegmentY = *yAveragingData--;
 
  493    averagingSegmentLengthPainterUnits = 
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
 
  496  double startAverageXPainterUnits;
 
  497  double startAverageYPainterUnits;
 
  498  if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
 
  501        nullptr, 
nullptr, 
nullptr,
 
  502        nullptr, 
nullptr, 
nullptr );
 
  506    startAverageXPainterUnits = endAverageSegmentX;
 
  507    startAverageYPainterUnits = endAverageSegmentY;
 
  510  double calculatedAngle = std::fmod( 
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
 
  511  if ( calculatedAngle > 90 && calculatedAngle < 270 )
 
  512    calculatedAngle += 180;
 
  514  return calculatedAngle;
 
 
  517typedef std::function<bool ( 
double x, 
double y, 
double z, 
double m, 
double distanceFromStart, 
double angle )> 
VisitPointFunction;
 
  525  double distanceTraversed = 0;
 
  526  const int totalPoints = line->
numPoints();
 
  527  if ( totalPoints == 0 )
 
  530  const double *x = line->
xData();
 
  531  const double *y = line->
yData();
 
  532  const double *z = line->
is3D() ? line->
zData() : 
nullptr;
 
  535  const double *xPainterUnits = linePainterUnits->
xData();
 
  536  const double *yPainterUnits = linePainterUnits->
yData();
 
  540  double prevZ = z ? *z++ : 0.0;
 
  541  double prevM = m ? *m++ : 0.0;
 
  543  double prevXPainterUnits = *xPainterUnits++;
 
  544  double prevYPainterUnits = *yPainterUnits++;
 
  548    visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
 
  552  double pZ = std::numeric_limits<double>::quiet_NaN();
 
  553  double pM = std::numeric_limits<double>::quiet_NaN();
 
  554  double nextPointDistance = emitFirstPoint ? 0 : distance;
 
  555  for ( 
int i = 1; i < totalPoints; ++i )
 
  559    double thisZ = z ? *z++ : 0.0;
 
  560    double thisM = m ? *m++ : 0.0;
 
  561    double thisXPainterUnits = *xPainterUnits++;
 
  562    double thisYPainterUnits = *yPainterUnits++;
 
  564    double angle = std::fmod( 
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
 
  565    if ( angle > 90 && angle < 270 )
 
  571    while ( nextPointDistance < distanceTraversed + segmentLength || 
qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength ) )
 
  574      const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
 
  577          z ? &prevZ : 
nullptr, z ? &thisZ : 
nullptr, z ? &pZ : 
nullptr,
 
  578          m ? &prevM : 
nullptr, m ? &thisM : 
nullptr, m ? &pM : nullptr );
 
  580      double calculatedAngle = angle;
 
  581      if ( averageAngleLengthPainterUnits > 0 )
 
  583        const double targetPointFractionAlongSegment = distanceToPoint / segmentLength;
 
  584        const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
 
  587                          averageAngleLengthPainterUnits, prevXPainterUnits, prevYPainterUnits,
 
  588                          thisXPainterUnits, thisYPainterUnits, xPainterUnits,
 
  589                          yPainterUnits, totalPoints, i );
 
  592      if ( !visitPoint( pX, pY, pZ, pM, nextPointDistance, calculatedAngle ) )
 
  595      nextPointDistance += distance;
 
  598    distanceTraversed += segmentLength;
 
  603    prevXPainterUnits = thisXPainterUnits;
 
  604    prevYPainterUnits = thisYPainterUnits;
 
 
  610  return a + ( b - a ) * fraction;
 
 
  619  double distanceTraversed = 0;
 
  620  const int totalPoints = line->
numPoints();
 
  621  if ( totalPoints < 2 )
 
  624  const double *x = line->
xData();
 
  625  const double *y = line->
yData();
 
  626  const double *z = line->
is3D() ? line->
zData() : 
nullptr;
 
  629  const double *xPainterUnits = linePainterUnits->
xData();
 
  630  const double *yPainterUnits = linePainterUnits->
yData();
 
  634  double prevZ = z ? *z++ : 0.0;
 
  635  double prevM = m ? *m++ : 0.0;
 
  637  double prevXPainterUnits = *xPainterUnits++;
 
  638  double prevYPainterUnits = *yPainterUnits++;
 
  642    visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
 
  646  double prevValue = useZ ? prevZ : prevM;
 
  647  bool isFirstPoint = 
true;
 
  648  for ( 
int i = 1; i < totalPoints; ++i )
 
  652    double thisZ = z ? *z++ : 0.0;
 
  653    double thisM = m ? *m++ : 0.0;
 
  654    const double thisValue = useZ ? thisZ : thisM;
 
  655    double thisXPainterUnits = *xPainterUnits++;
 
  656    double thisYPainterUnits = *yPainterUnits++;
 
  658    double angle = std::fmod( 
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
 
  659    if ( angle > 90 && angle < 270 )
 
  666    const int direction = ( thisValue > prevValue ) ? 1 : ( thisValue < prevValue ) ? -1 : 0;
 
  667    if ( direction != 0 )
 
  670      double nextStepValue = direction > 0 ? std::ceil( prevValue / step ) * step
 
  671                             :  std::floor( prevValue / step ) * step;
 
  673      while ( ( direction > 0 && ( nextStepValue <= thisValue || 
qgsDoubleNear( nextStepValue, thisValue ) ) ) ||
 
  674              ( direction < 0 && ( nextStepValue >= thisValue || 
qgsDoubleNear( nextStepValue, thisValue ) ) ) )
 
  676        const double targetPointFractionAlongSegment = ( nextStepValue - prevValue ) / ( thisValue - prevValue );
 
  677        const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
 
  682        const double pZ = useZ ? nextStepValue : 
interpolateValue( prevZ, thisZ, targetPointFractionAlongSegment );
 
  683        const double pM = useZ ? 
interpolateValue( prevM, thisM, targetPointFractionAlongSegment ) : nextStepValue;
 
  685        double calculatedAngle = angle;
 
  686        if ( averageAngleLengthPainterUnits > 0 )
 
  689                              targetPointDistanceAlongSegment,
 
  690                              segmentLengthPainterUnits, averageAngleLengthPainterUnits,
 
  691                              prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits,
 
  692                              xPainterUnits, yPainterUnits,
 
  696        if ( !
qgsDoubleNear( targetPointFractionAlongSegment, 0 ) || isFirstPoint )
 
  698          if ( !visitPoint( pX, pY, pZ, pM, distanceTraversed + segmentLength * targetPointFractionAlongSegment, calculatedAngle ) )
 
  702        nextStepValue += direction * step;
 
  705    else if ( isFirstPoint && emitFirstPoint )
 
  707      if ( !visitPoint( prevX, prevY, prevZ, prevM, distanceTraversed,
 
  711    isFirstPoint = 
false;
 
  717    prevXPainterUnits = thisXPainterUnits;
 
  718    prevYPainterUnits = thisYPainterUnits;
 
  719    prevValue = thisValue;
 
  720    distanceTraversed += segmentLength;
 
 
  731  visitPointsByInterpolatedZM( line, linePainterUnits, emitFirstPoint, distance, averageAngleLengthPainterUnits, visitPoint, 
false );
 
 
  734QPointF QgsLinearReferencingSymbolLayer::pointToPainter( 
QgsSymbolRenderContext &context, 
double x, 
double y, 
double z )
 
  740    pt = QPointF( x, y );
 
  745    pt = QPointF( x, y );
 
  752void QgsLinearReferencingSymbolLayer::renderPolylineInterval( 
const QgsLineString *line, 
QgsSymbolRenderContext &context, 
double skipMultiples, 
const QPointF &labelOffsetPainterUnits, 
double averageAngleLengthPainterUnits, 
bool showMarker )
 
  754  double distance = mInterval;
 
  764  std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
 
  771  const bool hasZ = line->
is3D();
 
  777  switch ( mPlacement )
 
  795  QgsLinearReferencingSymbolLayerLabelProvider *labelProvider = 
nullptr;
 
  800    labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
 
  803  func( line, painterUnitsGeometry.get(), emitFirstPoint, distance, averageAngleLengthPainterUnits, [&context, &numericContext, skipMultiples, 
showMarker,
 
  804                  labelOffsetPainterUnits, hasZ, hasM, labelProvider, 
this]( 
double x, 
double y, 
double z, 
double m, 
double distanceFromStart, 
double angle ) -> 
bool 
  806    if ( context.renderContext().renderingStopped() )
 
  809    double labelValue = 0;
 
  810    bool labelVertex = true;
 
  811    switch ( mLabelSource )
 
  813      case Qgis::LinearReferencingLabelSource::CartesianDistance2D:
 
  814        labelValue = distanceFromStart;
 
  816      case Qgis::LinearReferencingLabelSource::Z:
 
  818        labelVertex = hasZ && !std::isnan( labelValue );
 
  820      case Qgis::LinearReferencingLabelSource::M:
 
  822        labelVertex = hasM && !std::isnan( labelValue );
 
  829    if ( skipMultiples > 0 && 
qgsDoubleNear( std::fmod( labelValue,  skipMultiples ), 0 ) )
 
  832    const QPointF pt = pointToPainter( context, x, y, z );
 
  837        mMarkerSymbol->setLineAngle( 90 - angle );
 
  841    const double angleRadians = ( mRotateLabels ? 
angle : 0 ) * M_PI / 180.0;
 
  842    const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
 
  843    + labelOffsetPainterUnits.y() * std::sin( angleRadians );
 
  844    const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
 
  845    + labelOffsetPainterUnits.y() * std::cos( angleRadians );
 
  847    const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
 
  848    if ( !labelProvider )
 
  856      labelProvider->addLabel(
 
  857        QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
 
  865void QgsLinearReferencingSymbolLayer::renderPolylineVertex( 
const QgsLineString *line, 
QgsSymbolRenderContext &context, 
double skipMultiples, 
const QPointF &labelOffsetPainterUnits, 
double averageAngleLengthPainterUnits, 
bool showMarker )
 
  870  averageAngleLengthPainterUnits = std::max( averageAngleLengthPainterUnits, 0.1 );
 
  875  QgsLinearReferencingSymbolLayerLabelProvider *labelProvider = 
nullptr;
 
  880    labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
 
  883  const double *xData = line->
xData();
 
  884  const double *yData = line->
yData();
 
  885  const double *zData = line->
is3D() ? line->
zData() : 
nullptr;
 
  886  const double *mData = line->
isMeasure() ? line->
mData() : 
nullptr;
 
  891  std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
 
  897  const double *xPainterUnits = painterUnitsGeometry->xData();
 
  898  const double *yPainterUnits = painterUnitsGeometry->yData();
 
  900  double currentDistance = 0;
 
  901  double prevX = *xData;
 
  902  double prevY = *yData;
 
  904  for ( 
int i = 0; i < size; ++i )
 
  909    double thisX = *xData++;
 
  910    double thisY = *yData++;
 
  911    double thisZ = zData ? *zData++ : 0;
 
  912    double thisM = mData ? *mData++ : 0;
 
  913    double thisXPainterUnits = *xPainterUnits++;
 
  914    double thisYPainterUnits = *yPainterUnits++;
 
  917    currentDistance += thisSegmentLength;
 
  919    if ( skipMultiples > 0 && 
qgsDoubleNear( std::fmod( currentDistance,  skipMultiples ), 0 ) )
 
  926    const QPointF pt = pointToPainter( context, thisX, thisY, thisZ );
 
  929    double painterDistRemaining = averageAngleLengthPainterUnits;
 
  930    double startAverageSegmentX = thisXPainterUnits;
 
  931    double startAverageSegmentY = thisYPainterUnits;
 
  933    const double *xAveragingData = xPainterUnits;
 
  934    const double *yAveragingData = yPainterUnits;
 
  935    double endAverageSegmentX = *xAveragingData;
 
  936    double endAverageSegmentY = *yAveragingData;
 
  937    double averagingSegmentLengthPainterUnits = 
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
 
  940    while ( ( j < size - 1 ) && ( painterDistRemaining > averagingSegmentLengthPainterUnits ) )
 
  942      painterDistRemaining -= averagingSegmentLengthPainterUnits;
 
  943      startAverageSegmentX = endAverageSegmentX;
 
  944      startAverageSegmentY = endAverageSegmentY;
 
  946      endAverageSegmentX = *xAveragingData++;
 
  947      endAverageSegmentY = *yAveragingData++;
 
  949      averagingSegmentLengthPainterUnits = 
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
 
  952    double endAverageXPainterUnits = thisXPainterUnits;
 
  953    double endAverageYPainterUnits = thisYPainterUnits;
 
  954    if ( ( j < size - 1 ) && painterDistRemaining < averagingSegmentLengthPainterUnits )
 
  957          nullptr, 
nullptr, 
nullptr,
 
  958          nullptr, 
nullptr, 
nullptr );
 
  960    else if ( i < size - 2 )
 
  962      endAverageXPainterUnits = endAverageSegmentX;
 
  963      endAverageYPainterUnits = endAverageSegmentY;
 
  968    painterDistRemaining = averageAngleLengthPainterUnits;
 
  969    startAverageSegmentX = thisXPainterUnits;
 
  970    startAverageSegmentY = thisYPainterUnits;
 
  972    xAveragingData = xPainterUnits - 2;
 
  973    yAveragingData = yPainterUnits - 2;
 
  975    endAverageSegmentX = *xAveragingData;
 
  976    endAverageSegmentY = *yAveragingData;
 
  977    averagingSegmentLengthPainterUnits = 
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
 
  979    while ( j > 0 && painterDistRemaining > averagingSegmentLengthPainterUnits )
 
  981      painterDistRemaining -= averagingSegmentLengthPainterUnits;
 
  982      startAverageSegmentX = endAverageSegmentX;
 
  983      startAverageSegmentY = endAverageSegmentY;
 
  985      endAverageSegmentX = *xAveragingData--;
 
  986      endAverageSegmentY = *yAveragingData--;
 
  988      averagingSegmentLengthPainterUnits = 
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
 
  991    double startAverageXPainterUnits = thisXPainterUnits;
 
  992    double startAverageYPainterUnits = thisYPainterUnits;
 
  993    if ( j > 0 && painterDistRemaining < averagingSegmentLengthPainterUnits )
 
  996          nullptr, 
nullptr, 
nullptr,
 
  997          nullptr, 
nullptr, 
nullptr );
 
 1001      startAverageXPainterUnits = endAverageSegmentX;
 
 1002      startAverageYPainterUnits = endAverageSegmentY;
 
 1005    double calculatedAngle = std::fmod( 
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
 
 1007    if ( calculatedAngle > 90 && calculatedAngle < 270 )
 
 1008      calculatedAngle += 180;
 
 1012      if ( mRotateLabels )
 
 1013        mMarkerSymbol->setLineAngle( 90 - calculatedAngle );
 
 1017    const double angleRadians = mRotateLabels ? ( calculatedAngle * M_PI / 180.0 ) : 0;
 
 1018    const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
 
 1019                      + labelOffsetPainterUnits.y() * std::sin( angleRadians );
 
 1020    const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
 
 1021                      + labelOffsetPainterUnits.y() * std::cos( angleRadians );
 
 1023    double labelValue = 0;
 
 1024    bool labelVertex = 
true;
 
 1025    switch ( mLabelSource )
 
 1028        labelValue = currentDistance;
 
 1032        labelVertex = 
static_cast< bool >( zData ) && !std::isnan( labelValue );
 
 1036        labelVertex = 
static_cast< bool >( mData ) && !std::isnan( labelValue );
 
 1043    const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
 
 1044    if ( !labelProvider )
 
 1052      labelProvider->addLabel(
 
 1053        QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
 
 1068  mTextFormat = format;
 
 
 1073  return mNumericFormat.get();
 
 
 1078  mNumericFormat.reset( format );
 
 
 1093  return mSkipMultiplesOf;
 
 
 1109  if ( show && !mMarkerSymbol )
 
 
 1127  return mLabelSource;
 
 
 1132  mLabelSource = source;
 
 
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
 
@ IsSymbolLayerSubSymbol
Symbol is being rendered as a sub-symbol of a QgsSymbolLayer.
 
@ OverPoint
Arranges candidates over a point (or centroid of a polygon), or at a preset offset from the point....
 
@ DisableFeatureClipping
If present, indicates that features should never be clipped to the map extent during rendering.
 
@ AffectsLabeling
If present, indicates that the symbol layer will participate in the map labeling problem.
 
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
 
@ Point
Text at point of origin layout mode.
 
@ Horizontal
Horizontally oriented text.
 
LinearReferencingPlacement
Defines how/where the labels should be placed in a linear referencing symbol layer.
 
@ IntervalZ
Place labels at regular intervals, linearly interpolated using Z values.
 
@ Vertex
Place labels on every vertex in the line.
 
@ IntervalM
Place labels at regular intervals, linearly interpolated using M values.
 
@ IntervalCartesian2D
Place labels at regular intervals, using Cartesian distance calculations on a 2D plane.
 
LinearReferencingLabelSource
Defines what quantity to use for the labels shown in a linear referencing symbol layer.
 
@ CartesianDistance2D
Distance along line, calculated using Cartesian calculations on a 2D plane.
 
QFlags< SymbolRenderHint > SymbolRenderHints
Symbol render hints.
 
Abstract base class for all geometries.
 
bool isMeasure() const
Returns true if the geometry contains m values.
 
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
 
const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary const part after the last part of the geometry.
 
const_part_iterator const_parts_begin() const
Returns STL-style iterator pointing to the const first part of the geometry.
 
An abstract interface class for label providers.
 
virtual QList< QgsLabelFeature * > labelFeatures(QgsRenderContext &context)=0
Returns list of label features (they are owned by the provider and thus deleted on its destruction)
 
virtual void drawLabel(QgsRenderContext &context, pal::LabelPosition *label) const =0
Draw this label at the position determined by the labeling engine.
 
@ DrawLabels
Whether the labels should be rendered.
 
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean.
 
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
 
static QgsNumericFormatRegistry * numericFormatRegistry()
Gets the registry of available numeric formats.
 
static void pointOnLineWithDistance(double x1, double y1, double x2, double y2, double distance, double &x, double &y, double *z1=nullptr, double *z2=nullptr, double *z=nullptr, double *m1=nullptr, double *m2=nullptr, double *m=nullptr)
Calculates the point a specified distance from (x1, y1) toward a second point (x2,...
 
static double distance2D(double x1, double y1, double x2, double y2)
Returns the 2D distance between (x1, y1) and (x2, y2).
 
static double azimuth(double x1, double y1, double x2, double y2)
Calculates Cartesian azimuth between points (x1, y1) and (x2, y2) (clockwise in degree,...
 
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlags())
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
 
Provides map labeling functionality.
 
Line string geometry type, with support for z-dimension and m-values.
 
const double * yData() const
Returns a const pointer to the y vertex data.
 
const double * xData() const
Returns a const pointer to the x vertex data.
 
const double * zData() const
Returns a const pointer to the z vertex data, or nullptr if the linestring does not have z values.
 
int numPoints() const override
Returns the number of points in the curve.
 
const double * mData() const
Returns a const pointer to the m vertex data, or nullptr if the linestring does not have m values.
 
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
 
Abstract base class for line symbol layers.
 
Line symbol layer used for decorating according to linear referencing.
 
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
 
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
 
void setShowMarker(bool show)
Sets whether a marker symbol should be shown corresponding to the labeled point on line.
 
void setSkipMultiplesOf(double multiple)
Sets the multiple distance to skip labels for.
 
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
 
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
 
QgsTextFormat textFormat() const
Returns the text format used to render the layer.
 
QString layerType() const override
Returns a string that represents this layer type.
 
bool showMarker() const
Returns true if a marker symbol should be shown corresponding to the labeled point on line.
 
void setNumericFormat(QgsNumericFormat *format)
Sets the numeric format used to format the labels for the layer.
 
QgsNumericFormat * numericFormat() const
Returns the numeric format used to format the labels for the layer.
 
void setInterval(double interval)
Sets the interval between labels.
 
~QgsLinearReferencingSymbolLayer() override
 
void setLabelSource(Qgis::LinearReferencingLabelSource source)
Sets the label source, which dictates what quantity to use for the labels shown.
 
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
 
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
 
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
 
void setTextFormat(const QgsTextFormat &format)
Sets the text format used to render the layer.
 
QgsLinearReferencingSymbolLayer()
 
Qgis::LinearReferencingLabelSource labelSource() const
Returns the label source, which dictates what quantity to use for the labels shown.
 
double skipMultiplesOf() const
Returns the multiple distance to skip labels for.
 
QgsLinearReferencingSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
 
void setPlacement(Qgis::LinearReferencingPlacement placement)
Sets the placement mode for the labels.
 
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsLinearReferencingSymbolLayer, using the specified properties.
 
double interval() const
Returns the interval between labels.
 
Qgis::LinearReferencingPlacement placement() const
Returns the placement mode for the labels.
 
Perform transforms between map coordinates and device coordinates.
 
void setMapRotation(double degrees, double cx, double cy)
Sets map rotation in degrees (clockwise).
 
double mapUnitsPerPixel() const
Returns the current map units per pixel.
 
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
 
void transformInPlace(double &x, double &y) const
Transforms map coordinates to device coordinates.
 
static std::unique_ptr< QgsMarkerSymbol > createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
 
A context for numeric formats.
 
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context to use when evaluating QgsExpressions.
 
QPointF toQPointF() const
Converts a point to a QPointF.
 
Point geometry type, with support for z-dimension and m-values.
 
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
 
A container for the context for various read/write operations on objects.
 
Contains information about the context of a rendering operation.
 
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
 
QPainter * painter()
Returns the destination QPainter for the render operation.
 
QgsExpressionContext & expressionContext()
Gets the expression context.
 
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
 
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
 
QgsLabelingEngine * labelingEngine() const
Gets access to new labeling engine (may be nullptr).
 
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
 
const QgsAbstractGeometry * geometry() const
Returns pointer to the unsegmentized geometry.
 
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
 
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
 
static QString encodePoint(QPointF point)
Encodes a QPointF to a string.
 
static QPointF decodePoint(const QString &string)
Decodes a QSizeF from a string.
 
Abstract base class for symbol layers.
 
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
 
@ SkipMultiples
Skip multiples of.
 
@ ShowMarker
Show markers.
 
@ AverageAngleLength
Length to average symbol angles over.
 
@ Interval
Line marker interval.
 
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
 
QgsPropertyCollection mDataDefinedProperties
 
Encapsulates the context in which a symbol is being rendered.
 
const QgsFeature * feature() const
Returns the current feature being rendered.
 
QgsFields fields() const
Fields of the layer.
 
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
 
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
 
Abstract base class for all rendered symbols.
 
Qgis::SymbolType type() const
Returns the symbol's type.
 
Contains pre-calculated metrics of a QgsTextDocument.
 
static QgsTextDocumentMetrics calculateMetrics(const QgsTextDocument &document, const QgsTextFormat &format, const QgsRenderContext &context, double scaleFactor=1.0, const QgsTextDocumentRenderContext &documentContext=QgsTextDocumentRenderContext())
Returns precalculated text metrics for a text document, when rendered using the given base format and...
 
Represents a document consisting of one or more QgsTextBlock objects.
 
static QgsTextDocument fromTextAndFormat(const QStringList &lines, const QgsTextFormat &format)
Constructor for QgsTextDocument consisting of a set of lines, respecting settings from a text format.
 
Container for all settings relating to text rendering.
 
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
 
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
 
Adds extra information to QgsLabelFeature for text labels.
 
static void drawDocument(const QRectF &rect, const QgsTextFormat &format, const QgsTextDocument &document, const QgsTextDocumentMetrics &metrics, QgsRenderContext &context, Qgis::TextHorizontalAlignment horizontalAlignment=Qgis::TextHorizontalAlignment::Left, Qgis::TextVerticalAlignment verticalAlignment=Qgis::TextVerticalAlignment::Top, double rotation=0, Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags())
Draws a text document within a rectangle using the specified settings.
 
static void drawText(const QRectF &rect, double rotation, Qgis::TextHorizontalAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, Qgis::TextVerticalAlignment vAlignment=Qgis::TextVerticalAlignment::Top, Qgis::TextRendererFlags flags=Qgis::TextRendererFlags(), Qgis::TextLayoutMode mode=Qgis::TextLayoutMode::Rectangle)
Draws text within a rectangle using the specified settings.
 
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
 
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
 
LabelPosition is a candidate feature label position.
 
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)
 
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
 
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
 
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
 
std::function< bool(double x, double y, double z, double m, double distanceFromStart, double angle)> VisitPointFunction
 
void visitPointsByInterpolatedM(const QgsLineString *line, const QgsLineString *linePainterUnits, bool emitFirstPoint, const double distance, const double averageAngleLengthPainterUnits, const VisitPointFunction &visitPoint)
 
void visitPointsByRegularDistance(const QgsLineString *line, const QgsLineString *linePainterUnits, bool emitFirstPoint, const double distance, const double averageAngleLengthPainterUnits, const VisitPointFunction &visitPoint)
 
double calculateAveragedAngle(double targetPointDistanceAlongSegment, double segmentLengthPainterUnits, double averageAngleLengthPainterUnits, double prevXPainterUnits, double prevYPainterUnits, double thisXPainterUnits, double thisYPainterUnits, const double *xPainterUnits, const double *yPainterUnits, int totalPoints, int i)
 
std::function< void(const QgsLineString *, const QgsLineString *, bool, double, double, const VisitPointFunction &) > VisitPointAtDistanceFunction
 
void visitPointsByInterpolatedZM(const QgsLineString *line, const QgsLineString *linePainterUnits, bool emitFirstPoint, const double step, const double averageAngleLengthPainterUnits, const VisitPointFunction &visitPoint, bool useZ)
 
void visitPointsByInterpolatedZ(const QgsLineString *line, const QgsLineString *linePainterUnits, bool emitFirstPoint, const double distance, const double averageAngleLengthPainterUnits, const VisitPointFunction &visitPoint)
 
double interpolateValue(double a, double b, double fraction)