47#include <QDomDocument>
52using namespace Qt::StringLiterals;
59 mCustomDashVector << 5 << 2;
69 mCustomDashPatternUnit = unit;
70 mDashPatternOffsetUnit = unit;
71 mTrimDistanceStartUnit = unit;
72 mTrimDistanceEndUnit = unit;
95 mCustomDashPatternMapUnitScale = scale;
113 if ( props.contains( u
"line_color"_s ) )
117 else if ( props.contains( u
"outline_color"_s ) )
121 else if ( props.contains( u
"color"_s ) )
126 if ( props.contains( u
"line_width"_s ) )
128 width = props[u
"line_width"_s].toDouble();
130 else if ( props.contains( u
"outline_width"_s ) )
132 width = props[u
"outline_width"_s].toDouble();
134 else if ( props.contains( u
"width"_s ) )
137 width = props[u
"width"_s].toDouble();
139 if ( props.contains( u
"line_style"_s ) )
143 else if ( props.contains( u
"outline_style"_s ) )
147 else if ( props.contains( u
"penstyle"_s ) )
153 if ( props.contains( u
"line_width_unit"_s ) )
157 else if ( props.contains( u
"outline_width_unit"_s ) )
161 else if ( props.contains( u
"width_unit"_s ) )
166 if ( props.contains( u
"width_map_unit_scale"_s ) )
168 if ( props.contains( u
"offset"_s ) )
169 l->
setOffset( props[u
"offset"_s].toDouble() );
170 if ( props.contains( u
"offset_unit"_s ) )
172 if ( props.contains( u
"offset_map_unit_scale"_s ) )
174 if ( props.contains( u
"joinstyle"_s ) )
176 if ( props.contains( u
"capstyle"_s ) )
179 if ( props.contains( u
"use_custom_dash"_s ) )
183 if ( props.contains( u
"customdash"_s ) )
187 if ( props.contains( u
"customdash_unit"_s ) )
191 if ( props.contains( u
"customdash_map_unit_scale"_s ) )
196 if ( props.contains( u
"draw_inside_polygon"_s ) )
201 if ( props.contains( u
"ring_filter"_s ) )
206 if ( props.contains( u
"dash_pattern_offset"_s ) )
208 if ( props.contains( u
"dash_pattern_offset_unit"_s ) )
210 if ( props.contains( u
"dash_pattern_offset_map_unit_scale"_s ) )
213 if ( props.contains( u
"trim_distance_start"_s ) )
215 if ( props.contains( u
"trim_distance_start_unit"_s ) )
217 if ( props.contains( u
"trim_distance_start_map_unit_scale"_s ) )
219 if ( props.contains( u
"trim_distance_end"_s ) )
221 if ( props.contains( u
"trim_distance_end_unit"_s ) )
223 if ( props.contains( u
"trim_distance_end_map_unit_scale"_s ) )
226 if ( props.contains( u
"align_dash_pattern"_s ) )
229 if ( props.contains( u
"tweak_dash_pattern_on_corners"_s ) )
239 return u
"SimpleLine"_s;
251 mPen.setColor( penColor );
253 mPen.setWidthF( scaledWidth );
257 const double dashWidthDiv = std::max( 1.0, scaledWidth );
258 if ( mUseCustomDashPattern )
260 mPen.setStyle( Qt::CustomDashLine );
264 QVector<qreal> scaledVector;
265 QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
266 for ( ; it != mCustomDashVector.constEnd(); ++it )
271 mPen.setDashPattern( scaledVector );
275 mPen.setStyle( mPenStyle );
278 if ( mDashPatternOffset && mPen.style() != Qt::SolidLine )
283 mPen.setJoinStyle( mPenJoinStyle );
284 mPen.setCapStyle( mPenCapStyle );
289 selColor.setAlphaF( context.
opacity() );
290 mSelPen.setColor( selColor );
307 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
314 if ( mDrawInsidePolygon )
322 if ( mDrawInsidePolygon )
325 QPainterPath clipPath;
326 clipPath.addPolygon( points );
331 for (
auto it = rings->constBegin(); it != rings->constEnd(); ++it )
333 QPolygonF ring = *it;
334 clipPath.addPolygon( ring );
339 p->setClipPath( clipPath, Qt::IntersectClip );
362 for (
const QPolygonF &ring : std::as_const( *rings ) )
378 if ( mDrawInsidePolygon )
413 double totalLength = -1;
417 startTrim = startTrim * 0.01 * totalLength;
425 if ( totalLength < 0 )
427 endTrim = endTrim * 0.01 * totalLength;
448 QPolygonF points = pts;
449 trimPoints( points, mTrimDistanceStart, mTrimDistanceEnd, mTrimDistanceStartUnit, mTrimDistanceEndUnit, mTrimDistanceStartMapUnitScale, mTrimDistanceEndMapUnitScale,
mDataDefinedProperties, context );
453 mPen.setColor( penColor );
456 applyDataDefinedSymbology( context, mPen, mSelPen,
offset );
459 const QPen pen = useSelectedColor ? mSelPen : mPen;
461 if ( !pen.dashPattern().isEmpty() )
464 const QVector<double> pattern = pen.dashPattern();
465 bool foundNonNull =
false;
466 for (
int i = 0; i < pattern.size(); ++i )
478 p->setBrush( Qt::NoBrush );
481 std::unique_ptr< QgsScopedQPainterState > painterState;
482 if ( points.size() <= 2
485 && ( p->renderHints() & QPainter::Antialiasing ) )
487 painterState = std::make_unique< QgsScopedQPainterState >( p );
488 p->setRenderHint( QPainter::Antialiasing,
false );
491 const bool applyPatternTweaks = mAlignDashPattern && ( pen.style() != Qt::SolidLine || !pen.dashPattern().empty() ) && pen.dashOffset() == 0;
495 if ( applyPatternTweaks )
497 drawPathWithDashPatternTweaks( p, points, pen );
503 path.addPolygon( points );
519 for (
const QPolygonF &part : mline )
521 if ( applyPatternTweaks )
523 drawPathWithDashPatternTweaks( p, part, pen );
529 path.addPolygon( part );
540 map[u
"line_width"_s] = QString::number(
mWidth );
546 map[u
"offset"_s] = QString::number(
mOffset );
549 map[u
"use_custom_dash"_s] = ( mUseCustomDashPattern ? u
"1"_s : u
"0"_s );
553 map[u
"dash_pattern_offset"_s] = QString::number( mDashPatternOffset );
556 map[u
"trim_distance_start"_s] = QString::number( mTrimDistanceStart );
559 map[u
"trim_distance_end"_s] = QString::number( mTrimDistanceEnd );
562 map[u
"draw_inside_polygon"_s] = ( mDrawInsidePolygon ? u
"1"_s : u
"0"_s );
563 map[u
"ring_filter"_s] = QString::number(
static_cast< int >(
mRingFilter ) );
564 map[u
"align_dash_pattern"_s] = mAlignDashPattern ? u
"1"_s : u
"0"_s;
565 map[u
"tweak_dash_pattern_on_corners"_s] = mPatternCartographicTweakOnSharpCorners ? u
"1"_s : u
"0"_s;
605 toSld( doc, element, context );
610 if ( mPenStyle == Qt::NoPen )
614 QDomElement symbolizerElem = doc.createElement( u
"se:LineSymbolizer"_s );
615 if ( !props.value( u
"uom"_s, QString() ).toString().isEmpty() )
616 symbolizerElem.setAttribute( u
"uom"_s, props.value( u
"uom"_s, QString() ).toString() );
617 element.appendChild( symbolizerElem );
623 QDomElement strokeElem = doc.createElement( u
"se:Stroke"_s );
624 symbolizerElem.appendChild( strokeElem );
626 Qt::PenStyle
penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
634 QDomElement perpOffsetElem = doc.createElement( u
"se:PerpendicularOffset"_s );
637 symbolizerElem.appendChild( perpOffsetElem );
644 if ( mUseCustomDashPattern )
658 QDomElement strokeElem = element.firstChildElement( u
"Stroke"_s );
659 if ( strokeElem.isNull() )
673 QDomElement perpOffsetElem = element.firstChildElement( u
"PerpendicularOffset"_s );
674 if ( !perpOffsetElem.isNull() )
677 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
682 double scaleFactor = 1.0;
683 const QString uom = element.attribute( u
"uom"_s );
698void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context, QPen &pen, QPen &selPen,
double &offset )
704 bool hasStrokeWidthExpression =
false;
711 pen.setWidthF( scaledWidth );
712 selPen.setWidthF( scaledWidth );
713 hasStrokeWidthExpression =
true;
722 penColor.setAlphaF( context.
opacity() * penColor.alphaF() );
723 pen.setColor( penColor );
737 const double dashWidthDiv = std::max( hasStrokeWidthExpression ? pen.widthF() : mPen.widthF(), 1.0 );
741 const QString customDashString
743 const QStringList dashList = customDashString.split(
';' );
744 QVector<qreal> dashVector;
745 for (
const QString &dash : dashList )
749 pen.setDashPattern( dashVector );
755 QVector<qreal> scaledVector;
756 for (
double v : std::as_const( mCustomDashVector ) )
761 mPen.setDashPattern( scaledVector );
765 double patternOffset = mDashPatternOffset;
777 const QString lineStyleString
786 const QString joinStyleString
795 const QString capStyleString
801void QgsSimpleLineSymbolLayer::drawPathWithDashPatternTweaks( QPainter *painter,
const QPolygonF &points, QPen pen )
const
803 if ( pen.dashPattern().empty() || points.size() < 2 )
806 if ( pen.widthF() <= 1.0 )
808 pen.setWidthF( 1.0001 );
811 QVector< qreal > sourcePattern = pen.dashPattern();
812 const double dashWidthDiv = pen.widthF();
814 for (
int i = 0; i < sourcePattern.size(); ++i )
815 sourcePattern[i] *= pen.widthF();
817 QVector< qreal > buffer;
818 QPolygonF bufferedPoints;
819 QPolygonF previousSegmentBuffer;
824 auto ptIt = points.constBegin();
825 double totalBufferLength = 0;
826 int patternIndex = 0;
827 double currentRemainingDashLength = 0;
828 double currentRemainingGapLength = 0;
830 auto compressPattern = [](
const QVector< qreal > &buffer ) -> QVector< qreal > {
831 QVector< qreal > result;
832 result.reserve( buffer.size() );
833 for (
auto it = buffer.begin(); it != buffer.end(); )
837 while ( dash == 0 && !result.empty() )
839 result.last() += gap;
841 if ( it == buffer.end() )
846 while ( gap == 0 && it != buffer.end() )
851 result << dash << gap;
856 double currentBufferLineLength = 0;
858 [pen, painter, &buffer, &bufferedPoints, &previousSegmentBuffer, ¤tRemainingDashLength, ¤tRemainingGapLength, ¤tBufferLineLength, &totalBufferLength, dashWidthDiv, &compressPattern](
861 if ( buffer.empty() || bufferedPoints.size() < 2 )
866 if ( currentRemainingDashLength )
869 buffer << currentRemainingDashLength << 0.0;
870 totalBufferLength += currentRemainingDashLength;
872 QVector< qreal > compressed = compressPattern( buffer );
873 if ( !currentRemainingDashLength )
876 totalBufferLength -= compressed.last();
877 compressed.last() = 0;
881 const double scaleFactor = currentBufferLineLength / totalBufferLength;
883 bool shouldFlushPreviousSegmentBuffer =
false;
885 if ( !previousSegmentBuffer.empty() )
889 if ( !firstDashSubstring.empty() )
895 compressed = compressed.mid( 2 );
896 shouldFlushPreviousSegmentBuffer = !compressed.empty();
899 if ( !previousSegmentBuffer.empty() && ( shouldFlushPreviousSegmentBuffer || !nextPoint ) )
901 QPen adjustedPen = pen;
902 adjustedPen.setStyle( Qt::SolidLine );
903 painter->setPen( adjustedPen );
905 path.addPolygon( previousSegmentBuffer );
906 painter->drawPath( path );
907 previousSegmentBuffer.clear();
910 double finalDash = 0;
917 if ( !compressed.empty() )
919 finalDash = compressed.at( compressed.size() - 2 );
920 const double finalGap = compressed.size() > 2 ? compressed.at( compressed.size() - 3 ) : 0;
922 const QPolygonF thisPoints = bufferedPoints;
928 previousSegmentBuffer << bufferedPoints;
932 currentBufferLineLength = 0;
933 currentRemainingDashLength = 0;
934 currentRemainingGapLength = 0;
935 totalBufferLength = 0;
938 if ( !bufferedPoints.empty() && ( !compressed.empty() || !nextPoint ) )
940 QPen adjustedPen = pen;
941 if ( !compressed.empty() )
944 compressed = compressed.mid( 0, 32 );
945 std::for_each( compressed.begin(), compressed.end(), [scaleFactor, dashWidthDiv]( qreal &element ) { element *= scaleFactor / dashWidthDiv; } );
946 adjustedPen.setDashPattern( compressed );
950 adjustedPen.setStyle( Qt::SolidLine );
953 painter->setPen( adjustedPen );
955 path.addPolygon( bufferedPoints );
956 painter->drawPath( path );
959 bufferedPoints.clear();
965 bufferedPoints << p2;
966 for ( ; ptIt != points.constEnd(); ++ptIt )
974 double remainingSegmentDistance = std::sqrt( std::pow( p2.x() - p1.x(), 2.0 ) + std::pow( p2.y() - p1.y(), 2.0 ) );
975 currentBufferLineLength += remainingSegmentDistance;
979 if ( currentRemainingDashLength > 0 )
982 if ( remainingSegmentDistance >= currentRemainingDashLength )
985 buffer << currentRemainingDashLength << 0.0;
986 totalBufferLength += currentRemainingDashLength;
987 remainingSegmentDistance -= currentRemainingDashLength;
989 currentRemainingDashLength = 0.0;
990 currentRemainingGapLength = sourcePattern.at( patternIndex );
991 if ( currentRemainingGapLength == 0.0 )
999 buffer << remainingSegmentDistance << 0.0;
1000 totalBufferLength += remainingSegmentDistance;
1001 currentRemainingDashLength -= remainingSegmentDistance;
1005 if ( currentRemainingGapLength > 0 )
1008 if ( remainingSegmentDistance >= currentRemainingGapLength )
1011 buffer << 0.0 << currentRemainingGapLength;
1012 totalBufferLength += currentRemainingGapLength;
1013 remainingSegmentDistance -= currentRemainingGapLength;
1014 currentRemainingGapLength = 0.0;
1020 buffer << 0.0 << remainingSegmentDistance;
1021 totalBufferLength += remainingSegmentDistance;
1022 currentRemainingGapLength -= remainingSegmentDistance;
1027 if ( patternIndex + 1 >= sourcePattern.size() )
1032 const double nextPatternDashLength = sourcePattern.at( patternIndex );
1033 const double nextPatternGapLength = sourcePattern.at( patternIndex + 1 );
1034 if ( nextPatternDashLength + nextPatternGapLength <= remainingSegmentDistance )
1036 buffer << nextPatternDashLength << nextPatternGapLength;
1037 remainingSegmentDistance -= nextPatternDashLength + nextPatternGapLength;
1038 totalBufferLength += nextPatternDashLength + nextPatternGapLength;
1041 else if ( nextPatternDashLength <= remainingSegmentDistance )
1044 buffer << nextPatternDashLength << remainingSegmentDistance - nextPatternDashLength;
1045 totalBufferLength += remainingSegmentDistance;
1046 currentRemainingGapLength = nextPatternGapLength - ( remainingSegmentDistance - nextPatternDashLength );
1047 currentRemainingDashLength = 0;
1054 buffer << remainingSegmentDistance << 0.0;
1055 totalBufferLength += remainingSegmentDistance;
1056 currentRemainingGapLength = 0;
1057 currentRemainingDashLength = nextPatternDashLength - remainingSegmentDistance;
1062 bufferedPoints << p1;
1063 if ( mPatternCartographicTweakOnSharpCorners && ptIt + 1 != points.constEnd() )
1065 QPointF nextPoint = *( ptIt + 1 );
1071 flushBuffer( &nextPoint );
1072 bufferedPoints << p1;
1075 if ( patternIndex % 2 == 1 )
1079 currentRemainingDashLength = sourcePattern.at( patternIndex );
1086 flushBuffer(
nullptr );
1087 if ( !previousSegmentBuffer.empty() )
1089 QPen adjustedPen = pen;
1090 adjustedPen.setStyle( Qt::SolidLine );
1091 painter->setPen( adjustedPen );
1093 path.addPolygon( previousSegmentBuffer );
1094 painter->drawPath( path );
1095 previousSegmentBuffer.clear();
1101 if ( mDrawInsidePolygon )
1114 unit = mCustomDashPatternUnit;
1115 return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
1147 return mPenStyle != Qt::SolidLine || mUseCustomDashPattern;
1152 return mAlignDashPattern;
1162 return mPatternCartographicTweakOnSharpCorners;
1167 mPatternCartographicTweakOnSharpCorners =
enabled;
1188 : mRotateSymbols( rotateSymbol )
1224 if ( mRenderingFeature )
1228 mFeatureSymbolOpacity = context.
opacity();
1229 mCurrentFeatureIsSelected = useSelectedColor;
1247 QString placementString = exprVal.toString();
1248 if ( placementString.compare(
"interval"_L1, Qt::CaseInsensitive ) == 0 )
1252 else if ( placementString.compare(
"vertex"_L1, Qt::CaseInsensitive ) == 0 )
1256 else if ( placementString.compare(
"innervertices"_L1, Qt::CaseInsensitive ) == 0 )
1260 else if ( placementString.compare(
"lastvertex"_L1, Qt::CaseInsensitive ) == 0 )
1264 else if ( placementString.compare(
"firstvertex"_L1, Qt::CaseInsensitive ) == 0 )
1268 else if ( placementString.compare(
"centerpoint"_L1, Qt::CaseInsensitive ) == 0 )
1272 else if ( placementString.compare(
"curvepoint"_L1, Qt::CaseInsensitive ) == 0 )
1276 else if ( placementString.compare(
"segmentcenter"_L1, Qt::CaseInsensitive ) == 0 )
1289 double averageOver = mAverageAngleLength;
1297 QgsSymbolLayerUtils::BlankSegments blankSegments;
1302 QList<QList<QgsSymbolLayerUtils::BlankSegments>> allBlankSegments = QgsSymbolLayerUtils::parseBlankSegments( strBlankSegments, context.
renderContext(),
blankSegmentsUnit(), error );
1304 if ( !error.isEmpty() )
1306 QgsDebugError( u
"Badly formatted blank segment '%1', skip it: %2"_s.arg( strBlankSegments ).arg( error ) );
1312 if ( iPart >= 0 &&
mRingIndex >= 0 && iPart < allBlankSegments.count() &&
mRingIndex < allBlankSegments.at( iPart ).count() )
1314 blankSegments = allBlankSegments.at( iPart ).at(
mRingIndex );
1319 QPolygonF points = pts;
1320 trimPoints( points, mTrimDistanceStart, mTrimDistanceEnd, mTrimDistanceStartUnit, mTrimDistanceEndUnit, mTrimDistanceStartMapUnitScale, mTrimDistanceEndMapUnitScale,
mDataDefinedProperties, context );
1325 renderPolylineInterval( points, context, averageOver, blankSegments );
1327 renderPolylineCentral( points, context, averageOver, blankSegments );
1333 mHasRenderedFirstPart = mRenderingFeature;
1347 QList<QPolygonF> mline =
::
1350 for (
int part = 0; part < mline.count(); ++part )
1352 const QPolygonF &points2 = mline[part];
1355 renderPolylineInterval( points2, context, averageOver, blankSegments );
1357 renderPolylineCentral( points2, context, averageOver, blankSegments );
1367 mHasRenderedFirstPart = mRenderingFeature;
1376 QgsSymbolLayerUtils::ExtraItems extraItems;
1381 extraItems = QgsSymbolLayerUtils::parseExtraItems( strExtraItems, error );
1383 if ( !error.isEmpty() )
1385 QgsDebugError( u
"Badly formatted extra items '%1', skip it: %2"_s.arg( strExtraItems ).arg( error ) );
1390 for ( std::pair<QPointF, double> &extraItem : extraItems )
1412 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
1428 mBlockExtraItemsRendering =
true;
1443 for (
int i = 0; i < rings->size(); ++i )
1454 mBlockExtraItemsRendering =
true;
1465 mBlockExtraItemsRendering =
false;
1481 mIntervalUnit = unit;
1482 mOffsetAlongLineUnit = unit;
1483 mAverageAngleLengthUnit = unit;
1507 map[u
"interval"_s] = QString::number(
interval() );
1508 map[u
"offset"_s] = QString::number(
mOffset );
1516 map[u
"average_angle_length"_s] = QString::number( mAverageAngleLength );
1519 map[u
"trim_distance_start"_s] = QString::number( mTrimDistanceStart );
1522 map[u
"trim_distance_end"_s] = QString::number( mTrimDistanceEnd );
1529 map[u
"ring_filter"_s] = QString::number(
static_cast< int >(
mRingFilter ) );
1530 map[u
"place_on_every_part"_s] = mPlaceOnEveryPart;
1536 return mPlaceOnEveryPart
1546 mRenderingFeature =
true;
1547 mHasRenderedFirstPart =
false;
1552 mRenderingFeature =
false;
1563 renderSymbol( mFinalVertex, &feature, context, -1, mCurrentFeatureIsSelected );
1564 mFeatureSymbolOpacity = 1;
1604 if (
properties.contains( u
"offset_unit"_s ) )
1608 if (
properties.contains( u
"interval_unit"_s ) )
1612 if (
properties.contains( u
"offset_along_line"_s ) )
1616 if (
properties.contains( u
"offset_along_line_unit"_s ) )
1620 if (
properties.contains( ( u
"offset_along_line_map_unit_scale"_s ) ) )
1625 if (
properties.contains( u
"offset_map_unit_scale"_s ) )
1629 if (
properties.contains( u
"interval_map_unit_scale"_s ) )
1634 if (
properties.contains( u
"average_angle_length"_s ) )
1638 if (
properties.contains( u
"average_angle_unit"_s ) )
1642 if (
properties.contains( ( u
"average_angle_map_unit_scale"_s ) ) )
1646 if (
properties.contains( u
"blank_segments_unit"_s ) )
1651 if (
properties.contains( u
"trim_distance_start"_s ) )
1653 if (
properties.contains( u
"trim_distance_start_unit"_s ) )
1655 if (
properties.contains( u
"trim_distance_start_map_unit_scale"_s ) )
1657 if (
properties.contains( u
"trim_distance_end"_s ) )
1659 if (
properties.contains( u
"trim_distance_end_unit"_s ) )
1661 if (
properties.contains( u
"trim_distance_end_map_unit_scale"_s ) )
1666 if (
properties[u
"placement"_s] ==
"vertex"_L1 )
1668 else if (
properties[u
"placement"_s] ==
"lastvertex"_L1 )
1670 else if (
properties[u
"placement"_s] ==
"firstvertex"_L1 )
1672 else if (
properties[u
"placement"_s] ==
"centralpoint"_L1 )
1674 else if (
properties[u
"placement"_s] ==
"curvepoint"_L1 )
1676 else if (
properties[u
"placement"_s] ==
"segmentcenter"_L1 )
1681 else if (
properties.contains( u
"placements"_s ) )
1687 if (
properties.contains( u
"ring_filter"_s ) )
1703class BlankSegmentsWalker
1706 BlankSegmentsWalker(
const QPolygonF &points,
const QgsSymbolLayerUtils::BlankSegments &blankSegments )
1707 : mBlankSegments( blankSegments )
1709 , mItBlankSegment( blankSegments.cbegin() )
1711 mDistances.reserve( mPoints.count() );
1715 bool insideBlankSegment(
double distance )
1717 while ( mItBlankSegment != mBlankSegments.cend() && distance > mItBlankSegment->second )
1722 return ( mItBlankSegment != mBlankSegments.cend() && distance >= mItBlankSegment->first );
1727 bool insideBlankSegment(
const QPointF &point,
int pointIndex )
1729 if ( pointIndex < 0 || pointIndex >= mPoints.count() )
1733 if ( pointIndex >= mDistances.count() )
1735 for (
int i =
static_cast<int>( mDistances.count() ); i < pointIndex + 1; i++ )
1737 const QPointF diff = mPoints.at( i ) - mPoints.at( i - 1 );
1738 const double distance = std::sqrt( std::pow( diff.x(), 2 ) + std::pow( diff.y(), 2 ) );
1739 const double totalDistance = distance + mDistances.last();
1740 mDistances << totalDistance;
1744 const QPointF diff = mPoints.at( pointIndex ) - point;
1745 const double distance = std::sqrt( std::pow( diff.x(), 2 ) + std::pow( diff.y(), 2 ) );
1746 const double currentDistance = mDistances.at( pointIndex ) + distance;
1748 return insideBlankSegment( currentDistance );
1752 const QgsSymbolLayerUtils::BlankSegments &mBlankSegments;
1753 const QPolygonF &mPoints;
1754 QList<double> mDistances;
1755 QgsSymbolLayerUtils::BlankSegments::const_iterator mItBlankSegment;
1762void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval(
const QPolygonF &points,
QgsSymbolRenderContext &context,
double averageOver,
const QgsSymbolLayerUtils::BlankSegments &blankSegments )
1764 if ( points.isEmpty() )
1768 double lengthLeft = 0;
1773 QgsExpressionContextScope *scope =
new QgsExpressionContextScope();
1800 constexpr double EPSILON = 1e-5;
1801 if ( painterUnitInterval <
EPSILON )
1804 double painterUnitOffsetAlongLine = 0;
1807 double totalLength = -1;
1828 if ( points.isClosed() )
1830 if ( painterUnitOffsetAlongLine > 0 )
1832 if ( totalLength < 0 )
1834 painterUnitOffsetAlongLine = std::fmod( painterUnitOffsetAlongLine, totalLength );
1836 else if ( painterUnitOffsetAlongLine < 0 )
1838 if ( totalLength < 0 )
1840 painterUnitOffsetAlongLine = totalLength - std::fmod( -painterUnitOffsetAlongLine, totalLength );
1852 lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1854 if ( averageOver > 0 && !
qgsDoubleNear( averageOver, 0.0 ) )
1856 QVector< QPointF > angleStartPoints;
1857 QVector< QPointF > symbolPoints;
1858 QVector< QPointF > angleEndPoints;
1867 QList<int> pointIndices;
1868 collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft, blankSegments.isEmpty() ?
nullptr : &pointIndices );
1870 if ( symbolPoints.empty() )
1876 if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1879 symbolPoints.pop_back();
1882 angleEndPoints.reserve( symbolPoints.size() );
1883 angleStartPoints.reserve( symbolPoints.size() );
1884 if ( averageOver <= painterUnitOffsetAlongLine )
1886 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver,
nullptr, 0, symbolPoints.size() );
1890 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0,
nullptr, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1892 collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver,
nullptr, 0, symbolPoints.size() );
1895 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
1896 for (
int i = 0; i < symbolPoints.size(); ++i )
1901 const QPointF pt = symbolPoints[i];
1902 if ( i < pointIndices.count() && blankSegmentsWalker.insideBlankSegment( pt, pointIndices.at( i ) ) )
1906 const QPointF startPt = angleStartPoints[i];
1907 const QPointF endPt = angleEndPoints[i];
1909 Line l( startPt, endPt );
1924 QPointF lastPt = points[0];
1925 BlankSegmentsWalker itBlankSegment( points, blankSegments );
1926 for (
int i = 1; i < points.count(); ++i )
1931 const QPointF &pt = points[i];
1937 Line l( lastPt, pt );
1938 QPointF diff = l.diffForInterval( painterUnitInterval );
1943 double c = 1 - lengthLeft / painterUnitInterval;
1945 lengthLeft += l.length();
1954 while ( lengthLeft > painterUnitInterval )
1961 if ( !itBlankSegment.insideBlankSegment( lastPt, i - 1 ) )
1967 lengthLeft -= painterUnitInterval;
1975static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1978 double a1 = Line( prevPt, pt ).angle();
1979 double a2 = Line( pt, nextPt ).angle();
1980 double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
1982 return std::atan2( unitY, unitX );
1985void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex(
1989 if ( points.isEmpty() )
1994 int i = -1, maxCount = 0;
1995 bool isRing =
false;
1997 QgsExpressionContextScope *scope =
new QgsExpressionContextScope();
2009 double totalLength = -1;
2029 if ( points.isClosed() )
2033 if ( totalLength < 0 )
2039 if ( totalLength < 0 )
2113 i = points.count() - 1;
2115 maxCount = points.count();
2123 maxCount = points.count() - 1;
2131 maxCount = points.count();
2132 if ( points.first() == points.last() )
2149 renderOffsetVertexAlongLine( points, i, distance, context,
placement, blankSegments );
2156 prevPoint = points.at( 0 );
2158 QPointF symbolPoint;
2159 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2160 for ( ; i < maxCount; ++i )
2171 QPointF currentPoint = points.at( i );
2172 symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ), 0.5 * ( currentPoint.y() + prevPoint.y() ) );
2175 double angle = std::atan2( currentPoint.y() - prevPoint.y(), currentPoint.x() - prevPoint.x() );
2178 prevPoint = currentPoint;
2182 symbolPoint = points.at( i );
2186 double angle = markerAngle( points, isRing, i );
2191 mFinalVertex = symbolPoint;
2197double QgsTemplatedLineSymbolLayerBase::markerAngle(
const QPolygonF &points,
bool isRing,
int vertex )
2200 const QPointF &pt = points[vertex];
2202 if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
2204 int prevIndex = vertex - 1;
2205 int nextIndex = vertex + 1;
2207 if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
2209 prevIndex = points.count() - 2;
2213 QPointF prevPoint, nextPoint;
2214 while ( prevIndex >= 0 )
2216 prevPoint = points[prevIndex];
2217 if ( prevPoint != pt )
2224 while ( nextIndex < points.count() )
2226 nextPoint = points[nextIndex];
2227 if ( nextPoint != pt )
2234 if ( prevIndex >= 0 && nextIndex < points.count() )
2236 angle = _averageAngle( prevPoint, pt, nextPoint );
2243 while ( vertex < points.size() - 1 )
2245 const QPointF &nextPt = points[vertex + 1];
2248 angle = Line( pt, nextPt ).angle();
2257 while ( vertex >= 1 )
2259 const QPointF &prevPt = points[vertex - 1];
2262 angle = Line( prevPt, pt ).angle();
2272void QgsTemplatedLineSymbolLayerBase::renderOffsetVertexAlongLine(
2276 if ( points.isEmpty() )
2286 bool isRing =
false;
2287 if ( points.first() == points.last() )
2289 double angle = markerAngle( points, isRing, vertex );
2292 mFinalVertex = points[vertex];
2298 int pointIncrement = distance > 0 ? 1 : -1;
2299 QPointF previousPoint = points[vertex];
2300 int startPoint = distance > 0 ? std::min( vertex + 1,
static_cast<int>( points.count() ) - 1 ) : std::max( vertex - 1, 0 );
2301 int endPoint = distance > 0 ? points.count() - 1 : 0;
2302 double distanceLeft = std::fabs( distance );
2303 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2305 for (
int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
2307 const QPointF &pt = points[i];
2309 if ( previousPoint == pt )
2313 Line l( previousPoint, pt );
2315 if ( distanceLeft < l.length() )
2318 QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
2324 mFinalVertex = markerPoint;
2330 distanceLeft -= l.length();
2337void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints(
2338 const QVector<QPointF> &p, QVector<QPointF> &dest,
double intervalPainterUnits,
double initialOffset, QList<int> *pointIndices,
double initialLag,
int numberPointsRequired
2344 QVector< QPointF > points = p;
2345 const bool closedRing = points.first() == points.last();
2347 double lengthLeft = initialOffset;
2349 double initialLagLeft = initialLag > 0 ? -initialLag : 1;
2350 if ( initialLagLeft < 0 && closedRing )
2353 QPointF lastPt = points.constLast();
2354 QVector< QPointF > pseudoPoints;
2355 for (
int i = points.count() - 2; i > 0; --i )
2357 if ( initialLagLeft >= 0 )
2362 const QPointF &pt = points[i];
2367 Line l( lastPt, pt );
2368 initialLagLeft += l.length();
2373 std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
2375 points = pseudoPoints;
2380 while ( initialLagLeft < 0 )
2382 dest << points.constFirst();
2383 initialLagLeft += intervalPainterUnits;
2386 if ( initialLag > 0 )
2388 lengthLeft += intervalPainterUnits - initialLagLeft;
2391 QPointF lastPt = points[0];
2392 for (
int i = 1; i < points.count(); ++i )
2394 const QPointF &pt = points[i];
2398 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2407 Line l( lastPt, pt );
2408 QPointF diff = l.diffForInterval( intervalPainterUnits );
2412 double c = 1 - lengthLeft / intervalPainterUnits;
2414 lengthLeft += l.length();
2417 while ( lengthLeft > intervalPainterUnits ||
qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
2421 lengthLeft -= intervalPainterUnits;
2424 *pointIndices << i - 1;
2427 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2432 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2436 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2443 if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2446 while ( dest.size() < numberPointsRequired )
2447 dest << points.constLast();
2451void QgsTemplatedLineSymbolLayerBase::renderPolylineCentral(
const QPolygonF &points,
QgsSymbolRenderContext &context,
double averageAngleOver,
const QgsSymbolLayerUtils::BlankSegments &blankSegments )
2453 if ( !points.isEmpty() )
2457 QPolygonF::const_iterator it = points.constBegin();
2459 for ( ++it; it != points.constEnd(); ++it )
2461 length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) + ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2467 const double midPoint = length / 2;
2469 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2470 if ( blankSegmentsWalker.insideBlankSegment( midPoint ) )
2474 double thisSymbolAngle = 0;
2476 if ( averageAngleOver > 0 && !
qgsDoubleNear( averageAngleOver, 0.0 ) )
2478 QVector< QPointF > angleStartPoints;
2479 QVector< QPointF > symbolPoints;
2480 QVector< QPointF > angleEndPoints;
2484 collectOffsetPoints( points, symbolPoints, midPoint, midPoint,
nullptr, 0.0, 2 );
2485 collectOffsetPoints( points, angleStartPoints, midPoint, 0,
nullptr, averageAngleOver, 2 );
2486 collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver,
nullptr, 0, 2 );
2488 pt = symbolPoints.at( 1 );
2489 Line l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
2490 thisSymbolAngle = l.angle();
2495 it = points.constBegin();
2497 qreal last_at = 0, next_at = 0;
2499 for ( ++it; it != points.constEnd(); ++it )
2502 next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) + ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2503 if ( next_at >= midPoint )
2510 Line l( last, next );
2511 qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
2512 pt = last + ( next - last ) * k;
2513 thisSymbolAngle = l.angle();
2564 if ( props.contains( u
"interval"_s ) )
2565 interval = props[u
"interval"_s].toDouble();
2566 if ( props.contains( u
"rotate"_s ) )
2567 rotate = ( props[u
"rotate"_s].toString() ==
"1"_L1 );
2569 auto x = std::make_unique< QgsMarkerLineSymbolLayer >( rotate,
interval );
2576 return u
"MarkerLine"_s;
2596 mMarker->setRenderHints( hints );
2618 toSld( doc, element, context );
2624 for (
int i = 0; i <
mMarker->symbolLayerCount(); i++ )
2626 QDomElement symbolizerElem = doc.createElement( u
"se:LineSymbolizer"_s );
2627 if ( !props.value( u
"uom"_s, QString() ).toString().isEmpty() )
2628 symbolizerElem.setAttribute( u
"uom"_s, props.value( u
"uom"_s, QString() ).toString() );
2629 element.appendChild( symbolizerElem );
2659 QDomElement strokeElem = doc.createElement( u
"se:Stroke"_s );
2660 symbolizerElem.appendChild( strokeElem );
2663 QDomElement graphicStrokeElem = doc.createElement( u
"se:GraphicStroke"_s );
2664 strokeElem.appendChild( graphicStrokeElem );
2669 markerLayer->writeSldMarker( doc, graphicStrokeElem, context );
2677 QgsDebugError( u
"Missing marker line symbol layer. Skip it."_s );
2680 if ( !gap.isEmpty() )
2682 QDomElement gapElem = doc.createElement( u
"se:Gap"_s );
2684 graphicStrokeElem.appendChild( gapElem );
2689 QDomElement perpOffsetElem = doc.createElement( u
"se:PerpendicularOffset"_s );
2692 symbolizerElem.appendChild( perpOffsetElem );
2702 QDomElement strokeElem = element.firstChildElement( u
"Stroke"_s );
2703 if ( strokeElem.isNull() )
2706 QDomElement graphicStrokeElem = strokeElem.firstChildElement( u
"GraphicStroke"_s );
2707 if ( graphicStrokeElem.isNull() )
2715 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
2717 if ( it.key() ==
"placement"_L1 )
2719 if ( it.value() ==
"points"_L1 )
2721 else if ( it.value() ==
"firstPoint"_L1 )
2723 else if ( it.value() ==
"lastPoint"_L1 )
2725 else if ( it.value() ==
"centralPoint"_L1 )
2728 else if ( it.value() ==
"rotateMarker"_L1 )
2734 std::unique_ptr< QgsMarkerSymbol > marker;
2740 layers.append( l.release() );
2741 marker = std::make_unique<QgsMarkerSymbol>( layers );
2748 QDomElement gapElem = graphicStrokeElem.firstChildElement( u
"Gap"_s );
2749 if ( !gapElem.isNull() )
2752 double d = gapElem.firstChild().firstChild().nodeValue().toDouble( &ok );
2758 QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( u
"PerpendicularOffset"_s );
2759 if ( !perpOffsetElem.isNull() )
2762 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
2767 double scaleFactor = 1.0;
2768 const QString uom = element.attribute( u
"uom"_s );
2791 mMarker->setDataDefinedSize( property );
2798 const double prevOpacity =
mMarker->opacity();
2801 mMarker->setOpacity( prevOpacity );
2806 mMarker->setLineAngle( angle );
2824 mMarker->renderPoint( point, feature, context, layer, selected );
2836 return mMarker->size( context );
2842 mMarker->setOutputUnit( unit );
2865 attr.unite(
mMarker->usedAttributes( context ) );
2901 if ( props.contains( u
"interval"_s ) )
2902 interval = props[u
"interval"_s].toDouble();
2903 if ( props.contains( u
"rotate"_s ) )
2904 rotate = ( props[u
"rotate"_s] ==
"1"_L1 );
2906 auto x = std::make_unique< QgsHashedLineSymbolLayer >( rotate,
interval );
2908 if ( props.contains( u
"hash_angle"_s ) )
2910 x->setHashAngle( props[u
"hash_angle"_s].toDouble() );
2913 if ( props.contains( u
"hash_length"_s ) )
2914 x->setHashLength( props[u
"hash_length"_s].toDouble() );
2916 if ( props.contains( u
"hash_length_unit"_s ) )
2919 if ( props.contains( u
"hash_length_map_unit_scale"_s ) )
2927 return u
"HashLine"_s;
2936 mHashSymbol->setRenderHints( hints );
2949 map[u
"hash_angle"_s] = QString::number( mHashAngle );
2951 map[u
"hash_length"_s] = QString::number( mHashLength );
2962 x->setHashAngle( mHashAngle );
2963 x->setHashLength( mHashLength );
2964 x->setHashLengthUnit( mHashLengthUnit );
2965 x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2971 mHashSymbol->setColor(
color );
2977 return mHashSymbol ? mHashSymbol->color() :
mColor;
2982 return mHashSymbol.get();
2993 mHashSymbol.reset(
static_cast<QgsLineSymbol *
>( symbol ) );
2994 mColor = mHashSymbol->color();
3000 mHashLength =
width;
3015 return ( mHashSymbol->width( context ) / 2.0 )
3023 mHashSymbol->setOutputUnit( unit );
3030 attr.unite( mHashSymbol->usedAttributes( context ) );
3038 if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
3047 mHashSymbol->setDataDefinedWidth( property );
3067 || ( mHashSymbol && mHashSymbol->usesMapUnits() );
3072 mSymbolLineAngle = angle;
3077 return mSymbolAngle;
3082 mSymbolAngle = angle;
3087 double lineLength = mHashLength;
3093 const double w = context.
convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
3107 points << QPointF( start.
x(), start.
y() ) << QPointF( end.
x(), end.
y() );
3112 mHashSymbol->renderPolyline( points, feature, context, layer, selected );
3129 const double prevOpacity = mHashSymbol->opacity();
3130 mHashSymbol->setOpacity( mHashSymbol->opacity() * context.
opacity() );
3132 mHashSymbol->setOpacity( prevOpacity );
3151 QPolygonF offsetPoints;
3154 renderLine( points, context, patternThickness, patternLength, brush );
3163 renderLine( part, context, patternThickness, patternLength, brush );
3168void QgsAbstractBrushedLineSymbolLayer::renderLine(
const QPolygonF &points,
QgsSymbolRenderContext &context,
const double lineThickness,
const double patternLength,
const QBrush &sourceBrush )
3174 QBrush brush = sourceBrush;
3179 QPolygonF inputPoints;
3180 inputPoints.reserve( points.size() );
3182 double minX = std::numeric_limits< double >::max();
3183 double minY = std::numeric_limits< double >::max();
3184 double maxX = std::numeric_limits< double >::lowest();
3185 double maxY = std::numeric_limits< double >::lowest();
3187 for (
const QPointF &pt : std::as_const( points ) )
3194 minX = std::min( minX, pt.x() );
3195 minY = std::min( minY, pt.y() );
3196 maxX = std::max( maxX, pt.x() );
3197 maxY = std::max( maxY, pt.y() );
3200 if ( inputPoints.size() < 2 )
3204 constexpr int ANTIALIAS_ALLOWANCE_PIXELS = 10;
3206 constexpr double ANTIALIAS_OVERLAP_PIXELS = 0.5;
3209 const int imageWidth =
static_cast< int >( std::ceil( maxX - minX ) + lineThickness * 2 ) + ANTIALIAS_ALLOWANCE_PIXELS * 2;
3210 const int imageHeight =
static_cast< int >( std::ceil( maxY - minY ) + lineThickness * 2 ) + ANTIALIAS_ALLOWANCE_PIXELS * 2;
3212 const bool isClosedLine =
qgsDoubleNear( points.at( 0 ).x(), points.constLast().x(), 0.01 ) &&
qgsDoubleNear( points.at( 0 ).y(), points.constLast().y(), 0.01 );
3214 QImage temporaryImage( imageWidth, imageHeight, QImage::Format_ARGB32_Premultiplied );
3215 if ( temporaryImage.isNull() )
3224 temporaryImage.fill( Qt::transparent );
3247 QPainterPathStroker stroker;
3248 stroker.setWidth( lineThickness );
3249 stroker.setCapStyle( cap );
3250 stroker.setJoinStyle( join );
3253 path.addPolygon( inputPoints );
3254 const QPainterPath stroke = stroker.createStroke( path ).simplified();
3257 QPainter imagePainter;
3258 imagePainter.begin( &temporaryImage );
3260 imagePainter.translate( -minX + lineThickness + ANTIALIAS_ALLOWANCE_PIXELS, -minY + lineThickness + ANTIALIAS_ALLOWANCE_PIXELS );
3262 imagePainter.setClipPath( stroke, Qt::IntersectClip );
3263 imagePainter.setPen( Qt::NoPen );
3265 QPointF segmentStartPoint = inputPoints.at( 0 );
3268 double progressThroughImage = 0;
3270 QgsPoint prevSegmentPolygonEndLeft;
3271 QgsPoint prevSegmentPolygonEndRight;
3274 QgsPoint startLinePolygonLeft;
3275 QgsPoint startLinePolygonRight;
3277 for (
int i = 1; i < inputPoints.size(); ++i )
3282 const QPointF segmentEndPoint = inputPoints.at( i );
3283 const double segmentAngleDegrees = 180.0 / M_PI *
QgsGeometryUtilsBase::lineAngle( segmentStartPoint.x(), segmentStartPoint.y(), segmentEndPoint.x(), segmentEndPoint.y() ) - 90;
3286 QgsPoint thisSegmentPolygonEndLeft;
3287 QgsPoint thisSegmentPolygonEndRight;
3289 QgsPoint thisSegmentPolygonEndLeftForPainter;
3290 QgsPoint thisSegmentPolygonEndRightForPainter;
3298 const QgsPoint startPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, segmentAngleDegrees );
3299 const QgsPoint endPointLeft = QgsPoint( segmentEndPoint ).project( lineThickness / 2, segmentAngleDegrees );
3300 const QgsPoint startPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3301 const QgsPoint endPointRight = QgsPoint( segmentEndPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3305 const double lastSegmentAngleDegrees = 180.0
3307 *
QgsGeometryUtilsBase::lineAngle( points.at( points.size() - 2 ).x(), points.at( points.size() - 2 ).y(), segmentStartPoint.x(), segmentStartPoint.y() )
3311 const QgsPoint lastSegmentStartPointLeft = QgsPoint( points.at( points.size() - 2 ) ).project( lineThickness / 2, lastSegmentAngleDegrees );
3312 const QgsPoint lastSegmentEndPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, lastSegmentAngleDegrees );
3313 const QgsPoint lastSegmentStartPointRight = QgsPoint( points.at( points.size() - 2 ) ).project( -lineThickness / 2, lastSegmentAngleDegrees );
3314 const QgsPoint lastSegmentEndPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, lastSegmentAngleDegrees );
3319 QgsPoint intersectionPoint;
3320 bool isIntersection =
false;
3322 if ( !isIntersection )
3323 prevSegmentPolygonEndLeft = startPointLeft;
3324 isIntersection =
false;
3325 QgsGeometryUtils::segmentIntersection( lastSegmentStartPointRight, lastSegmentEndPointRight, startPointRight, endPointRight, prevSegmentPolygonEndRight, isIntersection, 1e-8,
true );
3326 if ( !isIntersection )
3327 prevSegmentPolygonEndRight = startPointRight;
3329 startLinePolygonLeft = prevSegmentPolygonEndLeft;
3330 startLinePolygonRight = prevSegmentPolygonEndRight;
3334 prevSegmentPolygonEndLeft = QgsPoint( segmentStartPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3335 if ( cap != Qt::PenCapStyle::FlatCap )
3336 prevSegmentPolygonEndLeft = prevSegmentPolygonEndLeft.
project( lineThickness / 2, segmentAngleDegrees - 90 );
3337 prevSegmentPolygonEndRight = QgsPoint( segmentStartPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3338 if ( cap != Qt::PenCapStyle::FlatCap )
3339 prevSegmentPolygonEndRight = prevSegmentPolygonEndRight.
project( lineThickness / 2, segmentAngleDegrees - 90 );
3343 if ( i < inputPoints.size() - 1 )
3348 const QgsPoint startPointLeft = QgsPoint( segmentStartPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3349 const QgsPoint endPointLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3350 const QgsPoint startPointRight = QgsPoint( segmentStartPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3351 const QgsPoint endPointRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3355 const double nextSegmentAngleDegrees = 180.0 / M_PI *
QgsGeometryUtilsBase::lineAngle( segmentEndPoint.x(), segmentEndPoint.y(), inputPoints.at( i + 1 ).x(), inputPoints.at( i + 1 ).y() ) - 90;
3358 const QgsPoint nextSegmentStartPointLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, nextSegmentAngleDegrees );
3359 const QgsPoint nextSegmentEndPointLeft = QgsPoint( inputPoints.at( i + 1 ) ).
project( lineThickness / 2, nextSegmentAngleDegrees );
3360 const QgsPoint nextSegmentStartPointRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, nextSegmentAngleDegrees );
3361 const QgsPoint nextSegmentEndPointRight = QgsPoint( inputPoints.at( i + 1 ) ).
project( -lineThickness / 2, nextSegmentAngleDegrees );
3366 QgsPoint intersectionPoint;
3367 bool isIntersection =
false;
3369 if ( !isIntersection )
3370 thisSegmentPolygonEndLeft = endPointLeft;
3371 isIntersection =
false;
3372 QgsGeometryUtils::segmentIntersection( startPointRight, endPointRight, nextSegmentStartPointRight, nextSegmentEndPointRight, thisSegmentPolygonEndRight, isIntersection, 1e-8,
true );
3373 if ( !isIntersection )
3374 thisSegmentPolygonEndRight = endPointRight;
3376 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3377 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3385 thisSegmentPolygonEndLeft = startLinePolygonLeft;
3386 thisSegmentPolygonEndRight = startLinePolygonRight;
3388 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3389 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3393 thisSegmentPolygonEndLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3394 if ( cap != Qt::PenCapStyle::FlatCap )
3395 thisSegmentPolygonEndLeft = thisSegmentPolygonEndLeft.
project( lineThickness / 2, segmentAngleDegrees + 90 );
3396 thisSegmentPolygonEndRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3397 if ( cap != Qt::PenCapStyle::FlatCap )
3398 thisSegmentPolygonEndRight = thisSegmentPolygonEndRight.
project( lineThickness / 2, segmentAngleDegrees + 90 );
3400 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft;
3401 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight;
3407 QTransform brushTransform;
3408 brushTransform.translate( segmentStartPoint.x(), segmentStartPoint.y() );
3409 brushTransform.rotate( -segmentAngleDegrees );
3410 if ( i == 1 && cap != Qt::PenCapStyle::FlatCap )
3414 brushTransform.translate( -( lineThickness / 2 ), 0 );
3416 brushTransform.translate( -progressThroughImage, -lineThickness / 2 );
3418 brush.setTransform( brushTransform );
3419 imagePainter.setBrush( brush );
3422 imagePainter.drawPolygon(
3424 << prevSegmentPolygonEndLeft.
toQPointF()
3425 << thisSegmentPolygonEndLeftForPainter.
toQPointF()
3426 << thisSegmentPolygonEndRightForPainter.
toQPointF()
3427 << prevSegmentPolygonEndRight.
toQPointF()
3428 << prevSegmentPolygonEndLeft.
toQPointF()
3432 imagePainter.setPen( QPen( QColor( 0, 255, 255 ), 2 ) );
3433 imagePainter.setBrush( Qt::NoBrush );
3434 imagePainter.drawPolygon( QPolygonF() << prevSegmentPolygonEndLeft.
toQPointF()
3435 << thisSegmentPolygonEndLeftForPainter.
toQPointF()
3436 << thisSegmentPolygonEndRightForPainter.
toQPointF()
3437 << prevSegmentPolygonEndRight.
toQPointF()
3438 << prevSegmentPolygonEndLeft.
toQPointF() );
3439 imagePainter.setPen( Qt::NoPen );
3444 progressThroughImage += sqrt( std::pow( segmentStartPoint.x() - segmentEndPoint.x(), 2 ) + std::pow( segmentStartPoint.y() - segmentEndPoint.y(), 2 ) )
3445 + ( i == 1 && cap != Qt::PenCapStyle::FlatCap ? lineThickness / 2 : 0 );
3446 progressThroughImage = fmod( progressThroughImage, patternLength );
3449 segmentStartPoint = segmentEndPoint;
3450 prevSegmentPolygonEndLeft = thisSegmentPolygonEndLeft;
3451 prevSegmentPolygonEndRight = thisSegmentPolygonEndRight;
3459 p->drawImage( QPointF( minX - lineThickness - ANTIALIAS_ALLOWANCE_PIXELS, minY - lineThickness - ANTIALIAS_ALLOWANCE_PIXELS ), temporaryImage );
3475 auto res = std::make_unique<QgsRasterLineSymbolLayer>();
3477 if (
properties.contains( u
"line_width"_s ) )
3479 res->setWidth(
properties[u
"line_width"_s].toDouble() );
3481 if (
properties.contains( u
"line_width_unit"_s ) )
3485 if (
properties.contains( u
"width_map_unit_scale"_s ) )
3491 res->setPath(
properties[u
"imageFile"_s].toString() );
3495 res->setOffset(
properties[u
"offset"_s].toDouble() );
3497 if (
properties.contains( u
"offset_unit"_s ) )
3501 if (
properties.contains( u
"offset_map_unit_scale"_s ) )
3513 res->setOpacity(
properties[u
"alpha"_s].toDouble() );
3516 return res.release();
3523 map[u
"imageFile"_s] =
mPath;
3525 map[u
"line_width"_s] = QString::number(
mWidth );
3532 map[u
"offset"_s] = QString::number(
mOffset );
3536 map[u
"alpha"_s] = QString::number(
mOpacity );
3543 auto res = std::make_unique< QgsRasterLineSymbolLayer >(
mPath );
3554 return res.release();
3559 const QVariantMap::iterator it =
properties.find( u
"imageFile"_s );
3560 if ( it !=
properties.end() && it.value().userType() == QMetaType::Type::QString )
3576 return u
"RasterLine"_s;
3591 bool cached =
false;
3594 QSize(
static_cast< int >( std::round( originalSize.width() / originalSize.height() * std::max( 1.0, scaledHeight ) ) ),
static_cast< int >( std::ceil( scaledHeight ) ) ),
3622 double strokeWidth =
mWidth;
3639 bool cached =
false;
3642 QSize(
static_cast< int >( std::round( originalSize.width() / originalSize.height() * std::max( 1.0, scaledHeight ) ) ),
static_cast< int >( std::ceil( scaledHeight ) ) ),
3651 if ( useSelectedColor )
3656 const QBrush brush( sourceImage );
3724 auto res = std::make_unique<QgsLineburstSymbolLayer>();
3726 if (
properties.contains( u
"line_width"_s ) )
3728 res->setWidth(
properties[u
"line_width"_s].toDouble() );
3730 if (
properties.contains( u
"line_width_unit"_s ) )
3734 if (
properties.contains( u
"width_map_unit_scale"_s ) )
3741 res->setOffset(
properties[u
"offset"_s].toDouble() );
3743 if (
properties.contains( u
"offset_unit"_s ) )
3747 if (
properties.contains( u
"offset_map_unit_scale"_s ) )
3757 if (
properties.contains( u
"color_type"_s ) )
3764 if (
properties.contains( u
"gradient_color2"_s ) )
3779 return res.release();
3786 map[u
"line_width"_s] = QString::number(
mWidth );
3793 map[u
"offset"_s] = QString::number(
mOffset );
3810 auto res = std::make_unique< QgsLineburstSymbolLayer >();
3825 return res.release();
3830 return u
"Lineburst"_s;
3849 double strokeWidth =
mWidth;
3865 if ( useSelectedColor )
3869 color1.setAlphaF( context.
opacity() * color1.alphaF() );
3880 QGradient gradient = QLinearGradient( QPointF( 0, 0 ), QPointF( 0, scaledWidth ) );
3893 gradient.setColorAt( 0.0, color1 );
3894 gradient.setColorAt( 1.0,
color2 );
3896 const QBrush brush( gradient );
3973 if ( props.contains( u
"line_width"_s ) )
3975 width = props[u
"line_width"_s].toDouble();
3977 else if ( props.contains( u
"outline_width"_s ) )
3979 width = props[u
"outline_width"_s].toDouble();
3981 else if ( props.contains( u
"width"_s ) )
3983 width = props[u
"width"_s].toDouble();
3988 if ( props.contains( u
"line_width_unit"_s ) )
3992 else if ( props.contains( u
"outline_width_unit"_s ) )
3996 else if ( props.contains( u
"width_unit"_s ) )
4001 if ( props.contains( u
"width_map_unit_scale"_s ) )
4003 if ( props.contains( u
"offset"_s ) )
4004 l->setOffset( props[u
"offset"_s].toDouble() );
4005 if ( props.contains( u
"offset_unit"_s ) )
4007 if ( props.contains( u
"offset_map_unit_scale"_s ) )
4009 if ( props.contains( u
"joinstyle"_s ) )
4011 if ( props.contains( u
"capstyle"_s ) )
4014 l->restoreOldDataDefinedProperties( props );
4021 return u
"FilledLine"_s;
4070 Qt::PenJoinStyle join = mPenJoinStyle;
4079 Qt::PenCapStyle cap = mPenCapStyle;
4095 const double prevOpacity = mFill->opacity();
4096 mFill->setOpacity( mFill->opacity() * context.
opacity() );
4103 if ( points.count() >= 2 )
4122 auto inputPoly = std::make_unique< QgsPolygon >(
static_cast< QgsLineString *
>( ls.release() ) );
4128 if ( !parts.empty() )
4155 std::unique_ptr< QgsAbstractGeometry > bufferedGeom =
QgsGeos::fromGeos( buffered.get() );
4157 for (
const QList< QPolygonF > &polygon : parts )
4159 QVector< QPolygonF > rings;
4160 for (
int i = 1; i < polygon.size(); ++i )
4161 rings << polygon.at( i );
4162 mFill->renderPolygon( polygon.value( 0 ), &rings, context.
feature(), context.
renderContext(), -1, useSelectedColor );
4170 mFill->setOpacity( prevOpacity );
4177 map[u
"line_width"_s] = QString::number(
mWidth );
4182 map[u
"offset"_s] = QString::number(
mOffset );
4196 res->setSubSymbol( mFill->clone() );
4197 return res.release();
4232 attr.unite( mFill->usedAttributes( context ) );
4240 if ( mFill && mFill->hasDataDefinedProperties() )
4249 mFill->setColor(
c );
4254 return mFill ? mFill->color() :
mColor;
4263 || ( mFill && mFill->usesMapUnits() );
4270 mFill->setMapUnitScale( scale );
4277 return mFill->mapUnitScale();
4286 mFill->setOutputUnit( unit );
4293 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.
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.
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 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 geos::unique_ptr offsetCurve(const GEOSGeometry *geometry, double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr, QgsFeedback *feedback=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, QgsFeedback *feedback=nullptr) const override
Buffers the geometry.
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.
Perform transforms between map coordinates and device coordinates.
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(), Qgis::StringFormat format=Qgis::StringFormat::PlainText)
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 ...
A grouped map of multiple QgsProperty objects, each referenced by an integer key value.
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 convertToMapUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to map units.
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.
double dxfWidth(QgsSymbolRenderContext &context) const override
Gets line width.
double dxfOffset(QgsSymbolRenderContext &context) const override
Gets offset.
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...
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.
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)
void copyCommonProperties(QgsSymbolLayer *destLayer) const
Copies all common base class properties from this layer to another symbol layer.
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.
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.
@ ExtraItems
String list of tuple (x, y and rotation angle) to define extra items to be rendered for templated lin...
@ 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.
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 setTrimDistanceStartMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the start of the line.
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...
void renderPolyline(const QPolygonF &pts, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
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 destLayer.
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.
void setTrimDistanceEndMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the end of the line.
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 setTrimDistanceStartUnit(Qgis::RenderUnit unit)
Sets the unit for the trim distance for the start of the line.
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.
void setTrimDistanceStart(double distance)
Sets the trim distance for the start of the line, which dictates a length from the start of the line ...
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.
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...
const QgsMapUnitScale & offsetAlongLineMapUnitScale() const
Returns the map unit scale used for calculating the offset in map units along line for symbols.
void setTrimDistanceEndUnit(Qgis::RenderUnit unit)
Sets the unit for the trim distance for the end of the line.
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
void trimPoints(QPolygonF &points, double startTrim, double endTrim, Qgis::RenderUnit trimDistanceStartUnit, Qgis::RenderUnit trimDistanceEndUnit, const QgsMapUnitScale &trimDistanceStartMapUnitScale, const QgsMapUnitScale &trimDistanceEndMapUnitScale, const QgsPropertyCollection &mDataDefinedProperties, QgsSymbolRenderContext &context)
trim points according to start and end trim distance based on data defined properties and render cont...
#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.