50 QgsLinearReferencingSymbolLayerLabelProvider()
61 ~QgsLinearReferencingSymbolLayerLabelProvider()
63 qDeleteAll( mLabels );
66 void addLabel(
const QPointF &painterPoint,
double angleRadians,
const QString &text,
QgsRenderContext &context,
const QgsTextFormat &format )
85 std::unique_ptr< QgsTextLabelFeatureWithFormat > feature = std::make_unique< QgsTextLabelFeatureWithFormat >( mLabels.size(),
86 QgsGeos::asGeos( &mapPoint ), QSizeF( size.width() * uPP, size.height() * uPP ), format );
88 feature->setDocument( doc, documentMetrics );
89 feature->setFixedAngle( angleRadians );
90 feature->setHasFixedAngle(
true );
93 feature->setQuadOffset( QPointF( 1, 1 ) );
95 mLabels.append( feature.release() );
110 QgsTextLabelFeatureWithFormat *lf = qgis::down_cast<QgsTextLabelFeatureWithFormat *>( label->getFeaturePart()->feature() );
117 QList<QgsLabelFeature *> mLabels;
125 mNumericFormat = std::make_unique< QgsBasicNumericFormat >();
132 std::unique_ptr< QgsLinearReferencingSymbolLayer > res = std::make_unique< QgsLinearReferencingSymbolLayer >();
136 const double interval =
properties.value( QStringLiteral(
"interval" ) ).toDouble( &ok );
139 const double skipMultiples =
properties.value( QStringLiteral(
"skip_multiples" ) ).toDouble( &ok );
141 res->setSkipMultiplesOf( skipMultiples );
142 res->setRotateLabels(
properties.value( QStringLiteral(
"rotate" ),
true ).toBool() );
143 res->setShowMarker(
properties.value( QStringLiteral(
"show_marker" ),
false ).toBool() );
150 const QString textFormatXml =
properties.value( QStringLiteral(
"text_format" ) ).toString();
151 if ( !textFormatXml.isEmpty() )
155 doc.setContent( textFormatXml );
156 elem = doc.documentElement();
163 const QString numericFormatXml =
properties.value( QStringLiteral(
"numeric_format" ) ).toString();
164 if ( !numericFormatXml.isEmpty() )
167 doc.setContent( numericFormatXml );
171 if (
properties.contains( QStringLiteral(
"label_offset" ) ) )
175 if (
properties.contains( QStringLiteral(
"label_offset_unit" ) ) )
179 if (
properties.contains( ( QStringLiteral(
"label_offset_map_unit_scale" ) ) ) )
183 if (
properties.contains( QStringLiteral(
"average_angle_length" ) ) )
185 res->setAverageAngleLength(
properties[QStringLiteral(
"average_angle_length" )].toDouble() );
187 if (
properties.contains( QStringLiteral(
"average_angle_unit" ) ) )
191 if (
properties.contains( ( QStringLiteral(
"average_angle_map_unit_scale" ) ) ) )
196 return res.release();
201 std::unique_ptr< QgsLinearReferencingSymbolLayer > res = std::make_unique< QgsLinearReferencingSymbolLayer >();
202 res->setPlacement( mPlacement );
203 res->setLabelSource( mLabelSource );
204 res->setInterval( mInterval );
205 res->setSkipMultiplesOf( mSkipMultiplesOf );
206 res->setRotateLabels( mRotateLabels );
207 res->setLabelOffset( mLabelOffset );
208 res->setLabelOffsetUnit( mLabelOffsetUnit );
209 res->setLabelOffsetMapUnitScale( mLabelOffsetMapUnitScale );
210 res->setShowMarker( mShowMarker );
211 res->setAverageAngleLength( mAverageAngleLength );
212 res->setAverageAngleUnit( mAverageAngleLengthUnit );
213 res->setAverageAngleMapUnitScale( mAverageAngleLengthMapUnitScale );
215 res->mTextFormat = mTextFormat;
216 res->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() : nullptr );
217 if ( mNumericFormat )
218 res->mNumericFormat.reset( mNumericFormat->clone() );
223 return res.release();
228 QDomDocument textFormatDoc;
233 const QDomElement textElem = mTextFormat.
writeXml( textFormatDoc, rwContext );
234 textFormatDoc.appendChild( textElem );
236 QDomDocument numericFormatDoc;
237 QDomElement numericFormatElem = numericFormatDoc.createElement( QStringLiteral(
"numericFormat" ) );
238 mNumericFormat->writeXml( numericFormatElem, numericFormatDoc, rwContext );
239 numericFormatDoc.appendChild( numericFormatElem );
250 QStringLiteral(
"interval" ), mInterval
253 QStringLiteral(
"rotate" ), mRotateLabels
256 QStringLiteral(
"show_marker" ), mShowMarker
259 QStringLiteral(
"text_format" ), textFormatDoc.toString()
262 QStringLiteral(
"numeric_format" ), numericFormatDoc.toString()
274 QStringLiteral(
"average_angle_length" ), mAverageAngleLength
284 if ( mSkipMultiplesOf >= 0 )
286 res.insert( QStringLiteral(
"skip_multiples" ), mSkipMultiplesOf );
294 return QStringLiteral(
"LinearReferencing" );
305 return mShowMarker ? mMarkerSymbol.get() :
nullptr;
312 mMarkerSymbol.reset( qgis::down_cast<QgsMarkerSymbol *>( symbol ) );
326 mMarkerSymbol->setRenderHints( hints );
335 QgsLinearReferencingSymbolLayerLabelProvider *provider =
new QgsLinearReferencingSymbolLayerLabelProvider();
336 mLabelProviderId = labelingEngine->addProvider( provider );
348void QgsLinearReferencingSymbolLayer::renderGeometryPart(
QgsSymbolRenderContext &context,
const QgsAbstractGeometry *geometry,
double labelOffsetPainterUnitsX,
double labelOffsetPainterUnitsY,
double skipMultiples,
double averageAngleDistancePainterUnits,
bool showMarker )
350 if (
const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( geometry ) )
352 renderLineString( context, line, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
354 else if (
const QgsPolygon *polygon = qgsgeometry_cast< const QgsPolygon * >( geometry ) )
356 renderLineString( context, qgsgeometry_cast< const QgsLineString *>( polygon->exteriorRing() ), labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
357 for (
int i = 0; i < polygon->numInteriorRings(); ++i )
359 renderLineString( context, qgsgeometry_cast< const QgsLineString *>( polygon->interiorRing( i ) ), labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
364void QgsLinearReferencingSymbolLayer::renderLineString(
QgsSymbolRenderContext &context,
const QgsLineString *line,
double labelOffsetPainterUnitsX,
double labelOffsetPainterUnitsY,
double skipMultiples,
double averageAngleDistancePainterUnits,
bool showMarker )
369 switch ( mPlacement )
374 renderPolylineInterval( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits,
showMarker );
378 renderPolylineVertex( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits,
showMarker );
398 double skipMultiples = mSkipMultiplesOf;
405 double labelOffsetX = mLabelOffset.x();
406 double labelOffsetY = mLabelOffset.y();
408 double averageOver = mAverageAngleLength;
424 const double averageAngleDistancePainterUnits = context.
renderContext().
convertToPainterUnits( averageOver, mAverageAngleLengthUnit, mAverageAngleLengthMapUnitScale ) / 2;
428 renderGeometryPart( context, *partIt, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
434 double averageAngleLengthPainterUnits,
double prevXPainterUnits,
double prevYPainterUnits,
435 double thisXPainterUnits,
double thisYPainterUnits,
const double *xPainterUnits,
436 const double *yPainterUnits,
int totalPoints,
int i )
440 double painterDistRemaining = averageAngleLengthPainterUnits + targetPointDistanceAlongSegment;
441 double startAverageSegmentX = prevXPainterUnits;
442 double startAverageSegmentY = prevYPainterUnits;
443 double endAverageSegmentX = thisXPainterUnits;
444 double endAverageSegmentY = thisYPainterUnits;
445 double averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
446 const double *xAveragingData = xPainterUnits;
447 const double *yAveragingData = yPainterUnits;
450 while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
452 if ( j >= totalPoints - 1 )
455 painterDistRemaining -= averagingSegmentLengthPainterUnits;
456 startAverageSegmentX = endAverageSegmentX;
457 startAverageSegmentY = endAverageSegmentY;
459 endAverageSegmentX = *xAveragingData++;
460 endAverageSegmentY = *yAveragingData++;
462 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
465 double endAverageXPainterUnits;
466 double endAverageYPainterUnits;
467 if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
470 nullptr,
nullptr,
nullptr,
471 nullptr,
nullptr,
nullptr );
475 endAverageXPainterUnits = endAverageSegmentX;
476 endAverageYPainterUnits = endAverageSegmentY;
481 painterDistRemaining = ( segmentLengthPainterUnits - targetPointDistanceAlongSegment ) + averageAngleLengthPainterUnits;
482 startAverageSegmentX = thisXPainterUnits;
483 startAverageSegmentY = thisYPainterUnits;
484 endAverageSegmentX = prevXPainterUnits;
485 endAverageSegmentY = prevYPainterUnits;
486 averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
487 xAveragingData = xPainterUnits - 2;
488 yAveragingData = yPainterUnits - 2;
489 while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
494 painterDistRemaining -= averagingSegmentLengthPainterUnits;
495 startAverageSegmentX = endAverageSegmentX;
496 startAverageSegmentY = endAverageSegmentY;
498 endAverageSegmentX = *xAveragingData--;
499 endAverageSegmentY = *yAveragingData--;
501 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
504 double startAverageXPainterUnits;
505 double startAverageYPainterUnits;
506 if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
509 nullptr,
nullptr,
nullptr,
510 nullptr,
nullptr,
nullptr );
514 startAverageXPainterUnits = endAverageSegmentX;
515 startAverageYPainterUnits = endAverageSegmentY;
518 double calculatedAngle = std::fmod(
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
519 if ( calculatedAngle > 90 && calculatedAngle < 270 )
520 calculatedAngle += 180;
522 return calculatedAngle;
525typedef std::function<bool (
double x,
double y,
double z,
double m,
double distanceFromStart,
double angle )>
VisitPointFunction;
533 double distanceTraversed = 0;
534 const int totalPoints = line->
numPoints();
535 if ( totalPoints == 0 )
538 const double *x = line->
xData();
539 const double *y = line->
yData();
540 const double *z = line->
is3D() ? line->
zData() :
nullptr;
543 const double *xPainterUnits = linePainterUnits->
xData();
544 const double *yPainterUnits = linePainterUnits->
yData();
548 double prevZ = z ? *z++ : 0.0;
549 double prevM = m ? *m++ : 0.0;
551 double prevXPainterUnits = *xPainterUnits++;
552 double prevYPainterUnits = *yPainterUnits++;
556 visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
560 double pZ = std::numeric_limits<double>::quiet_NaN();
561 double pM = std::numeric_limits<double>::quiet_NaN();
562 double nextPointDistance = emitFirstPoint ? 0 : distance;
563 for (
int i = 1; i < totalPoints; ++i )
567 double thisZ = z ? *z++ : 0.0;
568 double thisM = m ? *m++ : 0.0;
569 double thisXPainterUnits = *xPainterUnits++;
570 double thisYPainterUnits = *yPainterUnits++;
572 double angle = std::fmod(
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
573 if ( angle > 90 && angle < 270 )
579 while ( nextPointDistance < distanceTraversed + segmentLength ||
qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength ) )
582 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
585 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
586 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM : nullptr );
588 double calculatedAngle = angle;
589 if ( averageAngleLengthPainterUnits > 0 )
591 const double targetPointFractionAlongSegment = distanceToPoint / segmentLength;
592 const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
595 averageAngleLengthPainterUnits, prevXPainterUnits, prevYPainterUnits,
596 thisXPainterUnits, thisYPainterUnits, xPainterUnits,
597 yPainterUnits, totalPoints, i );
600 if ( !visitPoint( pX, pY, pZ, pM, nextPointDistance, calculatedAngle ) )
603 nextPointDistance += distance;
606 distanceTraversed += segmentLength;
611 prevXPainterUnits = thisXPainterUnits;
612 prevYPainterUnits = thisYPainterUnits;
618 return a + ( b - a ) * fraction;
627 double distanceTraversed = 0;
628 const int totalPoints = line->
numPoints();
629 if ( totalPoints < 2 )
632 const double *x = line->
xData();
633 const double *y = line->
yData();
634 const double *z = line->
is3D() ? line->
zData() :
nullptr;
637 const double *xPainterUnits = linePainterUnits->
xData();
638 const double *yPainterUnits = linePainterUnits->
yData();
642 double prevZ = z ? *z++ : 0.0;
643 double prevM = m ? *m++ : 0.0;
645 double prevXPainterUnits = *xPainterUnits++;
646 double prevYPainterUnits = *yPainterUnits++;
650 visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
654 double prevValue = useZ ? prevZ : prevM;
655 bool isFirstPoint =
true;
656 for (
int i = 1; i < totalPoints; ++i )
660 double thisZ = z ? *z++ : 0.0;
661 double thisM = m ? *m++ : 0.0;
662 const double thisValue = useZ ? thisZ : thisM;
663 double thisXPainterUnits = *xPainterUnits++;
664 double thisYPainterUnits = *yPainterUnits++;
666 double angle = std::fmod(
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
667 if ( angle > 90 && angle < 270 )
674 const int direction = ( thisValue > prevValue ) ? 1 : ( thisValue < prevValue ) ? -1 : 0;
675 if ( direction != 0 )
678 double nextStepValue = direction > 0 ? std::ceil( prevValue / step ) * step
679 : std::floor( prevValue / step ) * step;
681 while ( ( direction > 0 && ( nextStepValue <= thisValue ||
qgsDoubleNear( nextStepValue, thisValue ) ) ) ||
682 ( direction < 0 && ( nextStepValue >= thisValue ||
qgsDoubleNear( nextStepValue, thisValue ) ) ) )
684 const double targetPointFractionAlongSegment = ( nextStepValue - prevValue ) / ( thisValue - prevValue );
685 const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
690 const double pZ = useZ ? nextStepValue :
interpolateValue( prevZ, thisZ, targetPointFractionAlongSegment );
691 const double pM = useZ ?
interpolateValue( prevM, thisM, targetPointFractionAlongSegment ) : nextStepValue;
693 double calculatedAngle = angle;
694 if ( averageAngleLengthPainterUnits > 0 )
697 targetPointDistanceAlongSegment,
698 segmentLengthPainterUnits, averageAngleLengthPainterUnits,
699 prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits,
700 xPainterUnits, yPainterUnits,
704 if ( !
qgsDoubleNear( targetPointFractionAlongSegment, 0 ) || isFirstPoint )
706 if ( !visitPoint( pX, pY, pZ, pM, distanceTraversed + segmentLength * targetPointFractionAlongSegment, calculatedAngle ) )
710 nextStepValue += direction * step;
713 else if ( isFirstPoint && emitFirstPoint )
715 if ( !visitPoint( prevX, prevY, prevZ, prevM, distanceTraversed,
719 isFirstPoint =
false;
725 prevXPainterUnits = thisXPainterUnits;
726 prevYPainterUnits = thisYPainterUnits;
727 prevValue = thisValue;
728 distanceTraversed += segmentLength;
739 visitPointsByInterpolatedZM( line, linePainterUnits, emitFirstPoint, distance, averageAngleLengthPainterUnits, visitPoint,
false );
742QPointF QgsLinearReferencingSymbolLayer::pointToPainter(
QgsSymbolRenderContext &context,
double x,
double y,
double z )
748 pt = QPointF( x, y );
753 pt = QPointF( x, y );
760void QgsLinearReferencingSymbolLayer::renderPolylineInterval(
const QgsLineString *line,
QgsSymbolRenderContext &context,
double skipMultiples,
const QPointF &labelOffsetPainterUnits,
double averageAngleLengthPainterUnits,
bool showMarker )
762 double distance = mInterval;
772 std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
779 const bool hasZ = line->
is3D();
785 switch ( mPlacement )
803 QgsLinearReferencingSymbolLayerLabelProvider *labelProvider =
nullptr;
808 labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
811 func( line, painterUnitsGeometry.get(), emitFirstPoint, distance, averageAngleLengthPainterUnits, [&context, &numericContext, skipMultiples,
showMarker,
812 labelOffsetPainterUnits, hasZ, hasM, labelProvider,
this](
double x,
double y,
double z,
double m,
double distanceFromStart,
double angle ) ->
bool
814 if ( context.renderContext().renderingStopped() )
817 double labelValue = 0;
818 bool labelVertex = true;
819 switch ( mLabelSource )
821 case Qgis::LinearReferencingLabelSource::CartesianDistance2D:
822 labelValue = distanceFromStart;
824 case Qgis::LinearReferencingLabelSource::Z:
826 labelVertex = hasZ && !std::isnan( labelValue );
828 case Qgis::LinearReferencingLabelSource::M:
830 labelVertex = hasM && !std::isnan( labelValue );
837 if ( skipMultiples > 0 &&
qgsDoubleNear( std::fmod( labelValue, skipMultiples ), 0 ) )
840 const QPointF pt = pointToPainter( context, x, y, z );
845 mMarkerSymbol->setLineAngle( 90 - angle );
849 const double angleRadians = ( mRotateLabels ?
angle : 0 ) * M_PI / 180.0;
850 const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
851 + labelOffsetPainterUnits.y() * std::sin( angleRadians );
852 const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
853 + labelOffsetPainterUnits.y() * std::cos( angleRadians );
855 const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
856 if ( !labelProvider )
864 labelProvider->addLabel(
865 QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
873void QgsLinearReferencingSymbolLayer::renderPolylineVertex(
const QgsLineString *line,
QgsSymbolRenderContext &context,
double skipMultiples,
const QPointF &labelOffsetPainterUnits,
double averageAngleLengthPainterUnits,
bool showMarker )
878 averageAngleLengthPainterUnits = std::max( averageAngleLengthPainterUnits, 0.1 );
883 QgsLinearReferencingSymbolLayerLabelProvider *labelProvider =
nullptr;
888 labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
891 const double *xData = line->
xData();
892 const double *yData = line->
yData();
893 const double *zData = line->
is3D() ? line->
zData() :
nullptr;
894 const double *mData = line->
isMeasure() ? line->
mData() :
nullptr;
899 std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
905 const double *xPainterUnits = painterUnitsGeometry->xData();
906 const double *yPainterUnits = painterUnitsGeometry->yData();
908 double currentDistance = 0;
909 double prevX = *xData;
910 double prevY = *yData;
912 for (
int i = 0; i < size; ++i )
917 double thisX = *xData++;
918 double thisY = *yData++;
919 double thisZ = zData ? *zData++ : 0;
920 double thisM = mData ? *mData++ : 0;
921 double thisXPainterUnits = *xPainterUnits++;
922 double thisYPainterUnits = *yPainterUnits++;
925 currentDistance += thisSegmentLength;
927 if ( skipMultiples > 0 &&
qgsDoubleNear( std::fmod( currentDistance, skipMultiples ), 0 ) )
934 const QPointF pt = pointToPainter( context, thisX, thisY, thisZ );
937 double painterDistRemaining = averageAngleLengthPainterUnits;
938 double startAverageSegmentX = thisXPainterUnits;
939 double startAverageSegmentY = thisYPainterUnits;
941 const double *xAveragingData = xPainterUnits;
942 const double *yAveragingData = yPainterUnits;
943 double endAverageSegmentX = *xAveragingData;
944 double endAverageSegmentY = *yAveragingData;
945 double averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
948 while ( ( j < size - 1 ) && ( painterDistRemaining > averagingSegmentLengthPainterUnits ) )
950 painterDistRemaining -= averagingSegmentLengthPainterUnits;
951 startAverageSegmentX = endAverageSegmentX;
952 startAverageSegmentY = endAverageSegmentY;
954 endAverageSegmentX = *xAveragingData++;
955 endAverageSegmentY = *yAveragingData++;
957 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
960 double endAverageXPainterUnits = thisXPainterUnits;
961 double endAverageYPainterUnits = thisYPainterUnits;
962 if ( ( j < size - 1 ) && painterDistRemaining < averagingSegmentLengthPainterUnits )
965 nullptr,
nullptr,
nullptr,
966 nullptr,
nullptr,
nullptr );
968 else if ( i < size - 2 )
970 endAverageXPainterUnits = endAverageSegmentX;
971 endAverageYPainterUnits = endAverageSegmentY;
976 painterDistRemaining = averageAngleLengthPainterUnits;
977 startAverageSegmentX = thisXPainterUnits;
978 startAverageSegmentY = thisYPainterUnits;
980 xAveragingData = xPainterUnits - 2;
981 yAveragingData = yPainterUnits - 2;
983 endAverageSegmentX = *xAveragingData;
984 endAverageSegmentY = *yAveragingData;
985 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
987 while ( j > 0 && painterDistRemaining > averagingSegmentLengthPainterUnits )
989 painterDistRemaining -= averagingSegmentLengthPainterUnits;
990 startAverageSegmentX = endAverageSegmentX;
991 startAverageSegmentY = endAverageSegmentY;
993 endAverageSegmentX = *xAveragingData--;
994 endAverageSegmentY = *yAveragingData--;
996 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
999 double startAverageXPainterUnits = thisXPainterUnits;
1000 double startAverageYPainterUnits = thisYPainterUnits;
1001 if ( j > 0 && painterDistRemaining < averagingSegmentLengthPainterUnits )
1004 nullptr,
nullptr,
nullptr,
1005 nullptr,
nullptr,
nullptr );
1009 startAverageXPainterUnits = endAverageSegmentX;
1010 startAverageYPainterUnits = endAverageSegmentY;
1013 double calculatedAngle = std::fmod(
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
1015 if ( calculatedAngle > 90 && calculatedAngle < 270 )
1016 calculatedAngle += 180;
1020 if ( mRotateLabels )
1021 mMarkerSymbol->setLineAngle( 90 - calculatedAngle );
1025 const double angleRadians = mRotateLabels ? ( calculatedAngle * M_PI / 180.0 ) : 0;
1026 const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
1027 + labelOffsetPainterUnits.y() * std::sin( angleRadians );
1028 const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
1029 + labelOffsetPainterUnits.y() * std::cos( angleRadians );
1031 double labelValue = 0;
1032 bool labelVertex =
true;
1033 switch ( mLabelSource )
1036 labelValue = currentDistance;
1040 labelVertex =
static_cast< bool >( zData ) && !std::isnan( labelValue );
1044 labelVertex =
static_cast< bool >( mData ) && !std::isnan( labelValue );
1051 const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
1052 if ( !labelProvider )
1060 labelProvider->addLabel(
1061 QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
1076 mTextFormat = format;
1081 return mNumericFormat.get();
1086 mNumericFormat.reset( format );
1101 return mSkipMultiplesOf;
1117 if ( show && !mMarkerSymbol )
1135 return mLabelSource;
1140 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.
The QgsAbstractLabelProvider class is an interface class.
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...
The QgsLabelingEngine class 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 accordingly 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 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.
The class is used as a container of context for various read/write operations on other 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.
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
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.
QSizeF documentSize(Qgis::TextLayoutMode mode, Qgis::TextOrientation orientation) const
Returns the overall size of the document.
static QgsTextDocumentMetrics calculateMetrics(const QgsTextDocument &document, const QgsTextFormat &format, const QgsRenderContext &context, double scaleFactor=1.0)
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 fromHtml(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of HTML formatted lines.
static QgsTextDocument fromPlainText(const QStringList &lines)
Constructor for QgsTextDocument consisting of a set of plain text lines.
Container for all settings relating to text rendering.
void readXml(const QDomElement &elem, const QgsReadWriteContext &context)
Read settings from a DOM element.
bool allowHtmlFormatting() const
Returns true if text should be treated as a HTML document and HTML tags should be used for formatting...
QDomElement writeXml(QDomDocument &doc, const QgsReadWriteContext &context) const
Write settings into a DOM element.
Class that 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)