34 #include <QDomDocument>
35 #include <QDomElement>
40 : mPenStyle( penStyle )
44 mCustomDashVector << 5 << 2;
54 mCustomDashPatternUnit = unit;
78 mCustomDashPatternMapUnitScale = scale;
98 if ( props.contains( QStringLiteral(
"line_color" ) ) )
102 else if ( props.contains( QStringLiteral(
"outline_color" ) ) )
106 else if ( props.contains( QStringLiteral(
"color" ) ) )
111 if ( props.contains( QStringLiteral(
"line_width" ) ) )
113 width = props[QStringLiteral(
"line_width" )].toDouble();
115 else if ( props.contains( QStringLiteral(
"outline_width" ) ) )
117 width = props[QStringLiteral(
"outline_width" )].toDouble();
119 else if ( props.contains( QStringLiteral(
"width" ) ) )
122 width = props[QStringLiteral(
"width" )].toDouble();
124 if ( props.contains( QStringLiteral(
"line_style" ) ) )
128 else if ( props.contains( QStringLiteral(
"outline_style" ) ) )
132 else if ( props.contains( QStringLiteral(
"penstyle" ) ) )
138 if ( props.contains( QStringLiteral(
"line_width_unit" ) ) )
142 else if ( props.contains( QStringLiteral(
"outline_width_unit" ) ) )
146 else if ( props.contains( QStringLiteral(
"width_unit" ) ) )
151 if ( props.contains( QStringLiteral(
"width_map_unit_scale" ) ) )
153 if ( props.contains( QStringLiteral(
"offset" ) ) )
154 l->
setOffset( props[QStringLiteral(
"offset" )].toDouble() );
155 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
157 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
159 if ( props.contains( QStringLiteral(
"joinstyle" ) ) )
161 if ( props.contains( QStringLiteral(
"capstyle" ) ) )
164 if ( props.contains( QStringLiteral(
"use_custom_dash" ) ) )
168 if ( props.contains( QStringLiteral(
"customdash" ) ) )
172 if ( props.contains( QStringLiteral(
"customdash_unit" ) ) )
176 if ( props.contains( QStringLiteral(
"customdash_map_unit_scale" ) ) )
181 if ( props.contains( QStringLiteral(
"draw_inside_polygon" ) ) )
186 if ( props.contains( QStringLiteral(
"ring_filter" ) ) )
191 if ( props.contains( QStringLiteral(
"dash_pattern_offset" ) ) )
193 if ( props.contains( QStringLiteral(
"dash_pattern_offset_unit" ) ) )
195 if ( props.contains( QStringLiteral(
"dash_pattern_offset_map_unit_scale" ) ) )
198 if ( props.contains( QStringLiteral(
"trim_distance_start" ) ) )
200 if ( props.contains( QStringLiteral(
"trim_distance_start_unit" ) ) )
202 if ( props.contains( QStringLiteral(
"trim_distance_start_map_unit_scale" ) ) )
204 if ( props.contains( QStringLiteral(
"trim_distance_end" ) ) )
206 if ( props.contains( QStringLiteral(
"trim_distance_end_unit" ) ) )
208 if ( props.contains( QStringLiteral(
"trim_distance_end_map_unit_scale" ) ) )
211 if ( props.contains( QStringLiteral(
"align_dash_pattern" ) ) )
214 if ( props.contains( QStringLiteral(
"tweak_dash_pattern_on_corners" ) ) )
224 return QStringLiteral(
"SimpleLine" );
231 mPen.setColor( penColor );
233 mPen.setWidthF( scaledWidth );
237 const double dashWidthDiv = std::max( 1.0, scaledWidth );
238 if ( mUseCustomDashPattern )
240 mPen.setStyle( Qt::CustomDashLine );
244 QVector<qreal> scaledVector;
245 QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
246 for ( ; it != mCustomDashVector.constEnd(); ++it )
251 mPen.setDashPattern( scaledVector );
255 mPen.setStyle( mPenStyle );
258 if ( mDashPatternOffset && mPen.style() != Qt::SolidLine )
263 mPen.setJoinStyle( mPenJoinStyle );
264 mPen.setCapStyle( mPenCapStyle );
269 selColor.setAlphaF( context.
opacity() );
270 mSelPen.setColor( selColor );
287 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
294 if ( mDrawInsidePolygon )
302 if ( mDrawInsidePolygon )
305 QPainterPath clipPath;
306 clipPath.addPolygon( points );
311 for (
auto it = rings->constBegin(); it != rings->constEnd(); ++it )
313 QPolygonF ring = *it;
314 clipPath.addPolygon( ring );
319 p->setClipPath( clipPath, Qt::IntersectClip );
342 for (
const QPolygonF &ring : std::as_const( *rings ) )
358 if ( mDrawInsidePolygon )
374 QPolygonF points = pts;
376 double startTrim = mTrimDistanceStart;
382 double endTrim = mTrimDistanceEnd;
389 double totalLength = -1;
393 startTrim = startTrim * 0.01 * totalLength;
401 if ( totalLength < 0 )
403 endTrim = endTrim * 0.01 * totalLength;
416 mPen.setColor( penColor );
419 applyDataDefinedSymbology( context, mPen, mSelPen,
offset );
421 const QPen pen = context.
selected() ? mSelPen : mPen;
422 p->setBrush( Qt::NoBrush );
425 std::unique_ptr< QgsScopedQPainterState > painterState;
426 if ( points.size() <= 2 &&
429 ( p->renderHints() & QPainter::Antialiasing ) )
431 painterState = std::make_unique< QgsScopedQPainterState >( p );
432 p->setRenderHint( QPainter::Antialiasing,
false );
435 const bool applyPatternTweaks = mAlignDashPattern
436 && ( pen.style() != Qt::SolidLine || !pen.dashPattern().empty() )
437 && pen.dashOffset() == 0;
441 if ( applyPatternTweaks )
443 drawPathWithDashPatternTweaks( p, points, pen );
449 path.addPolygon( points );
464 for (
const QPolygonF &part : mline )
466 if ( applyPatternTweaks )
468 drawPathWithDashPatternTweaks( p, part, pen );
474 path.addPolygon( part );
485 map[QStringLiteral(
"line_width" )] = QString::number(
mWidth );
491 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
494 map[QStringLiteral(
"use_custom_dash" )] = ( mUseCustomDashPattern ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
498 map[QStringLiteral(
"dash_pattern_offset" )] = QString::number( mDashPatternOffset );
501 map[QStringLiteral(
"trim_distance_start" )] = QString::number( mTrimDistanceStart );
504 map[QStringLiteral(
"trim_distance_end" )] = QString::number( mTrimDistanceEnd );
507 map[QStringLiteral(
"draw_inside_polygon" )] = ( mDrawInsidePolygon ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
508 map[QStringLiteral(
"ring_filter" )] = QString::number(
static_cast< int >(
mRingFilter ) );
509 map[QStringLiteral(
"align_dash_pattern" )] = mAlignDashPattern ? QStringLiteral(
"1" ) : QStringLiteral(
"0" );
510 map[QStringLiteral(
"tweak_dash_pattern_on_corners" )] = mPatternCartographicTweakOnSharpCorners ? QStringLiteral(
"1" ) : QStringLiteral(
"0" );
549 if ( mPenStyle == Qt::NoPen )
552 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:LineSymbolizer" ) );
553 if ( !props.value( QStringLiteral(
"uom" ), QString() ).toString().isEmpty() )
554 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ).toString() );
555 element.appendChild( symbolizerElem );
561 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
562 symbolizerElem.appendChild( strokeElem );
564 Qt::PenStyle
penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
573 QDomElement perpOffsetElem = doc.createElement( QStringLiteral(
"se:PerpendicularOffset" ) );
576 symbolizerElem.appendChild( perpOffsetElem );
582 if ( mUseCustomDashPattern )
585 mPen.color(), mPenJoinStyle,
586 mPenCapStyle,
mOffset, &mCustomDashVector );
599 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
600 if ( strokeElem.isNull() )
617 QDomElement perpOffsetElem = element.firstChildElement( QStringLiteral(
"PerpendicularOffset" ) );
618 if ( !perpOffsetElem.isNull() )
621 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
626 QString uom = element.attribute( QStringLiteral(
"uom" ) );
640 void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context, QPen &pen, QPen &selPen,
double &offset )
646 bool hasStrokeWidthExpression =
false;
653 pen.setWidthF( scaledWidth );
654 selPen.setWidthF( scaledWidth );
655 hasStrokeWidthExpression =
true;
664 penColor.setAlphaF( context.
opacity() * penColor.alphaF() );
665 pen.setColor( penColor );
679 const double dashWidthDiv = std::max( hasStrokeWidthExpression ? pen.widthF() : mPen.widthF(), 1.0 );
683 QVector<qreal> dashVector;
685 if ( !exprVal.isNull() )
687 QStringList dashList = exprVal.toString().split(
';' );
688 QStringList::const_iterator dashIt = dashList.constBegin();
689 for ( ; dashIt != dashList.constEnd(); ++dashIt )
693 pen.setDashPattern( dashVector );
700 QVector<qreal> scaledVector;
701 for (
double v : std::as_const( mCustomDashVector ) )
706 mPen.setDashPattern( scaledVector );
710 double patternOffset = mDashPatternOffset;
723 if ( !exprVal.isNull() )
732 if ( !exprVal.isNull() )
741 if ( !exprVal.isNull() )
746 void QgsSimpleLineSymbolLayer::drawPathWithDashPatternTweaks( QPainter *painter,
const QPolygonF &points, QPen pen )
const
748 if ( pen.dashPattern().empty() || points.size() < 2 )
751 QVector< qreal > sourcePattern = pen.dashPattern();
752 const double dashWidthDiv = std::max( 1.0001, pen.widthF() );
754 for (
int i = 0; i < sourcePattern.size(); ++ i )
755 sourcePattern[i] *= pen.widthF();
757 if ( pen.widthF() <= 1.0 )
758 pen.setWidthF( 1.0001 );
760 QVector< qreal > buffer;
761 QPolygonF bufferedPoints;
762 QPolygonF previousSegmentBuffer;
767 auto ptIt = points.constBegin();
768 double totalBufferLength = 0;
769 int patternIndex = 0;
770 double currentRemainingDashLength = 0;
771 double currentRemainingGapLength = 0;
773 auto compressPattern = [](
const QVector< qreal > &buffer ) -> QVector< qreal >
775 QVector< qreal > result;
776 result.reserve( buffer.size() );
777 for (
auto it = buffer.begin(); it != buffer.end(); )
781 while ( dash == 0 && !result.empty() )
783 result.last() += gap;
785 if ( it == buffer.end() )
790 while ( gap == 0 && it != buffer.end() )
795 result << dash << gap;
800 double currentBufferLineLength = 0;
801 auto flushBuffer = [pen, painter, &buffer, &bufferedPoints, &previousSegmentBuffer, ¤tRemainingDashLength, ¤tRemainingGapLength, ¤tBufferLineLength, &totalBufferLength,
802 dashWidthDiv, &compressPattern]( QPointF * nextPoint )
804 if ( buffer.empty() || bufferedPoints.size() < 2 )
809 if ( currentRemainingDashLength )
812 buffer << currentRemainingDashLength << 0.0;
813 totalBufferLength += currentRemainingDashLength;
815 QVector< qreal > compressed = compressPattern( buffer );
816 if ( !currentRemainingDashLength )
819 totalBufferLength -= compressed.last();
820 compressed.last() = 0;
824 const double scaleFactor = currentBufferLineLength / totalBufferLength;
826 bool shouldFlushPreviousSegmentBuffer =
false;
828 if ( !previousSegmentBuffer.empty() )
832 if ( !firstDashSubstring.empty() )
838 compressed = compressed.mid( 2 );
839 shouldFlushPreviousSegmentBuffer = !compressed.empty();
842 if ( !previousSegmentBuffer.empty() && ( shouldFlushPreviousSegmentBuffer || !nextPoint ) )
844 QPen adjustedPen = pen;
845 adjustedPen.setStyle( Qt::SolidLine );
846 painter->setPen( adjustedPen );
848 path.addPolygon( previousSegmentBuffer );
849 painter->drawPath( path );
850 previousSegmentBuffer.clear();
853 double finalDash = 0;
860 if ( !compressed.empty() )
862 finalDash = compressed.at( compressed.size() - 2 );
863 const double finalGap = compressed.size() > 2 ? compressed.at( compressed.size() - 3 ) : 0;
865 const QPolygonF thisPoints = bufferedPoints;
871 previousSegmentBuffer << bufferedPoints;
875 currentBufferLineLength = 0;
876 currentRemainingDashLength = 0;
877 currentRemainingGapLength = 0;
878 totalBufferLength = 0;
881 if ( !bufferedPoints.empty() && ( !compressed.empty() || !nextPoint ) )
883 QPen adjustedPen = pen;
884 if ( !compressed.empty() )
887 compressed = compressed.mid( 0, 32 );
888 std::for_each( compressed.begin(), compressed.end(), [scaleFactor, dashWidthDiv]( qreal & element ) { element *= scaleFactor / dashWidthDiv; } );
889 adjustedPen.setDashPattern( compressed );
893 adjustedPen.setStyle( Qt::SolidLine );
896 painter->setPen( adjustedPen );
898 path.addPolygon( bufferedPoints );
899 painter->drawPath( path );
902 bufferedPoints.clear();
908 bufferedPoints << p2;
909 for ( ; ptIt != points.constEnd(); ++ptIt )
917 double remainingSegmentDistance = std::sqrt( std::pow( p2.x() - p1.x(), 2.0 ) + std::pow( p2.y() - p1.y(), 2.0 ) );
918 currentBufferLineLength += remainingSegmentDistance;
922 if ( currentRemainingDashLength > 0 )
925 if ( remainingSegmentDistance >= currentRemainingDashLength )
928 buffer << currentRemainingDashLength << 0.0;
929 totalBufferLength += currentRemainingDashLength;
930 remainingSegmentDistance -= currentRemainingDashLength;
932 currentRemainingDashLength = 0.0;
933 currentRemainingGapLength = sourcePattern.at( patternIndex );
938 buffer << remainingSegmentDistance << 0.0;
939 totalBufferLength += remainingSegmentDistance;
940 currentRemainingDashLength -= remainingSegmentDistance;
944 if ( currentRemainingGapLength > 0 )
947 if ( remainingSegmentDistance >= currentRemainingGapLength )
950 buffer << 0.0 << currentRemainingGapLength;
951 totalBufferLength += currentRemainingGapLength;
952 remainingSegmentDistance -= currentRemainingGapLength;
953 currentRemainingGapLength = 0.0;
959 buffer << 0.0 << remainingSegmentDistance;
960 totalBufferLength += remainingSegmentDistance;
961 currentRemainingGapLength -= remainingSegmentDistance;
966 if ( patternIndex >= sourcePattern.size() )
969 const double nextPatternDashLength = sourcePattern.at( patternIndex );
970 const double nextPatternGapLength = sourcePattern.at( patternIndex + 1 );
971 if ( nextPatternDashLength + nextPatternGapLength <= remainingSegmentDistance )
973 buffer << nextPatternDashLength << nextPatternGapLength;
974 remainingSegmentDistance -= nextPatternDashLength + nextPatternGapLength;
975 totalBufferLength += nextPatternDashLength + nextPatternGapLength;
978 else if ( nextPatternDashLength <= remainingSegmentDistance )
981 buffer << nextPatternDashLength << remainingSegmentDistance - nextPatternDashLength;
982 totalBufferLength += remainingSegmentDistance;
983 currentRemainingGapLength = nextPatternGapLength - ( remainingSegmentDistance - nextPatternDashLength );
984 currentRemainingDashLength = 0;
991 buffer << remainingSegmentDistance << 0.0;
992 totalBufferLength += remainingSegmentDistance;
993 currentRemainingGapLength = 0;
994 currentRemainingDashLength = nextPatternDashLength - remainingSegmentDistance;
999 bufferedPoints << p1;
1000 if ( mPatternCartographicTweakOnSharpCorners && ptIt + 1 != points.constEnd() )
1002 QPointF nextPoint = *( ptIt + 1 );
1008 flushBuffer( &nextPoint );
1009 bufferedPoints << p1;
1012 if ( patternIndex % 2 == 1 )
1016 currentRemainingDashLength = sourcePattern.at( patternIndex );
1023 flushBuffer(
nullptr );
1024 if ( !previousSegmentBuffer.empty() )
1026 QPen adjustedPen = pen;
1027 adjustedPen.setStyle( Qt::SolidLine );
1028 painter->setPen( adjustedPen );
1030 path.addPolygon( previousSegmentBuffer );
1031 painter->drawPath( path );
1032 previousSegmentBuffer.clear();
1038 if ( mDrawInsidePolygon )
1052 unit = mCustomDashPatternUnit;
1053 return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
1090 return mPenStyle != Qt::SolidLine || mUseCustomDashPattern;
1095 return mAlignDashPattern;
1105 return mPatternCartographicTweakOnSharpCorners;
1110 mPatternCartographicTweakOnSharpCorners =
enabled;
1139 MyLine( QPointF p1, QPointF p2 )
1140 : mVertical( false )
1141 , mIncreasing( false )
1153 mIncreasing = ( p2.y() > p1.y() );
1158 mT = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
1159 mIncreasing = ( p2.x() > p1.x() );
1163 double x = ( p2.x() - p1.x() );
1164 double y = ( p2.y() - p1.y() );
1165 mLength = std::sqrt( x * x + y * y );
1171 double a = ( mVertical ? M_PI_2 : std::atan( mT ) );
1179 QPointF diffForInterval(
double interval )
1182 return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
1184 double alpha = std::atan( mT );
1185 double dx = std::cos( alpha ) * interval;
1186 double dy = std::sin( alpha ) * interval;
1187 return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
1190 double length() {
return mLength; }
1205 : mRotateSymbols( rotateSymbol )
1206 , mInterval( interval )
1228 if ( !exprVal.isNull() )
1230 QString placementString = exprVal.toString();
1231 if ( placementString.compare( QLatin1String(
"interval" ), Qt::CaseInsensitive ) == 0 )
1235 else if ( placementString.compare( QLatin1String(
"vertex" ), Qt::CaseInsensitive ) == 0 )
1239 else if ( placementString.compare( QLatin1String(
"lastvertex" ), Qt::CaseInsensitive ) == 0 )
1243 else if ( placementString.compare( QLatin1String(
"firstvertex" ), Qt::CaseInsensitive ) == 0 )
1247 else if ( placementString.compare( QLatin1String(
"centerpoint" ), Qt::CaseInsensitive ) == 0 )
1251 else if ( placementString.compare( QLatin1String(
"curvepoint" ), Qt::CaseInsensitive ) == 0 )
1255 else if ( placementString.compare( QLatin1String(
"segmentcenter" ), Qt::CaseInsensitive ) == 0 )
1268 double averageOver = mAverageAngleLength;
1281 renderPolylineInterval( points, context, averageOver );
1285 renderPolylineCentral( points, context, averageOver );
1293 renderPolylineVertex( points, context,
placement );
1302 for (
int part = 0; part < mline.count(); ++part )
1304 const QPolygonF &points2 = mline[ part ];
1309 renderPolylineInterval( points2, context, averageOver );
1313 renderPolylineCentral( points2, context, averageOver );
1321 renderPolylineVertex( points2, context,
placement );
1338 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
1368 for (
int i = 0; i < rings->size(); ++i )
1420 map[QStringLiteral(
"rotate" )] = (
rotateSymbols() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1421 map[QStringLiteral(
"interval" )] = QString::number(
interval() );
1422 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
1423 map[QStringLiteral(
"offset_along_line" )] = QString::number(
offsetAlongLine() );
1430 map[QStringLiteral(
"average_angle_length" )] = QString::number( mAverageAngleLength );
1434 switch ( mPlacement )
1437 map[QStringLiteral(
"placement" )] = QStringLiteral(
"vertex" );
1440 map[QStringLiteral(
"placement" )] = QStringLiteral(
"lastvertex" );
1443 map[QStringLiteral(
"placement" )] = QStringLiteral(
"firstvertex" );
1446 map[QStringLiteral(
"placement" )] = QStringLiteral(
"centralpoint" );
1449 map[QStringLiteral(
"placement" )] = QStringLiteral(
"curvepoint" );
1452 map[QStringLiteral(
"placement" )] = QStringLiteral(
"interval" );
1455 map[QStringLiteral(
"placement" )] = QStringLiteral(
"segmentcenter" );
1459 map[QStringLiteral(
"ring_filter" )] = QString::number(
static_cast< int >(
mRingFilter ) );
1465 switch ( mPlacement )
1503 if (
properties.contains( QStringLiteral(
"offset" ) ) )
1507 if (
properties.contains( QStringLiteral(
"offset_unit" ) ) )
1511 if (
properties.contains( QStringLiteral(
"interval_unit" ) ) )
1515 if (
properties.contains( QStringLiteral(
"offset_along_line" ) ) )
1519 if (
properties.contains( QStringLiteral(
"offset_along_line_unit" ) ) )
1523 if (
properties.contains( ( QStringLiteral(
"offset_along_line_map_unit_scale" ) ) ) )
1528 if (
properties.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
1532 if (
properties.contains( QStringLiteral(
"interval_map_unit_scale" ) ) )
1537 if (
properties.contains( QStringLiteral(
"average_angle_length" ) ) )
1541 if (
properties.contains( QStringLiteral(
"average_angle_unit" ) ) )
1545 if (
properties.contains( ( QStringLiteral(
"average_angle_map_unit_scale" ) ) ) )
1550 if (
properties.contains( QStringLiteral(
"placement" ) ) )
1552 if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"vertex" ) )
1554 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"lastvertex" ) )
1556 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"firstvertex" ) )
1558 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"centralpoint" ) )
1560 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"curvepoint" ) )
1562 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"segmentcenter" ) )
1568 if (
properties.contains( QStringLiteral(
"ring_filter" ) ) )
1576 void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval(
const QPolygonF &points,
QgsSymbolRenderContext &context,
double averageOver )
1578 if ( points.isEmpty() )
1581 double lengthLeft = 0;
1613 if ( painterUnitInterval < 0 )
1624 lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1626 if ( averageOver > 0 && !
qgsDoubleNear( averageOver, 0.0 ) )
1628 QVector< QPointF > angleStartPoints;
1629 QVector< QPointF > symbolPoints;
1630 QVector< QPointF > angleEndPoints;
1638 collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft );
1640 if ( symbolPoints.empty() )
1646 if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1649 symbolPoints.pop_back();
1652 angleEndPoints.reserve( symbolPoints.size() );
1653 angleStartPoints.reserve( symbolPoints.size() );
1654 if ( averageOver <= painterUnitOffsetAlongLine )
1656 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver, 0, symbolPoints.size() );
1660 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1662 collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver, 0, symbolPoints.size() );
1665 for (
int i = 0; i < symbolPoints.size(); ++ i )
1670 const QPointF pt = symbolPoints[i];
1671 const QPointF startPt = angleStartPoints[i];
1672 const QPointF endPt = angleEndPoints[i];
1674 MyLine l( startPt, endPt );
1689 QPointF lastPt = points[0];
1690 for (
int i = 1; i < points.count(); ++i )
1695 const QPointF &pt = points[i];
1701 MyLine l( lastPt, pt );
1702 QPointF diff = l.diffForInterval( painterUnitInterval );
1706 double c = 1 - lengthLeft / painterUnitInterval;
1708 lengthLeft += l.length();
1717 while ( lengthLeft > painterUnitInterval )
1721 lengthLeft -= painterUnitInterval;
1733 static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1736 double a1 = MyLine( prevPt, pt ).angle();
1737 double a2 = MyLine( pt, nextPt ).angle();
1738 double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
1740 return std::atan2( unitY, unitX );
1745 if ( points.isEmpty() )
1750 int i = -1, maxCount = 0;
1751 bool isRing =
false;
1824 i = points.count() - 1;
1825 maxCount = points.count();
1833 maxCount = points.count();
1834 if ( points.first() == points.last() )
1851 renderOffsetVertexAlongLine( points, i, distance, context );
1859 prevPoint = points.at( 0 );
1861 QPointF symbolPoint;
1862 for ( ; i < maxCount; ++i )
1873 QPointF currentPoint = points.at( i );
1874 symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ),
1875 0.5 * ( currentPoint.y() + prevPoint.y() ) );
1878 double angle = std::atan2( currentPoint.y() - prevPoint.y(),
1879 currentPoint.x() - prevPoint.x() );
1882 prevPoint = currentPoint;
1886 symbolPoint = points.at( i );
1890 double angle = markerAngle( points, isRing, i );
1899 double QgsTemplatedLineSymbolLayerBase::markerAngle(
const QPolygonF &points,
bool isRing,
int vertex )
1902 const QPointF &pt = points[vertex];
1904 if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
1906 int prevIndex = vertex - 1;
1907 int nextIndex = vertex + 1;
1909 if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
1911 prevIndex = points.count() - 2;
1915 QPointF prevPoint, nextPoint;
1916 while ( prevIndex >= 0 )
1918 prevPoint = points[ prevIndex ];
1919 if ( prevPoint != pt )
1926 while ( nextIndex < points.count() )
1928 nextPoint = points[ nextIndex ];
1929 if ( nextPoint != pt )
1936 if ( prevIndex >= 0 && nextIndex < points.count() )
1938 angle = _averageAngle( prevPoint, pt, nextPoint );
1945 while ( vertex < points.size() - 1 )
1947 const QPointF &nextPt = points[vertex + 1];
1950 angle = MyLine( pt, nextPt ).angle();
1959 while ( vertex >= 1 )
1961 const QPointF &prevPt = points[vertex - 1];
1964 angle = MyLine( prevPt, pt ).angle();
1974 void QgsTemplatedLineSymbolLayerBase::renderOffsetVertexAlongLine(
const QPolygonF &points,
int vertex,
double distance,
QgsSymbolRenderContext &context )
1976 if ( points.isEmpty() )
1985 bool isRing =
false;
1986 if ( points.first() == points.last() )
1988 double angle = markerAngle( points, isRing, vertex );
1995 int pointIncrement = distance > 0 ? 1 : -1;
1996 QPointF previousPoint = points[vertex];
1997 int startPoint = distance > 0 ? std::min( vertex + 1,
static_cast<int>( points.count() ) - 1 ) : std::max( vertex - 1, 0 );
1998 int endPoint = distance > 0 ? points.count() - 1 : 0;
1999 double distanceLeft = std::fabs( distance );
2001 for (
int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
2003 const QPointF &pt = points[i];
2005 if ( previousPoint == pt )
2009 MyLine l( previousPoint, pt );
2011 if ( distanceLeft < l.length() )
2014 QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
2024 distanceLeft -= l.length();
2031 void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints(
const QVector<QPointF> &p, QVector<QPointF> &dest,
double intervalPainterUnits,
double initialOffset,
double initialLag,
int numberPointsRequired )
2036 QVector< QPointF > points = p;
2037 const bool closedRing = points.first() == points.last();
2039 double lengthLeft = initialOffset;
2041 double initialLagLeft = initialLag > 0 ? -initialLag : 1;
2042 if ( initialLagLeft < 0 && closedRing )
2045 QPointF lastPt = points.constLast();
2046 QVector< QPointF > pseudoPoints;
2047 for (
int i = points.count() - 2; i > 0; --i )
2049 if ( initialLagLeft >= 0 )
2054 const QPointF &pt = points[i];
2059 MyLine l( lastPt, pt );
2060 initialLagLeft += l.length();
2065 std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
2067 points = pseudoPoints;
2072 while ( initialLagLeft < 0 )
2074 dest << points.constFirst();
2075 initialLagLeft += intervalPainterUnits;
2078 if ( initialLag > 0 )
2080 lengthLeft += intervalPainterUnits - initialLagLeft;
2083 QPointF lastPt = points[0];
2084 for (
int i = 1; i < points.count(); ++i )
2086 const QPointF &pt = points[i];
2090 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2099 MyLine l( lastPt, pt );
2100 QPointF diff = l.diffForInterval( intervalPainterUnits );
2104 double c = 1 - lengthLeft / intervalPainterUnits;
2106 lengthLeft += l.length();
2109 while ( lengthLeft > intervalPainterUnits ||
qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
2113 lengthLeft -= intervalPainterUnits;
2116 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2121 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2125 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2132 if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2135 while ( dest.size() < numberPointsRequired )
2136 dest << points.constLast();
2140 void QgsTemplatedLineSymbolLayerBase::renderPolylineCentral(
const QPolygonF &points,
QgsSymbolRenderContext &context,
double averageAngleOver )
2142 if ( !points.isEmpty() )
2146 QPolygonF::const_iterator it = points.constBegin();
2148 for ( ++it; it != points.constEnd(); ++it )
2150 length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2151 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2157 const double midPoint = length / 2;
2160 double thisSymbolAngle = 0;
2162 if ( averageAngleOver > 0 && !
qgsDoubleNear( averageAngleOver, 0.0 ) )
2164 QVector< QPointF > angleStartPoints;
2165 QVector< QPointF > symbolPoints;
2166 QVector< QPointF > angleEndPoints;
2168 collectOffsetPoints( points, symbolPoints, midPoint, midPoint, 0.0, 2 );
2169 collectOffsetPoints( points, angleStartPoints, midPoint, 0, averageAngleOver, 2 );
2170 collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver, 0, 2 );
2172 pt = symbolPoints.at( 1 );
2173 MyLine l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
2174 thisSymbolAngle = l.angle();
2179 it = points.constBegin();
2181 qreal last_at = 0, next_at = 0;
2184 for ( ++it; it != points.constEnd(); ++it )
2187 next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2188 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2189 if ( next_at >= midPoint )
2197 MyLine l( last, next );
2198 qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
2199 pt = last + ( next - last ) * k;
2200 thisSymbolAngle = l.angle();
2252 if ( props.contains( QStringLiteral(
"interval" ) ) )
2253 interval = props[QStringLiteral(
"interval" )].toDouble();
2254 if ( props.contains( QStringLiteral(
"rotate" ) ) )
2255 rotate = ( props[QStringLiteral(
"rotate" )].toString() == QLatin1String(
"1" ) );
2257 std::unique_ptr< QgsMarkerLineSymbolLayer > x = std::make_unique< QgsMarkerLineSymbolLayer >( rotate,
interval );
2264 return QStringLiteral(
"MarkerLine" );
2281 Qgis::SymbolRenderHints hints = Qgis::SymbolRenderHints();
2284 mMarker->setRenderHints( hints );
2297 std::unique_ptr< QgsMarkerLineSymbolLayer > x = std::make_unique< QgsMarkerLineSymbolLayer >(
rotateSymbols(),
interval() );
2304 for (
int i = 0; i <
mMarker->symbolLayerCount(); i++ )
2306 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:LineSymbolizer" ) );
2307 if ( !props.value( QStringLiteral(
"uom" ), QString() ).toString().isEmpty() )
2308 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ).toString() );
2309 element.appendChild( symbolizerElem );
2344 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
2345 symbolizerElem.appendChild( strokeElem );
2348 QDomElement graphicStrokeElem = doc.createElement( QStringLiteral(
"se:GraphicStroke" ) );
2349 strokeElem.appendChild( graphicStrokeElem );
2354 markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
2358 graphicStrokeElem.appendChild( doc.createComment( QStringLiteral(
"QgsMarkerSymbolLayer expected, %1 found. Skip it." ).arg( layer->
layerType() ) ) );
2362 graphicStrokeElem.appendChild( doc.createComment( QStringLiteral(
"Missing marker line symbol layer. Skip it." ) ) );
2365 if ( !gap.isEmpty() )
2367 QDomElement gapElem = doc.createElement( QStringLiteral(
"se:Gap" ) );
2369 graphicStrokeElem.appendChild( gapElem );
2374 QDomElement perpOffsetElem = doc.createElement( QStringLiteral(
"se:PerpendicularOffset" ) );
2377 symbolizerElem.appendChild( perpOffsetElem );
2386 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
2387 if ( strokeElem.isNull() )
2390 QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral(
"GraphicStroke" ) );
2391 if ( graphicStrokeElem.isNull() )
2399 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
2401 if ( it.key() == QLatin1String(
"placement" ) )
2403 if ( it.value() == QLatin1String(
"points" ) )
2405 else if ( it.value() == QLatin1String(
"firstPoint" ) )
2407 else if ( it.value() == QLatin1String(
"lastPoint" ) )
2409 else if ( it.value() == QLatin1String(
"centralPoint" ) )
2412 else if ( it.value() == QLatin1String(
"rotateMarker" ) )
2418 std::unique_ptr< QgsMarkerSymbol > marker;
2432 QDomElement gapElem = graphicStrokeElem.firstChildElement( QStringLiteral(
"Gap" ) );
2433 if ( !gapElem.isNull() )
2436 double d = gapElem.firstChild().nodeValue().toDouble( &ok );
2442 QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( QStringLiteral(
"PerpendicularOffset" ) );
2443 if ( !perpOffsetElem.isNull() )
2446 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
2451 QString uom = element.attribute( QStringLiteral(
"uom" ) );
2473 mMarker->setDataDefinedSize( property );
2480 const double prevOpacity =
mMarker->opacity();
2483 mMarker->setOpacity( prevOpacity );
2503 mMarker->renderPoint( point, feature, context, layer, selected );
2513 return mMarker->size( context );
2519 mMarker->setOutputUnit( unit );
2539 attr.unite(
mMarker->usedAttributes( context ) );
2554 return (
mMarker->size( context ) / 2.0 ) +
2576 if ( props.contains( QStringLiteral(
"interval" ) ) )
2577 interval = props[QStringLiteral(
"interval" )].toDouble();
2578 if ( props.contains( QStringLiteral(
"rotate" ) ) )
2579 rotate = ( props[QStringLiteral(
"rotate" )] == QLatin1String(
"1" ) );
2581 std::unique_ptr< QgsHashedLineSymbolLayer > x = std::make_unique< QgsHashedLineSymbolLayer >( rotate,
interval );
2583 if ( props.contains( QStringLiteral(
"hash_angle" ) ) )
2585 x->setHashAngle( props[QStringLiteral(
"hash_angle" )].toDouble() );
2588 if ( props.contains( QStringLiteral(
"hash_length" ) ) )
2589 x->setHashLength( props[QStringLiteral(
"hash_length" )].toDouble() );
2591 if ( props.contains( QStringLiteral(
"hash_length_unit" ) ) )
2594 if ( props.contains( QStringLiteral(
"hash_length_map_unit_scale" ) ) )
2602 return QStringLiteral(
"HashLine" );
2608 Qgis::SymbolRenderHints hints = Qgis::SymbolRenderHints();
2611 mHashSymbol->setRenderHints( hints );
2624 map[ QStringLiteral(
"hash_angle" ) ] = QString::number( mHashAngle );
2626 map[QStringLiteral(
"hash_length" )] = QString::number( mHashLength );
2635 std::unique_ptr< QgsHashedLineSymbolLayer > x = std::make_unique< QgsHashedLineSymbolLayer >(
rotateSymbols(),
interval() );
2637 x->setHashAngle( mHashAngle );
2638 x->setHashLength( mHashLength );
2639 x->setHashLengthUnit( mHashLengthUnit );
2640 x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2646 mHashSymbol->setColor(
color );
2652 return mHashSymbol ? mHashSymbol->color() :
mColor;
2657 return mHashSymbol.get();
2668 mHashSymbol.reset(
static_cast<QgsLineSymbol *
>( symbol ) );
2669 mColor = mHashSymbol->color();
2675 mHashLength =
width;
2690 return ( mHashSymbol->width( context ) / 2.0 )
2698 mHashSymbol->setOutputUnit( unit );
2708 attr.unite( mHashSymbol->usedAttributes( context ) );
2716 if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
2725 mHashSymbol->setDataDefinedWidth( property );
2738 || ( mHashSymbol && mHashSymbol->usesMapUnits() );
2743 mSymbolLineAngle =
angle;
2748 return mSymbolAngle;
2753 mSymbolAngle =
angle;
2758 double lineLength = mHashLength;
2764 const double w = context.
convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
2778 points << QPointF( start.
x(), start.
y() ) << QPointF( end.
x(), end.
y() );
2781 mHashSymbol->renderPolyline( points, feature, context, layer, selected );
2796 const double prevOpacity = mHashSymbol->opacity();
2797 mHashSymbol->setOpacity( mHashSymbol->opacity() * context.
opacity() );
2799 mHashSymbol->setOpacity( prevOpacity );
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
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 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.
QColor valueAsColor(int key, const QgsExpressionContext &context, const QColor &defaultColor=QColor(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a color.
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.
Curve polygon geometry type.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
Exports QGIS layers to the DXF format.
static double mapUnitScaleFactor(double scale, QgsUnitTypes::RenderUnit symbolUnits, QgsUnitTypes::DistanceUnit mapUnits, double mapUnitsPerPixel=1.0)
Returns scale factor for conversion to map units.
QgsUnitTypes::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.
RAII class to pop scope from an expression context on destruction.
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...
Line symbol layer type which draws repeating line sections along a line feature.
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.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
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
The fill color.
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
The fill color.
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
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.
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
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
QgsUnitTypes::RenderUnit mWidthUnit
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units for the line's offset.
void setWidthMapUnitScale(const QgsMapUnitScale &scale)
void setWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the line's width.
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the line's offset.
void setOffset(double offset)
Sets the line's offset.
RenderRingFilter mRingFilter
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
QgsUnitTypes::RenderUnit widthUnit() const
Returns 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.
QgsUnitTypes::RenderUnit mOffsetUnit
A line symbol type, for rendering LineString and MultiLineString geometries.
Perform transforms between map coordinates and device coordinates.
double mapUnitsPerPixel() const
Returns current map units per pixel.
void transformInPlace(double &x, double &y) const
Transforms device coordinates to map coordinates.
Struct for storing maximum and minimum scales for measurements in map units.
Line symbol layer type which draws repeating marker symbols along a line feature.
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
The fill color.
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.
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
The fill color.
void setSymbolLineAngle(double angle) override
Sets the line angle modification for the symbol's angle.
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.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
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.
A class to represent a 2D point.
QgsPointXY project(double distance, double bearing) const SIP_HOLDGIL
Returns a new point which corresponds to this point projected by a specified distance in a specified ...
Point geometry type, with support for z-dimension and m-values.
QVariant value(int key, const QgsExpressionContext &context, const QVariant &defaultValue=QVariant()) const override
Returns the calculated value of the property with the specified key from within the collection.
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
A store for object properties.
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.
const QgsAbstractGeometry * geometry() const
Returns pointer to the unsegmentized geometry.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
QColor selectionColor() const
Returns the color to use when rendering selected features.
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
Flags flags() const
Returns combination of flags used for rendering.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
const QgsVectorSimplifyMethod & vectorSimplifyMethod() const
Returns the simplification settings to use when rendering vector layers.
Scoped object for saving and restoring a QPainter object's state.
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
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...
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
QVector< qreal > dxfCustomDashPattern(QgsUnitTypes::RenderUnit &unit) const override
Gets dash pattern.
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Creates a new QgsSimpleLineSymbolLayer, using the settings serialized in the properties map (correspo...
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.
QgsUnitTypes::RenderUnit outputUnit() const override
Returns the units to use for sizes and widths within the symbol layer.
void setDashPatternOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the dash pattern offset.
Qt::PenStyle dxfPenStyle() const override
Gets pen style.
void setCustomDashPatternMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for lengths used in the custom dash pattern.
void setTrimDistanceEndMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the trim distance for the end of the line.
double estimateMaxBleed(const QgsRenderContext &context) const override
Returns the estimated maximum distance which the layer style will bleed outside the drawn shape when ...
QVector< qreal > customDashVector() const
Returns the custom dash vector, which is the pattern of alternating drawn/skipped lengths used while ...
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...
void setCustomDashPatternUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for lengths used in the custom dash pattern.
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.
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...
void setTrimDistanceStartUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the trim distance for the start of the line.
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.
void setTrimDistanceEndUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the trim distance for the end of the line.
Qt::PenCapStyle penCapStyle() const
Returns the pen cap style used to render the line (e.g.
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets 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.
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.
bool alignDashPattern() const
Returns true if dash patterns should be aligned to the start and end of lines, by applying subtle twe...
static QString encodePenStyle(Qt::PenStyle style)
static Qt::PenJoinStyle decodePenJoinStyle(const QString &str)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
static bool createExpressionElement(QDomDocument &doc, QDomElement &element, const QString &function)
Creates a OGC Expression element based on the provided function expression.
static QColor decodeColor(const QString &str)
static double rescaleUom(double size, QgsUnitTypes::RenderUnit unit, const QVariantMap &props)
Rescales the given size based on the uomScale found in the props, if any is found,...
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
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 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 void lineToSld(QDomDocument &doc, QDomElement &element, Qt::PenStyle penStyle, const QColor &color, double width=-1, const Qt::PenJoinStyle *penJoinStyle=nullptr, const Qt::PenCapStyle *penCapStyle=nullptr, const QVector< qreal > *customDashPattern=nullptr, double dashOffset=0.0)
static QDomElement createVendorOptionElement(QDomDocument &doc, const QString &name, const QString &value)
static double sizeInPixelsFromSldUom(const QString &uom, double size)
Returns the size scaled in pixels according to the uom attribute.
static void appendPolyline(QPolygonF &target, const QPolygonF &line)
Appends a polyline line to an existing target polyline.
static QString encodeColor(const QColor &color)
static double polylineLength(const QPolygonF &polyline)
Returns the total length of a polyline.
static void createGeometryElement(QDomDocument &doc, QDomElement &element, const QString &geomFunc)
static Qt::PenStyle decodePenStyle(const QString &str)
static QgsSymbolLayer * createMarkerLayerFromSld(QDomElement &element)
static QString encodePenJoinStyle(Qt::PenJoinStyle style)
static QgsStringMap getVendorOptionList(QDomElement &element)
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 QString encodeRealVector(const QVector< qreal > &v)
Property
Data definable properties.
@ PropertyStrokeStyle
Stroke style (eg solid, dashed)
@ PropertyPlacement
Line marker placement.
@ PropertyCapStyle
Line cap style.
@ PropertyLineDistance
Distance between lines, or length of lines for hash line symbols.
@ PropertyOffsetAlongLine
Offset along line.
@ PropertyCustomDash
Custom dash pattern.
@ PropertyJoinStyle
Line join style.
@ PropertyTrimEnd
Trim distance from end of line (since QGIS 3.20)
@ PropertyLineAngle
Line angle, or angle of hash lines for hash line symbols.
@ PropertyTrimStart
Trim distance from start of line (since QGIS 3.20)
@ PropertyOffset
Symbol offset.
@ PropertyStrokeWidth
Stroke width.
@ PropertyDashPatternOffset
Dash pattern offset,.
@ PropertyAverageAngleLength
Length to average symbol angles over.
@ PropertyInterval
Line marker interval.
@ PropertyStrokeColor
Stroke color.
@ PropertyWidth
Symbol width.
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
static const bool SELECTION_IS_OPAQUE
Whether styles for selected features ignore symbol alpha.
virtual QColor color() const
The fill color.
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
void restoreOldDataDefinedProperties(const QVariantMap &stringMap)
Restores older data defined properties from string map.
virtual QgsSymbolLayer * clone() const =0
Shall be reimplemented by subclasses to create a deep copy of the instance.
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 QgsSymbol * subSymbol()
Returns the symbol's sub symbol, if present.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
QgsPropertyCollection mDataDefinedProperties
virtual bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
QgsFields fields() const
Fields of the layer.
bool selected() const
Returns true if symbols should be rendered using the selected symbol coloring and style.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
QgsWkbTypes::GeometryType originalGeometryType() const
Returns the geometry type for the original feature geometry being rendered.
const QgsFeature * feature() const
Returns the current feature being rendered.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
qreal opacity() const
Returns the opacity for the symbol.
Abstract base class for all rendered symbols.
Qgis::SymbolType type() const
Returns the symbol's type.
Base class for templated line symbols, e.g.
bool rotateSymbols() const
Returns true if the repeating symbols be rotated to match their line segment orientation.
static void setCommonProperties(QgsTemplatedLineSymbolLayerBase *destLayer, const QVariantMap &properties)
Sets all common symbol properties in the destLayer, using the settings serialized in the properties m...
const QgsMapUnitScale & intervalMapUnitScale() const
Returns the map unit scale for the interval between symbols.
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
QgsMapUnitScale mapUnitScale() const FINAL
void setMapUnitScale(const QgsMapUnitScale &scale) FINAL
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Placement placement() const
Returns the placement of the symbols.
Placement
Defines how/where the templated symbol should be placed on the line.
@ Vertex
Place symbols on every vertex in the line.
@ LastVertex
Place symbols on the last vertex in the line.
@ CentralPoint
Place symbols at the mid point of the line.
@ FirstVertex
Place symbols on the first vertex in the line.
@ SegmentCenter
Place symbols at the center of every line segment.
@ Interval
Place symbols at regular intervals.
@ CurvePoint
Place symbols at every virtual curve point in the line (used when rendering curved geometry types onl...
double interval() const
Returns the interval between individual 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...
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.
void setOffsetAlongLine(double offsetAlongLine)
Sets the the offset along the line for the symbol placement.
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.
QgsUnitTypes::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.
void setPlacement(Placement placement)
Sets the placement of the symbols.
void setOffsetAlongLineUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit used for calculating the offset along line for symbols.
void setInterval(double interval)
Sets the interval between individual symbols.
const QgsMapUnitScale & offsetAlongLineMapUnitScale() const
Returns the map unit scale used for calculating the offset in map units along line for symbols.
QgsUnitTypes::RenderUnit averageAngleUnit() const
Returns the unit for the length over which the line's direction is averaged when calculating individu...
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
QgsUnitTypes::RenderUnit offsetAlongLineUnit() const
Returns the unit used for calculating the offset along line for symbols.
QgsUnitTypes::RenderUnit intervalUnit() const
Returns the units for the interval between symbols.
void setAverageAngleUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the length over which the line's direction is averaged when calculating individual ...
void setIntervalUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the interval between 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 QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
RenderUnit
Rendering size units.
@ RenderUnknownUnit
Mixed or unknown units.
@ RenderMetersInMapUnits
Meters value as Map units.
@ RenderPercentage
Percentage of another measurement (e.g., canvas size, feature size)
@ RenderMillimeters
Millimeters.
@ RenderMapUnits
Map units.
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
float threshold() const
Gets the simplification threshold of the vector layer managed.
@ AntialiasingSimplification
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'.
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)
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.
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)
QLineF segment(int index, QRectF rect, double radius)
QList< QgsSymbolLayer * > QgsSymbolLayerList
QList< QPolygonF > offsetLine(QPolygonF polyline, double dist, QgsWkbTypes::GeometryType geometryType)
calculate geometry shifted by a specified distance
Single variable definition for use within a QgsExpressionContextScope.
Utility class for identifying a unique vertex within a geometry.
VertexType type
Vertex type.
@ SegmentVertex
The actual start or end point of a segment.
@ CurveVertex
An intermediate point on a segment defining the curvature of the segment.