37using namespace Qt::StringLiterals;
44 : QgsTextLabelFeature( id, std::move( geometry ), size )
48 QgsTextFormat mFormat;
55 QgsLinearReferencingSymbolLayerLabelProvider()
56 : QgsAbstractLabelProvider( nullptr )
66 ~QgsLinearReferencingSymbolLayerLabelProvider()
override
68 qDeleteAll( mLabels );
71 void addLabel(
const QPointF &painterPoint,
double angleRadians,
const QString &text, QgsRenderContext &context,
const QgsTextFormat &format )
74 QgsPoint mapPoint( painterPoint );
82 auto feature = std::make_unique< QgsTextLabelFeatureWithFormat >( mLabels.size(),
83 QgsGeos::asGeos( &mapPoint ), QSizeF( size.width() * uPP, size.height() * uPP ), format );
85 feature->setDocument( doc, documentMetrics );
86 feature->setFixedAngle( angleRadians );
87 feature->setHasFixedAngle(
true );
90 feature->setQuadOffset( QPointF( 1, 1 ) );
92 mLabels.append( feature.release() );
95 QList<QgsLabelFeature *>
labelFeatures( QgsRenderContext & )
final
100 void drawLabel( QgsRenderContext &context, pal::LabelPosition *label )
const final
107 QgsTextLabelFeatureWithFormat *lf = qgis::down_cast<QgsTextLabelFeatureWithFormat *>( label->getFeaturePart()->feature() );
114 QList<QgsLabelFeature *> mLabels;
122 mNumericFormat = std::make_unique< QgsBasicNumericFormat >();
129 auto res = std::make_unique< QgsLinearReferencingSymbolLayer >();
136 const double skipMultiples =
properties.value( u
"skip_multiples"_s ).toDouble( &ok );
138 res->setSkipMultiplesOf( skipMultiples );
139 res->setRotateLabels(
properties.value( u
"rotate"_s,
true ).toBool() );
140 res->setShowMarker(
properties.value( u
"show_marker"_s,
false ).toBool() );
147 const QString textFormatXml =
properties.value( u
"text_format"_s ).toString();
148 if ( !textFormatXml.isEmpty() )
152 doc.setContent( textFormatXml );
153 elem = doc.documentElement();
160 const QString numericFormatXml =
properties.value( u
"numeric_format"_s ).toString();
161 if ( !numericFormatXml.isEmpty() )
164 doc.setContent( numericFormatXml );
168 if (
properties.contains( u
"label_offset"_s ) )
172 if (
properties.contains( u
"label_offset_unit"_s ) )
176 if (
properties.contains( ( u
"label_offset_map_unit_scale"_s ) ) )
180 if (
properties.contains( u
"average_angle_length"_s ) )
182 res->setAverageAngleLength(
properties[u
"average_angle_length"_s].toDouble() );
184 if (
properties.contains( u
"average_angle_unit"_s ) )
188 if (
properties.contains( ( u
"average_angle_map_unit_scale"_s ) ) )
193 return res.release();
198 auto res = std::make_unique< QgsLinearReferencingSymbolLayer >();
199 res->setPlacement( mPlacement );
200 res->setLabelSource( mLabelSource );
201 res->setInterval( mInterval );
202 res->setSkipMultiplesOf( mSkipMultiplesOf );
203 res->setRotateLabels( mRotateLabels );
204 res->setLabelOffset( mLabelOffset );
205 res->setLabelOffsetUnit( mLabelOffsetUnit );
206 res->setLabelOffsetMapUnitScale( mLabelOffsetMapUnitScale );
207 res->setShowMarker( mShowMarker );
208 res->setAverageAngleLength( mAverageAngleLength );
209 res->setAverageAngleUnit( mAverageAngleLengthUnit );
210 res->setAverageAngleMapUnitScale( mAverageAngleLengthMapUnitScale );
212 res->mTextFormat = mTextFormat;
213 res->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() :
nullptr );
214 if ( mNumericFormat )
215 res->mNumericFormat.reset( mNumericFormat->clone() );
220 return res.release();
225 QDomDocument textFormatDoc;
230 const QDomElement textElem = mTextFormat.writeXml( textFormatDoc, rwContext );
231 textFormatDoc.appendChild( textElem );
233 QDomDocument numericFormatDoc;
234 QDomElement numericFormatElem = numericFormatDoc.createElement( u
"numericFormat"_s );
235 mNumericFormat->writeXml( numericFormatElem, numericFormatDoc, rwContext );
236 numericFormatDoc.appendChild( numericFormatElem );
247 u
"interval"_s, mInterval
250 u
"rotate"_s, mRotateLabels
253 u
"show_marker"_s, mShowMarker
256 u
"text_format"_s, textFormatDoc.toString()
259 u
"numeric_format"_s, numericFormatDoc.toString()
271 u
"average_angle_length"_s, mAverageAngleLength
281 if ( mSkipMultiplesOf >= 0 )
283 res.insert( u
"skip_multiples"_s, mSkipMultiplesOf );
291 return u
"LinearReferencing"_s;
302 return mShowMarker ? mMarkerSymbol.get() :
nullptr;
309 mMarkerSymbol.reset( qgis::down_cast<QgsMarkerSymbol *>( symbol ) );
323 mMarkerSymbol->setRenderHints( hints );
332 QgsLinearReferencingSymbolLayerLabelProvider *provider =
new QgsLinearReferencingSymbolLayerLabelProvider();
333 mLabelProviderId = labelingEngine->addProvider( provider );
345void QgsLinearReferencingSymbolLayer::renderGeometryPart(
QgsSymbolRenderContext &context,
const QgsAbstractGeometry *geometry,
double labelOffsetPainterUnitsX,
double labelOffsetPainterUnitsY,
double skipMultiples,
double averageAngleDistancePainterUnits,
bool showMarker )
349 renderLineString( context, line, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
354 for (
int i = 0; i < polygon->numInteriorRings(); ++i )
361void QgsLinearReferencingSymbolLayer::renderLineString(
QgsSymbolRenderContext &context,
const QgsLineString *line,
double labelOffsetPainterUnitsX,
double labelOffsetPainterUnitsY,
double skipMultiples,
double averageAngleDistancePainterUnits,
bool showMarker )
366 switch ( mPlacement )
371 renderPolylineInterval( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits,
showMarker );
375 renderPolylineVertex( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits,
showMarker );
395 double skipMultiples = mSkipMultiplesOf;
402 double labelOffsetX = mLabelOffset.x();
403 double labelOffsetY = mLabelOffset.y();
405 double averageOver = mAverageAngleLength;
421 const double averageAngleDistancePainterUnits = context.
renderContext().
convertToPainterUnits( averageOver, mAverageAngleLengthUnit, mAverageAngleLengthMapUnitScale ) / 2;
425 renderGeometryPart( context, *partIt, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
431 double averageAngleLengthPainterUnits,
double prevXPainterUnits,
double prevYPainterUnits,
432 double thisXPainterUnits,
double thisYPainterUnits,
const double *xPainterUnits,
433 const double *yPainterUnits,
int totalPoints,
int i )
437 double painterDistRemaining = averageAngleLengthPainterUnits + targetPointDistanceAlongSegment;
438 double startAverageSegmentX = prevXPainterUnits;
439 double startAverageSegmentY = prevYPainterUnits;
440 double endAverageSegmentX = thisXPainterUnits;
441 double endAverageSegmentY = thisYPainterUnits;
442 double averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
443 const double *xAveragingData = xPainterUnits;
444 const double *yAveragingData = yPainterUnits;
447 while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
449 if ( j >= totalPoints - 1 )
452 painterDistRemaining -= averagingSegmentLengthPainterUnits;
453 startAverageSegmentX = endAverageSegmentX;
454 startAverageSegmentY = endAverageSegmentY;
456 endAverageSegmentX = *xAveragingData++;
457 endAverageSegmentY = *yAveragingData++;
459 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
462 double endAverageXPainterUnits;
463 double endAverageYPainterUnits;
464 if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
467 nullptr,
nullptr,
nullptr,
468 nullptr,
nullptr,
nullptr );
472 endAverageXPainterUnits = endAverageSegmentX;
473 endAverageYPainterUnits = endAverageSegmentY;
478 painterDistRemaining = ( segmentLengthPainterUnits - targetPointDistanceAlongSegment ) + averageAngleLengthPainterUnits;
479 startAverageSegmentX = thisXPainterUnits;
480 startAverageSegmentY = thisYPainterUnits;
481 endAverageSegmentX = prevXPainterUnits;
482 endAverageSegmentY = prevYPainterUnits;
483 averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
484 xAveragingData = xPainterUnits - 2;
485 yAveragingData = yPainterUnits - 2;
486 while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
491 painterDistRemaining -= averagingSegmentLengthPainterUnits;
492 startAverageSegmentX = endAverageSegmentX;
493 startAverageSegmentY = endAverageSegmentY;
495 endAverageSegmentX = *xAveragingData--;
496 endAverageSegmentY = *yAveragingData--;
498 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
501 double startAverageXPainterUnits;
502 double startAverageYPainterUnits;
503 if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
506 nullptr,
nullptr,
nullptr,
507 nullptr,
nullptr,
nullptr );
511 startAverageXPainterUnits = endAverageSegmentX;
512 startAverageYPainterUnits = endAverageSegmentY;
515 double calculatedAngle = std::fmod(
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
516 if ( calculatedAngle > 90 && calculatedAngle < 270 )
517 calculatedAngle += 180;
519 return calculatedAngle;
522typedef std::function<bool (
double x,
double y,
double z,
double m,
double distanceFromStart,
double angle )>
VisitPointFunction;
530 double distanceTraversed = 0;
531 const int totalPoints = line->
numPoints();
532 if ( totalPoints == 0 )
535 const double *x = line->
xData();
536 const double *y = line->
yData();
537 const double *z = line->
is3D() ? line->
zData() :
nullptr;
540 const double *xPainterUnits = linePainterUnits->
xData();
541 const double *yPainterUnits = linePainterUnits->
yData();
545 double prevZ = z ? *z++ : 0.0;
546 double prevM = m ? *m++ : 0.0;
548 double prevXPainterUnits = *xPainterUnits++;
549 double prevYPainterUnits = *yPainterUnits++;
553 visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
557 double pZ = std::numeric_limits<double>::quiet_NaN();
558 double pM = std::numeric_limits<double>::quiet_NaN();
559 double nextPointDistance = emitFirstPoint ? 0 : distance;
560 for (
int i = 1; i < totalPoints; ++i )
564 double thisZ = z ? *z++ : 0.0;
565 double thisM = m ? *m++ : 0.0;
566 double thisXPainterUnits = *xPainterUnits++;
567 double thisYPainterUnits = *yPainterUnits++;
569 double angle = std::fmod(
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
570 if ( angle > 90 && angle < 270 )
576 while ( nextPointDistance < distanceTraversed + segmentLength ||
qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength ) )
579 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
582 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
583 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
585 double calculatedAngle = angle;
586 if ( averageAngleLengthPainterUnits > 0 )
588 const double targetPointFractionAlongSegment = distanceToPoint / segmentLength;
589 const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
592 averageAngleLengthPainterUnits, prevXPainterUnits, prevYPainterUnits,
593 thisXPainterUnits, thisYPainterUnits, xPainterUnits,
594 yPainterUnits, totalPoints, i );
597 if ( !visitPoint( pX, pY, pZ, pM, nextPointDistance, calculatedAngle ) )
600 nextPointDistance += distance;
603 distanceTraversed += segmentLength;
608 prevXPainterUnits = thisXPainterUnits;
609 prevYPainterUnits = thisYPainterUnits;
615 return a + ( b - a ) * fraction;
624 double distanceTraversed = 0;
625 const int totalPoints = line->
numPoints();
626 if ( totalPoints < 2 )
629 const double *x = line->
xData();
630 const double *y = line->
yData();
631 const double *z = line->
is3D() ? line->
zData() :
nullptr;
634 const double *xPainterUnits = linePainterUnits->
xData();
635 const double *yPainterUnits = linePainterUnits->
yData();
639 double prevZ = z ? *z++ : 0.0;
640 double prevM = m ? *m++ : 0.0;
642 double prevXPainterUnits = *xPainterUnits++;
643 double prevYPainterUnits = *yPainterUnits++;
647 visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
651 double prevValue = useZ ? prevZ : prevM;
652 bool isFirstPoint =
true;
653 for (
int i = 1; i < totalPoints; ++i )
657 double thisZ = z ? *z++ : 0.0;
658 double thisM = m ? *m++ : 0.0;
659 const double thisValue = useZ ? thisZ : thisM;
660 double thisXPainterUnits = *xPainterUnits++;
661 double thisYPainterUnits = *yPainterUnits++;
663 double angle = std::fmod(
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
664 if ( angle > 90 && angle < 270 )
671 const int direction = ( thisValue > prevValue ) ? 1 : ( thisValue < prevValue ) ? -1 : 0;
672 if ( direction != 0 )
675 double nextStepValue = direction > 0 ? std::ceil( prevValue / step ) * step
676 : std::floor( prevValue / step ) * step;
678 while ( ( direction > 0 && ( nextStepValue <= thisValue ||
qgsDoubleNear( nextStepValue, thisValue ) ) ) ||
679 ( direction < 0 && ( nextStepValue >= thisValue ||
qgsDoubleNear( nextStepValue, thisValue ) ) ) )
681 const double targetPointFractionAlongSegment = ( nextStepValue - prevValue ) / ( thisValue - prevValue );
682 const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
687 const double pZ = useZ ? nextStepValue :
interpolateValue( prevZ, thisZ, targetPointFractionAlongSegment );
688 const double pM = useZ ?
interpolateValue( prevM, thisM, targetPointFractionAlongSegment ) : nextStepValue;
690 double calculatedAngle = angle;
691 if ( averageAngleLengthPainterUnits > 0 )
694 targetPointDistanceAlongSegment,
695 segmentLengthPainterUnits, averageAngleLengthPainterUnits,
696 prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits,
697 xPainterUnits, yPainterUnits,
701 if ( !
qgsDoubleNear( targetPointFractionAlongSegment, 0 ) || isFirstPoint )
703 if ( !visitPoint( pX, pY, pZ, pM, distanceTraversed + segmentLength * targetPointFractionAlongSegment, calculatedAngle ) )
707 nextStepValue += direction * step;
710 else if ( isFirstPoint && emitFirstPoint )
712 if ( !visitPoint( prevX, prevY, prevZ, prevM, distanceTraversed,
716 isFirstPoint =
false;
722 prevXPainterUnits = thisXPainterUnits;
723 prevYPainterUnits = thisYPainterUnits;
724 prevValue = thisValue;
725 distanceTraversed += segmentLength;
736 visitPointsByInterpolatedZM( line, linePainterUnits, emitFirstPoint, distance, averageAngleLengthPainterUnits, visitPoint,
false );
739QPointF QgsLinearReferencingSymbolLayer::pointToPainter(
QgsSymbolRenderContext &context,
double x,
double y,
double z )
745 pt = QPointF( x, y );
750 pt = QPointF( x, y );
757void QgsLinearReferencingSymbolLayer::renderPolylineInterval(
const QgsLineString *line,
QgsSymbolRenderContext &context,
double skipMultiples,
const QPointF &labelOffsetPainterUnits,
double averageAngleLengthPainterUnits,
bool showMarker )
759 double distance = mInterval;
766 QgsNumericFormatContext numericContext;
769 std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
776 const bool hasZ = line->
is3D();
782 switch ( mPlacement )
800 QgsLinearReferencingSymbolLayerLabelProvider *labelProvider =
nullptr;
805 labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
808 func( line, painterUnitsGeometry.get(), emitFirstPoint, distance, averageAngleLengthPainterUnits, [&context, &numericContext, skipMultiples,
showMarker,
809 labelOffsetPainterUnits, hasZ, hasM, labelProvider,
this](
double x,
double y,
double z,
double m,
double distanceFromStart,
double angle ) ->
bool
811 if ( context.renderContext().renderingStopped() )
814 double labelValue = 0;
815 bool labelVertex = true;
816 switch ( mLabelSource )
818 case Qgis::LinearReferencingLabelSource::CartesianDistance2D:
819 labelValue = distanceFromStart;
821 case Qgis::LinearReferencingLabelSource::Z:
823 labelVertex = hasZ && !std::isnan( labelValue );
825 case Qgis::LinearReferencingLabelSource::M:
827 labelVertex = hasM && !std::isnan( labelValue );
834 if ( skipMultiples > 0 &&
qgsDoubleNear( std::fmod( labelValue, skipMultiples ), 0 ) )
837 const QPointF pt = pointToPainter( context, x, y, z );
842 mMarkerSymbol->setLineAngle( 90 - angle );
846 const double angleRadians = ( mRotateLabels ?
angle : 0 ) * M_PI / 180.0;
847 const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
848 + labelOffsetPainterUnits.y() * std::sin( angleRadians );
849 const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
850 + labelOffsetPainterUnits.y() * std::cos( angleRadians );
852 const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
853 if ( !labelProvider )
861 labelProvider->addLabel(
862 QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
870void QgsLinearReferencingSymbolLayer::renderPolylineVertex(
const QgsLineString *line,
QgsSymbolRenderContext &context,
double skipMultiples,
const QPointF &labelOffsetPainterUnits,
double averageAngleLengthPainterUnits,
bool showMarker )
875 averageAngleLengthPainterUnits = std::max( averageAngleLengthPainterUnits, 0.1 );
877 QgsNumericFormatContext numericContext;
880 QgsLinearReferencingSymbolLayerLabelProvider *labelProvider =
nullptr;
885 labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
888 const double *xData = line->
xData();
889 const double *yData = line->
yData();
890 const double *zData = line->
is3D() ? line->
zData() :
nullptr;
891 const double *mData = line->
isMeasure() ? line->
mData() :
nullptr;
896 std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
902 const double *xPainterUnits = painterUnitsGeometry->xData();
903 const double *yPainterUnits = painterUnitsGeometry->yData();
905 double currentDistance = 0;
906 double prevX = *xData;
907 double prevY = *yData;
909 for (
int i = 0; i < size; ++i )
914 double thisX = *xData++;
915 double thisY = *yData++;
916 double thisZ = zData ? *zData++ : 0;
917 double thisM = mData ? *mData++ : 0;
918 double thisXPainterUnits = *xPainterUnits++;
919 double thisYPainterUnits = *yPainterUnits++;
922 currentDistance += thisSegmentLength;
924 if ( skipMultiples > 0 &&
qgsDoubleNear( std::fmod( currentDistance, skipMultiples ), 0 ) )
931 const QPointF pt = pointToPainter( context, thisX, thisY, thisZ );
934 double painterDistRemaining = averageAngleLengthPainterUnits;
935 double startAverageSegmentX = thisXPainterUnits;
936 double startAverageSegmentY = thisYPainterUnits;
938 const double *xAveragingData = xPainterUnits;
939 const double *yAveragingData = yPainterUnits;
940 double endAverageSegmentX = *xAveragingData;
941 double endAverageSegmentY = *yAveragingData;
942 double averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
945 while ( ( j < size - 1 ) && ( painterDistRemaining > averagingSegmentLengthPainterUnits ) )
947 painterDistRemaining -= averagingSegmentLengthPainterUnits;
948 startAverageSegmentX = endAverageSegmentX;
949 startAverageSegmentY = endAverageSegmentY;
951 endAverageSegmentX = *xAveragingData++;
952 endAverageSegmentY = *yAveragingData++;
954 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
957 double endAverageXPainterUnits = thisXPainterUnits;
958 double endAverageYPainterUnits = thisYPainterUnits;
959 if ( ( j < size - 1 ) && painterDistRemaining < averagingSegmentLengthPainterUnits )
962 nullptr,
nullptr,
nullptr,
963 nullptr,
nullptr,
nullptr );
965 else if ( i < size - 2 )
967 endAverageXPainterUnits = endAverageSegmentX;
968 endAverageYPainterUnits = endAverageSegmentY;
973 painterDistRemaining = averageAngleLengthPainterUnits;
974 startAverageSegmentX = thisXPainterUnits;
975 startAverageSegmentY = thisYPainterUnits;
977 xAveragingData = xPainterUnits - 2;
978 yAveragingData = yPainterUnits - 2;
980 endAverageSegmentX = *xAveragingData;
981 endAverageSegmentY = *yAveragingData;
982 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
984 while ( j > 0 && painterDistRemaining > averagingSegmentLengthPainterUnits )
986 painterDistRemaining -= averagingSegmentLengthPainterUnits;
987 startAverageSegmentX = endAverageSegmentX;
988 startAverageSegmentY = endAverageSegmentY;
990 endAverageSegmentX = *xAveragingData--;
991 endAverageSegmentY = *yAveragingData--;
993 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
996 double startAverageXPainterUnits = thisXPainterUnits;
997 double startAverageYPainterUnits = thisYPainterUnits;
998 if ( j > 0 && painterDistRemaining < averagingSegmentLengthPainterUnits )
1001 nullptr,
nullptr,
nullptr,
1002 nullptr,
nullptr,
nullptr );
1006 startAverageXPainterUnits = endAverageSegmentX;
1007 startAverageYPainterUnits = endAverageSegmentY;
1010 double calculatedAngle = std::fmod(
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
1012 if ( calculatedAngle > 90 && calculatedAngle < 270 )
1013 calculatedAngle += 180;
1017 if ( mRotateLabels )
1018 mMarkerSymbol->setLineAngle( 90 - calculatedAngle );
1022 const double angleRadians = mRotateLabels ? ( calculatedAngle * M_PI / 180.0 ) : 0;
1023 const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
1024 + labelOffsetPainterUnits.y() * std::sin( angleRadians );
1025 const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
1026 + labelOffsetPainterUnits.y() * std::cos( angleRadians );
1028 double labelValue = 0;
1029 bool labelVertex =
true;
1030 switch ( mLabelSource )
1033 labelValue = currentDistance;
1037 labelVertex =
static_cast< bool >( zData ) && !std::isnan( labelValue );
1041 labelVertex =
static_cast< bool >( mData ) && !std::isnan( labelValue );
1048 const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
1049 if ( !labelProvider )
1057 labelProvider->addLabel(
1058 QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
1073 mTextFormat = format;
1078 return mNumericFormat.get();
1083 mNumericFormat.reset( format );
1098 return mSkipMultiplesOf;
1114 if ( show && !mMarkerSymbol )
1132 return mLabelSource;
1137 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.
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.
QgsLineSymbolLayer(const QgsLineSymbolLayer &other)=delete
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.
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.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context to use when evaluating QgsExpressions.
QPointF toQPointF() const
Converts a point to a QPointF.
A container for the context for various read/write operations on objects.
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
QgsSymbolLayer(const QgsSymbolLayer &other)
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.
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...
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.
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.
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< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
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).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
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)