40 : QgsTextLabelFeature( id, std::move( geometry ), size )
44 QgsTextFormat mFormat;
51 QgsLinearReferencingSymbolLayerLabelProvider()
52 : QgsAbstractLabelProvider( nullptr )
62 ~QgsLinearReferencingSymbolLayerLabelProvider()
override
64 qDeleteAll( mLabels );
67 void addLabel(
const QPointF &painterPoint,
double angleRadians,
const QString &text, QgsRenderContext &context,
const QgsTextFormat &format )
70 QgsPoint mapPoint( painterPoint );
78 auto feature = std::make_unique< QgsTextLabelFeatureWithFormat >( mLabels.size(),
79 QgsGeos::asGeos( &mapPoint ), QSizeF( size.width() * uPP, size.height() * uPP ), format );
81 feature->setDocument( doc, documentMetrics );
82 feature->setFixedAngle( angleRadians );
83 feature->setHasFixedAngle(
true );
86 feature->setQuadOffset( QPointF( 1, 1 ) );
88 mLabels.append( feature.release() );
91 QList<QgsLabelFeature *>
labelFeatures( QgsRenderContext & )
final
96 void drawLabel( QgsRenderContext &context, pal::LabelPosition *label )
const final
103 QgsTextLabelFeatureWithFormat *lf = qgis::down_cast<QgsTextLabelFeatureWithFormat *>( label->getFeaturePart()->feature() );
110 QList<QgsLabelFeature *> mLabels;
118 mNumericFormat = std::make_unique< QgsBasicNumericFormat >();
125 auto res = std::make_unique< QgsLinearReferencingSymbolLayer >();
129 const double interval =
properties.value( QStringLiteral(
"interval" ) ).toDouble( &ok );
132 const double skipMultiples =
properties.value( QStringLiteral(
"skip_multiples" ) ).toDouble( &ok );
134 res->setSkipMultiplesOf( skipMultiples );
135 res->setRotateLabels(
properties.value( QStringLiteral(
"rotate" ),
true ).toBool() );
136 res->setShowMarker(
properties.value( QStringLiteral(
"show_marker" ),
false ).toBool() );
143 const QString textFormatXml =
properties.value( QStringLiteral(
"text_format" ) ).toString();
144 if ( !textFormatXml.isEmpty() )
148 doc.setContent( textFormatXml );
149 elem = doc.documentElement();
156 const QString numericFormatXml =
properties.value( QStringLiteral(
"numeric_format" ) ).toString();
157 if ( !numericFormatXml.isEmpty() )
160 doc.setContent( numericFormatXml );
164 if (
properties.contains( QStringLiteral(
"label_offset" ) ) )
168 if (
properties.contains( QStringLiteral(
"label_offset_unit" ) ) )
172 if (
properties.contains( ( QStringLiteral(
"label_offset_map_unit_scale" ) ) ) )
176 if (
properties.contains( QStringLiteral(
"average_angle_length" ) ) )
178 res->setAverageAngleLength(
properties[QStringLiteral(
"average_angle_length" )].toDouble() );
180 if (
properties.contains( QStringLiteral(
"average_angle_unit" ) ) )
184 if (
properties.contains( ( QStringLiteral(
"average_angle_map_unit_scale" ) ) ) )
189 return res.release();
194 auto res = std::make_unique< QgsLinearReferencingSymbolLayer >();
195 res->setPlacement( mPlacement );
196 res->setLabelSource( mLabelSource );
197 res->setInterval( mInterval );
198 res->setSkipMultiplesOf( mSkipMultiplesOf );
199 res->setRotateLabels( mRotateLabels );
200 res->setLabelOffset( mLabelOffset );
201 res->setLabelOffsetUnit( mLabelOffsetUnit );
202 res->setLabelOffsetMapUnitScale( mLabelOffsetMapUnitScale );
203 res->setShowMarker( mShowMarker );
204 res->setAverageAngleLength( mAverageAngleLength );
205 res->setAverageAngleUnit( mAverageAngleLengthUnit );
206 res->setAverageAngleMapUnitScale( mAverageAngleLengthMapUnitScale );
208 res->mTextFormat = mTextFormat;
209 res->mMarkerSymbol.reset( mMarkerSymbol ? mMarkerSymbol->clone() :
nullptr );
210 if ( mNumericFormat )
211 res->mNumericFormat.reset( mNumericFormat->clone() );
216 return res.release();
221 QDomDocument textFormatDoc;
226 const QDomElement textElem = mTextFormat.writeXml( textFormatDoc, rwContext );
227 textFormatDoc.appendChild( textElem );
229 QDomDocument numericFormatDoc;
230 QDomElement numericFormatElem = numericFormatDoc.createElement( QStringLiteral(
"numericFormat" ) );
231 mNumericFormat->writeXml( numericFormatElem, numericFormatDoc, rwContext );
232 numericFormatDoc.appendChild( numericFormatElem );
243 QStringLiteral(
"interval" ), mInterval
246 QStringLiteral(
"rotate" ), mRotateLabels
249 QStringLiteral(
"show_marker" ), mShowMarker
252 QStringLiteral(
"text_format" ), textFormatDoc.toString()
255 QStringLiteral(
"numeric_format" ), numericFormatDoc.toString()
267 QStringLiteral(
"average_angle_length" ), mAverageAngleLength
277 if ( mSkipMultiplesOf >= 0 )
279 res.insert( QStringLiteral(
"skip_multiples" ), mSkipMultiplesOf );
287 return QStringLiteral(
"LinearReferencing" );
298 return mShowMarker ? mMarkerSymbol.get() :
nullptr;
305 mMarkerSymbol.reset( qgis::down_cast<QgsMarkerSymbol *>( symbol ) );
319 mMarkerSymbol->setRenderHints( hints );
328 QgsLinearReferencingSymbolLayerLabelProvider *provider =
new QgsLinearReferencingSymbolLayerLabelProvider();
329 mLabelProviderId = labelingEngine->addProvider( provider );
341void QgsLinearReferencingSymbolLayer::renderGeometryPart(
QgsSymbolRenderContext &context,
const QgsAbstractGeometry *geometry,
double labelOffsetPainterUnitsX,
double labelOffsetPainterUnitsY,
double skipMultiples,
double averageAngleDistancePainterUnits,
bool showMarker )
345 renderLineString( context, line, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
350 for (
int i = 0; i < polygon->numInteriorRings(); ++i )
357void QgsLinearReferencingSymbolLayer::renderLineString(
QgsSymbolRenderContext &context,
const QgsLineString *line,
double labelOffsetPainterUnitsX,
double labelOffsetPainterUnitsY,
double skipMultiples,
double averageAngleDistancePainterUnits,
bool showMarker )
362 switch ( mPlacement )
367 renderPolylineInterval( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits,
showMarker );
371 renderPolylineVertex( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits,
showMarker );
391 double skipMultiples = mSkipMultiplesOf;
398 double labelOffsetX = mLabelOffset.x();
399 double labelOffsetY = mLabelOffset.y();
401 double averageOver = mAverageAngleLength;
417 const double averageAngleDistancePainterUnits = context.
renderContext().
convertToPainterUnits( averageOver, mAverageAngleLengthUnit, mAverageAngleLengthMapUnitScale ) / 2;
421 renderGeometryPart( context, *partIt, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
427 double averageAngleLengthPainterUnits,
double prevXPainterUnits,
double prevYPainterUnits,
428 double thisXPainterUnits,
double thisYPainterUnits,
const double *xPainterUnits,
429 const double *yPainterUnits,
int totalPoints,
int i )
433 double painterDistRemaining = averageAngleLengthPainterUnits + targetPointDistanceAlongSegment;
434 double startAverageSegmentX = prevXPainterUnits;
435 double startAverageSegmentY = prevYPainterUnits;
436 double endAverageSegmentX = thisXPainterUnits;
437 double endAverageSegmentY = thisYPainterUnits;
438 double averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
439 const double *xAveragingData = xPainterUnits;
440 const double *yAveragingData = yPainterUnits;
443 while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
445 if ( j >= totalPoints - 1 )
448 painterDistRemaining -= averagingSegmentLengthPainterUnits;
449 startAverageSegmentX = endAverageSegmentX;
450 startAverageSegmentY = endAverageSegmentY;
452 endAverageSegmentX = *xAveragingData++;
453 endAverageSegmentY = *yAveragingData++;
455 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
458 double endAverageXPainterUnits;
459 double endAverageYPainterUnits;
460 if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
463 nullptr,
nullptr,
nullptr,
464 nullptr,
nullptr,
nullptr );
468 endAverageXPainterUnits = endAverageSegmentX;
469 endAverageYPainterUnits = endAverageSegmentY;
474 painterDistRemaining = ( segmentLengthPainterUnits - targetPointDistanceAlongSegment ) + averageAngleLengthPainterUnits;
475 startAverageSegmentX = thisXPainterUnits;
476 startAverageSegmentY = thisYPainterUnits;
477 endAverageSegmentX = prevXPainterUnits;
478 endAverageSegmentY = prevYPainterUnits;
479 averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
480 xAveragingData = xPainterUnits - 2;
481 yAveragingData = yPainterUnits - 2;
482 while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
487 painterDistRemaining -= averagingSegmentLengthPainterUnits;
488 startAverageSegmentX = endAverageSegmentX;
489 startAverageSegmentY = endAverageSegmentY;
491 endAverageSegmentX = *xAveragingData--;
492 endAverageSegmentY = *yAveragingData--;
494 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
497 double startAverageXPainterUnits;
498 double startAverageYPainterUnits;
499 if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
502 nullptr,
nullptr,
nullptr,
503 nullptr,
nullptr,
nullptr );
507 startAverageXPainterUnits = endAverageSegmentX;
508 startAverageYPainterUnits = endAverageSegmentY;
511 double calculatedAngle = std::fmod(
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
512 if ( calculatedAngle > 90 && calculatedAngle < 270 )
513 calculatedAngle += 180;
515 return calculatedAngle;
518typedef std::function<bool (
double x,
double y,
double z,
double m,
double distanceFromStart,
double angle )>
VisitPointFunction;
526 double distanceTraversed = 0;
527 const int totalPoints = line->
numPoints();
528 if ( totalPoints == 0 )
531 const double *x = line->
xData();
532 const double *y = line->
yData();
533 const double *z = line->
is3D() ? line->
zData() :
nullptr;
536 const double *xPainterUnits = linePainterUnits->
xData();
537 const double *yPainterUnits = linePainterUnits->
yData();
541 double prevZ = z ? *z++ : 0.0;
542 double prevM = m ? *m++ : 0.0;
544 double prevXPainterUnits = *xPainterUnits++;
545 double prevYPainterUnits = *yPainterUnits++;
549 visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
553 double pZ = std::numeric_limits<double>::quiet_NaN();
554 double pM = std::numeric_limits<double>::quiet_NaN();
555 double nextPointDistance = emitFirstPoint ? 0 : distance;
556 for (
int i = 1; i < totalPoints; ++i )
560 double thisZ = z ? *z++ : 0.0;
561 double thisM = m ? *m++ : 0.0;
562 double thisXPainterUnits = *xPainterUnits++;
563 double thisYPainterUnits = *yPainterUnits++;
565 double angle = std::fmod(
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
566 if ( angle > 90 && angle < 270 )
572 while ( nextPointDistance < distanceTraversed + segmentLength ||
qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength ) )
575 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
578 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
579 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
581 double calculatedAngle = angle;
582 if ( averageAngleLengthPainterUnits > 0 )
584 const double targetPointFractionAlongSegment = distanceToPoint / segmentLength;
585 const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
588 averageAngleLengthPainterUnits, prevXPainterUnits, prevYPainterUnits,
589 thisXPainterUnits, thisYPainterUnits, xPainterUnits,
590 yPainterUnits, totalPoints, i );
593 if ( !visitPoint( pX, pY, pZ, pM, nextPointDistance, calculatedAngle ) )
596 nextPointDistance += distance;
599 distanceTraversed += segmentLength;
604 prevXPainterUnits = thisXPainterUnits;
605 prevYPainterUnits = thisYPainterUnits;
611 return a + ( b - a ) * fraction;
620 double distanceTraversed = 0;
621 const int totalPoints = line->
numPoints();
622 if ( totalPoints < 2 )
625 const double *x = line->
xData();
626 const double *y = line->
yData();
627 const double *z = line->
is3D() ? line->
zData() :
nullptr;
630 const double *xPainterUnits = linePainterUnits->
xData();
631 const double *yPainterUnits = linePainterUnits->
yData();
635 double prevZ = z ? *z++ : 0.0;
636 double prevM = m ? *m++ : 0.0;
638 double prevXPainterUnits = *xPainterUnits++;
639 double prevYPainterUnits = *yPainterUnits++;
643 visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
647 double prevValue = useZ ? prevZ : prevM;
648 bool isFirstPoint =
true;
649 for (
int i = 1; i < totalPoints; ++i )
653 double thisZ = z ? *z++ : 0.0;
654 double thisM = m ? *m++ : 0.0;
655 const double thisValue = useZ ? thisZ : thisM;
656 double thisXPainterUnits = *xPainterUnits++;
657 double thisYPainterUnits = *yPainterUnits++;
659 double angle = std::fmod(
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
660 if ( angle > 90 && angle < 270 )
667 const int direction = ( thisValue > prevValue ) ? 1 : ( thisValue < prevValue ) ? -1 : 0;
668 if ( direction != 0 )
671 double nextStepValue = direction > 0 ? std::ceil( prevValue / step ) * step
672 : std::floor( prevValue / step ) * step;
674 while ( ( direction > 0 && ( nextStepValue <= thisValue ||
qgsDoubleNear( nextStepValue, thisValue ) ) ) ||
675 ( direction < 0 && ( nextStepValue >= thisValue ||
qgsDoubleNear( nextStepValue, thisValue ) ) ) )
677 const double targetPointFractionAlongSegment = ( nextStepValue - prevValue ) / ( thisValue - prevValue );
678 const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
683 const double pZ = useZ ? nextStepValue :
interpolateValue( prevZ, thisZ, targetPointFractionAlongSegment );
684 const double pM = useZ ?
interpolateValue( prevM, thisM, targetPointFractionAlongSegment ) : nextStepValue;
686 double calculatedAngle = angle;
687 if ( averageAngleLengthPainterUnits > 0 )
690 targetPointDistanceAlongSegment,
691 segmentLengthPainterUnits, averageAngleLengthPainterUnits,
692 prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits,
693 xPainterUnits, yPainterUnits,
697 if ( !
qgsDoubleNear( targetPointFractionAlongSegment, 0 ) || isFirstPoint )
699 if ( !visitPoint( pX, pY, pZ, pM, distanceTraversed + segmentLength * targetPointFractionAlongSegment, calculatedAngle ) )
703 nextStepValue += direction * step;
706 else if ( isFirstPoint && emitFirstPoint )
708 if ( !visitPoint( prevX, prevY, prevZ, prevM, distanceTraversed,
712 isFirstPoint =
false;
718 prevXPainterUnits = thisXPainterUnits;
719 prevYPainterUnits = thisYPainterUnits;
720 prevValue = thisValue;
721 distanceTraversed += segmentLength;
732 visitPointsByInterpolatedZM( line, linePainterUnits, emitFirstPoint, distance, averageAngleLengthPainterUnits, visitPoint,
false );
735QPointF QgsLinearReferencingSymbolLayer::pointToPainter(
QgsSymbolRenderContext &context,
double x,
double y,
double z )
741 pt = QPointF( x, y );
746 pt = QPointF( x, y );
753void QgsLinearReferencingSymbolLayer::renderPolylineInterval(
const QgsLineString *line,
QgsSymbolRenderContext &context,
double skipMultiples,
const QPointF &labelOffsetPainterUnits,
double averageAngleLengthPainterUnits,
bool showMarker )
755 double distance = mInterval;
762 QgsNumericFormatContext numericContext;
765 std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
772 const bool hasZ = line->
is3D();
778 switch ( mPlacement )
796 QgsLinearReferencingSymbolLayerLabelProvider *labelProvider =
nullptr;
801 labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
804 func( line, painterUnitsGeometry.get(), emitFirstPoint, distance, averageAngleLengthPainterUnits, [&context, &numericContext, skipMultiples,
showMarker,
805 labelOffsetPainterUnits, hasZ, hasM, labelProvider,
this](
double x,
double y,
double z,
double m,
double distanceFromStart,
double angle ) ->
bool
807 if ( context.renderContext().renderingStopped() )
810 double labelValue = 0;
811 bool labelVertex = true;
812 switch ( mLabelSource )
814 case Qgis::LinearReferencingLabelSource::CartesianDistance2D:
815 labelValue = distanceFromStart;
817 case Qgis::LinearReferencingLabelSource::Z:
819 labelVertex = hasZ && !std::isnan( labelValue );
821 case Qgis::LinearReferencingLabelSource::M:
823 labelVertex = hasM && !std::isnan( labelValue );
830 if ( skipMultiples > 0 &&
qgsDoubleNear( std::fmod( labelValue, skipMultiples ), 0 ) )
833 const QPointF pt = pointToPainter( context, x, y, z );
838 mMarkerSymbol->setLineAngle( 90 - angle );
842 const double angleRadians = ( mRotateLabels ?
angle : 0 ) * M_PI / 180.0;
843 const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
844 + labelOffsetPainterUnits.y() * std::sin( angleRadians );
845 const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
846 + labelOffsetPainterUnits.y() * std::cos( angleRadians );
848 const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
849 if ( !labelProvider )
857 labelProvider->addLabel(
858 QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
866void QgsLinearReferencingSymbolLayer::renderPolylineVertex(
const QgsLineString *line,
QgsSymbolRenderContext &context,
double skipMultiples,
const QPointF &labelOffsetPainterUnits,
double averageAngleLengthPainterUnits,
bool showMarker )
871 averageAngleLengthPainterUnits = std::max( averageAngleLengthPainterUnits, 0.1 );
873 QgsNumericFormatContext numericContext;
876 QgsLinearReferencingSymbolLayerLabelProvider *labelProvider =
nullptr;
881 labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
884 const double *xData = line->
xData();
885 const double *yData = line->
yData();
886 const double *zData = line->
is3D() ? line->
zData() :
nullptr;
887 const double *mData = line->
isMeasure() ? line->
mData() :
nullptr;
892 std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
898 const double *xPainterUnits = painterUnitsGeometry->xData();
899 const double *yPainterUnits = painterUnitsGeometry->yData();
901 double currentDistance = 0;
902 double prevX = *xData;
903 double prevY = *yData;
905 for (
int i = 0; i < size; ++i )
910 double thisX = *xData++;
911 double thisY = *yData++;
912 double thisZ = zData ? *zData++ : 0;
913 double thisM = mData ? *mData++ : 0;
914 double thisXPainterUnits = *xPainterUnits++;
915 double thisYPainterUnits = *yPainterUnits++;
918 currentDistance += thisSegmentLength;
920 if ( skipMultiples > 0 &&
qgsDoubleNear( std::fmod( currentDistance, skipMultiples ), 0 ) )
927 const QPointF pt = pointToPainter( context, thisX, thisY, thisZ );
930 double painterDistRemaining = averageAngleLengthPainterUnits;
931 double startAverageSegmentX = thisXPainterUnits;
932 double startAverageSegmentY = thisYPainterUnits;
934 const double *xAveragingData = xPainterUnits;
935 const double *yAveragingData = yPainterUnits;
936 double endAverageSegmentX = *xAveragingData;
937 double endAverageSegmentY = *yAveragingData;
938 double averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
941 while ( ( j < size - 1 ) && ( painterDistRemaining > averagingSegmentLengthPainterUnits ) )
943 painterDistRemaining -= averagingSegmentLengthPainterUnits;
944 startAverageSegmentX = endAverageSegmentX;
945 startAverageSegmentY = endAverageSegmentY;
947 endAverageSegmentX = *xAveragingData++;
948 endAverageSegmentY = *yAveragingData++;
950 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
953 double endAverageXPainterUnits = thisXPainterUnits;
954 double endAverageYPainterUnits = thisYPainterUnits;
955 if ( ( j < size - 1 ) && painterDistRemaining < averagingSegmentLengthPainterUnits )
958 nullptr,
nullptr,
nullptr,
959 nullptr,
nullptr,
nullptr );
961 else if ( i < size - 2 )
963 endAverageXPainterUnits = endAverageSegmentX;
964 endAverageYPainterUnits = endAverageSegmentY;
969 painterDistRemaining = averageAngleLengthPainterUnits;
970 startAverageSegmentX = thisXPainterUnits;
971 startAverageSegmentY = thisYPainterUnits;
973 xAveragingData = xPainterUnits - 2;
974 yAveragingData = yPainterUnits - 2;
976 endAverageSegmentX = *xAveragingData;
977 endAverageSegmentY = *yAveragingData;
978 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
980 while ( j > 0 && painterDistRemaining > averagingSegmentLengthPainterUnits )
982 painterDistRemaining -= averagingSegmentLengthPainterUnits;
983 startAverageSegmentX = endAverageSegmentX;
984 startAverageSegmentY = endAverageSegmentY;
986 endAverageSegmentX = *xAveragingData--;
987 endAverageSegmentY = *yAveragingData--;
989 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
992 double startAverageXPainterUnits = thisXPainterUnits;
993 double startAverageYPainterUnits = thisYPainterUnits;
994 if ( j > 0 && painterDistRemaining < averagingSegmentLengthPainterUnits )
997 nullptr,
nullptr,
nullptr,
998 nullptr,
nullptr,
nullptr );
1002 startAverageXPainterUnits = endAverageSegmentX;
1003 startAverageYPainterUnits = endAverageSegmentY;
1006 double calculatedAngle = std::fmod(
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
1008 if ( calculatedAngle > 90 && calculatedAngle < 270 )
1009 calculatedAngle += 180;
1013 if ( mRotateLabels )
1014 mMarkerSymbol->setLineAngle( 90 - calculatedAngle );
1018 const double angleRadians = mRotateLabels ? ( calculatedAngle * M_PI / 180.0 ) : 0;
1019 const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
1020 + labelOffsetPainterUnits.y() * std::sin( angleRadians );
1021 const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
1022 + labelOffsetPainterUnits.y() * std::cos( angleRadians );
1024 double labelValue = 0;
1025 bool labelVertex =
true;
1026 switch ( mLabelSource )
1029 labelValue = currentDistance;
1033 labelVertex =
static_cast< bool >( zData ) && !std::isnan( labelValue );
1037 labelVertex =
static_cast< bool >( mData ) && !std::isnan( labelValue );
1044 const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
1045 if ( !labelProvider )
1053 labelProvider->addLabel(
1054 QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
1069 mTextFormat = format;
1074 return mNumericFormat.get();
1079 mNumericFormat.reset( format );
1094 return mSkipMultiplesOf;
1110 if ( show && !mMarkerSymbol )
1128 return mLabelSource;
1133 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)