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