32 #include <QDomDocument>
33 #include <QDomElement>
38 : mPenStyle( penStyle )
42 mCustomDashVector << 5 << 2;
50 mCustomDashPatternUnit = unit;
74 mCustomDashPatternMapUnitScale = scale;
94 if ( props.contains( QStringLiteral(
"line_color" ) ) )
98 else if ( props.contains( QStringLiteral(
"outline_color" ) ) )
102 else if ( props.contains( QStringLiteral(
"color" ) ) )
107 if ( props.contains( QStringLiteral(
"line_width" ) ) )
109 width = props[QStringLiteral(
"line_width" )].toDouble();
111 else if ( props.contains( QStringLiteral(
"outline_width" ) ) )
113 width = props[QStringLiteral(
"outline_width" )].toDouble();
115 else if ( props.contains( QStringLiteral(
"width" ) ) )
118 width = props[QStringLiteral(
"width" )].toDouble();
120 if ( props.contains( QStringLiteral(
"line_style" ) ) )
124 else if ( props.contains( QStringLiteral(
"outline_style" ) ) )
128 else if ( props.contains( QStringLiteral(
"penstyle" ) ) )
134 if ( props.contains( QStringLiteral(
"line_width_unit" ) ) )
138 else if ( props.contains( QStringLiteral(
"outline_width_unit" ) ) )
142 else if ( props.contains( QStringLiteral(
"width_unit" ) ) )
147 if ( props.contains( QStringLiteral(
"width_map_unit_scale" ) ) )
149 if ( props.contains( QStringLiteral(
"offset" ) ) )
150 l->
setOffset( props[QStringLiteral(
"offset" )].toDouble() );
151 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
153 if ( props.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
155 if ( props.contains( QStringLiteral(
"joinstyle" ) ) )
157 if ( props.contains( QStringLiteral(
"capstyle" ) ) )
160 if ( props.contains( QStringLiteral(
"use_custom_dash" ) ) )
164 if ( props.contains( QStringLiteral(
"customdash" ) ) )
168 if ( props.contains( QStringLiteral(
"customdash_unit" ) ) )
172 if ( props.contains( QStringLiteral(
"customdash_map_unit_scale" ) ) )
177 if ( props.contains( QStringLiteral(
"draw_inside_polygon" ) ) )
182 if ( props.contains( QStringLiteral(
"ring_filter" ) ) )
187 if ( props.contains( QStringLiteral(
"dash_pattern_offset" ) ) )
189 if ( props.contains( QStringLiteral(
"dash_pattern_offset_unit" ) ) )
191 if ( props.contains( QStringLiteral(
"dash_pattern_offset_map_unit_scale" ) ) )
194 if ( props.contains( QStringLiteral(
"align_dash_pattern" ) ) )
197 if ( props.contains( QStringLiteral(
"tweak_dash_pattern_on_corners" ) ) )
208 return QStringLiteral(
"SimpleLine" );
215 mPen.setColor( penColor );
217 mPen.setWidthF( scaledWidth );
221 const double dashWidthDiv = std::max( 1.0, scaledWidth );
222 if ( mUseCustomDashPattern )
224 mPen.setStyle( Qt::CustomDashLine );
228 QVector<qreal> scaledVector;
229 QVector<qreal>::const_iterator it = mCustomDashVector.constBegin();
230 for ( ; it != mCustomDashVector.constEnd(); ++it )
235 mPen.setDashPattern( scaledVector );
239 mPen.setStyle( mPenStyle );
242 if ( mDashPatternOffset && mPen.style() != Qt::SolidLine )
247 mPen.setJoinStyle( mPenJoinStyle );
248 mPen.setCapStyle( mPenCapStyle );
253 selColor.setAlphaF( context.
opacity() );
254 mSelPen.setColor( selColor );
270 if ( mDrawInsidePolygon )
278 if ( mDrawInsidePolygon )
281 QPainterPath clipPath;
282 clipPath.addPolygon( points );
287 for (
auto it = rings->constBegin(); it != rings->constEnd(); ++it )
289 QPolygonF ring = *it;
290 clipPath.addPolygon( ring );
295 p->setClipPath( clipPath, Qt::IntersectClip );
314 for (
const QPolygonF &ring : qgis::as_const( *rings ) )
324 if ( mDrawInsidePolygon )
342 mPen.setColor( penColor );
345 applyDataDefinedSymbology( context, mPen, mSelPen,
offset );
347 const QPen pen = context.
selected() ? mSelPen : mPen;
348 p->setBrush( Qt::NoBrush );
351 std::unique_ptr< QgsScopedQPainterState > painterState;
352 if ( points.size() <= 2 &&
355 ( p->renderHints() & QPainter::Antialiasing ) )
357 painterState = qgis::make_unique< QgsScopedQPainterState >( p );
358 p->setRenderHint( QPainter::Antialiasing,
false );
361 const bool applyPatternTweaks = mAlignDashPattern
362 && ( pen.style() != Qt::SolidLine || !pen.dashPattern().empty() )
363 && pen.dashOffset() == 0;
367 if ( applyPatternTweaks )
369 drawPathWithDashPatternTweaks( p, points, pen );
375 path.addPolygon( points );
390 for (
const QPolygonF &part : mline )
392 if ( applyPatternTweaks )
394 drawPathWithDashPatternTweaks( p, part, pen );
400 path.addPolygon( part );
411 map[QStringLiteral(
"line_width" )] = QString::number(
mWidth );
417 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
420 map[QStringLiteral(
"use_custom_dash" )] = ( mUseCustomDashPattern ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
424 map[QStringLiteral(
"dash_pattern_offset" )] = QString::number( mDashPatternOffset );
427 map[QStringLiteral(
"draw_inside_polygon" )] = ( mDrawInsidePolygon ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
428 map[QStringLiteral(
"ring_filter" )] = QString::number(
static_cast< int >(
mRingFilter ) );
429 map[QStringLiteral(
"align_dash_pattern" )] = mAlignDashPattern ? QStringLiteral(
"1" ) : QStringLiteral(
"0" );
430 map[QStringLiteral(
"tweak_dash_pattern_on_corners" )] = mPatternCartographicTweakOnSharpCorners ? QStringLiteral(
"1" ) : QStringLiteral(
"0" );
463 if ( mPenStyle == Qt::NoPen )
466 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:LineSymbolizer" ) );
467 if ( !props.value( QStringLiteral(
"uom" ), QString() ).toString().isEmpty() )
468 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ).toString() );
469 element.appendChild( symbolizerElem );
475 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
476 symbolizerElem.appendChild( strokeElem );
478 Qt::PenStyle
penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
487 QDomElement perpOffsetElem = doc.createElement( QStringLiteral(
"se:PerpendicularOffset" ) );
490 symbolizerElem.appendChild( perpOffsetElem );
496 if ( mUseCustomDashPattern )
499 mPen.color(), mPenJoinStyle,
500 mPenCapStyle,
mOffset, &mCustomDashVector );
513 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
514 if ( strokeElem.isNull() )
531 QDomElement perpOffsetElem = element.firstChildElement( QStringLiteral(
"PerpendicularOffset" ) );
532 if ( !perpOffsetElem.isNull() )
535 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
540 QString uom = element.attribute( QStringLiteral(
"uom" ) );
554 void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context, QPen &pen, QPen &selPen,
double &offset )
560 bool hasStrokeWidthExpression =
false;
567 pen.setWidthF( scaledWidth );
568 selPen.setWidthF( scaledWidth );
569 hasStrokeWidthExpression =
true;
578 penColor.setAlphaF( context.
opacity() * penColor.alphaF() );
579 pen.setColor( penColor );
593 const double dashWidthDiv = std::max( hasStrokeWidthExpression ? pen.widthF() : mPen.widthF(), 1.0 );
597 QVector<qreal> dashVector;
599 if ( exprVal.isValid() )
601 QStringList dashList = exprVal.toString().split(
';' );
602 QStringList::const_iterator dashIt = dashList.constBegin();
603 for ( ; dashIt != dashList.constEnd(); ++dashIt )
607 pen.setDashPattern( dashVector );
614 QVector<qreal> scaledVector;
615 for (
double v : mCustomDashVector )
620 mPen.setDashPattern( scaledVector );
624 double patternOffset = mDashPatternOffset;
637 if ( exprVal.isValid() )
646 if ( exprVal.isValid() )
655 if ( exprVal.isValid() )
660 void QgsSimpleLineSymbolLayer::drawPathWithDashPatternTweaks( QPainter *painter,
const QPolygonF &points, QPen pen )
const
662 if ( pen.dashPattern().empty() || points.size() < 2 )
665 QVector< qreal > sourcePattern = pen.dashPattern();
666 const double dashWidthDiv = std::max( 1.0001, pen.widthF() );
668 for (
int i = 0; i < sourcePattern.size(); ++ i )
669 sourcePattern[i] *= pen.widthF();
671 if ( pen.widthF() <= 1.0 )
672 pen.setWidthF( 1.0001 );
674 QVector< qreal > buffer;
675 QPolygonF bufferedPoints;
676 QPolygonF previousSegmentBuffer;
681 auto ptIt = points.constBegin();
682 double totalBufferLength = 0;
683 int patternIndex = 0;
684 double currentRemainingDashLength = 0;
685 double currentRemainingGapLength = 0;
687 auto compressPattern = [](
const QVector< qreal > &buffer ) -> QVector< qreal >
689 QVector< qreal > result;
690 result.reserve( buffer.size() );
691 for (
auto it = buffer.begin(); it != buffer.end(); )
695 while ( dash == 0 && !result.empty() )
697 result.last() += gap;
699 if ( it == buffer.end() )
704 while ( gap == 0 && it != buffer.end() )
709 result << dash << gap;
714 double currentBufferLineLength = 0;
715 auto flushBuffer = [pen, painter, &buffer, &bufferedPoints, &previousSegmentBuffer, ¤tRemainingDashLength, ¤tRemainingGapLength, ¤tBufferLineLength, &totalBufferLength,
716 dashWidthDiv, &compressPattern]( QPointF * nextPoint )
718 if ( buffer.empty() || bufferedPoints.size() < 2 )
723 if ( currentRemainingDashLength )
726 buffer << currentRemainingDashLength << 0.0;
727 totalBufferLength += currentRemainingDashLength;
729 QVector< qreal > compressed = compressPattern( buffer );
730 if ( !currentRemainingDashLength )
733 totalBufferLength -= compressed.last();
734 compressed.last() = 0;
738 const double scaleFactor = currentBufferLineLength / totalBufferLength;
740 bool shouldFlushPreviousSegmentBuffer =
false;
742 if ( !previousSegmentBuffer.empty() )
746 if ( !firstDashSubstring.empty() )
752 compressed = compressed.mid( 2 );
753 shouldFlushPreviousSegmentBuffer = !compressed.empty();
756 if ( !previousSegmentBuffer.empty() && ( shouldFlushPreviousSegmentBuffer || !nextPoint ) )
758 QPen adjustedPen = pen;
759 adjustedPen.setStyle( Qt::SolidLine );
760 painter->setPen( adjustedPen );
762 path.addPolygon( previousSegmentBuffer );
763 painter->drawPath( path );
764 previousSegmentBuffer.clear();
767 double finalDash = 0;
774 if ( !compressed.empty() )
776 finalDash = compressed.at( compressed.size() - 2 );
777 const double finalGap = compressed.size() > 2 ? compressed.at( compressed.size() - 3 ) : 0;
779 const QPolygonF thisPoints = bufferedPoints;
785 previousSegmentBuffer << bufferedPoints;
789 currentBufferLineLength = 0;
790 currentRemainingDashLength = 0;
791 currentRemainingGapLength = 0;
792 totalBufferLength = 0;
795 if ( !bufferedPoints.empty() && ( !compressed.empty() || !nextPoint ) )
797 QPen adjustedPen = pen;
798 if ( !compressed.empty() )
801 compressed = compressed.mid( 0, 32 );
802 std::for_each( compressed.begin(), compressed.end(), [scaleFactor, dashWidthDiv]( qreal & element ) { element *= scaleFactor / dashWidthDiv; } );
803 adjustedPen.setDashPattern( compressed );
807 adjustedPen.setStyle( Qt::SolidLine );
810 painter->setPen( adjustedPen );
812 path.addPolygon( bufferedPoints );
813 painter->drawPath( path );
816 bufferedPoints.clear();
822 bufferedPoints << p2;
823 for ( ; ptIt != points.constEnd(); ++ptIt )
831 double remainingSegmentDistance = std::sqrt( std::pow( p2.x() - p1.x(), 2.0 ) + std::pow( p2.y() - p1.y(), 2.0 ) );
832 currentBufferLineLength += remainingSegmentDistance;
836 if ( currentRemainingDashLength > 0 )
839 if ( remainingSegmentDistance >= currentRemainingDashLength )
842 buffer << currentRemainingDashLength << 0.0;
843 totalBufferLength += currentRemainingDashLength;
844 remainingSegmentDistance -= currentRemainingDashLength;
846 currentRemainingDashLength = 0.0;
847 currentRemainingGapLength = sourcePattern.at( patternIndex );
852 buffer << remainingSegmentDistance << 0.0;
853 totalBufferLength += remainingSegmentDistance;
854 currentRemainingDashLength -= remainingSegmentDistance;
858 if ( currentRemainingGapLength > 0 )
861 if ( remainingSegmentDistance >= currentRemainingGapLength )
864 buffer << 0.0 << currentRemainingGapLength;
865 totalBufferLength += currentRemainingGapLength;
866 remainingSegmentDistance -= currentRemainingGapLength;
867 currentRemainingGapLength = 0.0;
873 buffer << 0.0 << remainingSegmentDistance;
874 totalBufferLength += remainingSegmentDistance;
875 currentRemainingGapLength -= remainingSegmentDistance;
880 if ( patternIndex >= sourcePattern.size() )
883 const double nextPatternDashLength = sourcePattern.at( patternIndex );
884 const double nextPatternGapLength = sourcePattern.at( patternIndex + 1 );
885 if ( nextPatternDashLength + nextPatternGapLength <= remainingSegmentDistance )
887 buffer << nextPatternDashLength << nextPatternGapLength;
888 remainingSegmentDistance -= nextPatternDashLength + nextPatternGapLength;
889 totalBufferLength += nextPatternDashLength + nextPatternGapLength;
892 else if ( nextPatternDashLength <= remainingSegmentDistance )
895 buffer << nextPatternDashLength << remainingSegmentDistance - nextPatternDashLength;
896 totalBufferLength += remainingSegmentDistance;
897 currentRemainingGapLength = nextPatternGapLength - ( remainingSegmentDistance - nextPatternDashLength );
898 currentRemainingDashLength = 0;
905 buffer << remainingSegmentDistance << 0.0;
906 totalBufferLength += remainingSegmentDistance;
907 currentRemainingGapLength = 0;
908 currentRemainingDashLength = nextPatternDashLength - remainingSegmentDistance;
913 bufferedPoints << p1;
914 if ( mPatternCartographicTweakOnSharpCorners && ptIt + 1 != points.constEnd() )
916 QPointF nextPoint = *( ptIt + 1 );
922 flushBuffer( &nextPoint );
923 bufferedPoints << p1;
926 if ( patternIndex % 2 == 1 )
930 currentRemainingDashLength = sourcePattern.at( patternIndex );
937 flushBuffer(
nullptr );
938 if ( !previousSegmentBuffer.empty() )
940 QPen adjustedPen = pen;
941 adjustedPen.setStyle( Qt::SolidLine );
942 painter->setPen( adjustedPen );
944 path.addPolygon( previousSegmentBuffer );
945 painter->drawPath( path );
946 previousSegmentBuffer.clear();
952 if ( mDrawInsidePolygon )
966 unit = mCustomDashPatternUnit;
967 return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
1004 return mPenStyle != Qt::SolidLine || mUseCustomDashPattern;
1009 return mAlignDashPattern;
1019 return mPatternCartographicTweakOnSharpCorners;
1024 mPatternCartographicTweakOnSharpCorners =
enabled;
1053 MyLine( QPointF p1, QPointF p2 )
1054 : mVertical( false )
1055 , mIncreasing( false )
1067 mIncreasing = ( p2.y() > p1.y() );
1072 mT = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
1073 mIncreasing = ( p2.x() > p1.x() );
1077 double x = ( p2.x() - p1.x() );
1078 double y = ( p2.y() - p1.y() );
1079 mLength = std::sqrt( x * x + y * y );
1085 double a = ( mVertical ? M_PI_2 : std::atan( mT ) );
1093 QPointF diffForInterval(
double interval )
1096 return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
1098 double alpha = std::atan( mT );
1099 double dx = std::cos( alpha ) * interval;
1100 double dy = std::sin( alpha ) * interval;
1101 return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
1104 double length() {
return mLength; }
1119 : mRotateSymbols( rotateSymbol )
1120 , mInterval( interval )
1140 if ( exprVal.isValid() )
1142 QString placementString = exprVal.toString();
1143 if ( placementString.compare( QLatin1String(
"interval" ), Qt::CaseInsensitive ) == 0 )
1147 else if ( placementString.compare( QLatin1String(
"vertex" ), Qt::CaseInsensitive ) == 0 )
1151 else if ( placementString.compare( QLatin1String(
"lastvertex" ), Qt::CaseInsensitive ) == 0 )
1155 else if ( placementString.compare( QLatin1String(
"firstvertex" ), Qt::CaseInsensitive ) == 0 )
1159 else if ( placementString.compare( QLatin1String(
"centerpoint" ), Qt::CaseInsensitive ) == 0 )
1163 else if ( placementString.compare( QLatin1String(
"curvepoint" ), Qt::CaseInsensitive ) == 0 )
1167 else if ( placementString.compare( QLatin1String(
"segmentcenter" ), Qt::CaseInsensitive ) == 0 )
1180 double averageOver = mAverageAngleLength;
1193 renderPolylineInterval( points, context, averageOver );
1197 renderPolylineCentral( points, context, averageOver );
1205 renderPolylineVertex( points, context,
placement );
1214 for (
int part = 0; part < mline.count(); ++part )
1216 const QPolygonF &points2 = mline[ part ];
1221 renderPolylineInterval( points2, context, averageOver );
1225 renderPolylineCentral( points2, context, averageOver );
1233 renderPolylineVertex( points2, context,
placement );
1267 for (
int i = 0; i < rings->size(); ++i )
1316 map[QStringLiteral(
"rotate" )] = (
rotateSymbols() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1317 map[QStringLiteral(
"interval" )] = QString::number(
interval() );
1318 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
1319 map[QStringLiteral(
"offset_along_line" )] = QString::number(
offsetAlongLine() );
1326 map[QStringLiteral(
"average_angle_length" )] = QString::number( mAverageAngleLength );
1330 switch ( mPlacement )
1333 map[QStringLiteral(
"placement" )] = QStringLiteral(
"vertex" );
1336 map[QStringLiteral(
"placement" )] = QStringLiteral(
"lastvertex" );
1339 map[QStringLiteral(
"placement" )] = QStringLiteral(
"firstvertex" );
1342 map[QStringLiteral(
"placement" )] = QStringLiteral(
"centralpoint" );
1345 map[QStringLiteral(
"placement" )] = QStringLiteral(
"curvepoint" );
1348 map[QStringLiteral(
"placement" )] = QStringLiteral(
"interval" );
1351 map[QStringLiteral(
"placement" )] = QStringLiteral(
"segmentcenter" );
1355 map[QStringLiteral(
"ring_filter" )] = QString::number(
static_cast< int >(
mRingFilter ) );
1361 switch ( mPlacement )
1399 if (
properties.contains( QStringLiteral(
"offset" ) ) )
1403 if (
properties.contains( QStringLiteral(
"offset_unit" ) ) )
1407 if (
properties.contains( QStringLiteral(
"interval_unit" ) ) )
1411 if (
properties.contains( QStringLiteral(
"offset_along_line" ) ) )
1415 if (
properties.contains( QStringLiteral(
"offset_along_line_unit" ) ) )
1419 if (
properties.contains( ( QStringLiteral(
"offset_along_line_map_unit_scale" ) ) ) )
1424 if (
properties.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
1428 if (
properties.contains( QStringLiteral(
"interval_map_unit_scale" ) ) )
1433 if (
properties.contains( QStringLiteral(
"average_angle_length" ) ) )
1437 if (
properties.contains( QStringLiteral(
"average_angle_unit" ) ) )
1441 if (
properties.contains( ( QStringLiteral(
"average_angle_map_unit_scale" ) ) ) )
1446 if (
properties.contains( QStringLiteral(
"placement" ) ) )
1448 if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"vertex" ) )
1450 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"lastvertex" ) )
1452 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"firstvertex" ) )
1454 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"centralpoint" ) )
1456 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"curvepoint" ) )
1458 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"segmentcenter" ) )
1464 if (
properties.contains( QStringLiteral(
"ring_filter" ) ) )
1472 void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval(
const QPolygonF &points,
QgsSymbolRenderContext &context,
double averageOver )
1474 if ( points.isEmpty() )
1477 double lengthLeft = 0;
1509 if ( painterUnitInterval < 0 )
1520 lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1522 if ( averageOver > 0 && !
qgsDoubleNear( averageOver, 0.0 ) )
1524 QVector< QPointF > angleStartPoints;
1525 QVector< QPointF > symbolPoints;
1526 QVector< QPointF > angleEndPoints;
1534 collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft );
1536 if ( symbolPoints.empty() )
1542 if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1545 symbolPoints.pop_back();
1548 angleEndPoints.reserve( symbolPoints.size() );
1549 angleStartPoints.reserve( symbolPoints.size() );
1550 if ( averageOver <= painterUnitOffsetAlongLine )
1552 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver, 0, symbolPoints.size() );
1556 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1558 collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver, 0, symbolPoints.size() );
1561 for (
int i = 0; i < symbolPoints.size(); ++ i )
1566 const QPointF pt = symbolPoints[i];
1567 const QPointF startPt = angleStartPoints[i];
1568 const QPointF endPt = angleEndPoints[i];
1570 MyLine l( startPt, endPt );
1585 QPointF lastPt = points[0];
1586 for (
int i = 1; i < points.count(); ++i )
1591 const QPointF &pt = points[i];
1597 MyLine l( lastPt, pt );
1598 QPointF diff = l.diffForInterval( painterUnitInterval );
1602 double c = 1 - lengthLeft / painterUnitInterval;
1604 lengthLeft += l.length();
1613 while ( lengthLeft > painterUnitInterval )
1617 lengthLeft -= painterUnitInterval;
1629 static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1632 double a1 = MyLine( prevPt, pt ).angle();
1633 double a2 = MyLine( pt, nextPt ).angle();
1634 double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
1636 return std::atan2( unitY, unitX );
1641 if ( points.isEmpty() )
1647 int i = -1, maxCount = 0;
1648 bool isRing =
false;
1721 i = points.count() - 1;
1722 maxCount = points.count();
1730 maxCount = points.count();
1731 if ( points.first() == points.last() )
1748 renderOffsetVertexAlongLine( points, i, distance, context );
1758 prevPoint = points.at( 0 );
1760 QPointF symbolPoint;
1761 for ( ; i < maxCount; ++i )
1772 QPointF currentPoint = points.at( i );
1773 symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ),
1774 0.5 * ( currentPoint.y() + prevPoint.y() ) );
1777 double angle = std::atan2( currentPoint.y() - prevPoint.y(),
1778 currentPoint.x() - prevPoint.x() );
1781 prevPoint = currentPoint;
1785 symbolPoint = points.at( i );
1789 double angle = markerAngle( points, isRing, i );
1801 double QgsTemplatedLineSymbolLayerBase::markerAngle(
const QPolygonF &points,
bool isRing,
int vertex )
1804 const QPointF &pt = points[vertex];
1806 if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
1808 int prevIndex = vertex - 1;
1809 int nextIndex = vertex + 1;
1811 if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
1813 prevIndex = points.count() - 2;
1817 QPointF prevPoint, nextPoint;
1818 while ( prevIndex >= 0 )
1820 prevPoint = points[ prevIndex ];
1821 if ( prevPoint != pt )
1828 while ( nextIndex < points.count() )
1830 nextPoint = points[ nextIndex ];
1831 if ( nextPoint != pt )
1838 if ( prevIndex >= 0 && nextIndex < points.count() )
1840 angle = _averageAngle( prevPoint, pt, nextPoint );
1847 while ( vertex < points.size() - 1 )
1849 const QPointF &nextPt = points[vertex + 1];
1852 angle = MyLine( pt, nextPt ).angle();
1861 while ( vertex >= 1 )
1863 const QPointF &prevPt = points[vertex - 1];
1866 angle = MyLine( prevPt, pt ).angle();
1876 void QgsTemplatedLineSymbolLayerBase::renderOffsetVertexAlongLine(
const QPolygonF &points,
int vertex,
double distance,
QgsSymbolRenderContext &context )
1878 if ( points.isEmpty() )
1888 bool isRing =
false;
1889 if ( points.first() == points.last() )
1891 double angle = markerAngle( points, isRing, vertex );
1898 int pointIncrement = distance > 0 ? 1 : -1;
1899 QPointF previousPoint = points[vertex];
1900 int startPoint = distance > 0 ? std::min( vertex + 1, points.count() - 1 ) : std::max( vertex - 1, 0 );
1901 int endPoint = distance > 0 ? points.count() - 1 : 0;
1902 double distanceLeft = std::fabs( distance );
1904 for (
int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
1906 const QPointF &pt = points[i];
1908 if ( previousPoint == pt )
1912 MyLine l( previousPoint, pt );
1914 if ( distanceLeft < l.length() )
1917 QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
1927 distanceLeft -= l.length();
1934 void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints(
const QVector<QPointF> &p, QVector<QPointF> &dest,
double intervalPainterUnits,
double initialOffset,
double initialLag,
int numberPointsRequired )
1939 QVector< QPointF > points = p;
1940 const bool closedRing = points.first() == points.last();
1942 double lengthLeft = initialOffset;
1944 double initialLagLeft = initialLag > 0 ? -initialLag : 1;
1945 if ( initialLagLeft < 0 && closedRing )
1948 QPointF lastPt = points.constLast();
1949 QVector< QPointF > pseudoPoints;
1950 for (
int i = points.count() - 2; i > 0; --i )
1952 if ( initialLagLeft >= 0 )
1957 const QPointF &pt = points[i];
1962 MyLine l( lastPt, pt );
1963 initialLagLeft += l.length();
1968 std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
1970 points = pseudoPoints;
1975 while ( initialLagLeft < 0 )
1977 dest << points.constFirst();
1978 initialLagLeft += intervalPainterUnits;
1981 if ( initialLag > 0 )
1983 lengthLeft += intervalPainterUnits - initialLagLeft;
1986 QPointF lastPt = points[0];
1987 for (
int i = 1; i < points.count(); ++i )
1989 const QPointF &pt = points[i];
1993 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2002 MyLine l( lastPt, pt );
2003 QPointF diff = l.diffForInterval( intervalPainterUnits );
2007 double c = 1 - lengthLeft / intervalPainterUnits;
2009 lengthLeft += l.length();
2012 while ( lengthLeft > intervalPainterUnits ||
qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
2016 lengthLeft -= intervalPainterUnits;
2019 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2024 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2028 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2035 if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2038 while ( dest.size() < numberPointsRequired )
2039 dest << points.constLast();
2043 void QgsTemplatedLineSymbolLayerBase::renderPolylineCentral(
const QPolygonF &points,
QgsSymbolRenderContext &context,
double averageAngleOver )
2045 if ( !points.isEmpty() )
2049 QPolygonF::const_iterator it = points.constBegin();
2051 for ( ++it; it != points.constEnd(); ++it )
2053 length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2054 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2060 const double midPoint = length / 2;
2063 double thisSymbolAngle = 0;
2065 if ( averageAngleOver > 0 && !
qgsDoubleNear( averageAngleOver, 0.0 ) )
2067 QVector< QPointF > angleStartPoints;
2068 QVector< QPointF > symbolPoints;
2069 QVector< QPointF > angleEndPoints;
2071 collectOffsetPoints( points, symbolPoints, midPoint, midPoint, 0.0, 2 );
2072 collectOffsetPoints( points, angleStartPoints, midPoint, 0, averageAngleOver, 2 );
2073 collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver, 0, 2 );
2075 pt = symbolPoints.at( 1 );
2076 MyLine l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
2077 thisSymbolAngle = l.angle();
2082 it = points.constBegin();
2084 qreal last_at = 0, next_at = 0;
2087 for ( ++it; it != points.constEnd(); ++it )
2090 next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2091 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2092 if ( next_at >= midPoint )
2100 MyLine l( last, next );
2101 qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
2102 pt = last + ( next - last ) * k;
2103 thisSymbolAngle = l.angle();
2153 if ( props.contains( QStringLiteral(
"interval" ) ) )
2154 interval = props[QStringLiteral(
"interval" )].toDouble();
2155 if ( props.contains( QStringLiteral(
"rotate" ) ) )
2156 rotate = ( props[QStringLiteral(
"rotate" )].toString() == QLatin1String(
"1" ) );
2158 std::unique_ptr< QgsMarkerLineSymbolLayer > x = qgis::make_unique< QgsMarkerLineSymbolLayer >( rotate,
interval );
2165 return QStringLiteral(
"MarkerLine" );
2182 QgsSymbol::RenderHints hints = QgsSymbol::RenderHints();
2185 mMarker->setRenderHints( hints );
2198 std::unique_ptr< QgsMarkerLineSymbolLayer > x = qgis::make_unique< QgsMarkerLineSymbolLayer >(
rotateSymbols(),
interval() );
2205 for (
int i = 0; i <
mMarker->symbolLayerCount(); i++ )
2207 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:LineSymbolizer" ) );
2208 if ( !props.value( QStringLiteral(
"uom" ), QString() ).toString().isEmpty() )
2209 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ).toString() );
2210 element.appendChild( symbolizerElem );
2245 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
2246 symbolizerElem.appendChild( strokeElem );
2249 QDomElement graphicStrokeElem = doc.createElement( QStringLiteral(
"se:GraphicStroke" ) );
2250 strokeElem.appendChild( graphicStrokeElem );
2256 graphicStrokeElem.appendChild( doc.createComment( QStringLiteral(
"MarkerSymbolLayerV2 expected, %1 found. Skip it." ).arg( layer->
layerType() ) ) );
2263 if ( !gap.isEmpty() )
2265 QDomElement gapElem = doc.createElement( QStringLiteral(
"se:Gap" ) );
2267 graphicStrokeElem.appendChild( gapElem );
2272 QDomElement perpOffsetElem = doc.createElement( QStringLiteral(
"se:PerpendicularOffset" ) );
2275 symbolizerElem.appendChild( perpOffsetElem );
2284 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
2285 if ( strokeElem.isNull() )
2288 QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral(
"GraphicStroke" ) );
2289 if ( graphicStrokeElem.isNull() )
2297 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
2299 if ( it.key() == QLatin1String(
"placement" ) )
2301 if ( it.value() == QLatin1String(
"points" ) )
2303 else if ( it.value() == QLatin1String(
"firstPoint" ) )
2305 else if ( it.value() == QLatin1String(
"lastPoint" ) )
2307 else if ( it.value() == QLatin1String(
"centralPoint" ) )
2310 else if ( it.value() == QLatin1String(
"rotateMarker" ) )
2316 std::unique_ptr< QgsMarkerSymbol > marker;
2330 QDomElement gapElem = graphicStrokeElem.firstChildElement( QStringLiteral(
"Gap" ) );
2331 if ( !gapElem.isNull() )
2334 double d = gapElem.firstChild().nodeValue().toDouble( &ok );
2340 QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( QStringLiteral(
"PerpendicularOffset" ) );
2341 if ( !perpOffsetElem.isNull() )
2344 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
2349 QString uom = element.attribute( QStringLiteral(
"uom" ) );
2371 mMarker->setDataDefinedSize( property );
2378 const double prevOpacity =
mMarker->opacity();
2381 mMarker->setOpacity( prevOpacity );
2401 mMarker->renderPoint( point, feature, context, layer, selected );
2411 return mMarker->size( context );
2417 mMarker->setOutputUnit( unit );
2437 attr.unite(
mMarker->usedAttributes( context ) );
2452 return (
mMarker->size( context ) / 2.0 ) +
2472 if ( props.contains( QStringLiteral(
"interval" ) ) )
2473 interval = props[QStringLiteral(
"interval" )].toDouble();
2474 if ( props.contains( QStringLiteral(
"rotate" ) ) )
2475 rotate = ( props[QStringLiteral(
"rotate" )] == QLatin1String(
"1" ) );
2477 std::unique_ptr< QgsHashedLineSymbolLayer > x = qgis::make_unique< QgsHashedLineSymbolLayer >( rotate,
interval );
2479 if ( props.contains( QStringLiteral(
"hash_angle" ) ) )
2481 x->setHashAngle( props[QStringLiteral(
"hash_angle" )].toDouble() );
2484 if ( props.contains( QStringLiteral(
"hash_length" ) ) )
2485 x->setHashLength( props[QStringLiteral(
"hash_length" )].toDouble() );
2487 if ( props.contains( QStringLiteral(
"hash_length_unit" ) ) )
2490 if ( props.contains( QStringLiteral(
"hash_length_map_unit_scale" ) ) )
2498 return QStringLiteral(
"HashLine" );
2504 QgsSymbol::RenderHints hints = QgsSymbol::RenderHints();
2507 mHashSymbol->setRenderHints( hints );
2520 map[ QStringLiteral(
"hash_angle" ) ] = QString::number( mHashAngle );
2522 map[QStringLiteral(
"hash_length" )] = QString::number( mHashLength );
2531 std::unique_ptr< QgsHashedLineSymbolLayer > x = qgis::make_unique< QgsHashedLineSymbolLayer >(
rotateSymbols(),
interval() );
2533 x->setHashAngle( mHashAngle );
2534 x->setHashLength( mHashLength );
2535 x->setHashLengthUnit( mHashLengthUnit );
2536 x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2542 mHashSymbol->setColor(
color );
2548 return mHashSymbol ? mHashSymbol->color() :
mColor;
2553 return mHashSymbol.get();
2564 mHashSymbol.reset(
static_cast<QgsLineSymbol *
>( symbol ) );
2565 mColor = mHashSymbol->color();
2571 mHashLength =
width;
2586 return ( mHashSymbol->width( context ) / 2.0 )
2594 mHashSymbol->setOutputUnit( unit );
2604 attr.unite( mHashSymbol->usedAttributes( context ) );
2612 if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
2621 mHashSymbol->setDataDefinedWidth( property );
2634 || ( mHashSymbol && mHashSymbol->usesMapUnits() );
2639 mSymbolLineAngle =
angle;
2644 return mSymbolAngle;
2649 mSymbolAngle =
angle;
2654 double lineLength = mHashLength;
2660 const double w = context.
convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
2674 points << QPointF( start.
x(), start.
y() ) << QPointF( end.
x(), end.
y() );
2677 mHashSymbol->renderPolyline( points, feature, context, layer, selected );
2692 const double prevOpacity = mHashSymbol->opacity();
2693 mHashSymbol->setOpacity( mHashSymbol->opacity() * context.
opacity() );
2695 mHashSymbol->setOpacity( prevOpacity );
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.
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
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.
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.
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.
virtual void writeSldMarker(QDomDocument &doc, QDomElement &element, const QVariantMap &props) const
Writes the symbol layer definition as a SLD XML element.
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.
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 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.
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...
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.
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
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 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.
@ PropertyLineAngle
Line angle, or angle of hash lines for hash line symbols.
@ 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.
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.
virtual bool setSubSymbol(QgsSymbol *symbol)
Sets layer's subsymbol. takes ownership of the passed symbol.
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.
SymbolType type() const
Returns the symbol's type.
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
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.
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.
virtual double symbolAngle() const =0
Returns the symbol's current angle, in degrees clockwise.
virtual void setSymbolAngle(double angle)=0
Sets the symbol's angle, in degrees clockwise.
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.
@ 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)
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.