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() );
219 return res.release();
224 QDomDocument textFormatDoc;
229 const QDomElement textElem = mTextFormat.writeXml( textFormatDoc, rwContext );
230 textFormatDoc.appendChild( textElem );
232 QDomDocument numericFormatDoc;
233 QDomElement numericFormatElem = numericFormatDoc.createElement( u
"numericFormat"_s );
234 mNumericFormat->writeXml( numericFormatElem, numericFormatDoc, rwContext );
235 numericFormatDoc.appendChild( numericFormatElem );
246 u
"interval"_s, mInterval
249 u
"rotate"_s, mRotateLabels
252 u
"show_marker"_s, mShowMarker
255 u
"text_format"_s, textFormatDoc.toString()
258 u
"numeric_format"_s, numericFormatDoc.toString()
270 u
"average_angle_length"_s, mAverageAngleLength
280 if ( mSkipMultiplesOf >= 0 )
282 res.insert( u
"skip_multiples"_s, mSkipMultiplesOf );
290 return u
"LinearReferencing"_s;
301 return mShowMarker ? mMarkerSymbol.get() :
nullptr;
308 mMarkerSymbol.reset( qgis::down_cast<QgsMarkerSymbol *>( symbol ) );
322 mMarkerSymbol->setRenderHints( hints );
331 QgsLinearReferencingSymbolLayerLabelProvider *provider =
new QgsLinearReferencingSymbolLayerLabelProvider();
332 mLabelProviderId = labelingEngine->addProvider( provider );
344void QgsLinearReferencingSymbolLayer::renderGeometryPart(
QgsSymbolRenderContext &context,
const QgsAbstractGeometry *geometry,
double labelOffsetPainterUnitsX,
double labelOffsetPainterUnitsY,
double skipMultiples,
double averageAngleDistancePainterUnits,
bool showMarker )
348 renderLineString( context, line, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
353 for (
int i = 0; i < polygon->numInteriorRings(); ++i )
360void QgsLinearReferencingSymbolLayer::renderLineString(
QgsSymbolRenderContext &context,
const QgsLineString *line,
double labelOffsetPainterUnitsX,
double labelOffsetPainterUnitsY,
double skipMultiples,
double averageAngleDistancePainterUnits,
bool showMarker )
365 switch ( mPlacement )
370 renderPolylineInterval( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits,
showMarker );
374 renderPolylineVertex( line, context, skipMultiples, QPointF( labelOffsetPainterUnitsX, labelOffsetPainterUnitsY ), averageAngleDistancePainterUnits,
showMarker );
394 double skipMultiples = mSkipMultiplesOf;
401 double labelOffsetX = mLabelOffset.x();
402 double labelOffsetY = mLabelOffset.y();
404 double averageOver = mAverageAngleLength;
420 const double averageAngleDistancePainterUnits = context.
renderContext().
convertToPainterUnits( averageOver, mAverageAngleLengthUnit, mAverageAngleLengthMapUnitScale ) / 2;
424 renderGeometryPart( context, *partIt, labelOffsetPainterUnitsX, labelOffsetPainterUnitsY, skipMultiples, averageAngleDistancePainterUnits,
showMarker );
430 double averageAngleLengthPainterUnits,
double prevXPainterUnits,
double prevYPainterUnits,
431 double thisXPainterUnits,
double thisYPainterUnits,
const double *xPainterUnits,
432 const double *yPainterUnits,
int totalPoints,
int i )
436 double painterDistRemaining = averageAngleLengthPainterUnits + targetPointDistanceAlongSegment;
437 double startAverageSegmentX = prevXPainterUnits;
438 double startAverageSegmentY = prevYPainterUnits;
439 double endAverageSegmentX = thisXPainterUnits;
440 double endAverageSegmentY = thisYPainterUnits;
441 double averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
442 const double *xAveragingData = xPainterUnits;
443 const double *yAveragingData = yPainterUnits;
446 while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
448 if ( j >= totalPoints - 1 )
451 painterDistRemaining -= averagingSegmentLengthPainterUnits;
452 startAverageSegmentX = endAverageSegmentX;
453 startAverageSegmentY = endAverageSegmentY;
455 endAverageSegmentX = *xAveragingData++;
456 endAverageSegmentY = *yAveragingData++;
458 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
461 double endAverageXPainterUnits;
462 double endAverageYPainterUnits;
463 if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
466 nullptr,
nullptr,
nullptr,
467 nullptr,
nullptr,
nullptr );
471 endAverageXPainterUnits = endAverageSegmentX;
472 endAverageYPainterUnits = endAverageSegmentY;
477 painterDistRemaining = ( segmentLengthPainterUnits - targetPointDistanceAlongSegment ) + averageAngleLengthPainterUnits;
478 startAverageSegmentX = thisXPainterUnits;
479 startAverageSegmentY = thisYPainterUnits;
480 endAverageSegmentX = prevXPainterUnits;
481 endAverageSegmentY = prevYPainterUnits;
482 averagingSegmentLengthPainterUnits = segmentLengthPainterUnits;
483 xAveragingData = xPainterUnits - 2;
484 yAveragingData = yPainterUnits - 2;
485 while ( painterDistRemaining > averagingSegmentLengthPainterUnits )
490 painterDistRemaining -= averagingSegmentLengthPainterUnits;
491 startAverageSegmentX = endAverageSegmentX;
492 startAverageSegmentY = endAverageSegmentY;
494 endAverageSegmentX = *xAveragingData--;
495 endAverageSegmentY = *yAveragingData--;
497 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
500 double startAverageXPainterUnits;
501 double startAverageYPainterUnits;
502 if ( painterDistRemaining < averagingSegmentLengthPainterUnits )
505 nullptr,
nullptr,
nullptr,
506 nullptr,
nullptr,
nullptr );
510 startAverageXPainterUnits = endAverageSegmentX;
511 startAverageYPainterUnits = endAverageSegmentY;
514 double calculatedAngle = std::fmod(
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
515 if ( calculatedAngle > 90 && calculatedAngle < 270 )
516 calculatedAngle += 180;
518 return calculatedAngle;
521typedef std::function<bool (
double x,
double y,
double z,
double m,
double distanceFromStart,
double angle )>
VisitPointFunction;
529 double distanceTraversed = 0;
530 const int totalPoints = line->
numPoints();
531 if ( totalPoints == 0 )
534 const double *x = line->
xData();
535 const double *y = line->
yData();
536 const double *z = line->
is3D() ? line->
zData() :
nullptr;
539 const double *xPainterUnits = linePainterUnits->
xData();
540 const double *yPainterUnits = linePainterUnits->
yData();
544 double prevZ = z ? *z++ : 0.0;
545 double prevM = m ? *m++ : 0.0;
547 double prevXPainterUnits = *xPainterUnits++;
548 double prevYPainterUnits = *yPainterUnits++;
552 visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
556 double pZ = std::numeric_limits<double>::quiet_NaN();
557 double pM = std::numeric_limits<double>::quiet_NaN();
558 double nextPointDistance = emitFirstPoint ? 0 : distance;
559 for (
int i = 1; i < totalPoints; ++i )
563 double thisZ = z ? *z++ : 0.0;
564 double thisM = m ? *m++ : 0.0;
565 double thisXPainterUnits = *xPainterUnits++;
566 double thisYPainterUnits = *yPainterUnits++;
568 double angle = std::fmod(
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
569 if ( angle > 90 && angle < 270 )
575 while ( nextPointDistance < distanceTraversed + segmentLength ||
qgsDoubleNear( nextPointDistance, distanceTraversed + segmentLength ) )
578 const double distanceToPoint = std::min( nextPointDistance - distanceTraversed, segmentLength );
581 z ? &prevZ :
nullptr, z ? &thisZ :
nullptr, z ? &pZ :
nullptr,
582 m ? &prevM :
nullptr, m ? &thisM :
nullptr, m ? &pM :
nullptr );
584 double calculatedAngle = angle;
585 if ( averageAngleLengthPainterUnits > 0 )
587 const double targetPointFractionAlongSegment = distanceToPoint / segmentLength;
588 const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
591 averageAngleLengthPainterUnits, prevXPainterUnits, prevYPainterUnits,
592 thisXPainterUnits, thisYPainterUnits, xPainterUnits,
593 yPainterUnits, totalPoints, i );
596 if ( !visitPoint( pX, pY, pZ, pM, nextPointDistance, calculatedAngle ) )
599 nextPointDistance += distance;
602 distanceTraversed += segmentLength;
607 prevXPainterUnits = thisXPainterUnits;
608 prevYPainterUnits = thisYPainterUnits;
614 return a + ( b - a ) * fraction;
623 double distanceTraversed = 0;
624 const int totalPoints = line->
numPoints();
625 if ( totalPoints < 2 )
628 const double *x = line->
xData();
629 const double *y = line->
yData();
630 const double *z = line->
is3D() ? line->
zData() :
nullptr;
633 const double *xPainterUnits = linePainterUnits->
xData();
634 const double *yPainterUnits = linePainterUnits->
yData();
638 double prevZ = z ? *z++ : 0.0;
639 double prevM = m ? *m++ : 0.0;
641 double prevXPainterUnits = *xPainterUnits++;
642 double prevYPainterUnits = *yPainterUnits++;
646 visitPoint( prevX, prevY, prevZ, prevM, 0, 0 );
650 double prevValue = useZ ? prevZ : prevM;
651 bool isFirstPoint =
true;
652 for (
int i = 1; i < totalPoints; ++i )
656 double thisZ = z ? *z++ : 0.0;
657 double thisM = m ? *m++ : 0.0;
658 const double thisValue = useZ ? thisZ : thisM;
659 double thisXPainterUnits = *xPainterUnits++;
660 double thisYPainterUnits = *yPainterUnits++;
662 double angle = std::fmod(
QgsGeometryUtilsBase::azimuth( prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits ) + 360, 360 );
663 if ( angle > 90 && angle < 270 )
670 const int direction = ( thisValue > prevValue ) ? 1 : ( thisValue < prevValue ) ? -1 : 0;
671 if ( direction != 0 )
674 double nextStepValue = direction > 0 ? std::ceil( prevValue / step ) * step
675 : std::floor( prevValue / step ) * step;
677 while ( ( direction > 0 && ( nextStepValue <= thisValue ||
qgsDoubleNear( nextStepValue, thisValue ) ) ) ||
678 ( direction < 0 && ( nextStepValue >= thisValue ||
qgsDoubleNear( nextStepValue, thisValue ) ) ) )
680 const double targetPointFractionAlongSegment = ( nextStepValue - prevValue ) / ( thisValue - prevValue );
681 const double targetPointDistanceAlongSegment = targetPointFractionAlongSegment * segmentLengthPainterUnits;
686 const double pZ = useZ ? nextStepValue :
interpolateValue( prevZ, thisZ, targetPointFractionAlongSegment );
687 const double pM = useZ ?
interpolateValue( prevM, thisM, targetPointFractionAlongSegment ) : nextStepValue;
689 double calculatedAngle = angle;
690 if ( averageAngleLengthPainterUnits > 0 )
693 targetPointDistanceAlongSegment,
694 segmentLengthPainterUnits, averageAngleLengthPainterUnits,
695 prevXPainterUnits, prevYPainterUnits, thisXPainterUnits, thisYPainterUnits,
696 xPainterUnits, yPainterUnits,
700 if ( !
qgsDoubleNear( targetPointFractionAlongSegment, 0 ) || isFirstPoint )
702 if ( !visitPoint( pX, pY, pZ, pM, distanceTraversed + segmentLength * targetPointFractionAlongSegment, calculatedAngle ) )
706 nextStepValue += direction * step;
709 else if ( isFirstPoint && emitFirstPoint )
711 if ( !visitPoint( prevX, prevY, prevZ, prevM, distanceTraversed,
715 isFirstPoint =
false;
721 prevXPainterUnits = thisXPainterUnits;
722 prevYPainterUnits = thisYPainterUnits;
723 prevValue = thisValue;
724 distanceTraversed += segmentLength;
735 visitPointsByInterpolatedZM( line, linePainterUnits, emitFirstPoint, distance, averageAngleLengthPainterUnits, visitPoint,
false );
738QPointF QgsLinearReferencingSymbolLayer::pointToPainter(
QgsSymbolRenderContext &context,
double x,
double y,
double z )
744 pt = QPointF( x, y );
749 pt = QPointF( x, y );
756void QgsLinearReferencingSymbolLayer::renderPolylineInterval(
const QgsLineString *line,
QgsSymbolRenderContext &context,
double skipMultiples,
const QPointF &labelOffsetPainterUnits,
double averageAngleLengthPainterUnits,
bool showMarker )
758 double distance = mInterval;
765 QgsNumericFormatContext numericContext;
768 std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
775 const bool hasZ = line->
is3D();
781 switch ( mPlacement )
799 QgsLinearReferencingSymbolLayerLabelProvider *labelProvider =
nullptr;
804 labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
807 func( line, painterUnitsGeometry.get(), emitFirstPoint, distance, averageAngleLengthPainterUnits, [&context, &numericContext, skipMultiples,
showMarker,
808 labelOffsetPainterUnits, hasZ, hasM, labelProvider,
this](
double x,
double y,
double z,
double m,
double distanceFromStart,
double angle ) ->
bool
810 if ( context.renderContext().renderingStopped() )
813 double labelValue = 0;
814 bool labelVertex = true;
815 switch ( mLabelSource )
817 case Qgis::LinearReferencingLabelSource::CartesianDistance2D:
818 labelValue = distanceFromStart;
820 case Qgis::LinearReferencingLabelSource::Z:
822 labelVertex = hasZ && !std::isnan( labelValue );
824 case Qgis::LinearReferencingLabelSource::M:
826 labelVertex = hasM && !std::isnan( labelValue );
833 if ( skipMultiples > 0 &&
qgsDoubleNear( std::fmod( labelValue, skipMultiples ), 0 ) )
836 const QPointF pt = pointToPainter( context, x, y, z );
841 mMarkerSymbol->setLineAngle( 90 - angle );
845 const double angleRadians = ( mRotateLabels ?
angle : 0 ) * M_PI / 180.0;
846 const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
847 + labelOffsetPainterUnits.y() * std::sin( angleRadians );
848 const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
849 + labelOffsetPainterUnits.y() * std::cos( angleRadians );
851 const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
852 if ( !labelProvider )
860 labelProvider->addLabel(
861 QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
869void QgsLinearReferencingSymbolLayer::renderPolylineVertex(
const QgsLineString *line,
QgsSymbolRenderContext &context,
double skipMultiples,
const QPointF &labelOffsetPainterUnits,
double averageAngleLengthPainterUnits,
bool showMarker )
874 averageAngleLengthPainterUnits = std::max( averageAngleLengthPainterUnits, 0.1 );
876 QgsNumericFormatContext numericContext;
879 QgsLinearReferencingSymbolLayerLabelProvider *labelProvider =
nullptr;
884 labelProvider = qgis::down_cast< QgsLinearReferencingSymbolLayerLabelProvider * >( labelingEngine->providerById( mLabelProviderId ) );
887 const double *xData = line->
xData();
888 const double *yData = line->
yData();
889 const double *zData = line->
is3D() ? line->
zData() :
nullptr;
890 const double *mData = line->
isMeasure() ? line->
mData() :
nullptr;
895 std::unique_ptr< QgsLineString > painterUnitsGeometry( line->
clone() );
901 const double *xPainterUnits = painterUnitsGeometry->xData();
902 const double *yPainterUnits = painterUnitsGeometry->yData();
904 double currentDistance = 0;
905 double prevX = *xData;
906 double prevY = *yData;
908 for (
int i = 0; i < size; ++i )
913 double thisX = *xData++;
914 double thisY = *yData++;
915 double thisZ = zData ? *zData++ : 0;
916 double thisM = mData ? *mData++ : 0;
917 double thisXPainterUnits = *xPainterUnits++;
918 double thisYPainterUnits = *yPainterUnits++;
921 currentDistance += thisSegmentLength;
923 if ( skipMultiples > 0 &&
qgsDoubleNear( std::fmod( currentDistance, skipMultiples ), 0 ) )
930 const QPointF pt = pointToPainter( context, thisX, thisY, thisZ );
933 double painterDistRemaining = averageAngleLengthPainterUnits;
934 double startAverageSegmentX = thisXPainterUnits;
935 double startAverageSegmentY = thisYPainterUnits;
937 const double *xAveragingData = xPainterUnits;
938 const double *yAveragingData = yPainterUnits;
939 double endAverageSegmentX = *xAveragingData;
940 double endAverageSegmentY = *yAveragingData;
941 double averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
944 while ( ( j < size - 1 ) && ( painterDistRemaining > averagingSegmentLengthPainterUnits ) )
946 painterDistRemaining -= averagingSegmentLengthPainterUnits;
947 startAverageSegmentX = endAverageSegmentX;
948 startAverageSegmentY = endAverageSegmentY;
950 endAverageSegmentX = *xAveragingData++;
951 endAverageSegmentY = *yAveragingData++;
953 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
956 double endAverageXPainterUnits = thisXPainterUnits;
957 double endAverageYPainterUnits = thisYPainterUnits;
958 if ( ( j < size - 1 ) && painterDistRemaining < averagingSegmentLengthPainterUnits )
961 nullptr,
nullptr,
nullptr,
962 nullptr,
nullptr,
nullptr );
964 else if ( i < size - 2 )
966 endAverageXPainterUnits = endAverageSegmentX;
967 endAverageYPainterUnits = endAverageSegmentY;
972 painterDistRemaining = averageAngleLengthPainterUnits;
973 startAverageSegmentX = thisXPainterUnits;
974 startAverageSegmentY = thisYPainterUnits;
976 xAveragingData = xPainterUnits - 2;
977 yAveragingData = yPainterUnits - 2;
979 endAverageSegmentX = *xAveragingData;
980 endAverageSegmentY = *yAveragingData;
981 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
983 while ( j > 0 && painterDistRemaining > averagingSegmentLengthPainterUnits )
985 painterDistRemaining -= averagingSegmentLengthPainterUnits;
986 startAverageSegmentX = endAverageSegmentX;
987 startAverageSegmentY = endAverageSegmentY;
989 endAverageSegmentX = *xAveragingData--;
990 endAverageSegmentY = *yAveragingData--;
992 averagingSegmentLengthPainterUnits =
QgsGeometryUtilsBase::distance2D( startAverageSegmentX, startAverageSegmentY, endAverageSegmentX, endAverageSegmentY );
995 double startAverageXPainterUnits = thisXPainterUnits;
996 double startAverageYPainterUnits = thisYPainterUnits;
997 if ( j > 0 && painterDistRemaining < averagingSegmentLengthPainterUnits )
1000 nullptr,
nullptr,
nullptr,
1001 nullptr,
nullptr,
nullptr );
1005 startAverageXPainterUnits = endAverageSegmentX;
1006 startAverageYPainterUnits = endAverageSegmentY;
1009 double calculatedAngle = std::fmod(
QgsGeometryUtilsBase::azimuth( startAverageXPainterUnits, startAverageYPainterUnits, endAverageXPainterUnits, endAverageYPainterUnits ) + 360, 360 );
1011 if ( calculatedAngle > 90 && calculatedAngle < 270 )
1012 calculatedAngle += 180;
1016 if ( mRotateLabels )
1017 mMarkerSymbol->setLineAngle( 90 - calculatedAngle );
1021 const double angleRadians = mRotateLabels ? ( calculatedAngle * M_PI / 180.0 ) : 0;
1022 const double dx = labelOffsetPainterUnits.x() * std::sin( angleRadians + M_PI_2 )
1023 + labelOffsetPainterUnits.y() * std::sin( angleRadians );
1024 const double dy = labelOffsetPainterUnits.x() * std::cos( angleRadians + M_PI_2 )
1025 + labelOffsetPainterUnits.y() * std::cos( angleRadians );
1027 double labelValue = 0;
1028 bool labelVertex =
true;
1029 switch ( mLabelSource )
1032 labelValue = currentDistance;
1036 labelVertex =
static_cast< bool >( zData ) && !std::isnan( labelValue );
1040 labelVertex =
static_cast< bool >( mData ) && !std::isnan( labelValue );
1047 const QString text = mNumericFormat->formatDouble( labelValue, numericContext );
1048 if ( !labelProvider )
1056 labelProvider->addLabel(
1057 QPointF( pt.x() + dx, pt.y() + dy ), angleRadians, text, context.
renderContext(), mTextFormat
1072 mTextFormat = format;
1077 return mNumericFormat.get();
1082 mNumericFormat.reset( format );
1097 return mSkipMultiplesOf;
1113 if ( show && !mMarkerSymbol )
1131 return mLabelSource;
1136 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 copyCommonProperties(QgsSymbolLayer *destLayer) const
Copies all common base class properties from this layer to another symbol layer.
@ SkipMultiples
Skip multiples of.
@ ShowMarker
Show markers.
@ AverageAngleLength
Length to average symbol angles over.
@ Interval
Line marker interval.
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)