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 )
393 QPolygonF points = pts;
395 double startTrim = mTrimDistanceStart;
401 double endTrim = mTrimDistanceEnd;
408 double totalLength = -1;
412 startTrim = startTrim * 0.01 * totalLength;
420 if ( totalLength < 0 )
422 endTrim = endTrim * 0.01 * totalLength;
435 mPen.setColor( penColor );
438 applyDataDefinedSymbology( context, mPen, mSelPen,
offset );
441 const QPen pen = useSelectedColor ? mSelPen : mPen;
443 if ( !pen.dashPattern().isEmpty() )
446 const QVector<double> pattern = pen.dashPattern();
447 bool foundNonNull =
false;
448 for (
int i = 0; i < pattern.size(); ++i )
460 p->setBrush( Qt::NoBrush );
463 std::unique_ptr< QgsScopedQPainterState > painterState;
464 if ( points.size() <= 2
467 && ( p->renderHints() & QPainter::Antialiasing ) )
469 painterState = std::make_unique< QgsScopedQPainterState >( p );
470 p->setRenderHint( QPainter::Antialiasing,
false );
473 const bool applyPatternTweaks = mAlignDashPattern && ( pen.style() != Qt::SolidLine || !pen.dashPattern().empty() ) && pen.dashOffset() == 0;
477 if ( applyPatternTweaks )
479 drawPathWithDashPatternTweaks( p, points, pen );
485 path.addPolygon( points );
501 for (
const QPolygonF &part : mline )
503 if ( applyPatternTweaks )
505 drawPathWithDashPatternTweaks( p, part, pen );
511 path.addPolygon( part );
522 map[u
"line_width"_s] = QString::number(
mWidth );
528 map[u
"offset"_s] = QString::number(
mOffset );
531 map[u
"use_custom_dash"_s] = ( mUseCustomDashPattern ? u
"1"_s : u
"0"_s );
535 map[u
"dash_pattern_offset"_s] = QString::number( mDashPatternOffset );
538 map[u
"trim_distance_start"_s] = QString::number( mTrimDistanceStart );
541 map[u
"trim_distance_end"_s] = QString::number( mTrimDistanceEnd );
544 map[u
"draw_inside_polygon"_s] = ( mDrawInsidePolygon ? u
"1"_s : u
"0"_s );
545 map[u
"ring_filter"_s] = QString::number(
static_cast< int >(
mRingFilter ) );
546 map[u
"align_dash_pattern"_s] = mAlignDashPattern ? u
"1"_s : u
"0"_s;
547 map[u
"tweak_dash_pattern_on_corners"_s] = mPatternCartographicTweakOnSharpCorners ? u
"1"_s : u
"0"_s;
587 toSld( doc, element, context );
592 if ( mPenStyle == Qt::NoPen )
596 QDomElement symbolizerElem = doc.createElement( u
"se:LineSymbolizer"_s );
597 if ( !props.value( u
"uom"_s, QString() ).toString().isEmpty() )
598 symbolizerElem.setAttribute( u
"uom"_s, props.value( u
"uom"_s, QString() ).toString() );
599 element.appendChild( symbolizerElem );
605 QDomElement strokeElem = doc.createElement( u
"se:Stroke"_s );
606 symbolizerElem.appendChild( strokeElem );
608 Qt::PenStyle
penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
616 QDomElement perpOffsetElem = doc.createElement( u
"se:PerpendicularOffset"_s );
619 symbolizerElem.appendChild( perpOffsetElem );
626 if ( mUseCustomDashPattern )
640 QDomElement strokeElem = element.firstChildElement( u
"Stroke"_s );
641 if ( strokeElem.isNull() )
655 QDomElement perpOffsetElem = element.firstChildElement( u
"PerpendicularOffset"_s );
656 if ( !perpOffsetElem.isNull() )
659 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
664 double scaleFactor = 1.0;
665 const QString uom = element.attribute( u
"uom"_s );
680void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context, QPen &pen, QPen &selPen,
double &offset )
686 bool hasStrokeWidthExpression =
false;
693 pen.setWidthF( scaledWidth );
694 selPen.setWidthF( scaledWidth );
695 hasStrokeWidthExpression =
true;
704 penColor.setAlphaF( context.
opacity() * penColor.alphaF() );
705 pen.setColor( penColor );
719 const double dashWidthDiv = std::max( hasStrokeWidthExpression ? pen.widthF() : mPen.widthF(), 1.0 );
723 const QString customDashString
725 const QStringList dashList = customDashString.split(
';' );
726 QVector<qreal> dashVector;
727 for (
const QString &dash : dashList )
731 pen.setDashPattern( dashVector );
737 QVector<qreal> scaledVector;
738 for (
double v : std::as_const( mCustomDashVector ) )
743 mPen.setDashPattern( scaledVector );
747 double patternOffset = mDashPatternOffset;
759 const QString lineStyleString
768 const QString joinStyleString
777 const QString capStyleString
783void QgsSimpleLineSymbolLayer::drawPathWithDashPatternTweaks( QPainter *painter,
const QPolygonF &points, QPen pen )
const
785 if ( pen.dashPattern().empty() || points.size() < 2 )
788 if ( pen.widthF() <= 1.0 )
790 pen.setWidthF( 1.0001 );
793 QVector< qreal > sourcePattern = pen.dashPattern();
794 const double dashWidthDiv = pen.widthF();
796 for (
int i = 0; i < sourcePattern.size(); ++i )
797 sourcePattern[i] *= pen.widthF();
799 QVector< qreal > buffer;
800 QPolygonF bufferedPoints;
801 QPolygonF previousSegmentBuffer;
806 auto ptIt = points.constBegin();
807 double totalBufferLength = 0;
808 int patternIndex = 0;
809 double currentRemainingDashLength = 0;
810 double currentRemainingGapLength = 0;
812 auto compressPattern = [](
const QVector< qreal > &buffer ) -> QVector< qreal > {
813 QVector< qreal > result;
814 result.reserve( buffer.size() );
815 for (
auto it = buffer.begin(); it != buffer.end(); )
819 while ( dash == 0 && !result.empty() )
821 result.last() += gap;
823 if ( it == buffer.end() )
828 while ( gap == 0 && it != buffer.end() )
833 result << dash << gap;
838 double currentBufferLineLength = 0;
840 [pen, painter, &buffer, &bufferedPoints, &previousSegmentBuffer, ¤tRemainingDashLength, ¤tRemainingGapLength, ¤tBufferLineLength, &totalBufferLength, dashWidthDiv, &compressPattern](
843 if ( buffer.empty() || bufferedPoints.size() < 2 )
848 if ( currentRemainingDashLength )
851 buffer << currentRemainingDashLength << 0.0;
852 totalBufferLength += currentRemainingDashLength;
854 QVector< qreal > compressed = compressPattern( buffer );
855 if ( !currentRemainingDashLength )
858 totalBufferLength -= compressed.last();
859 compressed.last() = 0;
863 const double scaleFactor = currentBufferLineLength / totalBufferLength;
865 bool shouldFlushPreviousSegmentBuffer =
false;
867 if ( !previousSegmentBuffer.empty() )
871 if ( !firstDashSubstring.empty() )
877 compressed = compressed.mid( 2 );
878 shouldFlushPreviousSegmentBuffer = !compressed.empty();
881 if ( !previousSegmentBuffer.empty() && ( shouldFlushPreviousSegmentBuffer || !nextPoint ) )
883 QPen adjustedPen = pen;
884 adjustedPen.setStyle( Qt::SolidLine );
885 painter->setPen( adjustedPen );
887 path.addPolygon( previousSegmentBuffer );
888 painter->drawPath( path );
889 previousSegmentBuffer.clear();
892 double finalDash = 0;
899 if ( !compressed.empty() )
901 finalDash = compressed.at( compressed.size() - 2 );
902 const double finalGap = compressed.size() > 2 ? compressed.at( compressed.size() - 3 ) : 0;
904 const QPolygonF thisPoints = bufferedPoints;
910 previousSegmentBuffer << bufferedPoints;
914 currentBufferLineLength = 0;
915 currentRemainingDashLength = 0;
916 currentRemainingGapLength = 0;
917 totalBufferLength = 0;
920 if ( !bufferedPoints.empty() && ( !compressed.empty() || !nextPoint ) )
922 QPen adjustedPen = pen;
923 if ( !compressed.empty() )
926 compressed = compressed.mid( 0, 32 );
927 std::for_each( compressed.begin(), compressed.end(), [scaleFactor, dashWidthDiv]( qreal &element ) { element *= scaleFactor / dashWidthDiv; } );
928 adjustedPen.setDashPattern( compressed );
932 adjustedPen.setStyle( Qt::SolidLine );
935 painter->setPen( adjustedPen );
937 path.addPolygon( bufferedPoints );
938 painter->drawPath( path );
941 bufferedPoints.clear();
947 bufferedPoints << p2;
948 for ( ; ptIt != points.constEnd(); ++ptIt )
956 double remainingSegmentDistance = std::sqrt( std::pow( p2.x() - p1.x(), 2.0 ) + std::pow( p2.y() - p1.y(), 2.0 ) );
957 currentBufferLineLength += remainingSegmentDistance;
961 if ( currentRemainingDashLength > 0 )
964 if ( remainingSegmentDistance >= currentRemainingDashLength )
967 buffer << currentRemainingDashLength << 0.0;
968 totalBufferLength += currentRemainingDashLength;
969 remainingSegmentDistance -= currentRemainingDashLength;
971 currentRemainingDashLength = 0.0;
972 currentRemainingGapLength = sourcePattern.at( patternIndex );
973 if ( currentRemainingGapLength == 0.0 )
981 buffer << remainingSegmentDistance << 0.0;
982 totalBufferLength += remainingSegmentDistance;
983 currentRemainingDashLength -= remainingSegmentDistance;
987 if ( currentRemainingGapLength > 0 )
990 if ( remainingSegmentDistance >= currentRemainingGapLength )
993 buffer << 0.0 << currentRemainingGapLength;
994 totalBufferLength += currentRemainingGapLength;
995 remainingSegmentDistance -= currentRemainingGapLength;
996 currentRemainingGapLength = 0.0;
1002 buffer << 0.0 << remainingSegmentDistance;
1003 totalBufferLength += remainingSegmentDistance;
1004 currentRemainingGapLength -= remainingSegmentDistance;
1009 if ( patternIndex + 1 >= sourcePattern.size() )
1014 const double nextPatternDashLength = sourcePattern.at( patternIndex );
1015 const double nextPatternGapLength = sourcePattern.at( patternIndex + 1 );
1016 if ( nextPatternDashLength + nextPatternGapLength <= remainingSegmentDistance )
1018 buffer << nextPatternDashLength << nextPatternGapLength;
1019 remainingSegmentDistance -= nextPatternDashLength + nextPatternGapLength;
1020 totalBufferLength += nextPatternDashLength + nextPatternGapLength;
1023 else if ( nextPatternDashLength <= remainingSegmentDistance )
1026 buffer << nextPatternDashLength << remainingSegmentDistance - nextPatternDashLength;
1027 totalBufferLength += remainingSegmentDistance;
1028 currentRemainingGapLength = nextPatternGapLength - ( remainingSegmentDistance - nextPatternDashLength );
1029 currentRemainingDashLength = 0;
1036 buffer << remainingSegmentDistance << 0.0;
1037 totalBufferLength += remainingSegmentDistance;
1038 currentRemainingGapLength = 0;
1039 currentRemainingDashLength = nextPatternDashLength - remainingSegmentDistance;
1044 bufferedPoints << p1;
1045 if ( mPatternCartographicTweakOnSharpCorners && ptIt + 1 != points.constEnd() )
1047 QPointF nextPoint = *( ptIt + 1 );
1053 flushBuffer( &nextPoint );
1054 bufferedPoints << p1;
1057 if ( patternIndex % 2 == 1 )
1061 currentRemainingDashLength = sourcePattern.at( patternIndex );
1068 flushBuffer(
nullptr );
1069 if ( !previousSegmentBuffer.empty() )
1071 QPen adjustedPen = pen;
1072 adjustedPen.setStyle( Qt::SolidLine );
1073 painter->setPen( adjustedPen );
1075 path.addPolygon( previousSegmentBuffer );
1076 painter->drawPath( path );
1077 previousSegmentBuffer.clear();
1083 if ( mDrawInsidePolygon )
1096 unit = mCustomDashPatternUnit;
1097 return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
1134 return mPenStyle != Qt::SolidLine || mUseCustomDashPattern;
1139 return mAlignDashPattern;
1149 return mPatternCartographicTweakOnSharpCorners;
1154 mPatternCartographicTweakOnSharpCorners =
enabled;
1179 : mRotateSymbols( rotateSymbol )
1215 if ( mRenderingFeature )
1219 mFeatureSymbolOpacity = context.
opacity();
1220 mCurrentFeatureIsSelected = useSelectedColor;
1238 QString placementString = exprVal.toString();
1239 if ( placementString.compare(
"interval"_L1, Qt::CaseInsensitive ) == 0 )
1243 else if ( placementString.compare(
"vertex"_L1, Qt::CaseInsensitive ) == 0 )
1247 else if ( placementString.compare(
"innervertices"_L1, Qt::CaseInsensitive ) == 0 )
1251 else if ( placementString.compare(
"lastvertex"_L1, Qt::CaseInsensitive ) == 0 )
1255 else if ( placementString.compare(
"firstvertex"_L1, Qt::CaseInsensitive ) == 0 )
1259 else if ( placementString.compare(
"centerpoint"_L1, Qt::CaseInsensitive ) == 0 )
1263 else if ( placementString.compare(
"curvepoint"_L1, Qt::CaseInsensitive ) == 0 )
1267 else if ( placementString.compare(
"segmentcenter"_L1, Qt::CaseInsensitive ) == 0 )
1280 double averageOver = mAverageAngleLength;
1295 if ( !error.isEmpty() )
1297 QgsDebugError( u
"Badly formatted blank segment '%1', skip it: %2"_s.arg( strBlankSegments ).arg( error ) );
1303 if ( iPart >= 0 &&
mRingIndex >= 0 && iPart < allBlankSegments.count() &&
mRingIndex < allBlankSegments.at( iPart ).count() )
1305 blankSegments = allBlankSegments.at( iPart ).at(
mRingIndex );
1313 renderPolylineInterval( points, context, averageOver, blankSegments );
1315 renderPolylineCentral( points, context, averageOver, blankSegments );
1321 mHasRenderedFirstPart = mRenderingFeature;
1335 QList<QPolygonF> mline =
::
1338 for (
int part = 0; part < mline.count(); ++part )
1340 const QPolygonF &points2 = mline[part];
1343 renderPolylineInterval( points2, context, averageOver, blankSegments );
1345 renderPolylineCentral( points2, context, averageOver, blankSegments );
1355 mHasRenderedFirstPart = mRenderingFeature;
1375 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
1405 for (
int i = 0; i < rings->size(); ++i )
1440 mIntervalUnit = unit;
1441 mOffsetAlongLineUnit = unit;
1442 mAverageAngleLengthUnit = unit;
1466 map[u
"interval"_s] = QString::number(
interval() );
1467 map[u
"offset"_s] = QString::number(
mOffset );
1475 map[u
"average_angle_length"_s] = QString::number( mAverageAngleLength );
1482 map[u
"ring_filter"_s] = QString::number(
static_cast< int >(
mRingFilter ) );
1483 map[u
"place_on_every_part"_s] = mPlaceOnEveryPart;
1489 return mPlaceOnEveryPart
1499 mRenderingFeature =
true;
1500 mHasRenderedFirstPart =
false;
1505 mRenderingFeature =
false;
1516 renderSymbol( mFinalVertex, &feature, context, -1, mCurrentFeatureIsSelected );
1517 mFeatureSymbolOpacity = 1;
1551 if (
properties.contains( u
"offset_unit"_s ) )
1555 if (
properties.contains( u
"interval_unit"_s ) )
1559 if (
properties.contains( u
"offset_along_line"_s ) )
1563 if (
properties.contains( u
"offset_along_line_unit"_s ) )
1567 if (
properties.contains( ( u
"offset_along_line_map_unit_scale"_s ) ) )
1572 if (
properties.contains( u
"offset_map_unit_scale"_s ) )
1576 if (
properties.contains( u
"interval_map_unit_scale"_s ) )
1581 if (
properties.contains( u
"average_angle_length"_s ) )
1585 if (
properties.contains( u
"average_angle_unit"_s ) )
1589 if (
properties.contains( ( u
"average_angle_map_unit_scale"_s ) ) )
1593 if (
properties.contains( u
"blank_segments_unit"_s ) )
1600 if (
properties[u
"placement"_s] ==
"vertex"_L1 )
1602 else if (
properties[u
"placement"_s] ==
"lastvertex"_L1 )
1604 else if (
properties[u
"placement"_s] ==
"firstvertex"_L1 )
1606 else if (
properties[u
"placement"_s] ==
"centralpoint"_L1 )
1608 else if (
properties[u
"placement"_s] ==
"curvepoint"_L1 )
1610 else if (
properties[u
"placement"_s] ==
"segmentcenter"_L1 )
1615 else if (
properties.contains( u
"placements"_s ) )
1621 if (
properties.contains( u
"ring_filter"_s ) )
1637class BlankSegmentsWalker
1641 : mBlankSegments( blankSegments )
1643 , mItBlankSegment( blankSegments.cbegin() )
1645 mDistances.reserve( mPoints.count() );
1649 bool insideBlankSegment(
double distance )
1651 while ( mItBlankSegment != mBlankSegments.cend() && distance > mItBlankSegment->second )
1656 return ( mItBlankSegment != mBlankSegments.cend() && distance >= mItBlankSegment->first );
1661 bool insideBlankSegment(
const QPointF &point,
int pointIndex )
1663 if ( pointIndex < 0 || pointIndex >= mPoints.count() )
1667 if ( pointIndex >= mDistances.count() )
1669 for (
int i =
static_cast<int>( mDistances.count() ); i < pointIndex + 1; i++ )
1671 const QPointF diff = mPoints.at( i ) - mPoints.at( i - 1 );
1672 const double distance = std::sqrt( std::pow( diff.x(), 2 ) + std::pow( diff.y(), 2 ) );
1673 const double totalDistance = distance + mDistances.last();
1674 mDistances << totalDistance;
1678 const QPointF diff = mPoints.at( pointIndex ) - point;
1679 const double distance = std::sqrt( std::pow( diff.x(), 2 ) + std::pow( diff.y(), 2 ) );
1680 const double currentDistance = mDistances.at( pointIndex ) + distance;
1682 return insideBlankSegment( currentDistance );
1687 const QPolygonF &mPoints;
1688 QList<double> mDistances;
1689 QgsBlankSegmentUtils::BlankSegments::const_iterator mItBlankSegment;
1698 if ( points.isEmpty() )
1702 double lengthLeft = 0;
1707 QgsExpressionContextScope *scope =
new QgsExpressionContextScope();
1734 constexpr double EPSILON = 1e-5;
1735 if ( painterUnitInterval <
EPSILON )
1738 double painterUnitOffsetAlongLine = 0;
1741 double totalLength = -1;
1762 if ( points.isClosed() )
1764 if ( painterUnitOffsetAlongLine > 0 )
1766 if ( totalLength < 0 )
1768 painterUnitOffsetAlongLine = std::fmod( painterUnitOffsetAlongLine, totalLength );
1770 else if ( painterUnitOffsetAlongLine < 0 )
1772 if ( totalLength < 0 )
1774 painterUnitOffsetAlongLine = totalLength - std::fmod( -painterUnitOffsetAlongLine, totalLength );
1786 lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1788 if ( averageOver > 0 && !
qgsDoubleNear( averageOver, 0.0 ) )
1790 QVector< QPointF > angleStartPoints;
1791 QVector< QPointF > symbolPoints;
1792 QVector< QPointF > angleEndPoints;
1801 QList<int> pointIndices;
1802 collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft, blankSegments.isEmpty() ?
nullptr : &pointIndices );
1804 if ( symbolPoints.empty() )
1810 if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1813 symbolPoints.pop_back();
1816 angleEndPoints.reserve( symbolPoints.size() );
1817 angleStartPoints.reserve( symbolPoints.size() );
1818 if ( averageOver <= painterUnitOffsetAlongLine )
1820 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver,
nullptr, 0, symbolPoints.size() );
1824 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0,
nullptr, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1826 collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver,
nullptr, 0, symbolPoints.size() );
1829 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
1830 for (
int i = 0; i < symbolPoints.size(); ++i )
1835 const QPointF pt = symbolPoints[i];
1836 if ( i < pointIndices.count() && blankSegmentsWalker.insideBlankSegment( pt, pointIndices.at( i ) ) )
1840 const QPointF startPt = angleStartPoints[i];
1841 const QPointF endPt = angleEndPoints[i];
1843 Line l( startPt, endPt );
1858 QPointF lastPt = points[0];
1859 BlankSegmentsWalker itBlankSegment( points, blankSegments );
1860 for (
int i = 1; i < points.count(); ++i )
1865 const QPointF &pt = points[i];
1871 Line l( lastPt, pt );
1872 QPointF diff = l.diffForInterval( painterUnitInterval );
1877 double c = 1 - lengthLeft / painterUnitInterval;
1879 lengthLeft += l.length();
1888 while ( lengthLeft > painterUnitInterval )
1895 if ( !itBlankSegment.insideBlankSegment( lastPt, i - 1 ) )
1901 lengthLeft -= painterUnitInterval;
1909static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1912 double a1 = Line( prevPt, pt ).angle();
1913 double a2 = Line( pt, nextPt ).angle();
1914 double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
1916 return std::atan2( unitY, unitX );
1919void QgsTemplatedLineSymbolLayerBase::renderPolylineVertex(
1923 if ( points.isEmpty() )
1928 int i = -1, maxCount = 0;
1929 bool isRing =
false;
1931 QgsExpressionContextScope *scope =
new QgsExpressionContextScope();
1943 double totalLength = -1;
1963 if ( points.isClosed() )
1967 if ( totalLength < 0 )
1973 if ( totalLength < 0 )
2047 i = points.count() - 1;
2049 maxCount = points.count();
2057 maxCount = points.count() - 1;
2065 maxCount = points.count();
2066 if ( points.first() == points.last() )
2083 renderOffsetVertexAlongLine( points, i, distance, context,
placement, blankSegments );
2090 prevPoint = points.at( 0 );
2092 QPointF symbolPoint;
2093 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2094 for ( ; i < maxCount; ++i )
2105 QPointF currentPoint = points.at( i );
2106 symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ), 0.5 * ( currentPoint.y() + prevPoint.y() ) );
2109 double angle = std::atan2( currentPoint.y() - prevPoint.y(), currentPoint.x() - prevPoint.x() );
2112 prevPoint = currentPoint;
2116 symbolPoint = points.at( i );
2120 double angle = markerAngle( points, isRing, i );
2125 mFinalVertex = symbolPoint;
2131double QgsTemplatedLineSymbolLayerBase::markerAngle(
const QPolygonF &points,
bool isRing,
int vertex )
2134 const QPointF &pt = points[vertex];
2136 if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
2138 int prevIndex = vertex - 1;
2139 int nextIndex = vertex + 1;
2141 if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
2143 prevIndex = points.count() - 2;
2147 QPointF prevPoint, nextPoint;
2148 while ( prevIndex >= 0 )
2150 prevPoint = points[prevIndex];
2151 if ( prevPoint != pt )
2158 while ( nextIndex < points.count() )
2160 nextPoint = points[nextIndex];
2161 if ( nextPoint != pt )
2168 if ( prevIndex >= 0 && nextIndex < points.count() )
2170 angle = _averageAngle( prevPoint, pt, nextPoint );
2177 while ( vertex < points.size() - 1 )
2179 const QPointF &nextPt = points[vertex + 1];
2182 angle = Line( pt, nextPt ).angle();
2191 while ( vertex >= 1 )
2193 const QPointF &prevPt = points[vertex - 1];
2196 angle = Line( prevPt, pt ).angle();
2206void QgsTemplatedLineSymbolLayerBase::renderOffsetVertexAlongLine(
2210 if ( points.isEmpty() )
2220 bool isRing =
false;
2221 if ( points.first() == points.last() )
2223 double angle = markerAngle( points, isRing, vertex );
2226 mFinalVertex = points[vertex];
2232 int pointIncrement = distance > 0 ? 1 : -1;
2233 QPointF previousPoint = points[vertex];
2234 int startPoint = distance > 0 ? std::min( vertex + 1,
static_cast<int>( points.count() ) - 1 ) : std::max( vertex - 1, 0 );
2235 int endPoint = distance > 0 ? points.count() - 1 : 0;
2236 double distanceLeft = std::fabs( distance );
2237 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2239 for (
int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
2241 const QPointF &pt = points[i];
2243 if ( previousPoint == pt )
2247 Line l( previousPoint, pt );
2249 if ( distanceLeft < l.length() )
2252 QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
2258 mFinalVertex = markerPoint;
2264 distanceLeft -= l.length();
2271void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints(
2272 const QVector<QPointF> &p, QVector<QPointF> &dest,
double intervalPainterUnits,
double initialOffset, QList<int> *pointIndices,
double initialLag,
int numberPointsRequired
2278 QVector< QPointF > points = p;
2279 const bool closedRing = points.first() == points.last();
2281 double lengthLeft = initialOffset;
2283 double initialLagLeft = initialLag > 0 ? -initialLag : 1;
2284 if ( initialLagLeft < 0 && closedRing )
2287 QPointF lastPt = points.constLast();
2288 QVector< QPointF > pseudoPoints;
2289 for (
int i = points.count() - 2; i > 0; --i )
2291 if ( initialLagLeft >= 0 )
2296 const QPointF &pt = points[i];
2301 Line l( lastPt, pt );
2302 initialLagLeft += l.length();
2307 std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
2309 points = pseudoPoints;
2314 while ( initialLagLeft < 0 )
2316 dest << points.constFirst();
2317 initialLagLeft += intervalPainterUnits;
2320 if ( initialLag > 0 )
2322 lengthLeft += intervalPainterUnits - initialLagLeft;
2325 QPointF lastPt = points[0];
2326 for (
int i = 1; i < points.count(); ++i )
2328 const QPointF &pt = points[i];
2332 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2341 Line l( lastPt, pt );
2342 QPointF diff = l.diffForInterval( intervalPainterUnits );
2346 double c = 1 - lengthLeft / intervalPainterUnits;
2348 lengthLeft += l.length();
2351 while ( lengthLeft > intervalPainterUnits ||
qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
2355 lengthLeft -= intervalPainterUnits;
2358 *pointIndices << i - 1;
2361 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2366 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2370 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2377 if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2380 while ( dest.size() < numberPointsRequired )
2381 dest << points.constLast();
2387 if ( !points.isEmpty() )
2391 QPolygonF::const_iterator it = points.constBegin();
2393 for ( ++it; it != points.constEnd(); ++it )
2395 length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) + ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2401 const double midPoint = length / 2;
2403 BlankSegmentsWalker blankSegmentsWalker( points, blankSegments );
2404 if ( blankSegmentsWalker.insideBlankSegment( midPoint ) )
2408 double thisSymbolAngle = 0;
2410 if ( averageAngleOver > 0 && !
qgsDoubleNear( averageAngleOver, 0.0 ) )
2412 QVector< QPointF > angleStartPoints;
2413 QVector< QPointF > symbolPoints;
2414 QVector< QPointF > angleEndPoints;
2418 collectOffsetPoints( points, symbolPoints, midPoint, midPoint,
nullptr, 0.0, 2 );
2419 collectOffsetPoints( points, angleStartPoints, midPoint, 0,
nullptr, averageAngleOver, 2 );
2420 collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver,
nullptr, 0, 2 );
2422 pt = symbolPoints.at( 1 );
2423 Line l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
2424 thisSymbolAngle = l.angle();
2429 it = points.constBegin();
2431 qreal last_at = 0, next_at = 0;
2433 for ( ++it; it != points.constEnd(); ++it )
2436 next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) + ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2437 if ( next_at >= midPoint )
2444 Line l( last, next );
2445 qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
2446 pt = last + ( next - last ) * k;
2447 thisSymbolAngle = l.angle();
2498 if ( props.contains( u
"interval"_s ) )
2499 interval = props[u
"interval"_s].toDouble();
2500 if ( props.contains( u
"rotate"_s ) )
2501 rotate = ( props[u
"rotate"_s].toString() ==
"1"_L1 );
2503 auto x = std::make_unique< QgsMarkerLineSymbolLayer >( rotate,
interval );
2510 return u
"MarkerLine"_s;
2530 mMarker->setRenderHints( hints );
2552 toSld( doc, element, context );
2558 for (
int i = 0; i <
mMarker->symbolLayerCount(); i++ )
2560 QDomElement symbolizerElem = doc.createElement( u
"se:LineSymbolizer"_s );
2561 if ( !props.value( u
"uom"_s, QString() ).toString().isEmpty() )
2562 symbolizerElem.setAttribute( u
"uom"_s, props.value( u
"uom"_s, QString() ).toString() );
2563 element.appendChild( symbolizerElem );
2593 QDomElement strokeElem = doc.createElement( u
"se:Stroke"_s );
2594 symbolizerElem.appendChild( strokeElem );
2597 QDomElement graphicStrokeElem = doc.createElement( u
"se:GraphicStroke"_s );
2598 strokeElem.appendChild( graphicStrokeElem );
2603 markerLayer->writeSldMarker( doc, graphicStrokeElem, context );
2611 QgsDebugError( u
"Missing marker line symbol layer. Skip it."_s );
2614 if ( !gap.isEmpty() )
2616 QDomElement gapElem = doc.createElement( u
"se:Gap"_s );
2618 graphicStrokeElem.appendChild( gapElem );
2623 QDomElement perpOffsetElem = doc.createElement( u
"se:PerpendicularOffset"_s );
2626 symbolizerElem.appendChild( perpOffsetElem );
2636 QDomElement strokeElem = element.firstChildElement( u
"Stroke"_s );
2637 if ( strokeElem.isNull() )
2640 QDomElement graphicStrokeElem = strokeElem.firstChildElement( u
"GraphicStroke"_s );
2641 if ( graphicStrokeElem.isNull() )
2649 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
2651 if ( it.key() ==
"placement"_L1 )
2653 if ( it.value() ==
"points"_L1 )
2655 else if ( it.value() ==
"firstPoint"_L1 )
2657 else if ( it.value() ==
"lastPoint"_L1 )
2659 else if ( it.value() ==
"centralPoint"_L1 )
2662 else if ( it.value() ==
"rotateMarker"_L1 )
2668 std::unique_ptr< QgsMarkerSymbol > marker;
2674 layers.append( l.release() );
2675 marker = std::make_unique<QgsMarkerSymbol>( layers );
2682 QDomElement gapElem = graphicStrokeElem.firstChildElement( u
"Gap"_s );
2683 if ( !gapElem.isNull() )
2686 double d = gapElem.firstChild().firstChild().nodeValue().toDouble( &ok );
2692 QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( u
"PerpendicularOffset"_s );
2693 if ( !perpOffsetElem.isNull() )
2696 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
2701 double scaleFactor = 1.0;
2702 const QString uom = element.attribute( u
"uom"_s );
2725 mMarker->setDataDefinedSize( property );
2732 const double prevOpacity =
mMarker->opacity();
2735 mMarker->setOpacity( prevOpacity );
2740 mMarker->setLineAngle( angle );
2758 mMarker->renderPoint( point, feature, context, layer, selected );
2770 return mMarker->size( context );
2776 mMarker->setOutputUnit( unit );
2799 attr.unite(
mMarker->usedAttributes( context ) );
2835 if ( props.contains( u
"interval"_s ) )
2836 interval = props[u
"interval"_s].toDouble();
2837 if ( props.contains( u
"rotate"_s ) )
2838 rotate = ( props[u
"rotate"_s] ==
"1"_L1 );
2840 auto x = std::make_unique< QgsHashedLineSymbolLayer >( rotate,
interval );
2842 if ( props.contains( u
"hash_angle"_s ) )
2844 x->setHashAngle( props[u
"hash_angle"_s].toDouble() );
2847 if ( props.contains( u
"hash_length"_s ) )
2848 x->setHashLength( props[u
"hash_length"_s].toDouble() );
2850 if ( props.contains( u
"hash_length_unit"_s ) )
2853 if ( props.contains( u
"hash_length_map_unit_scale"_s ) )
2861 return u
"HashLine"_s;
2870 mHashSymbol->setRenderHints( hints );
2883 map[u
"hash_angle"_s] = QString::number( mHashAngle );
2885 map[u
"hash_length"_s] = QString::number( mHashLength );
2896 x->setHashAngle( mHashAngle );
2897 x->setHashLength( mHashLength );
2898 x->setHashLengthUnit( mHashLengthUnit );
2899 x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2905 mHashSymbol->setColor(
color );
2911 return mHashSymbol ? mHashSymbol->color() :
mColor;
2916 return mHashSymbol.get();
2927 mHashSymbol.reset(
static_cast<QgsLineSymbol *
>( symbol ) );
2928 mColor = mHashSymbol->color();
2934 mHashLength =
width;
2949 return ( mHashSymbol->width( context ) / 2.0 )
2957 mHashSymbol->setOutputUnit( unit );
2964 attr.unite( mHashSymbol->usedAttributes( context ) );
2972 if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
2981 mHashSymbol->setDataDefinedWidth( property );
3001 || ( mHashSymbol && mHashSymbol->usesMapUnits() );
3006 mSymbolLineAngle = angle;
3011 return mSymbolAngle;
3016 mSymbolAngle = angle;
3021 double lineLength = mHashLength;
3027 const double w = context.
convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
3041 points << QPointF( start.
x(), start.
y() ) << QPointF( end.
x(), end.
y() );
3046 mHashSymbol->renderPolyline( points, feature, context, layer, selected );
3063 const double prevOpacity = mHashSymbol->opacity();
3064 mHashSymbol->setOpacity( mHashSymbol->opacity() * context.
opacity() );
3066 mHashSymbol->setOpacity( prevOpacity );
3085 QPolygonF offsetPoints;
3088 renderLine( points, context, patternThickness, patternLength, brush );
3097 renderLine( part, context, patternThickness, patternLength, brush );
3102void QgsAbstractBrushedLineSymbolLayer::renderLine(
const QPolygonF &points,
QgsSymbolRenderContext &context,
const double lineThickness,
const double patternLength,
const QBrush &sourceBrush )
3108 QBrush brush = sourceBrush;
3113 QPolygonF inputPoints;
3114 inputPoints.reserve( points.size() );
3116 double minX = std::numeric_limits< double >::max();
3117 double minY = std::numeric_limits< double >::max();
3118 double maxX = std::numeric_limits< double >::lowest();
3119 double maxY = std::numeric_limits< double >::lowest();
3121 for (
const QPointF &pt : std::as_const( points ) )
3128 minX = std::min( minX, pt.x() );
3129 minY = std::min( minY, pt.y() );
3130 maxX = std::max( maxX, pt.x() );
3131 maxY = std::max( maxY, pt.y() );
3134 if ( inputPoints.size() < 2 )
3138 constexpr int ANTIALIAS_ALLOWANCE_PIXELS = 10;
3140 constexpr double ANTIALIAS_OVERLAP_PIXELS = 0.5;
3143 const int imageWidth =
static_cast< int >( std::ceil( maxX - minX ) + lineThickness * 2 ) + ANTIALIAS_ALLOWANCE_PIXELS * 2;
3144 const int imageHeight =
static_cast< int >( std::ceil( maxY - minY ) + lineThickness * 2 ) + ANTIALIAS_ALLOWANCE_PIXELS * 2;
3146 const bool isClosedLine =
qgsDoubleNear( points.at( 0 ).x(), points.constLast().x(), 0.01 ) &&
qgsDoubleNear( points.at( 0 ).y(), points.constLast().y(), 0.01 );
3148 QImage temporaryImage( imageWidth, imageHeight, QImage::Format_ARGB32_Premultiplied );
3149 if ( temporaryImage.isNull() )
3158 temporaryImage.fill( Qt::transparent );
3181 QPainterPathStroker stroker;
3182 stroker.setWidth( lineThickness );
3183 stroker.setCapStyle( cap );
3184 stroker.setJoinStyle( join );
3187 path.addPolygon( inputPoints );
3188 const QPainterPath stroke = stroker.createStroke( path ).simplified();
3191 QPainter imagePainter;
3192 imagePainter.begin( &temporaryImage );
3194 imagePainter.translate( -minX + lineThickness + ANTIALIAS_ALLOWANCE_PIXELS, -minY + lineThickness + ANTIALIAS_ALLOWANCE_PIXELS );
3196 imagePainter.setClipPath( stroke, Qt::IntersectClip );
3197 imagePainter.setPen( Qt::NoPen );
3199 QPointF segmentStartPoint = inputPoints.at( 0 );
3202 double progressThroughImage = 0;
3204 QgsPoint prevSegmentPolygonEndLeft;
3205 QgsPoint prevSegmentPolygonEndRight;
3208 QgsPoint startLinePolygonLeft;
3209 QgsPoint startLinePolygonRight;
3211 for (
int i = 1; i < inputPoints.size(); ++i )
3216 const QPointF segmentEndPoint = inputPoints.at( i );
3217 const double segmentAngleDegrees = 180.0 / M_PI *
QgsGeometryUtilsBase::lineAngle( segmentStartPoint.x(), segmentStartPoint.y(), segmentEndPoint.x(), segmentEndPoint.y() ) - 90;
3220 QgsPoint thisSegmentPolygonEndLeft;
3221 QgsPoint thisSegmentPolygonEndRight;
3223 QgsPoint thisSegmentPolygonEndLeftForPainter;
3224 QgsPoint thisSegmentPolygonEndRightForPainter;
3232 const QgsPoint startPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, segmentAngleDegrees );
3233 const QgsPoint endPointLeft = QgsPoint( segmentEndPoint ).project( lineThickness / 2, segmentAngleDegrees );
3234 const QgsPoint startPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3235 const QgsPoint endPointRight = QgsPoint( segmentEndPoint ).project( -lineThickness / 2, segmentAngleDegrees );
3239 const double lastSegmentAngleDegrees = 180.0
3241 *
QgsGeometryUtilsBase::lineAngle( points.at( points.size() - 2 ).x(), points.at( points.size() - 2 ).y(), segmentStartPoint.x(), segmentStartPoint.y() )
3245 const QgsPoint lastSegmentStartPointLeft = QgsPoint( points.at( points.size() - 2 ) ).project( lineThickness / 2, lastSegmentAngleDegrees );
3246 const QgsPoint lastSegmentEndPointLeft = QgsPoint( segmentStartPoint ).project( lineThickness / 2, lastSegmentAngleDegrees );
3247 const QgsPoint lastSegmentStartPointRight = QgsPoint( points.at( points.size() - 2 ) ).project( -lineThickness / 2, lastSegmentAngleDegrees );
3248 const QgsPoint lastSegmentEndPointRight = QgsPoint( segmentStartPoint ).project( -lineThickness / 2, lastSegmentAngleDegrees );
3253 QgsPoint intersectionPoint;
3254 bool isIntersection =
false;
3256 if ( !isIntersection )
3257 prevSegmentPolygonEndLeft = startPointLeft;
3258 isIntersection =
false;
3259 QgsGeometryUtils::segmentIntersection( lastSegmentStartPointRight, lastSegmentEndPointRight, startPointRight, endPointRight, prevSegmentPolygonEndRight, isIntersection, 1e-8,
true );
3260 if ( !isIntersection )
3261 prevSegmentPolygonEndRight = startPointRight;
3263 startLinePolygonLeft = prevSegmentPolygonEndLeft;
3264 startLinePolygonRight = prevSegmentPolygonEndRight;
3268 prevSegmentPolygonEndLeft = QgsPoint( segmentStartPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3269 if ( cap != Qt::PenCapStyle::FlatCap )
3270 prevSegmentPolygonEndLeft = prevSegmentPolygonEndLeft.
project( lineThickness / 2, segmentAngleDegrees - 90 );
3271 prevSegmentPolygonEndRight = QgsPoint( segmentStartPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3272 if ( cap != Qt::PenCapStyle::FlatCap )
3273 prevSegmentPolygonEndRight = prevSegmentPolygonEndRight.
project( lineThickness / 2, segmentAngleDegrees - 90 );
3277 if ( i < inputPoints.size() - 1 )
3282 const QgsPoint startPointLeft = QgsPoint( segmentStartPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3283 const QgsPoint endPointLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3284 const QgsPoint startPointRight = QgsPoint( segmentStartPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3285 const QgsPoint endPointRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3289 const double nextSegmentAngleDegrees = 180.0 / M_PI *
QgsGeometryUtilsBase::lineAngle( segmentEndPoint.x(), segmentEndPoint.y(), inputPoints.at( i + 1 ).x(), inputPoints.at( i + 1 ).y() ) - 90;
3292 const QgsPoint nextSegmentStartPointLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, nextSegmentAngleDegrees );
3293 const QgsPoint nextSegmentEndPointLeft = QgsPoint( inputPoints.at( i + 1 ) ).
project( lineThickness / 2, nextSegmentAngleDegrees );
3294 const QgsPoint nextSegmentStartPointRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, nextSegmentAngleDegrees );
3295 const QgsPoint nextSegmentEndPointRight = QgsPoint( inputPoints.at( i + 1 ) ).
project( -lineThickness / 2, nextSegmentAngleDegrees );
3300 QgsPoint intersectionPoint;
3301 bool isIntersection =
false;
3303 if ( !isIntersection )
3304 thisSegmentPolygonEndLeft = endPointLeft;
3305 isIntersection =
false;
3306 QgsGeometryUtils::segmentIntersection( startPointRight, endPointRight, nextSegmentStartPointRight, nextSegmentEndPointRight, thisSegmentPolygonEndRight, isIntersection, 1e-8,
true );
3307 if ( !isIntersection )
3308 thisSegmentPolygonEndRight = endPointRight;
3310 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3311 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3319 thisSegmentPolygonEndLeft = startLinePolygonLeft;
3320 thisSegmentPolygonEndRight = startLinePolygonRight;
3322 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3323 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight.
project( ANTIALIAS_OVERLAP_PIXELS, segmentAngleDegrees + 90 );
3327 thisSegmentPolygonEndLeft = QgsPoint( segmentEndPoint ).
project( lineThickness / 2, segmentAngleDegrees );
3328 if ( cap != Qt::PenCapStyle::FlatCap )
3329 thisSegmentPolygonEndLeft = thisSegmentPolygonEndLeft.
project( lineThickness / 2, segmentAngleDegrees + 90 );
3330 thisSegmentPolygonEndRight = QgsPoint( segmentEndPoint ).
project( -lineThickness / 2, segmentAngleDegrees );
3331 if ( cap != Qt::PenCapStyle::FlatCap )
3332 thisSegmentPolygonEndRight = thisSegmentPolygonEndRight.
project( lineThickness / 2, segmentAngleDegrees + 90 );
3334 thisSegmentPolygonEndLeftForPainter = thisSegmentPolygonEndLeft;
3335 thisSegmentPolygonEndRightForPainter = thisSegmentPolygonEndRight;
3341 QTransform brushTransform;
3342 brushTransform.translate( segmentStartPoint.x(), segmentStartPoint.y() );
3343 brushTransform.rotate( -segmentAngleDegrees );
3344 if ( i == 1 && cap != Qt::PenCapStyle::FlatCap )
3348 brushTransform.translate( -( lineThickness / 2 ), 0 );
3350 brushTransform.translate( -progressThroughImage, -lineThickness / 2 );
3352 brush.setTransform( brushTransform );
3353 imagePainter.setBrush( brush );
3356 imagePainter.drawPolygon(
3358 << prevSegmentPolygonEndLeft.
toQPointF()
3359 << thisSegmentPolygonEndLeftForPainter.
toQPointF()
3360 << thisSegmentPolygonEndRightForPainter.
toQPointF()
3361 << prevSegmentPolygonEndRight.
toQPointF()
3362 << prevSegmentPolygonEndLeft.
toQPointF()
3366 imagePainter.setPen( QPen( QColor( 0, 255, 255 ), 2 ) );
3367 imagePainter.setBrush( Qt::NoBrush );
3368 imagePainter.drawPolygon( QPolygonF() << prevSegmentPolygonEndLeft.
toQPointF()
3369 << thisSegmentPolygonEndLeftForPainter.
toQPointF()
3370 << thisSegmentPolygonEndRightForPainter.
toQPointF()
3371 << prevSegmentPolygonEndRight.
toQPointF()
3372 << prevSegmentPolygonEndLeft.
toQPointF() );
3373 imagePainter.setPen( Qt::NoPen );
3378 progressThroughImage += sqrt( std::pow( segmentStartPoint.x() - segmentEndPoint.x(), 2 ) + std::pow( segmentStartPoint.y() - segmentEndPoint.y(), 2 ) )
3379 + ( i == 1 && cap != Qt::PenCapStyle::FlatCap ? lineThickness / 2 : 0 );
3380 progressThroughImage = fmod( progressThroughImage, patternLength );
3383 segmentStartPoint = segmentEndPoint;
3384 prevSegmentPolygonEndLeft = thisSegmentPolygonEndLeft;
3385 prevSegmentPolygonEndRight = thisSegmentPolygonEndRight;
3393 p->drawImage( QPointF( minX - lineThickness - ANTIALIAS_ALLOWANCE_PIXELS, minY - lineThickness - ANTIALIAS_ALLOWANCE_PIXELS ), temporaryImage );
3409 auto res = std::make_unique<QgsRasterLineSymbolLayer>();
3411 if (
properties.contains( u
"line_width"_s ) )
3413 res->setWidth(
properties[u
"line_width"_s].toDouble() );
3415 if (
properties.contains( u
"line_width_unit"_s ) )
3419 if (
properties.contains( u
"width_map_unit_scale"_s ) )
3425 res->setPath(
properties[u
"imageFile"_s].toString() );
3429 res->setOffset(
properties[u
"offset"_s].toDouble() );
3431 if (
properties.contains( u
"offset_unit"_s ) )
3435 if (
properties.contains( u
"offset_map_unit_scale"_s ) )
3447 res->setOpacity(
properties[u
"alpha"_s].toDouble() );
3450 return res.release();
3457 map[u
"imageFile"_s] =
mPath;
3459 map[u
"line_width"_s] = QString::number(
mWidth );
3466 map[u
"offset"_s] = QString::number(
mOffset );
3470 map[u
"alpha"_s] = QString::number(
mOpacity );
3477 auto res = std::make_unique< QgsRasterLineSymbolLayer >(
mPath );
3488 return res.release();
3493 const QVariantMap::iterator it =
properties.find( u
"imageFile"_s );
3494 if ( it !=
properties.end() && it.value().userType() == QMetaType::Type::QString )
3510 return u
"RasterLine"_s;
3525 bool cached =
false;
3528 QSize(
static_cast< int >( std::round( originalSize.width() / originalSize.height() * std::max( 1.0, scaledHeight ) ) ),
static_cast< int >( std::ceil( scaledHeight ) ) ),
3556 double strokeWidth =
mWidth;
3573 bool cached =
false;
3576 QSize(
static_cast< int >( std::round( originalSize.width() / originalSize.height() * std::max( 1.0, scaledHeight ) ) ),
static_cast< int >( std::ceil( scaledHeight ) ) ),
3585 if ( useSelectedColor )
3590 const QBrush brush( sourceImage );
3658 auto res = std::make_unique<QgsLineburstSymbolLayer>();
3660 if (
properties.contains( u
"line_width"_s ) )
3662 res->setWidth(
properties[u
"line_width"_s].toDouble() );
3664 if (
properties.contains( u
"line_width_unit"_s ) )
3668 if (
properties.contains( u
"width_map_unit_scale"_s ) )
3675 res->setOffset(
properties[u
"offset"_s].toDouble() );
3677 if (
properties.contains( u
"offset_unit"_s ) )
3681 if (
properties.contains( u
"offset_map_unit_scale"_s ) )
3691 if (
properties.contains( u
"color_type"_s ) )
3698 if (
properties.contains( u
"gradient_color2"_s ) )
3713 return res.release();
3720 map[u
"line_width"_s] = QString::number(
mWidth );
3727 map[u
"offset"_s] = QString::number(
mOffset );
3744 auto res = std::make_unique< QgsLineburstSymbolLayer >();
3759 return res.release();
3764 return u
"Lineburst"_s;
3783 double strokeWidth =
mWidth;
3799 if ( useSelectedColor )
3803 color1.setAlphaF( context.
opacity() * color1.alphaF() );
3814 QGradient gradient = QLinearGradient( QPointF( 0, 0 ), QPointF( 0, scaledWidth ) );
3827 gradient.setColorAt( 0.0, color1 );
3828 gradient.setColorAt( 1.0,
color2 );
3830 const QBrush brush( gradient );
3907 if ( props.contains( u
"line_width"_s ) )
3909 width = props[u
"line_width"_s].toDouble();
3911 else if ( props.contains( u
"outline_width"_s ) )
3913 width = props[u
"outline_width"_s].toDouble();
3915 else if ( props.contains( u
"width"_s ) )
3917 width = props[u
"width"_s].toDouble();
3922 if ( props.contains( u
"line_width_unit"_s ) )
3926 else if ( props.contains( u
"outline_width_unit"_s ) )
3930 else if ( props.contains( u
"width_unit"_s ) )
3935 if ( props.contains( u
"width_map_unit_scale"_s ) )
3937 if ( props.contains( u
"offset"_s ) )
3938 l->setOffset( props[u
"offset"_s].toDouble() );
3939 if ( props.contains( u
"offset_unit"_s ) )
3941 if ( props.contains( u
"offset_map_unit_scale"_s ) )
3943 if ( props.contains( u
"joinstyle"_s ) )
3945 if ( props.contains( u
"capstyle"_s ) )
3948 l->restoreOldDataDefinedProperties( props );
3955 return u
"FilledLine"_s;
4004 Qt::PenJoinStyle join = mPenJoinStyle;
4013 Qt::PenCapStyle cap = mPenCapStyle;
4029 const double prevOpacity = mFill->opacity();
4030 mFill->setOpacity( mFill->opacity() * context.
opacity() );
4037 if ( points.count() >= 2 )
4056 auto inputPoly = std::make_unique< QgsPolygon >(
static_cast< QgsLineString *
>( ls.release() ) );
4062 if ( !parts.empty() )
4088 std::unique_ptr< QgsAbstractGeometry > bufferedGeom =
QgsGeos::fromGeos( buffered.get() );
4090 for (
const QList< QPolygonF > &polygon : parts )
4092 QVector< QPolygonF > rings;
4093 for (
int i = 1; i < polygon.size(); ++i )
4094 rings << polygon.at( i );
4095 mFill->renderPolygon( polygon.value( 0 ), &rings, context.
feature(), context.
renderContext(), -1, useSelectedColor );
4103 mFill->setOpacity( prevOpacity );
4110 map[u
"line_width"_s] = QString::number(
mWidth );
4115 map[u
"offset"_s] = QString::number(
mOffset );
4129 res->setSubSymbol( mFill->clone() );
4130 return res.release();
4165 attr.unite( mFill->usedAttributes( context ) );
4173 if ( mFill && mFill->hasDataDefinedProperties() )
4182 mFill->setColor(
c );
4187 return mFill ? mFill->color() :
mColor;
4196 || ( mFill && mFill->usesMapUnits() );
4203 mFill->setMapUnitScale( scale );
4210 return mFill->mapUnitScale();
4219 mFill->setOutputUnit( unit );
4226 return mFill->outputUnit();
MarkerLinePlacement
Defines how/where the symbols should be placed on a line.
@ CurvePoint
Place symbols at every virtual curve point in the line (used when rendering curved geometry types onl...
@ InnerVertices
Inner vertices (i.e. all vertices except the first and last vertex).
@ LastVertex
Place symbols on the last vertex in the line.
@ CentralPoint
Place symbols at the mid point of the line.
@ SegmentCenter
Place symbols at the center of every line segment.
@ Vertex
Place symbols on every vertex in the line.
@ Interval
Place symbols at regular intervals.
@ FirstVertex
Place symbols on the first vertex in the line.
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
@ IsSymbolLayerSubSymbol
Symbol is being rendered as a sub-symbol of a QgsSymbolLayer.
@ AntialiasingSimplification
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'.
GradientColorSource
Gradient color sources.
@ ColorRamp
Gradient color ramp.
@ CanCalculateMaskGeometryPerFeature
If present, indicates that mask geometry can safely be calculated per feature for the symbol layer....
@ Curve
An intermediate point on a segment defining the curvature of the segment.
@ Segment
The actual start or end point of a segment.
QFlags< SymbolLayerFlag > SymbolLayerFlags
Symbol layer flags.
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
@ Miter
Use mitered joins.
RenderUnit
Rendering size units.
@ Percentage
Percentage of another measurement (e.g., canvas size, feature size).
@ Millimeters
Millimeters.
@ Points
Points (e.g., for font sizes).
@ Unknown
Mixed or unknown units.
@ MetersInMapUnits
Meters value as Map units.
@ Flat
Flat cap (in line with start/end of line).
@ RenderingSubSymbol
Set whenever a sub-symbol of a parent symbol is currently being rendered. Can be used during symbol a...
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
@ RenderLayerTree
The render is for a layer tree display where map based properties are not available and where avoidan...
@ RenderBlocking
Render and load remote sources in the same thread to ensure rendering remote sources (svg and images)...
QFlags< SymbolRenderHint > SymbolRenderHints
Symbol render hints.
@ MultiLineString
MultiLineString.
QFlags< MarkerLinePlacement > MarkerLinePlacements
Base class for line symbol layer types which draws line sections using a QBrush.
Qt::PenCapStyle mPenCapStyle
Qt::PenJoinStyle mPenJoinStyle
void renderPolylineUsingBrush(const QPolygonF &points, QgsSymbolRenderContext &context, const QBrush &brush, double patternThickness, double patternLength)
Renders a polyline of points using the specified brush.
static bool isGeneralizableByDeviceBoundingBox(const QgsRectangle &envelope, float mapToPixelTol=1.0f)
Returns whether the device-envelope can be replaced by its BBOX when is applied the specified toleran...
virtual double vertexAngle(QgsVertexId vertex) const =0
Returns approximate angle at a vertex.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
virtual bool nextVertex(QgsVertexId &id, QgsPoint &vertex) const =0
Returns next vertex id and coordinates.
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
static QgsImageCache * imageCache()
Returns the application's image cache, used for caching resampled versions of raster images.
QList< QPair< double, double > > BlankSegments
static QList< QList< BlankSegments > > parseBlankSegments(const QString &strBlankSegments, const QgsRenderContext &renderContext, Qgis::RenderUnit unit, QString &error)
Parse blank segments string representation strBlankSegments.
Abstract base class for color ramps.
static QColor colorFromString(const QString &string)
Decodes a string into a color value.
static QString colorToString(const QColor &color)
Encodes a color into a string value.
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates the symbol layer.
static QString typeString()
Returns the string identifier for QgsCptCityColorRamp.
Curve polygon geometry type.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Exports QGIS layers to the DXF format.
static double mapUnitScaleFactor(double scale, Qgis::RenderUnit symbolUnits, Qgis::DistanceUnit mapUnits, double mapUnitsPerPixel=1.0)
Returns scale factor for conversion to map units.
Qgis::DistanceUnit mapUnits() const
Retrieve map units.
double symbologyScale() const
Returns the reference scale for output.
void clipValueToMapUnitScale(double &value, const QgsMapUnitScale &scale, double pixelToMMFactor) const
Clips value to scale minimum/maximum.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
static const QString EXPR_GEOMETRY_RING_NUM
Inbuilt variable name for geometry ring number variable.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool isCanceled() const
Tells whether the operation has been canceled already.
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
static std::unique_ptr< QgsFillSymbol > createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
QString layerType() const override
Returns a string that represents this layer type.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsFilledLineSymbolLayer, using the settings serialized in the properties map (correspo...
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
~QgsFilledLineSymbolLayer() override
QgsFilledLineSymbolLayer(double width=DEFAULT_SIMPLELINE_WIDTH, QgsFillSymbol *fillSymbol=nullptr)
Constructor for QgsFilledLineSymbolLayer.
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setColor(const QColor &c) override
Sets the "representative" color for the symbol layer.
QColor color() const override
Returns the "representative" color of the symbol layer.
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
void startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
QgsFilledLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
QgsMapUnitScale mapUnitScale() const override
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
static double lineAngle(double x1, double y1, double x2, double y2)
Calculates the direction of line joining two points in radians, clockwise from the north direction.
static bool segmentIntersection(const QgsPoint &p1, const QgsPoint &p2, const QgsPoint &q1, const QgsPoint &q2, QgsPoint &intersectionPoint, bool &isIntersection, double tolerance=1e-8, bool acceptImproperIntersection=false)
Compute the intersection between two segments.
A geometry is the spatial representation of a feature.
QVector< QgsGeometry > coerceToType(Qgis::WkbType type, double defaultZ=0, double defaultM=0, bool avoidDuplicates=true) const
Attempts to coerce this geometry into the specified destination type.
static geos::unique_ptr offsetCurve(const GEOSGeometry *geometry, double distance, int segments, Qgis::JoinStyle joinStyle, double miterLimit, QString *errorMsg=nullptr)
Directly calculates the offset curve for a GEOS geometry object and returns a GEOS geometry result.
QgsAbstractGeometry * buffer(double distance, int segments, QString *errorMsg=nullptr) const override
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlags())
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
static std::unique_ptr< QgsAbstractGeometry > fromGeos(const GEOSGeometry *geos)
Create a geometry from a GEOSGeometry.
Gradient color ramp, which smoothly interpolates between two colors and also supports optional extra ...
static QgsColorRamp * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsColorRamp from a map of properties.
static QString typeString()
Returns the string identifier for QgsGradientColorRamp.
void addStopsToGradient(QGradient *gradient, double opacity=1) const
Copy color ramp stops to a QGradient.
double hashAngle() const
Returns the angle to use when drawing the hashed lines sections, in degrees clockwise.
QgsHashedLineSymbolLayer(bool rotateSymbol=true, double interval=3)
Constructor for QgsHashedLineSymbolLayer.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
void setWidth(double width) override
Sets the width of the line symbol layer.
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
double width() const override
Returns the estimated width for the line symbol layer.
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsHashedLineSymbolLayer, using the settings serialized in the properties map (correspo...
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
QgsHashedLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
~QgsHashedLineSymbolLayer() override
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
QColor color() const override
Returns the "representative" color of the symbol layer.
void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false) override
Renders the templated symbol at the specified point, using the given render context.
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
QString layerType() const override
Returns a string that represents this layer type.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
void setHashAngle(double angle)
Sets the angle to use when drawing the hashed lines sections, in degrees clockwise.
QSize originalSize(const QString &path, bool blocking=false) const
Returns the original size (in pixels) of the image at the specified path.
QImage pathAsImage(const QString &path, const QSize size, const bool keepAspectRatio, const double opacity, bool &fitsInCache, bool blocking=false, double targetDpi=96, int frameNumber=-1, bool *isMissing=nullptr)
Returns the specified path rendered as an image.
static void overlayColor(QImage &image, const QColor &color)
Overlays a color onto an image.
Line string geometry type, with support for z-dimension and m-values.
static std::unique_ptr< QgsLineString > fromQPolygonF(const QPolygonF &polygon)
Returns a new linestring from a QPolygonF polygon input.
Qgis::RenderUnit mOffsetUnit
RenderRingFilter
Options for filtering rings when the line symbol layer is being used to render a polygon's rings.
@ ExteriorRingOnly
Render the exterior ring only.
@ InteriorRingsOnly
Render the interior rings only.
@ AllRings
Render both exterior and interior rings.
QgsMapUnitScale mWidthMapUnitScale
QgsLineSymbolLayer(const QgsLineSymbolLayer &other)=delete
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
Qgis::RenderUnit mWidthUnit
void setOffset(double offset)
Sets the line's offset.
RenderRingFilter mRingFilter
void setOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the line's offset.
void setWidthUnit(Qgis::RenderUnit unit)
Sets the units for the line's width.
virtual double width() const
Returns the estimated width for the line symbol layer.
QgsMapUnitScale mOffsetMapUnitScale
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the line's offset.
QgsMapUnitScale mapUnitScale() const override
void setRingFilter(QgsLineSymbolLayer::RenderRingFilter filter)
Sets the line symbol layer's ring filter, which controls which rings are rendered when the line symbo...
void setMapUnitScale(const QgsMapUnitScale &scale) override
double offset() const
Returns the line's offset.
Qgis::RenderUnit offsetUnit() const
Returns the units for the line's offset.
Qgis::RenderUnit widthUnit() const
Returns the units for the line's width.
A line symbol type, for rendering LineString and MultiLineString geometries.
std::unique_ptr< QgsColorRamp > mGradientRamp
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
void setColorRamp(QgsColorRamp *ramp)
Sets the color ramp used for the gradient line.
QColor color2() const
Returns the color for endpoint of gradient, only used if the gradient color type is set to SimpleTwoC...
Qgis::GradientColorSource mGradientColorType
QString layerType() const override
Returns a string that represents this layer type.
~QgsLineburstSymbolLayer() override
QgsLineburstSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setMapUnitScale(const QgsMapUnitScale &scale) override
QgsMapUnitScale mapUnitScale() const override
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsLineburstSymbolLayer, using the settings serialized in the properties map (correspon...
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
QgsLineburstSymbolLayer(const QColor &color=DEFAULT_SIMPLELINE_COLOR, const QColor &color2=Qt::white)
Constructor for QgsLineburstSymbolLayer, with the specified start and end gradient colors.
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QgsColorRamp * colorRamp()
Returns the color ramp used for the gradient line.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
double mapUnitsPerPixel() const
Returns the current map units per pixel.
void transformInPlace(double &x, double &y) const
Transforms map coordinates to device coordinates.
Struct for storing maximum and minimum scales for measurements in map units.
Q_DECL_DEPRECATED bool rotateMarker() const
Shall the marker be rotated.
std::unique_ptr< QgsMarkerSymbol > mMarker
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
QgsMarkerLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
void setDataDefinedProperty(QgsSymbolLayer::Property key, const QgsProperty &property) override
Sets a data defined property for the layer.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
void setColor(const QColor &color) override
Sets the "representative" color for the symbol layer.
double symbolAngle() const override
Returns the symbol's current angle, in degrees clockwise.
double width() const override
Returns the estimated width for the line symbol layer.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsMarkerLineSymbolLayer, using the settings serialized in the properties map (correspo...
QgsMarkerLineSymbolLayer(bool rotateMarker=DEFAULT_MARKERLINE_ROTATE, double interval=DEFAULT_MARKERLINE_INTERVAL)
Constructor for QgsMarkerLineSymbolLayer.
void setWidth(double width) override
Sets the width of the line symbol layer.
QColor color() const override
Returns the "representative" color of the symbol layer.
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
~QgsMarkerLineSymbolLayer() override
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
QString layerType() const override
Returns a string that represents this layer type.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsMarkerLineSymbolLayer from an SLD XML DOM element.
void setSymbolAngle(double angle) override
Sets the symbol's angle, in degrees clockwise.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false) override
Renders the templated symbol at the specified point, using the given render context.
Abstract base class for marker symbol layers.
A marker symbol type, for rendering Point and MultiPoint geometries.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE(), 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 ...
bool isActive(int key) const final
Returns true if the collection contains an active property with the specified key.
A store for object properties.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
QgsRasterLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
double opacity() const
Returns the line opacity.
QString path() const
Returns the raster image path.
void setPath(const QString &path)
Set the raster image path.
QString layerType() const override
Returns a string that represents this layer type.
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
static void resolvePaths(QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving)
Turns relative paths in properties map to absolute when reading and vice versa when writing.
QgsRasterLineSymbolLayer(const QString &path=QString())
Constructor for QgsRasterLineSymbolLayer, with the specified raster image path.
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsRasterLineSymbolLayer, using the settings serialized in the properties map (correspo...
QColor color() const override
Returns the "representative" color of the symbol layer.
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
~QgsRasterLineSymbolLayer() override
void setMapUnitScale(const QgsMapUnitScale &scale) override
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
QgsMapUnitScale mapUnitScale() const override
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QgsVectorSimplifyMethod & vectorSimplifyMethod()
Returns the simplification settings to use when rendering vector layers.
double convertToPainterUnits(double size, Qgis::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
QgsExpressionContext & expressionContext()
Gets the expression context.
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected).
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QColor selectionColor() const
Returns the color to use when rendering selected features.
QgsFeedback * feedback() const
Returns the feedback object that can be queried regularly during rendering to check if rendering shou...
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
const QgsAbstractGeometry * geometry() const
Returns pointer to the unsegmentized geometry.
Scoped object for saving and restoring a QPainter object's state.
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
void setDrawInsidePolygon(bool drawInsidePolygon)
Sets whether the line should only be drawn inside polygons, and any portion of the line which falls o...
bool tweakDashPatternOnCorners() const
Returns true if dash patterns tweaks should be applied on sharp corners, to ensure that a double-leng...
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Qgis::SymbolLayerFlags flags() const override
Returns flags which control the symbol layer's behavior.
void setPenCapStyle(Qt::PenCapStyle style)
Sets the pen cap style used to render the line (e.g.
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
QgsMapUnitScale mapUnitScale() const override
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsSimpleLineSymbolLayer, using the settings serialized in the properties map (correspo...
Qgis::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QVector< qreal > customDashVector() const
Returns the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ...
Qt::PenJoinStyle penJoinStyle() const
Returns the pen join style used to render the line (e.g.
void renderPolygonStroke(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the outline of polygon, using the given render context.
Qt::PenStyle dxfPenStyle() const override
Gets pen style.
void setCustomDashPatternMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for lengths used in the custom dash pattern.
void setTrimDistanceEndMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the end of the line.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
void setTrimDistanceEnd(double distance)
Sets the trim distance for the end of the line, which dictates a length from the end of the line at w...
double dxfOffset(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets offset.
QgsSimpleLineSymbolLayer(const QColor &color=DEFAULT_SIMPLELINE_COLOR, double width=DEFAULT_SIMPLELINE_WIDTH, Qt::PenStyle penStyle=DEFAULT_SIMPLELINE_PENSTYLE)
Constructor for QgsSimpleLineSymbolLayer.
~QgsSimpleLineSymbolLayer() override
void setUseCustomDashPattern(bool b)
Sets whether the line uses a custom dash pattern.
void setTweakDashPatternOnCorners(bool enabled)
Sets whether dash patterns tweaks should be applied on sharp corners, to ensure that a double-length ...
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
void setCustomDashVector(const QVector< qreal > &vector)
Sets the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ren...
void setDashPatternOffset(double offset)
Sets the dash pattern offset, which dictates how far along the dash pattern the pattern should start ...
QColor dxfColor(QgsSymbolRenderContext &context) const override
Gets color.
QString layerType() const override
Returns a string that represents this layer type.
void setDashPatternOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the dash pattern offset.
QgsSimpleLineSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Qt::PenStyle penStyle() const
Returns the pen style used to render the line (e.g.
void setPenJoinStyle(Qt::PenJoinStyle style)
Sets the pen join style used to render the line (e.g.
void setAlignDashPattern(bool enabled)
Sets whether dash patterns should be aligned to the start and end of lines, by applying subtle tweaks...
static QgsSymbolLayer * createFromSld(QDomElement &element)
Creates a new QgsSimpleLineSymbolLayer from an SLD XML DOM element.
double dxfWidth(const QgsDxfExport &e, QgsSymbolRenderContext &context) const override
Gets line width.
void setTrimDistanceStartMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the start of the line.
QVector< qreal > dxfCustomDashPattern(Qgis::RenderUnit &unit) const override
Gets dash pattern.
Qt::PenCapStyle penCapStyle() const
Returns the pen cap style used to render the line (e.g.
void setTrimDistanceEndUnit(Qgis::RenderUnit unit)
Sets the unit for the trim distance for the end of the line.
void setDashPatternOffsetUnit(Qgis::RenderUnit unit)
Sets the unit for the dash pattern offset.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Q_DECL_DEPRECATED void toSld(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const override
Saves the symbol layer as SLD.
void setMapUnitScale(const QgsMapUnitScale &scale) override
void setTrimDistanceStart(double distance)
Sets the trim distance for the start of the line, which dictates a length from the start of the line ...
QString ogrFeatureStyle(double mmScaleFactor, double mapUnitScaleFactor) const override
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
void setTrimDistanceStartUnit(Qgis::RenderUnit unit)
Sets the unit for the trim distance for the start of the line.
bool alignDashPattern() const
Returns true if dash patterns should be aligned to the start and end of lines, by applying subtle twe...
void setCustomDashPatternUnit(Qgis::RenderUnit unit)
Sets the unit for lengths used in the custom dash pattern.
Holds SLD export options and other information related to SLD export of a QGIS layer style.
void setExtraProperties(const QVariantMap &properties)
Sets the open ended set of properties that can drive/inform the SLD encoding.
QVariantMap extraProperties() const
Returns the open ended set of properties that can drive/inform the SLD encoding.
static QString encodePenStyle(Qt::PenStyle style)
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static Q_DECL_DEPRECATED bool createExpressionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates a OGC Expression element based on the provided function expression.
static QString svgSymbolPathToName(const QString &path, const QgsPathResolver &pathResolver)
Determines an SVG symbol's name from its path.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
static double rescaleUom(double size, Qgis::RenderUnit unit, const QVariantMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
static std::unique_ptr< QgsSymbolLayer > createMarkerLayerFromSld(QDomElement &element)
Creates a new marker layer from a SLD DOM element.
static bool isSharpCorner(QPointF p1, QPointF p2, QPointF p3)
Returns true if the angle formed by the line p1 - p2 - p3 forms a "sharp" corner.
static QString ogrFeatureStylePen(double width, double mmScaleFactor, double mapUnitsScaleFactor, const QColor &c, Qt::PenJoinStyle joinStyle=Qt::MiterJoin, Qt::PenCapStyle capStyle=Qt::FlatCap, double offset=0.0, const QVector< qreal > *dashPattern=nullptr)
Create ogr feature style string for pen.
static Qt::PenCapStyle decodePenCapStyle(const QString &str)
static QList< QList< QPolygonF > > toQPolygonF(const QgsGeometry &geometry, Qgis::SymbolType type)
Converts a geometry to a set of QPolygonF objects representing how the geometry should be drawn for a...
static QVector< qreal > decodeRealVector(const QString &s)
static bool lineFromSld(QDomElement &element, Qt::PenStyle &penStyle, QColor &color, double &width, Qt::PenJoinStyle *penJoinStyle=nullptr, Qt::PenCapStyle *penCapStyle=nullptr, QVector< qreal > *customDashPattern=nullptr, double *dashOffset=nullptr)
static QString encodePenCapStyle(Qt::PenCapStyle style)
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
static void appendPolyline(QPolygonF &target, const QPolygonF &line)
Appends a polyline line to an existing target polyline.
static QString svgSymbolNameToPath(const QString &name, const QgsPathResolver &pathResolver)
Determines an SVG symbol's path from its name.
static QString encodeColor(const QColor &color)
static Qgis::EndCapStyle penCapStyleToEndCapStyle(Qt::PenCapStyle style)
Converts a Qt pen cap style to a QGIS end cap style.
static double polylineLength(const QPolygonF &polyline)
Returns the total length of a polyline.
static Qgis::RenderUnit decodeSldUom(const QString &str, double *scaleFactor=nullptr)
Decodes a SLD unit of measure string to a render unit.
static Q_DECL_DEPRECATED void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
Creates an SLD geometry element.
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
static Qt::PenStyle decodePenStyle(const QString &str)
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
static QgsStringMap getVendorOptionList(QDomElement &element)
static Qgis::JoinStyle penJoinStyleToJoinStyle(Qt::PenJoinStyle style)
Converts a Qt pen joinstyle to a QGIS join style.
static QPolygonF polylineSubstring(const QPolygonF &polyline, double startOffset, double endOffset)
Returns the substring of a polyline which starts at startOffset from the beginning of the line and en...
static void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, const QColor &color, QgsSldExportContext &context, double width=-1, const Qt::PenJoinStyle *penJoinStyle=nullptr, const Qt::PenCapStyle *penCapStyle=nullptr, const QVector< qreal > *customDashPattern=nullptr, double dashOffset=0.0)
static QString encodeRealVector(const QVector< qreal > &v)
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.
@ 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 startFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called before the layer will be rendered for a particular feature.
static void setCommonProperties(QgsTemplatedLineSymbolLayerBase *destLayer, const QVariantMap &properties)
Sets all common symbol properties in the destLayer, using the settings serialized in the properties m...
void setMapUnitScale(const QgsMapUnitScale &scale) final
void renderPolygonStroke(const QPolygonF &points, const QVector< QPolygonF > *rings, QgsSymbolRenderContext &context) final
Renders the line symbol layer along the outline of polygon, using the given render context.
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setIntervalUnit(Qgis::RenderUnit unit)
Sets the units for the interval between symbols.
void setAverageAngleUnit(Qgis::RenderUnit unit)
Sets the unit for the length over which the line's direction is averaged when calculating individual ...
double interval() const
Returns the interval between individual symbols.
void setOffsetAlongLineUnit(Qgis::RenderUnit unit)
Sets the unit used for calculating the offset along line for symbols.
void setAverageAngleMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the length over which the line's direction is averaged when calculating i...
const QgsMapUnitScale & intervalMapUnitScale() const
Returns the map unit scale for the interval between symbols.
double offsetAlongLine() const
Returns the offset along the line for the symbol placement.
~QgsTemplatedLineSymbolLayerBase() override
void copyTemplateSymbolProperties(QgsTemplatedLineSymbolLayerBase *destLayer) const
Copies all common properties of this layer to another templated symbol layer 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.
Qgis::RenderUnit offsetAlongLineUnit() const
Returns the unit used for calculating the offset along line for symbols.
Qgis::RenderUnit outputUnit() const final
Returns the units to use for sizes and widths within the symbol layer.
QgsTemplatedLineSymbolLayerBase(bool rotateSymbol=true, double interval=3)
Constructor for QgsTemplatedLineSymbolLayerBase.
virtual void setSymbolLineAngle(double angle)=0
Sets the line angle modification for the symbol's angle.
QgsMapUnitScale mapUnitScale() const final
void setInterval(double interval)
Sets the interval between individual symbols.
Qgis::RenderUnit intervalUnit() const
Returns the units for the interval between symbols.
Q_DECL_DEPRECATED Qgis::MarkerLinePlacement placement() const
Returns the placement of the symbols.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
void setPlaceOnEveryPart(bool respect)
Sets whether the placement applies for every part of multi-part feature geometries.
void setPlacements(Qgis::MarkerLinePlacements placements)
Sets the placement of the symbols.
void setOutputUnit(Qgis::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Qgis::RenderUnit averageAngleUnit() const
Returns the unit for the length over which the line's direction is averaged when calculating individu...
Q_DECL_DEPRECATED void setPlacement(Qgis::MarkerLinePlacement placement)
Sets the placement of the symbols.
void stopFeatureRender(const QgsFeature &feature, QgsRenderContext &context) override
Called after the layer has been rendered for a particular feature.
Qgis::RenderUnit blankSegmentsUnit() const
Returns the unit for for blank segments start and end distances.
void setBlankSegmentsUnit(Qgis::RenderUnit unit)
Sets the unit for blank segments start and end distances.
const QgsMapUnitScale & offsetAlongLineMapUnitScale() const
Returns the map unit scale used for calculating the offset in map units along line for symbols.
virtual void renderSymbol(const QPointF &point, const QgsFeature *feature, QgsRenderContext &context, int layer=-1, bool selected=false)=0
Renders the templated symbol at the specified point, using the given render context.
void setIntervalMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the interval between symbols.
void setOffsetAlongLineMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale used for calculating the offset in map units along line for symbols.
void setAverageAngleLength(double length)
Sets the length of line over which the line's direction is averaged when calculating individual symbo...
static Q_INVOKABLE Qgis::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
static Q_INVOKABLE QString encodeUnit(Qgis::DistanceUnit unit)
Encodes a distance unit to a string.
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
Qgis::VectorRenderingSimplificationFlags simplifyHints() const
Gets the simplification hints of the vector layer managed.
float threshold() const
Gets the simplification threshold of the vector layer managed.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored).
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
QString qgsFlagValueToKeys(const T &value, bool *returnOk=nullptr)
Returns the value for the given keys of a flag.
T qgsFlagKeysToValue(const QString &keys, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given keys of a flag.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
QMap< QString, QString > QgsStringMap
#define DEFAULT_MARKERLINE_INTERVAL
#define DEFAULT_SIMPLELINE_WIDTH
#define DEFAULT_MARKERLINE_ROTATE
#define DEFAULT_SIMPLELINE_PENSTYLE
#define DEFAULT_SIMPLELINE_COLOR
#define QgsDebugMsgLevel(str, level)
#define QgsDebugError(str)
QList< QgsSymbolLayer * > QgsSymbolLayerList
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, Qgis::GeometryType geometryType)
calculate geometry shifted by a specified distance
Single variable definition for use within a QgsExpressionContextScope.
Qgis::VertexType type
Vertex type.