46#include <QDomDocument>
55 mCustomDashVector << 5 << 2;
65 mCustomDashPatternUnit = unit;
66 mDashPatternOffsetUnit = unit;
67 mTrimDistanceStartUnit = unit;
68 mTrimDistanceEndUnit = unit;
92 mCustomDashPatternMapUnitScale = scale;
112 if ( props.contains( QStringLiteral(
"line_color" ) ) )
116 else if ( props.contains( QStringLiteral(
"outline_color" ) ) )
120 else if ( props.contains( QStringLiteral(
"color" ) ) )
125 if ( props.contains( QStringLiteral(
"line_width" ) ) )
127 width = props[QStringLiteral(
"line_width" )].toDouble();
129 else if ( props.contains( QStringLiteral(
"outline_width" ) ) )
131 width = props[QStringLiteral(
"outline_width" )].toDouble();
133 else if ( props.contains( QStringLiteral(
"width" ) ) )
136 width = props[QStringLiteral(
"width" )].toDouble();
138 if ( props.contains( QStringLiteral(
"line_style" ) ) )
142 else if ( props.contains( QStringLiteral(
"outline_style" ) ) )
146 else if ( props.contains( QStringLiteral(
"penstyle" ) ) )
152 if ( props.contains( QStringLiteral(
"line_width_unit" ) ) )
156 else if ( props.contains( QStringLiteral(
"outline_width_unit" ) ) )
160 else if ( props.contains( QStringLiteral(
"width_unit" ) ) )
165 if ( props.contains( QStringLiteral(
"width_map_unit_scale" ) ) )
167 if ( props.contains( QStringLiteral(
"offset" ) ) )
168 l->
setOffset( props[QStringLiteral(
"offset" )].toDouble() );
169 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
171 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
173 if ( props.contains( QStringLiteral(
"joinstyle" ) ) )
175 if ( props.contains( QStringLiteral(
"capstyle" ) ) )
178 if ( props.contains( QStringLiteral(
"use_custom_dash" ) ) )
182 if ( props.contains( QStringLiteral(
"customdash" ) ) )
186 if ( props.contains( QStringLiteral(
"customdash_unit" ) ) )
190 if ( props.contains( QStringLiteral(
"customdash_map_unit_scale" ) ) )
195 if ( props.contains( QStringLiteral(
"draw_inside_polygon" ) ) )
200 if ( props.contains( QStringLiteral(
"ring_filter" ) ) )
205 if ( props.contains( QStringLiteral(
"dash_pattern_offset" ) ) )
207 if ( props.contains( QStringLiteral(
"dash_pattern_offset_unit" ) ) )
209 if ( props.contains( QStringLiteral(
"dash_pattern_offset_map_unit_scale" ) ) )
212 if ( props.contains( QStringLiteral(
"trim_distance_start" ) ) )
214 if ( props.contains( QStringLiteral(
"trim_distance_start_unit" ) ) )
216 if ( props.contains( QStringLiteral(
"trim_distance_start_map_unit_scale" ) ) )
218 if ( props.contains( QStringLiteral(
"trim_distance_end" ) ) )
220 if ( props.contains( QStringLiteral(
"trim_distance_end_unit" ) ) )
222 if ( props.contains( QStringLiteral(
"trim_distance_end_map_unit_scale" ) ) )
225 if ( props.contains( QStringLiteral(
"align_dash_pattern" ) ) )
228 if ( props.contains( QStringLiteral(
"tweak_dash_pattern_on_corners" ) ) )
238 return QStringLiteral(
"SimpleLine" );
250 mPen.setColor( penColor );
252 mPen.setWidthF( scaledWidth );
256 const double dashWidthDiv = std::max( 1.0, scaledWidth );
257 if ( mUseCustomDashPattern )
259 mPen.setStyle( Qt::CustomDashLine );
263 QVector<qreal> scaledVector;
264 QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
265 for ( ; it != mCustomDashVector.constEnd(); ++it )
270 mPen.setDashPattern( scaledVector );
274 mPen.setStyle( mPenStyle );
277 if ( mDashPatternOffset && mPen.style() != Qt::SolidLine )
282 mPen.setJoinStyle( mPenJoinStyle );
283 mPen.setCapStyle( mPenCapStyle );
288 selColor.setAlphaF( context.
opacity() );
289 mSelPen.setColor( selColor );
306 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
313 if ( mDrawInsidePolygon )
321 if ( mDrawInsidePolygon )
324 QPainterPath clipPath;
325 clipPath.addPolygon( points );
330 for (
auto it = rings->constBegin(); it != rings->constEnd(); ++it )
332 QPolygonF ring = *it;
333 clipPath.addPolygon( ring );
338 p->setClipPath( clipPath, Qt::IntersectClip );
361 for (
const QPolygonF &ring : std::as_const( *rings ) )
377 if ( mDrawInsidePolygon )
393 QPolygonF points = pts;
395 double startTrim = mTrimDistanceStart;
401 double endTrim = mTrimDistanceEnd;
408 double totalLength = -1;
412 startTrim = startTrim * 0.01 * totalLength;
420 if ( totalLength < 0 )
422 endTrim = endTrim * 0.01 * totalLength;
435 mPen.setColor( penColor );
438 applyDataDefinedSymbology( context, mPen, mSelPen,
offset );
441 const QPen pen = useSelectedColor ? mSelPen : mPen;
443 if ( !pen.dashPattern().isEmpty() )
446 const QVector<double> pattern = pen.dashPattern();
447 bool foundNonNull =
false;
448 for (
int i = 0; i < pattern.size(); ++i )
460 p->setBrush( Qt::NoBrush );
463 std::unique_ptr< QgsScopedQPainterState > painterState;
464 if ( points.size() <= 2 &&
467 ( p->renderHints() & QPainter::Antialiasing ) )
469 painterState = std::make_unique< QgsScopedQPainterState >( p );
470 p->setRenderHint( QPainter::Antialiasing,
false );
473 const bool applyPatternTweaks = mAlignDashPattern
474 && ( pen.style() != Qt::SolidLine || !pen.dashPattern().empty() )
475 && pen.dashOffset() == 0;
479 if ( applyPatternTweaks )
481 drawPathWithDashPatternTweaks( p, points, pen );
487 path.addPolygon( points );
502 for (
const QPolygonF &part : mline )
504 if ( applyPatternTweaks )
506 drawPathWithDashPatternTweaks( p, part, pen );
512 path.addPolygon( part );
523 map[QStringLiteral(
"line_width" )] = QString::number(
mWidth );
529 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
532 map[QStringLiteral(
"use_custom_dash" )] = ( mUseCustomDashPattern ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
536 map[QStringLiteral(
"dash_pattern_offset" )] = QString::number( mDashPatternOffset );
539 map[QStringLiteral(
"trim_distance_start" )] = QString::number( mTrimDistanceStart );
542 map[QStringLiteral(
"trim_distance_end" )] = QString::number( mTrimDistanceEnd );
545 map[QStringLiteral(
"draw_inside_polygon" )] = ( mDrawInsidePolygon ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
546 map[QStringLiteral(
"ring_filter" )] = QString::number(
static_cast< int >(
mRingFilter ) );
547 map[QStringLiteral(
"align_dash_pattern" )] = mAlignDashPattern ? QStringLiteral(
"1" ) : QStringLiteral(
"0" );
548 map[QStringLiteral(
"tweak_dash_pattern_on_corners" )] = mPatternCartographicTweakOnSharpCorners ? QStringLiteral(
"1" ) : QStringLiteral(
"0" );
589 toSld( doc, element, context );
594 if ( mPenStyle == Qt::NoPen )
598 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:LineSymbolizer" ) );
599 if ( !props.value( QStringLiteral(
"uom" ), QString() ).toString().isEmpty() )
600 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ).toString() );
601 element.appendChild( symbolizerElem );
607 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
608 symbolizerElem.appendChild( strokeElem );
610 Qt::PenStyle
penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
619 QDomElement perpOffsetElem = doc.createElement( QStringLiteral(
"se:PerpendicularOffset" ) );
622 symbolizerElem.appendChild( perpOffsetElem );
629 if ( mUseCustomDashPattern )
632 mPen.color(), mPenJoinStyle,
633 mPenCapStyle,
mOffset, &mCustomDashVector );
646 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
647 if ( strokeElem.isNull() )
664 QDomElement perpOffsetElem = element.firstChildElement( QStringLiteral(
"PerpendicularOffset" ) );
665 if ( !perpOffsetElem.isNull() )
668 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
673 double scaleFactor = 1.0;
674 const QString uom = element.attribute( QStringLiteral(
"uom" ) );
689void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context, QPen &pen, QPen &selPen,
double &offset )
695 bool hasStrokeWidthExpression =
false;
702 pen.setWidthF( scaledWidth );
703 selPen.setWidthF( scaledWidth );
704 hasStrokeWidthExpression =
true;
713 penColor.setAlphaF( context.
opacity() * penColor.alphaF() );
714 pen.setColor( penColor );
728 const double dashWidthDiv = std::max( hasStrokeWidthExpression ? pen.widthF() : mPen.widthF(), 1.0 );
732 QVector<qreal> dashVector;
736 QStringList dashList = exprVal.toString().split(
';' );
737 QStringList::const_iterator dashIt = dashList.constBegin();
738 for ( ; dashIt != dashList.constEnd(); ++dashIt )
742 pen.setDashPattern( dashVector );
749 QVector<qreal> scaledVector;
750 for (
double v : std::as_const( mCustomDashVector ) )
755 mPen.setDashPattern( scaledVector );
759 double patternOffset = mDashPatternOffset;
795void QgsSimpleLineSymbolLayer::drawPathWithDashPatternTweaks( QPainter *painter,
const QPolygonF &points, QPen pen )
const
797 if ( pen.dashPattern().empty() || points.size() < 2 )
800 if ( pen.widthF() <= 1.0 )
802 pen.setWidthF( 1.0001 );
805 QVector< qreal > sourcePattern = pen.dashPattern();
806 const double dashWidthDiv = pen.widthF();
808 for (
int i = 0; i < sourcePattern.size(); ++ i )
809 sourcePattern[i] *= pen.widthF();
811 QVector< qreal > buffer;
812 QPolygonF bufferedPoints;
813 QPolygonF previousSegmentBuffer;
818 auto ptIt = points.constBegin();
819 double totalBufferLength = 0;
820 int patternIndex = 0;
821 double currentRemainingDashLength = 0;
822 double currentRemainingGapLength = 0;
824 auto compressPattern = [](
const QVector< qreal > &buffer ) -> QVector< qreal >
826 QVector< qreal > result;
827 result.reserve( buffer.size() );
828 for (
auto it = buffer.begin(); it != buffer.end(); )
832 while ( dash == 0 && !result.empty() )
834 result.last() += gap;
836 if ( it == buffer.end() )
841 while ( gap == 0 && it != buffer.end() )
846 result << dash << gap;
851 double currentBufferLineLength = 0;
852 auto flushBuffer = [pen, painter, &buffer, &bufferedPoints, &previousSegmentBuffer, ¤tRemainingDashLength, ¤tRemainingGapLength, ¤tBufferLineLength, &totalBufferLength,
853 dashWidthDiv, &compressPattern]( QPointF * nextPoint )
855 if ( buffer.empty() || bufferedPoints.size() < 2 )
860 if ( currentRemainingDashLength )
863 buffer << currentRemainingDashLength << 0.0;
864 totalBufferLength += currentRemainingDashLength;
866 QVector< qreal > compressed = compressPattern( buffer );
867 if ( !currentRemainingDashLength )
870 totalBufferLength -= compressed.last();
871 compressed.last() = 0;
875 const double scaleFactor = currentBufferLineLength / totalBufferLength;
877 bool shouldFlushPreviousSegmentBuffer =
false;
879 if ( !previousSegmentBuffer.empty() )
883 if ( !firstDashSubstring.empty() )
889 compressed = compressed.mid( 2 );
890 shouldFlushPreviousSegmentBuffer = !compressed.empty();
893 if ( !previousSegmentBuffer.empty() && ( shouldFlushPreviousSegmentBuffer || !nextPoint ) )
895 QPen adjustedPen = pen;
896 adjustedPen.setStyle( Qt::SolidLine );
897 painter->setPen( adjustedPen );
899 path.addPolygon( previousSegmentBuffer );
900 painter->drawPath( path );
901 previousSegmentBuffer.clear();
904 double finalDash = 0;
911 if ( !compressed.empty() )
913 finalDash = compressed.at( compressed.size() - 2 );
914 const double finalGap = compressed.size() > 2 ? compressed.at( compressed.size() - 3 ) : 0;
916 const QPolygonF thisPoints = bufferedPoints;
922 previousSegmentBuffer << bufferedPoints;
926 currentBufferLineLength = 0;
927 currentRemainingDashLength = 0;
928 currentRemainingGapLength = 0;
929 totalBufferLength = 0;
932 if ( !bufferedPoints.empty() && ( !compressed.empty() || !nextPoint ) )
934 QPen adjustedPen = pen;
935 if ( !compressed.empty() )
938 compressed = compressed.mid( 0, 32 );
939 std::for_each( compressed.begin(), compressed.end(), [scaleFactor, dashWidthDiv]( qreal & element ) { element *= scaleFactor / dashWidthDiv; } );
940 adjustedPen.setDashPattern( compressed );
944 adjustedPen.setStyle( Qt::SolidLine );
947 painter->setPen( adjustedPen );
949 path.addPolygon( bufferedPoints );
950 painter->drawPath( path );
953 bufferedPoints.clear();
959 bufferedPoints << p2;
960 for ( ; ptIt != points.constEnd(); ++ptIt )
968 double remainingSegmentDistance = std::sqrt( std::pow( p2.x() - p1.x(), 2.0 ) + std::pow( p2.y() - p1.y(), 2.0 ) );
969 currentBufferLineLength += remainingSegmentDistance;
973 if ( currentRemainingDashLength > 0 )
976 if ( remainingSegmentDistance >= currentRemainingDashLength )
979 buffer << currentRemainingDashLength << 0.0;
980 totalBufferLength += currentRemainingDashLength;
981 remainingSegmentDistance -= currentRemainingDashLength;
983 currentRemainingDashLength = 0.0;
984 currentRemainingGapLength = sourcePattern.at( patternIndex );
985 if ( currentRemainingGapLength == 0.0 )
993 buffer << remainingSegmentDistance << 0.0;
994 totalBufferLength += remainingSegmentDistance;
995 currentRemainingDashLength -= remainingSegmentDistance;
999 if ( currentRemainingGapLength > 0 )
1002 if ( remainingSegmentDistance >= currentRemainingGapLength )
1005 buffer << 0.0 << currentRemainingGapLength;
1006 totalBufferLength += currentRemainingGapLength;
1007 remainingSegmentDistance -= currentRemainingGapLength;
1008 currentRemainingGapLength = 0.0;
1014 buffer << 0.0 << remainingSegmentDistance;
1015 totalBufferLength += remainingSegmentDistance;
1016 currentRemainingGapLength -= remainingSegmentDistance;
1021 if ( patternIndex + 1 >= sourcePattern.size() )
1026 const double nextPatternDashLength = sourcePattern.at( patternIndex );
1027 const double nextPatternGapLength = sourcePattern.at( patternIndex + 1 );
1028 if ( nextPatternDashLength + nextPatternGapLength <= remainingSegmentDistance )
1030 buffer << nextPatternDashLength << nextPatternGapLength;
1031 remainingSegmentDistance -= nextPatternDashLength + nextPatternGapLength;
1032 totalBufferLength += nextPatternDashLength + nextPatternGapLength;
1035 else if ( nextPatternDashLength <= remainingSegmentDistance )
1038 buffer << nextPatternDashLength << remainingSegmentDistance - nextPatternDashLength;
1039 totalBufferLength += remainingSegmentDistance;
1040 currentRemainingGapLength = nextPatternGapLength - ( remainingSegmentDistance - nextPatternDashLength );
1041 currentRemainingDashLength = 0;
1048 buffer << remainingSegmentDistance << 0.0;
1049 totalBufferLength += remainingSegmentDistance;
1050 currentRemainingGapLength = 0;
1051 currentRemainingDashLength = nextPatternDashLength - remainingSegmentDistance;
1056 bufferedPoints << p1;
1057 if ( mPatternCartographicTweakOnSharpCorners && ptIt + 1 != points.constEnd() )
1059 QPointF nextPoint = *( ptIt + 1 );
1065 flushBuffer( &nextPoint );
1066 bufferedPoints << p1;
1069 if ( patternIndex % 2 == 1 )
1073 currentRemainingDashLength = sourcePattern.at( patternIndex );
1080 flushBuffer(
nullptr );
1081 if ( !previousSegmentBuffer.empty() )
1083 QPen adjustedPen = pen;
1084 adjustedPen.setStyle( Qt::SolidLine );
1085 painter->setPen( adjustedPen );
1087 path.addPolygon( previousSegmentBuffer );
1088 painter->drawPath( path );
1089 previousSegmentBuffer.clear();
1095 if ( mDrawInsidePolygon )
1109 unit = mCustomDashPatternUnit;
1110 return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
1147 return mPenStyle != Qt::SolidLine || mUseCustomDashPattern;
1152 return mAlignDashPattern;
1162 return mPatternCartographicTweakOnSharpCorners;
1167 mPatternCartographicTweakOnSharpCorners =
enabled;
1195 MyLine( QPointF p1, QPointF p2 )
1205 mIncreasing = ( p2.y() > p1.y() );
1210 mT = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
1211 mIncreasing = ( p2.x() > p1.x() );
1215 double x = ( p2.x() - p1.x() );
1216 double y = ( p2.y() - p1.y() );
1217 mLength = std::sqrt( x * x + y * y );
1223 double a = ( mVertical ? M_PI_2 : std::atan( mT ) );
1231 QPointF diffForInterval(
double interval )
const
1234 return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
1236 double alpha = std::atan( mT );
1237 double dx = std::cos( alpha ) * interval;
1238 double dy = std::sin( alpha ) * interval;
1239 return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
1242 double length()
const {
return mLength; }
1245 bool mVertical =
false;
1246 bool mIncreasing =
false;
1248 double mLength = 0.0;
1257 : mRotateSymbols( rotateSymbol )
1297 if ( mRenderingFeature )
1301 mFeatureSymbolOpacity = context.
opacity();
1302 mCurrentFeatureIsSelected = useSelectedColor;
1320 QString placementString = exprVal.toString();
1321 if ( placementString.compare( QLatin1String(
"interval" ), Qt::CaseInsensitive ) == 0 )
1325 else if ( placementString.compare( QLatin1String(
"vertex" ), Qt::CaseInsensitive ) == 0 )
1329 else if ( placementString.compare( QLatin1String(
"innervertices" ), Qt::CaseInsensitive ) == 0 )
1333 else if ( placementString.compare( QLatin1String(
"lastvertex" ), Qt::CaseInsensitive ) == 0 )
1337 else if ( placementString.compare( QLatin1String(
"firstvertex" ), Qt::CaseInsensitive ) == 0 )
1341 else if ( placementString.compare( QLatin1String(
"centerpoint" ), Qt::CaseInsensitive ) == 0 )
1345 else if ( placementString.compare( QLatin1String(
"curvepoint" ), Qt::CaseInsensitive ) == 0 )
1349 else if ( placementString.compare( QLatin1String(
"segmentcenter" ), Qt::CaseInsensitive ) == 0 )
1362 double averageOver = mAverageAngleLength;
1377 if ( !error.isEmpty() )
1379 QgsDebugError( QStringLiteral(
"Badly formatted blank segment '%1', skip it: %2" ).arg( strBlankSegments ).arg( error ) );
1385 if ( iPart >= 0 && mRingIndex >= 0 && iPart < allBlankSegments.count() && mRingIndex < allBlankSegments.at( iPart ).count() )
1387 blankSegments = allBlankSegments.at( iPart ).at( mRingIndex );
1395 renderPolylineInterval( points, context, averageOver, blankSegments );
1397 renderPolylineCentral( points, context, averageOver, blankSegments );
1401 && ( mPlaceOnEveryPart || !mHasRenderedFirstPart ) )
1404 mHasRenderedFirstPart = mRenderingFeature;
1420 for (
int part = 0; part < mline.count(); ++part )
1422 const QPolygonF &points2 = mline[ part ];
1425 renderPolylineInterval( points2, context, averageOver, blankSegments );
1427 renderPolylineCentral( points2, context, averageOver, blankSegments );
1435 && ( mPlaceOnEveryPart || !mHasRenderedFirstPart ) )
1438 mHasRenderedFirstPart = mRenderingFeature;
1458 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
1488 for (
int i = 0; i < rings->size(); ++i )
1523 mIntervalUnit = unit;
1524 mOffsetAlongLineUnit = unit;
1525 mAverageAngleLengthUnit = unit;
1550 map[QStringLiteral(
"rotate" )] = (
rotateSymbols() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1551 map[QStringLiteral(
"interval" )] = QString::number(
interval() );
1552 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
1553 map[QStringLiteral(
"offset_along_line" )] = QString::number(
offsetAlongLine() );
1560 map[QStringLiteral(
"average_angle_length" )] = QString::number( mAverageAngleLength );
1567 map[QStringLiteral(
"ring_filter" )] = QString::number(
static_cast< int >(
mRingFilter ) );
1568 map[QStringLiteral(
"place_on_every_part" )] = mPlaceOnEveryPart;
1574 return mPlaceOnEveryPart
1584 mRenderingFeature =
true;
1585 mHasRenderedFirstPart =
false;
1590 mRenderingFeature =
false;
1601 renderSymbol( mFinalVertex, &feature, context, -1, mCurrentFeatureIsSelected );
1602 mFeatureSymbolOpacity = 1;
1633 if (
properties.contains( QStringLiteral(
"offset" ) ) )
1637 if (
properties.contains( QStringLiteral(
"offset_unit" ) ) )
1641 if (
properties.contains( QStringLiteral(
"interval_unit" ) ) )
1645 if (
properties.contains( QStringLiteral(
"offset_along_line" ) ) )
1649 if (
properties.contains( QStringLiteral(
"offset_along_line_unit" ) ) )
1653 if (
properties.contains( ( QStringLiteral(
"offset_along_line_map_unit_scale" ) ) ) )
1658 if (
properties.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
1662 if (
properties.contains( QStringLiteral(
"interval_map_unit_scale" ) ) )
1667 if (
properties.contains( QStringLiteral(
"average_angle_length" ) ) )
1671 if (
properties.contains( QStringLiteral(
"average_angle_unit" ) ) )
1675 if (
properties.contains( ( QStringLiteral(
"average_angle_map_unit_scale" ) ) ) )
1679 if (
properties.contains( QStringLiteral(
"blank_segments_unit" ) ) )
1684 if (
properties.contains( QStringLiteral(
"placement" ) ) )
1686 if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"vertex" ) )
1688 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"lastvertex" ) )
1690 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"firstvertex" ) )
1692 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"centralpoint" ) )
1694 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"curvepoint" ) )
1696 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"segmentcenter" ) )
1701 else if (
properties.contains( QStringLiteral(
"placements" ) ) )
1707 if (
properties.contains( QStringLiteral(
"ring_filter" ) ) )
1723class BlankSegmentsWalker
1728 : mBlankSegments( blankSegments )
1730 , mItBlankSegment( blankSegments.cbegin() )
1732 mDistances.reserve( mPoints.count() );
1736 bool insideBlankSegment(
double distance )
1738 while ( mItBlankSegment != mBlankSegments.cend() && distance > mItBlankSegment->second )
1743 return ( mItBlankSegment != mBlankSegments.cend() && distance >= mItBlankSegment->first );
1748 bool insideBlankSegment(
const QPointF &point,
int pointIndex )
1750 if ( pointIndex < 0 || pointIndex >= mPoints.count() )
1754 if ( pointIndex >= mDistances.count() )
1756 for (
int i =
static_cast<int>( mDistances.count() ); i < pointIndex + 1; i++ )
1758 const QPointF diff = mPoints.at( i ) - mPoints.at( i - 1 );
1759 const double distance = std::sqrt( std::pow( diff.x(), 2 ) + std::pow( diff.y(), 2 ) );
1760 const double totalDistance = distance + mDistances.last();
1761 mDistances << totalDistance;
1765 const QPointF diff = mPoints.at( pointIndex ) - point;
1766 const double distance = std::sqrt( std::pow( diff.x(), 2 ) + std::pow( diff.y(), 2 ) );
1767 const double currentDistance = mDistances.at( pointIndex ) + distance;
1769 return insideBlankSegment( currentDistance );
1775 const QPolygonF &mPoints;
1776 QList<double> mDistances;
1777 QgsBlankSegmentUtils::BlankSegments::const_iterator mItBlankSegment;
1786 if ( points.isEmpty() )
1790 double lengthLeft = 0;
1795 QgsExpressionContextScope *scope =
new QgsExpressionContextScope();
1822 constexpr double EPSILON = 1e-5;
1823 if ( painterUnitInterval <
EPSILON )
1826 double painterUnitOffsetAlongLine = 0;
1829 double totalLength = -1;
1850 if ( points.isClosed() )
1852 if ( painterUnitOffsetAlongLine > 0 )
1854 if ( totalLength < 0 )
1856 painterUnitOffsetAlongLine = std::fmod( painterUnitOffsetAlongLine, totalLength );
1858 else if ( painterUnitOffsetAlongLine < 0 )
1860 if ( totalLength < 0 )
1862 painterUnitOffsetAlongLine = totalLength - std::fmod( -painterUnitOffsetAlongLine, totalLength );
1874 lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1876 if ( averageOver > 0 && !
qgsDoubleNear( averageOver, 0.0 ) )
1878 QVector< QPointF > angleStartPoints;
1879 QVector< QPointF > symbolPoints;
1880 QVector< QPointF > angleEndPoints;
1889 QList<int> pointIndices;
1890 collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft, blankSegments.isEmpty() ?
nullptr : &pointIndices );
1892 if ( symbolPoints.empty() )
1898 if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1901 symbolPoints.pop_back();
1904 angleEndPoints.reserve( symbolPoints.size() );
1905 angleStartPoints.reserve( symbolPoints.size() );
1906 if ( averageOver <= painterUnitOffsetAlongLine )
1908 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver,
nullptr, 0, symbolPoints.size() );
1912 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0,
nullptr, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1914 collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver,
nullptr, 0, symbolPoints.size() );
1917 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
1918 for (
int i = 0; i < symbolPoints.size(); ++ i )
1923 const QPointF pt = symbolPoints[i];
1924 if ( i < pointIndices.count() && blankSegmentsWalker.insideBlankSegment( pt, pointIndices.at( i ) ) )
1928 const QPointF startPt = angleStartPoints[i];
1929 const QPointF endPt = angleEndPoints[i];
1931 MyLine l( startPt, endPt );
1947 QPointF lastPt = points[0];
1948 BlankSegmentsWalker itBlankSegment( points, blankSegments );
1949 for (
int i = 1; i < points.count(); ++i )
1954 const QPointF &pt = points[i];
1960 MyLine l( lastPt, pt );
1961 QPointF diff = l.diffForInterval( painterUnitInterval );
1966 double c = 1 - lengthLeft / painterUnitInterval;
1968 lengthLeft += l.length();
1977 while ( lengthLeft > painterUnitInterval )
1984 if ( !itBlankSegment.insideBlankSegment( lastPt, i - 1 ) )
1990 lengthLeft -= painterUnitInterval;
1999static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
2002 double a1 = MyLine( prevPt, pt ).angle();
2003 double a2 = MyLine( pt, nextPt ).angle();
2004 double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
2006 return std::atan2( unitY, unitX );
2011 if ( points.isEmpty() )
2016 int i = -1, maxCount = 0;
2017 bool isRing =
false;
2019 QgsExpressionContextScope *scope =
new QgsExpressionContextScope();
2031 double totalLength = -1;
2051 if ( points.isClosed() )
2055 if ( totalLength < 0 )
2061 if ( totalLength < 0 )
2135 i = points.count() - 1;
2137 maxCount = points.count();
2145 maxCount = points.count() - 1;
2153 maxCount = points.count();
2154 if ( points.first() == points.last() )
2171 renderOffsetVertexAlongLine( points, i, distance, context,
placement, blankSegments );
2178 prevPoint = points.at( 0 );
2180 QPointF symbolPoint;
2181 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2182 for ( ; i < maxCount; ++i )
2193 QPointF currentPoint = points.at( i );
2194 symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ),
2195 0.5 * ( currentPoint.y() + prevPoint.y() ) );
2198 double angle = std::atan2( currentPoint.y() - prevPoint.y(),
2199 currentPoint.x() - prevPoint.x() );
2202 prevPoint = currentPoint;
2206 symbolPoint = points.at( i );
2210 double angle = markerAngle( points, isRing, i );
2215 mFinalVertex = symbolPoint;
2217 && !blankSegmentsWalker.insideBlankSegment( symbolPoint, i ) )
2222double QgsTemplatedLineSymbolLayerBase::markerAngle(
const QPolygonF &points,
bool isRing,
int vertex )
2225 const QPointF &pt = points[vertex];
2227 if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
2229 int prevIndex = vertex - 1;
2230 int nextIndex = vertex + 1;
2232 if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
2234 prevIndex = points.count() - 2;
2238 QPointF prevPoint, nextPoint;
2239 while ( prevIndex >= 0 )
2241 prevPoint = points[ prevIndex ];
2242 if ( prevPoint != pt )
2249 while ( nextIndex < points.count() )
2251 nextPoint = points[ nextIndex ];
2252 if ( nextPoint != pt )
2259 if ( prevIndex >= 0 && nextIndex < points.count() )
2261 angle = _averageAngle( prevPoint, pt, nextPoint );
2268 while ( vertex < points.size() - 1 )
2270 const QPointF &nextPt = points[vertex + 1];
2273 angle = MyLine( pt, nextPt ).angle();
2282 while ( vertex >= 1 )
2284 const QPointF &prevPt = points[vertex - 1];
2287 angle = MyLine( prevPt, pt ).angle();
2299 if ( points.isEmpty() )
2309 bool isRing =
false;
2310 if ( points.first() == points.last() )
2312 double angle = markerAngle( points, isRing, vertex );
2315 mFinalVertex = points[vertex];
2321 int pointIncrement = distance > 0 ? 1 : -1;
2322 QPointF previousPoint = points[vertex];
2323 int startPoint = distance > 0 ? std::min( vertex + 1,
static_cast<int>( points.count() ) - 1 ) : std::max( vertex - 1, 0 );
2324 int endPoint = distance > 0 ? points.count() - 1 : 0;
2325 double distanceLeft = std::fabs( distance );
2326 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2328 for (
int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
2330 const QPointF &pt = points[i];
2332 if ( previousPoint == pt )
2336 MyLine l( previousPoint, pt );
2338 if ( distanceLeft < l.length() )
2341 QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
2347 mFinalVertex = markerPoint;
2349 && !blankSegmentsWalker.insideBlankSegment( markerPoint, i - 1 ) )
2354 distanceLeft -= l.length();
2361void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints(
const QVector<QPointF> &p, QVector<QPointF> &dest,
double intervalPainterUnits,
double initialOffset,
2362 QList<int> *pointIndices,
2363 double initialLag,
int numberPointsRequired )
2368 QVector< QPointF > points = p;
2369 const bool closedRing = points.first() == points.last();
2371 double lengthLeft = initialOffset;
2373 double initialLagLeft = initialLag > 0 ? -initialLag : 1;
2374 if ( initialLagLeft < 0 && closedRing )
2377 QPointF lastPt = points.constLast();
2378 QVector< QPointF > pseudoPoints;
2379 for (
int i = points.count() - 2; i > 0; --i )
2381 if ( initialLagLeft >= 0 )
2386 const QPointF &pt = points[i];
2391 MyLine l( lastPt, pt );
2392 initialLagLeft += l.length();
2397 std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
2399 points = pseudoPoints;
2404 while ( initialLagLeft < 0 )
2406 dest << points.constFirst();
2407 initialLagLeft += intervalPainterUnits;
2410 if ( initialLag > 0 )
2412 lengthLeft += intervalPainterUnits - initialLagLeft;
2415 QPointF lastPt = points[0];
2416 for (
int i = 1; i < points.count(); ++i )
2418 const QPointF &pt = points[i];
2422 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2431 MyLine l( lastPt, pt );
2432 QPointF diff = l.diffForInterval( intervalPainterUnits );
2436 double c = 1 - lengthLeft / intervalPainterUnits;
2438 lengthLeft += l.length();
2441 while ( lengthLeft > intervalPainterUnits ||
qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
2445 lengthLeft -= intervalPainterUnits;
2448 *pointIndices << i - 1;
2451 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2456 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2460 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2467 if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2470 while ( dest.size() < numberPointsRequired )
2471 dest << points.constLast();
2477 if ( !points.isEmpty() )
2481 QPolygonF::const_iterator it = points.constBegin();
2483 for ( ++it; it != points.constEnd(); ++it )
2485 length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2486 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2492 const double midPoint = length / 2;
2494 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2495 if ( blankSegmentsWalker.insideBlankSegment( midPoint ) )
2499 double thisSymbolAngle = 0;
2501 if ( averageAngleOver > 0 && !
qgsDoubleNear( averageAngleOver, 0.0 ) )
2503 QVector< QPointF > angleStartPoints;
2504 QVector< QPointF > symbolPoints;
2505 QVector< QPointF > angleEndPoints;
2509 collectOffsetPoints( points, symbolPoints, midPoint, midPoint,
nullptr, 0.0, 2 );
2510 collectOffsetPoints( points, angleStartPoints, midPoint, 0,
nullptr, averageAngleOver, 2 );
2511 collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver,
nullptr, 0, 2 );
2513 pt = symbolPoints.at( 1 );
2514 MyLine l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
2515 thisSymbolAngle = l.angle();
2520 it = points.constBegin();
2522 qreal last_at = 0, next_at = 0;
2524 for ( ++it; it != points.constEnd(); ++it )
2527 next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2528 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2529 if ( next_at >= midPoint )
2536 MyLine l( last, next );
2537 qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
2538 pt = last + ( next - last ) * k;
2539 thisSymbolAngle = l.angle();
2591 if ( props.contains( QStringLiteral(
"interval" ) ) )
2592 interval = props[QStringLiteral(
"interval" )].toDouble();
2593 if ( props.contains( QStringLiteral(
"rotate" ) ) )
2594 rotate = ( props[QStringLiteral(
"rotate" )].toString() == QLatin1String(
"1" ) );
2596 auto x = std::make_unique< QgsMarkerLineSymbolLayer >( rotate,
interval );
2603 return QStringLiteral(
"MarkerLine" );
2623 mMarker->setRenderHints( hints );
2645 toSld( doc, element, context );
2651 for (
int i = 0; i <
mMarker->symbolLayerCount(); i++ )
2653 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:LineSymbolizer" ) );
2654 if ( !props.value( QStringLiteral(
"uom" ), QString() ).toString().isEmpty() )
2655 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ).toString() );
2656 element.appendChild( symbolizerElem );
2686 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
2687 symbolizerElem.appendChild( strokeElem );
2690 QDomElement graphicStrokeElem = doc.createElement( QStringLiteral(
"se:GraphicStroke" ) );
2691 strokeElem.appendChild( graphicStrokeElem );
2696 markerLayer->writeSldMarker( doc, graphicStrokeElem, context );
2700 QgsDebugError( QStringLiteral(
"QgsMarkerSymbolLayer expected, %1 found. Skip it." ).arg( layer->
layerType() ) );
2704 QgsDebugError( QStringLiteral(
"Missing marker line symbol layer. Skip it." ) );
2707 if ( !gap.isEmpty() )
2709 QDomElement gapElem = doc.createElement( QStringLiteral(
"se:Gap" ) );
2711 graphicStrokeElem.appendChild( gapElem );
2716 QDomElement perpOffsetElem = doc.createElement( QStringLiteral(
"se:PerpendicularOffset" ) );
2719 symbolizerElem.appendChild( perpOffsetElem );
2729 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
2730 if ( strokeElem.isNull() )
2733 QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral(
"GraphicStroke" ) );
2734 if ( graphicStrokeElem.isNull() )
2742 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
2744 if ( it.key() == QLatin1String(
"placement" ) )
2746 if ( it.value() == QLatin1String(
"points" ) )
2748 else if ( it.value() == QLatin1String(
"firstPoint" ) )
2750 else if ( it.value() == QLatin1String(
"lastPoint" ) )
2752 else if ( it.value() == QLatin1String(
"centralPoint" ) )
2755 else if ( it.value() == QLatin1String(
"rotateMarker" ) )
2761 std::unique_ptr< QgsMarkerSymbol > marker;
2767 layers.append( l.release() );
2768 marker = std::make_unique<QgsMarkerSymbol>( layers );
2775 QDomElement gapElem = graphicStrokeElem.firstChildElement( QStringLiteral(
"Gap" ) );
2776 if ( !gapElem.isNull() )
2779 double d = gapElem.firstChild().firstChild().nodeValue().toDouble( &ok );
2785 QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( QStringLiteral(
"PerpendicularOffset" ) );
2786 if ( !perpOffsetElem.isNull() )
2789 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
2794 double scaleFactor = 1.0;
2795 const QString uom = element.attribute( QStringLiteral(
"uom" ) );
2818 mMarker->setDataDefinedSize( property );
2825 const double prevOpacity =
mMarker->opacity();
2828 mMarker->setOpacity( prevOpacity );
2833 mMarker->setLineAngle( angle );
2851 mMarker->renderPoint( point, feature, context, layer, selected );
2863 return mMarker->size( context );
2869 mMarker->setOutputUnit( unit );
2887 attr.unite(
mMarker->usedAttributes( context ) );
2902 return (
mMarker->size( context ) / 2.0 ) +
2924 if ( props.contains( QStringLiteral(
"interval" ) ) )
2925 interval = props[QStringLiteral(
"interval" )].toDouble();
2926 if ( props.contains( QStringLiteral(
"rotate" ) ) )
2927 rotate = ( props[QStringLiteral(
"rotate" )] == QLatin1String(
"1" ) );
2929 auto x = std::make_unique< QgsHashedLineSymbolLayer >( rotate,
interval );
2931 if ( props.contains( QStringLiteral(
"hash_angle" ) ) )
2933 x->setHashAngle( props[QStringLiteral(
"hash_angle" )].toDouble() );
2936 if ( props.contains( QStringLiteral(
"hash_length" ) ) )
2937 x->setHashLength( props[QStringLiteral(
"hash_length" )].toDouble() );
2939 if ( props.contains( QStringLiteral(
"hash_length_unit" ) ) )
2942 if ( props.contains( QStringLiteral(
"hash_length_map_unit_scale" ) ) )
2950 return QStringLiteral(
"HashLine" );
2959 mHashSymbol->setRenderHints( hints );
2972 map[ QStringLiteral(
"hash_angle" ) ] = QString::number( mHashAngle );
2974 map[QStringLiteral(
"hash_length" )] = QString::number( mHashLength );
2985 x->setHashAngle( mHashAngle );
2986 x->setHashLength( mHashLength );
2987 x->setHashLengthUnit( mHashLengthUnit );
2988 x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2994 mHashSymbol->setColor(
color );
3000 return mHashSymbol ? mHashSymbol->color() :
mColor;
3005 return mHashSymbol.get();
3016 mHashSymbol.reset(
static_cast<QgsLineSymbol *
>( symbol ) );
3017 mColor = mHashSymbol->color();
3023 mHashLength =
width;
3038 return ( mHashSymbol->width( context ) / 2.0 )
3046 mHashSymbol->setOutputUnit( unit );
3053 attr.unite( mHashSymbol->usedAttributes( context ) );
3061 if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
3070 mHashSymbol->setDataDefinedWidth( property );
3084 || ( mHashSymbol && mHashSymbol->usesMapUnits() );
3089 mSymbolLineAngle = angle;
3094 return mSymbolAngle;
3099 mSymbolAngle = angle;
3104 double lineLength = mHashLength;
3110 const double w = context.
convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
3124 points << QPointF( start.
x(), start.
y() ) << QPointF( end.
x(), end.
y() );
3129 mHashSymbol->renderPolyline( points, feature, context, layer, selected );
3146 const double prevOpacity = mHashSymbol->opacity();
3147 mHashSymbol->setOpacity( mHashSymbol->opacity() * context.
opacity() );
3149 mHashSymbol->setOpacity( prevOpacity );
3168 QPolygonF offsetPoints;
3171 renderLine( points, context, patternThickness, patternLength, brush );
3180 renderLine( part, context, patternThickness, patternLength, brush );
3185void QgsAbstractBrushedLineSymbolLayer::renderLine(
const QPolygonF &points,
QgsSymbolRenderContext &context,
const double lineThickness,
3186 const double patternLength,
const QBrush &sourceBrush )
3192 QBrush brush = sourceBrush;
3197 QPolygonF inputPoints;
3198 inputPoints.reserve( points.size() );
3200 double minX = std::numeric_limits< double >::max();
3201 double minY = std::numeric_limits< double >::max();
3202 double maxX = std::numeric_limits< double >::lowest();
3203 double maxY = std::numeric_limits< double >::lowest();
3205 for (
const QPointF &pt : std::as_const( points ) )
3212 minX = std::min( minX, pt.x() );
3213 minY = std::min( minY, pt.y() );
3214 maxX = std::max( maxX, pt.x() );
3215 maxY = std::max( maxY, pt.y() );
3218 if ( inputPoints.size() < 2 )
3222 constexpr int ANTIALIAS_ALLOWANCE_PIXELS = 10;
3224 constexpr double ANTIALIAS_OVERLAP_PIXELS = 0.5;
3227 const int imageWidth =
static_cast< int >( std::ceil( maxX - minX ) + lineThickness * 2 ) + ANTIALIAS_ALLOWANCE_PIXELS * 2;
3228 const int imageHeight =
static_cast< int >( std::ceil( maxY - minY ) + lineThickness * 2 ) + ANTIALIAS_ALLOWANCE_PIXELS * 2;
3230 const bool isClosedLine =
qgsDoubleNear( points.at( 0 ).x(), points.constLast().x(), 0.01 )
3231 &&
qgsDoubleNear( points.at( 0 ).y(), points.constLast().y(), 0.01 );
3233 QImage temporaryImage( imageWidth, imageHeight, QImage::Format_ARGB32_Premultiplied );
3234 if ( temporaryImage.isNull() )
3243 temporaryImage.fill( Qt::transparent );
3266 QPainterPathStroker stroker;
3267 stroker.setWidth( lineThickness );
3268 stroker.setCapStyle( cap );
3269 stroker.setJoinStyle( join );
3272 path.addPolygon( inputPoints );
3273 const QPainterPath stroke = stroker.createStroke( path ).simplified();
3276 QPainter imagePainter;
3277 imagePainter.begin( &temporaryImage );
3279 imagePainter.translate( -minX + lineThickness + ANTIALIAS_ALLOWANCE_PIXELS, -minY + lineThickness + ANTIALIAS_ALLOWANCE_PIXELS );
3281 imagePainter.setClipPath( stroke, Qt::IntersectClip );
3282 imagePainter.setPen( Qt::NoPen );
3284 QPointF segmentStartPoint = inputPoints.at( 0 );
3287 double progressThroughImage = 0;
3289 QgsPoint prevSegmentPolygonEndLeft;
3290 QgsPoint prevSegmentPolygonEndRight;
3293 QgsPoint startLinePolygonLeft;
3294 QgsPoint startLinePolygonRight;
3296 for (
int i = 1; i < inputPoints.size(); ++i )
3301 const QPointF segmentEndPoint = inputPoints.at( i );
3303 segmentEndPoint.x(), segmentEndPoint.y() ) - 90;
3306 QgsPoint thisSegmentPolygonEndLeft;
3307 QgsPoint thisSegmentPolygonEndRight;
3309 QgsPoint thisSegmentPolygonEndLeftForPainter;
3310 QgsPoint thisSegmentPolygonEndRightForPainter;
3318 const QgsPoint startPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, segmentAngleDegrees );
3319 const QgsPoint endPointLeft = QgsPoint( segmentEndPoint ).project( lineThickness / 2, segmentAngleDegrees );
3320 const QgsPoint startPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3321 const QgsPoint endPointRight = QgsPoint( segmentEndPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3325 const double lastSegmentAngleDegrees = 180.0 / M_PI *
QgsGeometryUtilsBase::lineAngle( points.at( points.size() - 2 ).x(), points.at( points.size() - 2 ).y(),
3326 segmentStartPoint.x(), segmentStartPoint.y() ) - 90;
3329 const QgsPoint lastSegmentStartPointLeft = QgsPoint( points.at( points.size() - 2 ) ).project( lineThickness / 2, lastSegmentAngleDegrees );
3330 const QgsPoint lastSegmentEndPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, lastSegmentAngleDegrees );
3331 const QgsPoint lastSegmentStartPointRight = QgsPoint( points.at( points.size() - 2 ) ).project( -lineThickness / 2, lastSegmentAngleDegrees );
3332 const QgsPoint lastSegmentEndPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, lastSegmentAngleDegrees );
3337 QgsPoint intersectionPoint;
3338 bool isIntersection =
false;
3340 if ( !isIntersection )
3341 prevSegmentPolygonEndLeft = startPointLeft;
3342 isIntersection =
false;
3343 QgsGeometryUtils::segmentIntersection( lastSegmentStartPointRight, lastSegmentEndPointRight, startPointRight, endPointRight, prevSegmentPolygonEndRight, isIntersection, 1e-8,
true );
3344 if ( !isIntersection )
3345 prevSegmentPolygonEndRight = startPointRight;
3347 startLinePolygonLeft = prevSegmentPolygonEndLeft;
3348 startLinePolygonRight = prevSegmentPolygonEndRight;
3352 prevSegmentPolygonEndLeft = QgsPoint( segmentStartPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3353 if ( cap != Qt::PenCapStyle::FlatCap )
3354 prevSegmentPolygonEndLeft = prevSegmentPolygonEndLeft.
project( lineThickness / 2, segmentAngleDegrees - 90 );
3355 prevSegmentPolygonEndRight = QgsPoint( segmentStartPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3356 if ( cap != Qt::PenCapStyle::FlatCap )
3357 prevSegmentPolygonEndRight = prevSegmentPolygonEndRight.
project( lineThickness / 2, segmentAngleDegrees - 90 );
3361 if ( i < inputPoints.size() - 1 )
3366 const QgsPoint startPointLeft = QgsPoint( segmentStartPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3367 const QgsPoint endPointLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3368 const QgsPoint startPointRight = QgsPoint( segmentStartPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3369 const QgsPoint endPointRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3374 inputPoints.at( i + 1 ).x(), inputPoints.at( i + 1 ).y() ) - 90;
3377 const QgsPoint nextSegmentStartPointLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, nextSegmentAngleDegrees );
3378 const QgsPoint nextSegmentEndPointLeft = QgsPoint( inputPoints.at( i + 1 ) ).
project( lineThickness / 2, nextSegmentAngleDegrees );
3379 const QgsPoint nextSegmentStartPointRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, nextSegmentAngleDegrees );
3380 const QgsPoint nextSegmentEndPointRight = QgsPoint( inputPoints.at( i + 1 ) ).
project( -lineThickness / 2, nextSegmentAngleDegrees );
3385 QgsPoint intersectionPoint;
3386 bool isIntersection =
false;
3388 if ( !isIntersection )
3389 thisSegmentPolygonEndLeft = endPointLeft;
3390 isIntersection =
false;
3391 QgsGeometryUtils::segmentIntersection( startPointRight, endPointRight, nextSegmentStartPointRight, nextSegmentEndPointRight, thisSegmentPolygonEndRight, isIntersection, 1e-8,
true );
3392 if ( !isIntersection )
3393 thisSegmentPolygonEndRight = endPointRight;
3395 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3396 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3404 thisSegmentPolygonEndLeft = startLinePolygonLeft;
3405 thisSegmentPolygonEndRight = startLinePolygonRight;
3407 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3408 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3412 thisSegmentPolygonEndLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3413 if ( cap != Qt::PenCapStyle::FlatCap )
3414 thisSegmentPolygonEndLeft = thisSegmentPolygonEndLeft.
project( lineThickness / 2, segmentAngleDegrees + 90 );
3415 thisSegmentPolygonEndRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3416 if ( cap != Qt::PenCapStyle::FlatCap )
3417 thisSegmentPolygonEndRight = thisSegmentPolygonEndRight.
project( lineThickness / 2, segmentAngleDegrees + 90 );
3419 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft;
3420 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight;
3426 QTransform brushTransform;
3427 brushTransform.translate( segmentStartPoint.x(), segmentStartPoint.y() );
3428 brushTransform.rotate( -segmentAngleDegrees );
3429 if ( i == 1 && cap != Qt::PenCapStyle::FlatCap )
3433 brushTransform.translate( -( lineThickness / 2 ), 0 );
3435 brushTransform.translate( -progressThroughImage, -lineThickness / 2 );
3437 brush.setTransform( brushTransform );
3438 imagePainter.setBrush( brush );
3441 imagePainter.drawPolygon( QPolygonF() << prevSegmentPolygonEndLeft.
toQPointF()
3442 << thisSegmentPolygonEndLeftForPainter.
toQPointF()
3443 << thisSegmentPolygonEndRightForPainter.
toQPointF()
3444 << prevSegmentPolygonEndRight.
toQPointF()
3445 << prevSegmentPolygonEndLeft.
toQPointF() );
3448 imagePainter.setPen( QPen( QColor( 0, 255, 255 ), 2 ) );
3449 imagePainter.setBrush( Qt::NoBrush );
3450 imagePainter.drawPolygon( QPolygonF() << prevSegmentPolygonEndLeft.
toQPointF()
3451 << thisSegmentPolygonEndLeftForPainter.
toQPointF()
3452 << thisSegmentPolygonEndRightForPainter.
toQPointF()
3453 << prevSegmentPolygonEndRight.
toQPointF()
3454 << prevSegmentPolygonEndLeft.
toQPointF() );
3455 imagePainter.setPen( Qt::NoPen );
3460 progressThroughImage += sqrt( std::pow( segmentStartPoint.x() - segmentEndPoint.x(), 2 )
3461 + std::pow( segmentStartPoint.y() - segmentEndPoint.y(), 2 ) )
3462 + ( i == 1 && cap != Qt::PenCapStyle::FlatCap ? lineThickness / 2 : 0 );
3463 progressThroughImage = fmod( progressThroughImage, patternLength );
3466 segmentStartPoint = segmentEndPoint;
3467 prevSegmentPolygonEndLeft = thisSegmentPolygonEndLeft;
3468 prevSegmentPolygonEndRight = thisSegmentPolygonEndRight;
3476 p->drawImage( QPointF( minX - lineThickness - ANTIALIAS_ALLOWANCE_PIXELS,
3477 minY - lineThickness - ANTIALIAS_ALLOWANCE_PIXELS ), temporaryImage );
3494 auto res = std::make_unique<QgsRasterLineSymbolLayer>();
3496 if (
properties.contains( QStringLiteral(
"line_width" ) ) )
3498 res->setWidth(
properties[QStringLiteral(
"line_width" )].toDouble() );
3500 if (
properties.contains( QStringLiteral(
"line_width_unit" ) ) )
3504 if (
properties.contains( QStringLiteral(
"width_map_unit_scale" ) ) )
3509 if (
properties.contains( QStringLiteral(
"imageFile" ) ) )
3510 res->setPath(
properties[QStringLiteral(
"imageFile" )].toString() );
3512 if (
properties.contains( QStringLiteral(
"offset" ) ) )
3514 res->setOffset(
properties[QStringLiteral(
"offset" )].toDouble() );
3516 if (
properties.contains( QStringLiteral(
"offset_unit" ) ) )
3520 if (
properties.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
3525 if (
properties.contains( QStringLiteral(
"joinstyle" ) ) )
3527 if (
properties.contains( QStringLiteral(
"capstyle" ) ) )
3530 if (
properties.contains( QStringLiteral(
"alpha" ) ) )
3532 res->setOpacity(
properties[QStringLiteral(
"alpha" )].toDouble() );
3535 return res.release();
3542 map[QStringLiteral(
"imageFile" )] =
mPath;
3544 map[QStringLiteral(
"line_width" )] = QString::number(
mWidth );
3551 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
3555 map[QStringLiteral(
"alpha" )] = QString::number(
mOpacity );
3562 auto res = std::make_unique< QgsRasterLineSymbolLayer >(
mPath );
3574 return res.release();
3579 const QVariantMap::iterator it =
properties.find( QStringLiteral(
"imageFile" ) );
3580 if ( it !=
properties.end() && it.value().userType() == QMetaType::Type::QString )
3596 return QStringLiteral(
"RasterLine" );
3611 bool cached =
false;
3613 QSize(
static_cast< int >( std::round( originalSize.width() / originalSize.height() * std::max( 1.0, scaledHeight ) ) ),
3614 static_cast< int >( std::ceil( scaledHeight ) ) ),
3639 double strokeWidth =
mWidth;
3656 bool cached =
false;
3658 QSize(
static_cast< int >( std::round( originalSize.width() / originalSize.height() * std::max( 1.0, scaledHeight ) ) ),
3659 static_cast< int >( std::ceil( scaledHeight ) ) ),
3664 if ( useSelectedColor )
3669 const QBrush brush( sourceImage );
3739 auto res = std::make_unique<QgsLineburstSymbolLayer>();
3741 if (
properties.contains( QStringLiteral(
"line_width" ) ) )
3743 res->setWidth(
properties[QStringLiteral(
"line_width" )].toDouble() );
3745 if (
properties.contains( QStringLiteral(
"line_width_unit" ) ) )
3749 if (
properties.contains( QStringLiteral(
"width_map_unit_scale" ) ) )
3754 if (
properties.contains( QStringLiteral(
"offset" ) ) )
3756 res->setOffset(
properties[QStringLiteral(
"offset" )].toDouble() );
3758 if (
properties.contains( QStringLiteral(
"offset_unit" ) ) )
3762 if (
properties.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
3767 if (
properties.contains( QStringLiteral(
"joinstyle" ) ) )
3769 if (
properties.contains( QStringLiteral(
"capstyle" ) ) )
3772 if (
properties.contains( QStringLiteral(
"color_type" ) ) )
3775 if (
properties.contains( QStringLiteral(
"color" ) ) )
3779 if (
properties.contains( QStringLiteral(
"gradient_color2" ) ) )
3794 return res.release();
3801 map[QStringLiteral(
"line_width" )] = QString::number(
mWidth );
3808 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
3814 map[QStringLiteral(
"color_type" )] = QString::number(
static_cast< int >(
mGradientColorType ) );
3825 auto res = std::make_unique< QgsLineburstSymbolLayer >();
3841 return res.release();
3846 return QStringLiteral(
"Lineburst" );
3867 double strokeWidth =
mWidth;
3883 if ( useSelectedColor )
3887 color1.setAlphaF( context.
opacity() * color1.alphaF() );
3898 QGradient gradient = QLinearGradient( QPointF( 0, 0 ), QPointF( 0, scaledWidth ) );
3910 gradient.setColorAt( 0.0, color1 );
3911 gradient.setColorAt( 1.0,
color2 );
3913 const QBrush brush( gradient );
3992 if ( props.contains( QStringLiteral(
"line_width" ) ) )
3994 width = props[QStringLiteral(
"line_width" )].toDouble();
3996 else if ( props.contains( QStringLiteral(
"outline_width" ) ) )
3998 width = props[QStringLiteral(
"outline_width" )].toDouble();
4000 else if ( props.contains( QStringLiteral(
"width" ) ) )
4002 width = props[QStringLiteral(
"width" )].toDouble();
4007 if ( props.contains( QStringLiteral(
"line_width_unit" ) ) )
4011 else if ( props.contains( QStringLiteral(
"outline_width_unit" ) ) )
4015 else if ( props.contains( QStringLiteral(
"width_unit" ) ) )
4020 if ( props.contains( QStringLiteral(
"width_map_unit_scale" ) ) )
4022 if ( props.contains( QStringLiteral(
"offset" ) ) )
4023 l->setOffset( props[QStringLiteral(
"offset" )].toDouble() );
4024 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
4026 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
4028 if ( props.contains( QStringLiteral(
"joinstyle" ) ) )
4030 if ( props.contains( QStringLiteral(
"capstyle" ) ) )
4033 l->restoreOldDataDefinedProperties( props );
4040 return QStringLiteral(
"FilledLine" );
4089 Qt::PenJoinStyle join = mPenJoinStyle;
4098 Qt::PenCapStyle cap = mPenCapStyle;
4114 const double prevOpacity = mFill->opacity();
4115 mFill->setOpacity( mFill->opacity() * context.
opacity() );
4122 if ( points.count() >= 2 )
4140 auto inputPoly = std::make_unique< QgsPolygon >(
static_cast< QgsLineString *
>( ls.release() ) );
4146 if ( !parts.empty() )
4174 std::unique_ptr< QgsAbstractGeometry > bufferedGeom =
QgsGeos::fromGeos( buffered.get() );
4176 for (
const QList< QPolygonF > &polygon : parts )
4178 QVector< QPolygonF > rings;
4179 for (
int i = 1; i < polygon.size(); ++i )
4180 rings << polygon.at( i );
4181 mFill->renderPolygon( polygon.value( 0 ), &rings, context.
feature(), context.
renderContext(), -1, useSelectedColor );
4189 mFill->setOpacity( prevOpacity );
4196 map[QStringLiteral(
"line_width" )] = QString::number(
mWidth );
4201 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
4216 res->setSubSymbol( mFill->clone() );
4217 return res.release();
4252 attr.unite( mFill->usedAttributes( context ) );
4260 if ( mFill && mFill->hasDataDefinedProperties() )
4269 mFill->setColor(
c );
4274 return mFill ? mFill->color() :
mColor;
4281 || ( mFill && mFill->usesMapUnits() );
4288 mFill->setMapUnitScale( scale );
4295 return mFill->mapUnitScale();
4304 mFill->setOutputUnit( unit );
4311 return mFill->outputUnit();
MarkerLinePlacement
Defines how/where the symbols should be placed on a line.
@ CurvePoint
Place symbols at every virtual curve point in the line (used when rendering curved geometry types onl...
@ InnerVertices
Inner vertices (i.e. all vertices except the first and last vertex).
@ LastVertex
Place symbols on the last vertex in the line.
@ CentralPoint
Place symbols at the mid point of the line.
@ SegmentCenter
Place symbols at the center of every line segment.
@ Vertex
Place symbols on every vertex in the line.
@ Interval
Place symbols at regular intervals.
@ FirstVertex
Place symbols on the first vertex in the line.
@ 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.
@ AntialiasingSimplification
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'.
GradientColorSource
Gradient color sources.
@ ColorRamp
Gradient color ramp.
@ CanCalculateMaskGeometryPerFeature
If present, indicates that mask geometry can safely be calculated per feature for the symbol layer....
@ Curve
An intermediate point on a segment defining the curvature of the segment.
@ Segment
The actual start or end point of a segment.
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
@ Miter
Use mitered joins.
RenderUnit
Rendering size units.
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size).
@ Millimeters
Millimeters.
@ Points
Points (e.g., for font sizes).
@ Unknown
Mixed or unknown units.
@ MetersInMapUnits
Meters value as Map units.
@ Flat
Flat cap (in line with start/end of line).
@ RenderingSubSymbol
Set whenever a sub-symbol of a parent symbol is currently being rendered. Can be used during symbol a...
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
@ RenderLayerTree
The render is for a layer tree display where map based properties are not available and where avoidan...
@ RenderBlocking
Render and load remote sources in the same thread to ensure rendering remote sources (svg and images)...
QFlags< SymbolRenderHint > SymbolRenderHints
Symbol render hints.
@ MultiLineString
MultiLineString.
QFlags< MarkerLinePlacement > MarkerLinePlacements
Base class for line symbol layer types which draws line sections using a QBrush.
Qt::PenCapStyle mPenCapStyle
Qt::PenJoinStyle mPenJoinStyle
void renderPolylineUsingBrush(const QPolygonF &points, QgsSymbolRenderContext &context, const QBrush &brush, double patternThickness, double patternLength)
Renders a polyline of points using the specified brush.
static bool isGeneralizableByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
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 QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
QList< QPair< double, double > > BlankSegments
static QList< QList< BlankSegments > > parseBlankSegments(const QString &strBlankSegments, const QgsRenderContext &renderContext, Qgis::RenderUnit unit, QString &error)
Parse blank segments string representation strBlankSegments The blank segments are expected to be exp...
Abstract base class for color ramps.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
static QString typeString()
Returns the string identifier for QgsCptCityColorRamp.
Curve polygon geometry type.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Exports QGIS layers to the DXF format.
static double mapUnitScaleFactor(double scale, Qgis::RenderUnit symbolUnits, Qgis::DistanceUnit mapUnits, double mapUnitsPerPixel=1.0)
Returns scale factor for conversion to map units.
Qgis::DistanceUnit mapUnits() const
Retrieve map units.
double symbologyScale() const
Returns the reference scale for output.
void clipValueToMapUnitScale(double &value, const QgsMapUnitScale &scale, double pixelToMMFactor) const
Clips value to scale minimum/maximum.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
static const QString EXPR_GEOMETRY_RING_NUM
Inbuilt variable name for geometry ring number variable.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool isCanceled() const
Tells whether the operation has been canceled already.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
static std::unique_ptr< QgsFillSymbol > createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
QString layerType() const override
Returns a string that represents this layer type.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsFilledLineSymbolLayer, using the settings serialized in the properties map (correspo...
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
~QgsFilledLineSymbolLayer() override
QgsFilledLineSymbolLayer(double width=DEFAULT_SIMPLELINE_WIDTH, QgsFillSymbol *fillSymbol=nullptr)
Constructor for QgsFilledLineSymbolLayer.
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setColor(const QColor &c) override
Sets the "representative" color for the symbol layer.
QColor color() const override
Returns the "representative" color of the symbol layer.
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
QgsFilledLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QgsMapUnitScale mapUnitScale() const override
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
A geometry is the spatial representation of a feature.
QVector< QgsGeometry > coerceToType(Qgis::WkbType type, double defaultZ=0, double defaultM=0, bool avoidDuplicates=true) const
Attempts to coerce this geometry into the specified destination type.
static geos::unique_ptr offsetCurve(const GEOSGeometry *geometry, double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr)
Directly calculates the offset curve for a GEOS geometry object and returns a GEOS geometry result.
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
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...
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
static QString typeString()
Returns the string identifier for QgsGradientColorRamp.
void addStopsToGradient(QGradient *gradient, double opacity=1) const
Copy color ramp stops to a QGradient.
double hashAngle() const
Returns the angle to use when drawing the hashed lines sections, in degrees clockwise.
QgsHashedLineSymbolLayer(bool rotateSymbol=true, double interval=3)
Constructor for QgsHashedLineSymbolLayer.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
void setWidth(double width) override
Sets the width of the line symbol layer.
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
double width() const override
Returns the estimated width for the line symbol layer.
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsHashedLineSymbolLayer, using the settings serialized in the properties map (correspo...
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
QgsHashedLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
~QgsHashedLineSymbolLayer() override
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
QColor color() const override
Returns the "representative" color of the symbol layer.
void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false) override
Renders the templated symbol at the specified point, using the given render context.
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
QString layerType() const override
Returns a string that represents this layer type.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
void setHashAngle(double angle)
Sets the angle to use when drawing the hashed lines sections, in degrees clockwise.
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, double targetDpi=96, int frameNumber=-1, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
static void overlayColor(QImage &image, const QColor &color)
Overlays a color onto an image.
Line string geometry type, with support for z-dimension and m-values.
static std::unique_ptr< QgsLineString > fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
Qgis::RenderUnit mOffsetUnit
RenderRingFilter
Options for filtering rings when the line symbol layer is being used to render a polygon's rings.
@ ExteriorRingOnly
Render the exterior ring only.
@ InteriorRingsOnly
Render the interior rings only.
@ AllRings
Render both exterior and interior rings.
QgsMapUnitScale mWidthMapUnitScale
QgsLineSymbolLayer(const QgsLineSymbolLayer &other)=delete
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Qgis::RenderUnit mWidthUnit
void setOffset(double offset)
Sets the line's offset.
RenderRingFilter mRingFilter
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the line's offset.
void setWidthUnit(Qgis::RenderUnit unit)
Sets the units for the line's width.
virtual double width() const
Returns the estimated width for the line symbol layer.
QgsMapUnitScale mOffsetMapUnitScale
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the line's offset.
QgsMapUnitScale mapUnitScale() const override
void setRingFilter(QgsLineSymbolLayer::RenderRingFilter filter)
Sets the line symbol layer's ring filter, which controls which rings are rendered when the line symbo...
void setMapUnitScale(const QgsMapUnitScale &scale) override
double offset() const
Returns the line's offset.
Qgis::RenderUnit offsetUnit() const
Returns the units for the line's offset.
Qgis::RenderUnit widthUnit() const
Returns the units for the line's width.
A line symbol type, for rendering LineString and MultiLineString geometries.
std::unique_ptr< QgsColorRamp > mGradientRamp
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
void setColorRamp(QgsColorRamp *ramp)
Sets the color ramp used for the gradient line.
QColor color2() const
Returns the color for endpoint of gradient, only used if the gradient color type is set to SimpleTwoC...
Qgis::GradientColorSource mGradientColorType
QString layerType() const override
Returns a string that represents this layer type.
~QgsLineburstSymbolLayer() override
QgsLineburstSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsMapUnitScale mapUnitScale() const override
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsLineburstSymbolLayer, using the settings serialized in the properties map (correspon...
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
QgsLineburstSymbolLayer(const QColor &color=DEFAULT_SIMPLELINE_COLOR, const QColor &color2=Qt::white)
Constructor for QgsLineburstSymbolLayer, with the specified start and end gradient colors.
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QgsColorRamp * colorRamp()
Returns the color ramp used for the gradient line.
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.
double mapUnitsPerPixel() const
Returns the current map units per pixel.
void transformInPlace(double &x, double &y) const
Transforms map coordinates to device coordinates.
Struct for storing maximum and minimum scales for measurements in map units.
Q_DECL_DEPRECATED bool rotateMarker() const
Shall the marker be rotated.
std::unique_ptr< QgsMarkerSymbol > mMarker
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
QgsMarkerLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
double width() const override
Returns the estimated width for the line symbol layer.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsMarkerLineSymbolLayer, using the settings serialized in the properties map (correspo...
QgsMarkerLineSymbolLayer(bool rotateMarker=DEFAULT_MARKERLINE_ROTATE, double interval=DEFAULT_MARKERLINE_INTERVAL)
Constructor for QgsMarkerLineSymbolLayer.
void setWidth(double width) override
Sets the width of the line symbol layer.
QColor color() const override
Returns the "representative" color of the symbol layer.
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
~QgsMarkerLineSymbolLayer() override
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
QString layerType() const override
Returns a string that represents this layer type.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsMarkerLineSymbolLayer from an SLD XML DOM element.
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false) override
Renders the templated symbol at the specified point, using the given render context.
Abstract base class for marker symbol layers.
A marker symbol type, for rendering Point and MultiPoint geometries.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
Resolves relative paths into absolute paths and vice versa.
QgsPointXY project(double distance, double bearing) const
Returns a new point which corresponds to this point projected by a specified distance in a specified ...
QPointF toQPointF() const
Returns the point as a QPointF.
QgsPoint project(double distance, double azimuth, double inclination=90.0) const
Returns a new point which corresponds to this point projected by a specified distance with specified ...
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
A store for object properties.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
QgsRasterLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
double opacity() const
Returns the line opacity.
QString path() const
Returns the raster image path.
void setPath(const QString &path)
Set the raster image path.
QString layerType() const override
Returns a string that represents this layer type.
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
static void resolvePaths(QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving)
Turns relative paths in properties map to absolute when reading and vice versa when writing.
QgsRasterLineSymbolLayer(const QString &path=QString())
Constructor for QgsRasterLineSymbolLayer, with the specified raster image path.
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsRasterLineSymbolLayer, using the settings serialized in the properties map (correspo...
QColor color() const override
Returns the "representative" color of the symbol layer.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
~QgsRasterLineSymbolLayer() override
void setMapUnitScale(const QgsMapUnitScale &scale) override
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QgsMapUnitScale mapUnitScale() const override
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QgsVectorSimplifyMethod & vectorSimplifyMethod()
Returns the simplification settings to use when rendering vector layers.
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.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsExpressionContext & expressionContext()
Gets the expression context.
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected).
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QColor selectionColor() const
Returns the color to use when rendering selected features.
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
const QgsAbstractGeometry * geometry() const
Returns pointer to the unsegmentized geometry.
Scoped object for saving and restoring a QPainter object's state.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
void setDrawInsidePolygon(bool drawInsidePolygon)
Sets whether the line should only be drawn inside polygons, and any portion of the line which falls o...
bool tweakDashPatternOnCorners() const
Returns true if dash patterns tweaks should be applied on sharp corners, to ensure that a double-leng...
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
QgsMapUnitScale mapUnitScale() const override
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsSimpleLineSymbolLayer, using the settings serialized in the properties map (correspo...
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QVector< qreal > customDashVector() const
Returns the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ...
Qt::PenJoinStyle penJoinStyle() const
Returns the pen join style used to render the line (e.g.
void renderPolygonStroke(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the outline of polygon, using the given render context.
Qt::PenStyle dxfPenStyle() const override
Gets pen style.
void setCustomDashPatternMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for lengths used in the custom dash pattern.
void setTrimDistanceEndMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the end of the line.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
void setTrimDistanceEnd(double distance)
Sets the trim distance for the end of the line, which dictates a length from the end of the line at w...
double dxfOffset(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets offset.
QgsSimpleLineSymbolLayer(const QColor &color=DEFAULT_SIMPLELINE_COLOR, double width=DEFAULT_SIMPLELINE_WIDTH, Qt::PenStyle penStyle=DEFAULT_SIMPLELINE_PENSTYLE)
Constructor for QgsSimpleLineSymbolLayer.
~QgsSimpleLineSymbolLayer() override
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
void setTweakDashPatternOnCorners(bool enabled)
Sets whether dash patterns tweaks should be applied on sharp corners, to ensure that a double-length ...
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
void setCustomDashVector(const QVector< qreal > &vector)
Sets the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ren...
void setDashPatternOffset(double offset)
Sets the dash pattern offset, which dictates how far along the dash pattern the pattern should start ...
QColor dxfColor(QgsSymbolRenderContext &context) const override
Gets color.
QString layerType() const override
Returns a string that represents this layer type.
void setDashPatternOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the dash pattern offset.
QgsSimpleLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Qt::PenStyle penStyle() const
Returns the pen style used to render the line (e.g.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
void setAlignDashPattern(bool enabled)
Sets whether dash patterns should be aligned to the start and end of lines, by applying subtle tweaks...
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsSimpleLineSymbolLayer from an SLD XML DOM element.
double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets line width.
void setTrimDistanceStartMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the start of the line.
QVector< qreal > dxfCustomDashPattern(Qgis::RenderUnit &unit) const override
Gets dash pattern.
Qt::PenCapStyle penCapStyle() const
Returns the pen cap style used to render the line (e.g.
void setTrimDistanceEndUnit(Qgis::RenderUnit unit)
Sets the unit for the trim distance for the end of the line.
void setDashPatternOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the dash pattern offset.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setTrimDistanceStart(double distance)
Sets the trim distance for the start of the line, which dictates a length from the start of the line ...
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
void setTrimDistanceStartUnit(Qgis::RenderUnit unit)
Sets the unit for the trim distance for the start of the line.
bool alignDashPattern() const
Returns true if dash patterns should be aligned to the start and end of lines, by applying subtle twe...
void setCustomDashPatternUnit(Qgis::RenderUnit unit)
Sets the unit for lengths used in the custom dash pattern.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
QVariantMap extraProperties() const
Returns the open ended set of properties that can drive/inform the SLD encoding.
static QString encodePenStyle(Qt::PenStyle style)
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static Q_DECL_DEPRECATED bool createExpressionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates a OGC Expression element based on the provided function expression.
static QString svgSymbolPathToName(const QString &path, const QgsPathResolver &pathResolver)
Determines an SVG symbol's name from its path.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static double rescaleUom(double size, Qgis::RenderUnit unit, const QVariantMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
static std::unique_ptr< QgsSymbolLayer > createMarkerLayerFromSld(QDomElement &element)
Creates a new marker layer from a SLD DOM element.
static bool isSharpCorner(QPointF p1, QPointF p2, QPointF p3)
Returns true if the angle formed by the line p1 - p2 - p3 forms a "sharp" corner.
static QString ogrFeatureStylePen(double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor &c, Qt::PenJoinStyle joinStyle=Qt::MiterJoin, Qt::PenCapStyle capStyle=Qt::FlatCap, double offset=0.0, const QVector< qreal > *dashPattern=nullptr)
Create ogr feature style string for pen.
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
static QList< QList< QPolygonF > > toQPolygonF(const QgsGeometry &geometry, Qgis::SymbolType type)
Converts a geometry to a set of QPolygonF objects representing how the geometry should be drawn for a...
static QVector< qreal > decodeRealVector(const QString &s)
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)
static QString encodePenCapStyle(Qt::PenCapStyle style)
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
static void appendPolyline(QPolygonF &target, const QPolygonF &line)
Appends a polyline line to an existing target polyline.
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
static QString encodeColor(const QColor &color)
static Qgis::EndCapStyle penCapStyleToEndCapStyle(Qt::PenCapStyle style)
Converts a Qt pen cap style to a QGIS end cap style.
static double polylineLength(const QPolygonF &polyline)
Returns the total length of a polyline.
static Qgis::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
static Q_DECL_DEPRECATED void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
Creates an SLD geometry element.
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
static Qt::PenStyle decodePenStyle(const QString &str)
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
static QgsStringMap getVendorOptionList(QDomElement &element)
static Qgis::JoinStyle penJoinStyleToJoinStyle(Qt::PenJoinStyle style)
Converts a Qt pen joinstyle to a QGIS join style.
static QPolygonF polylineSubstring(const QPolygonF &polyline, double startOffset, double endOffset)
Returns the substring of a polyline which starts at startOffset from the beginning of the line and en...
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, const QColor &color, QgsSldExportContext &context, double width=-1, const Qt::PenJoinStyle *penJoinStyle=nullptr, const Qt::PenCapStyle *penCapStyle=nullptr, const QVector< qreal > *customDashPattern=nullptr, double dashOffset=0.0)
static QString encodeRealVector(const QVector< qreal > &v)
virtual QgsSymbolLayer * clone() const =0
Shall be reimplemented by subclasses to create a deep copy of the instance.
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
bool shouldRenderUsingSelectionColor(const QgsSymbolRenderContext &context) const
Returns true if the symbol layer should be rendered using the selection color from the render context...
static const bool SELECTION_IS_OPAQUE
Whether styles for selected features ignore symbol alpha.
bool installMasks(QgsRenderContext &context, bool recursive, const QRectF &rect=QRectF())
When rendering, install masks on context painter.
void removeMasks(QgsRenderContext &context, bool recursive)
When rendering, remove previously installed masks from context painter if recursive is true masks are...
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
Property
Data definable properties.
@ SecondaryColor
Secondary color (eg for gradient fills).
@ File
Filename, eg for svg files.
@ BlankSegments
String list of distance to define blank segments along line for templated line symbol layers.
@ DashPatternOffset
Dash pattern offset,.
@ OffsetAlongLine
Offset along line.
@ CustomDash
Custom dash pattern.
@ StrokeStyle
Stroke style (eg solid, dashed).
@ StrokeColor
Stroke color.
@ TrimStart
Trim distance from start of line.
@ CapStyle
Line cap style.
@ Placement
Line marker placement.
@ LineAngle
Line angle, or angle of hash lines for hash line symbols.
@ JoinStyle
Line join style.
@ AverageAngleLength
Length to average symbol angles over.
@ Interval
Line marker interval.
@ StrokeWidth
Stroke width.
@ LineDistance
Distance between lines, or length of lines for hash line symbols.
@ TrimEnd
Trim distance from end of line.
void restoreOldDataDefinedProperties(const QVariantMap &stringMap)
Restores older data defined properties from string map.
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
virtual QString layerType() const =0
Returns a string that represents this layer type.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
virtual void setColor(const QColor &color)
Sets the "representative" color for the symbol layer.
virtual QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
virtual QColor color() const
Returns the "representative" color of the symbol layer.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
virtual Qgis::SymbolLayerFlags flags() const
Returns flags which control the symbol layer's behavior.
QgsPropertyCollection mDataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
virtual bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
QgsSymbolLayer(const QgsSymbolLayer &other)
Encapsulates the context in which a symbol is being rendered.
const QgsFeature * feature() const
Returns the current feature being rendered.
Qgis::GeometryType originalGeometryType() const
Returns the geometry type for the original feature geometry being rendered.
QgsFields fields() const
Fields of the layer.
int geometryPartNum() const
Part number of current geometry.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
qreal opacity() const
Returns the opacity for the symbol.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Abstract base class for all rendered symbols.
qreal opacity() const
Returns the opacity for the symbol.
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Qgis::SymbolType type() const
Returns the symbol's type.
bool rotateSymbols() const
Returns true if the repeating symbols be rotated to match their line segment orientation.
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
static void setCommonProperties(QgsTemplatedLineSymbolLayerBase *destLayer, const QVariantMap &properties)
Sets all common symbol properties in the destLayer, using the settings serialized in the properties m...
void setMapUnitScale(const QgsMapUnitScale &scale) final
void renderPolygonStroke(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) final
Renders the line symbol layer along the outline of polygon, using the given render context.
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setIntervalUnit(Qgis::RenderUnit unit)
Sets the units for the interval between symbols.
void setAverageAngleUnit(Qgis::RenderUnit unit)
Sets the unit for the length over which the line's direction is averaged when calculating individual ...
double interval() const
Returns the interval between individual symbols.
void setOffsetAlongLineUnit(Qgis::RenderUnit unit)
Sets the unit used for calculating the offset along line for symbols.
void setAverageAngleMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the length over which the line's direction is averaged when calculating i...
const QgsMapUnitScale & intervalMapUnitScale() const
Returns the map unit scale for the interval between symbols.
double offsetAlongLine() const
Returns the offset along the line for the symbol placement.
~QgsTemplatedLineSymbolLayerBase() override
void copyTemplateSymbolProperties(QgsTemplatedLineSymbolLayerBase *destLayer) const
Copies all common properties of this layer to another templated symbol layer.
Qgis::MarkerLinePlacements placements() const
Returns the placement of the symbols.
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the symbol placement.
Qgis::RenderUnit offsetAlongLineUnit() const
Returns the unit used for calculating the offset along line for symbols.
Qgis::RenderUnit outputUnit() const final
Returns the units to use for sizes and widths within the symbol layer.
QgsTemplatedLineSymbolLayerBase(bool rotateSymbol=true, double interval=3)
Constructor for QgsTemplatedLineSymbolLayerBase.
virtual void setSymbolLineAngle(double angle)=0
Sets the line angle modification for the symbol's angle.
QgsMapUnitScale mapUnitScale() const final
void setInterval(double interval)
Sets the interval between individual symbols.
Qgis::RenderUnit intervalUnit() const
Returns the units for the interval between symbols.
Q_DECL_DEPRECATED Qgis::MarkerLinePlacement placement() const
Returns the placement of the symbols.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
void setPlaceOnEveryPart(bool respect)
Sets whether the placement applies for every part of multi-part feature geometries.
void setPlacements(Qgis::MarkerLinePlacements placements)
Sets the placement of the symbols.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Qgis::RenderUnit averageAngleUnit() const
Returns the unit for the length over which the line's direction is averaged when calculating individu...
Q_DECL_DEPRECATED void setPlacement(Qgis::MarkerLinePlacement placement)
Sets the placement of the symbols.
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
Qgis::RenderUnit blankSegmentsUnit() const
Returns the unit for for blank segments start and end distances.
void setBlankSegmentsUnit(Qgis::RenderUnit unit)
Sets the unit for blank segments start and end distances.
const QgsMapUnitScale & offsetAlongLineMapUnitScale() const
Returns the map unit scale used for calculating the offset in map units along line for symbols.
virtual void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false)=0
Renders the templated symbol at the specified point, using the given render context.
void setIntervalMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the interval between symbols.
void setOffsetAlongLineMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale used for calculating the offset in map units along line for symbols.
void setAverageAngleLength(double length)
Sets the length of line over which the line's direction is averaged when calculating individual symbo...
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.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Qgis::VectorRenderingSimplificationFlags simplifyHints() const
Gets the simplification hints of the vector layer managed.
float threshold() const
Gets the simplification threshold of the vector layer managed.
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.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given keys of a flag.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
QMap< QString, QString > QgsStringMap
#define DEFAULT_MARKERLINE_INTERVAL
#define DEFAULT_SIMPLELINE_WIDTH
#define DEFAULT_MARKERLINE_ROTATE
#define DEFAULT_SIMPLELINE_PENSTYLE
#define DEFAULT_SIMPLELINE_COLOR
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
QList< QgsSymbolLayer * > QgsSymbolLayerList
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, Qgis::GeometryType geometryType)
calculate geometry shifted by a specified distance
Single variable definition for use within a QgsExpressionContextScope.
Qgis::VertexType type
Vertex type.