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;
423 if ( !pen.dashPattern().isEmpty() )
426 const QVector<double> pattern = pen.dashPattern();
427 bool foundNonNull =
false;
428 for (
int i = 0; i < pattern.size(); ++i )
440 p->setBrush( Qt::NoBrush );
443 std::unique_ptr< QgsScopedQPainterState > painterState;
444 if ( points.size() <= 2 &&
447 ( p->renderHints() & QPainter::Antialiasing ) )
449 painterState = std::make_unique< QgsScopedQPainterState >( p );
450 p->setRenderHint( QPainter::Antialiasing,
false );
453 const bool applyPatternTweaks = mAlignDashPattern
454 && ( pen.style() != Qt::SolidLine || !pen.dashPattern().empty() )
455 && pen.dashOffset() == 0;
459 if ( applyPatternTweaks )
461 drawPathWithDashPatternTweaks( p, points, pen );
467 path.addPolygon( points );
482 for (
const QPolygonF &part : mline )
484 if ( applyPatternTweaks )
486 drawPathWithDashPatternTweaks( p, part, pen );
492 path.addPolygon( part );
503 map[QStringLiteral(
"line_width" )] = QString::number(
mWidth );
509 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
512 map[QStringLiteral(
"use_custom_dash" )] = ( mUseCustomDashPattern ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
516 map[QStringLiteral(
"dash_pattern_offset" )] = QString::number( mDashPatternOffset );
519 map[QStringLiteral(
"trim_distance_start" )] = QString::number( mTrimDistanceStart );
522 map[QStringLiteral(
"trim_distance_end" )] = QString::number( mTrimDistanceEnd );
525 map[QStringLiteral(
"draw_inside_polygon" )] = ( mDrawInsidePolygon ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
526 map[QStringLiteral(
"ring_filter" )] = QString::number(
static_cast< int >(
mRingFilter ) );
527 map[QStringLiteral(
"align_dash_pattern" )] = mAlignDashPattern ? QStringLiteral(
"1" ) : QStringLiteral(
"0" );
528 map[QStringLiteral(
"tweak_dash_pattern_on_corners" )] = mPatternCartographicTweakOnSharpCorners ? QStringLiteral(
"1" ) : QStringLiteral(
"0" );
567 if ( mPenStyle == Qt::NoPen )
570 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:LineSymbolizer" ) );
571 if ( !props.value( QStringLiteral(
"uom" ), QString() ).toString().isEmpty() )
572 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ).toString() );
573 element.appendChild( symbolizerElem );
579 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
580 symbolizerElem.appendChild( strokeElem );
582 Qt::PenStyle
penStyle = mUseCustomDashPattern ? Qt::CustomDashLine : mPenStyle;
591 QDomElement perpOffsetElem = doc.createElement( QStringLiteral(
"se:PerpendicularOffset" ) );
594 symbolizerElem.appendChild( perpOffsetElem );
600 if ( mUseCustomDashPattern )
603 mPen.color(), mPenJoinStyle,
604 mPenCapStyle,
mOffset, &mCustomDashVector );
617 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
618 if ( strokeElem.isNull() )
635 QDomElement perpOffsetElem = element.firstChildElement( QStringLiteral(
"PerpendicularOffset" ) );
636 if ( !perpOffsetElem.isNull() )
639 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
644 QString uom = element.attribute( QStringLiteral(
"uom" ) );
658 void QgsSimpleLineSymbolLayer::applyDataDefinedSymbology(
QgsSymbolRenderContext &context, QPen &pen, QPen &selPen,
double &offset )
664 bool hasStrokeWidthExpression =
false;
671 pen.setWidthF( scaledWidth );
672 selPen.setWidthF( scaledWidth );
673 hasStrokeWidthExpression =
true;
682 penColor.setAlphaF( context.
opacity() * penColor.alphaF() );
683 pen.setColor( penColor );
697 const double dashWidthDiv = std::max( hasStrokeWidthExpression ? pen.widthF() : mPen.widthF(), 1.0 );
701 QVector<qreal> dashVector;
703 if ( !exprVal.isNull() )
705 QStringList dashList = exprVal.toString().split(
';' );
706 QStringList::const_iterator dashIt = dashList.constBegin();
707 for ( ; dashIt != dashList.constEnd(); ++dashIt )
711 pen.setDashPattern( dashVector );
718 QVector<qreal> scaledVector;
719 for (
double v : std::as_const( mCustomDashVector ) )
724 mPen.setDashPattern( scaledVector );
728 double patternOffset = mDashPatternOffset;
741 if ( !exprVal.isNull() )
750 if ( !exprVal.isNull() )
759 if ( !exprVal.isNull() )
764 void QgsSimpleLineSymbolLayer::drawPathWithDashPatternTweaks( QPainter *painter,
const QPolygonF &points, QPen pen )
const
766 if ( pen.dashPattern().empty() || points.size() < 2 )
769 QVector< qreal > sourcePattern = pen.dashPattern();
770 const double dashWidthDiv = std::max( 1.0001, pen.widthF() );
772 for (
int i = 0; i < sourcePattern.size(); ++ i )
773 sourcePattern[i] *= pen.widthF();
775 if ( pen.widthF() <= 1.0 )
776 pen.setWidthF( 1.0001 );
778 QVector< qreal > buffer;
779 QPolygonF bufferedPoints;
780 QPolygonF previousSegmentBuffer;
785 auto ptIt = points.constBegin();
786 double totalBufferLength = 0;
787 int patternIndex = 0;
788 double currentRemainingDashLength = 0;
789 double currentRemainingGapLength = 0;
791 auto compressPattern = [](
const QVector< qreal > &buffer ) -> QVector< qreal >
793 QVector< qreal > result;
794 result.reserve( buffer.size() );
795 for (
auto it = buffer.begin(); it != buffer.end(); )
799 while ( dash == 0 && !result.empty() )
801 result.last() += gap;
803 if ( it == buffer.end() )
808 while ( gap == 0 && it != buffer.end() )
813 result << dash << gap;
818 double currentBufferLineLength = 0;
819 auto flushBuffer = [pen, painter, &buffer, &bufferedPoints, &previousSegmentBuffer, ¤tRemainingDashLength, ¤tRemainingGapLength, ¤tBufferLineLength, &totalBufferLength,
820 dashWidthDiv, &compressPattern]( QPointF * nextPoint )
822 if ( buffer.empty() || bufferedPoints.size() < 2 )
827 if ( currentRemainingDashLength )
830 buffer << currentRemainingDashLength << 0.0;
831 totalBufferLength += currentRemainingDashLength;
833 QVector< qreal > compressed = compressPattern( buffer );
834 if ( !currentRemainingDashLength )
837 totalBufferLength -= compressed.last();
838 compressed.last() = 0;
842 const double scaleFactor = currentBufferLineLength / totalBufferLength;
844 bool shouldFlushPreviousSegmentBuffer =
false;
846 if ( !previousSegmentBuffer.empty() )
850 if ( !firstDashSubstring.empty() )
856 compressed = compressed.mid( 2 );
857 shouldFlushPreviousSegmentBuffer = !compressed.empty();
860 if ( !previousSegmentBuffer.empty() && ( shouldFlushPreviousSegmentBuffer || !nextPoint ) )
862 QPen adjustedPen = pen;
863 adjustedPen.setStyle( Qt::SolidLine );
864 painter->setPen( adjustedPen );
866 path.addPolygon( previousSegmentBuffer );
867 painter->drawPath( path );
868 previousSegmentBuffer.clear();
871 double finalDash = 0;
878 if ( !compressed.empty() )
880 finalDash = compressed.at( compressed.size() - 2 );
881 const double finalGap = compressed.size() > 2 ? compressed.at( compressed.size() - 3 ) : 0;
883 const QPolygonF thisPoints = bufferedPoints;
889 previousSegmentBuffer << bufferedPoints;
893 currentBufferLineLength = 0;
894 currentRemainingDashLength = 0;
895 currentRemainingGapLength = 0;
896 totalBufferLength = 0;
899 if ( !bufferedPoints.empty() && ( !compressed.empty() || !nextPoint ) )
901 QPen adjustedPen = pen;
902 if ( !compressed.empty() )
905 compressed = compressed.mid( 0, 32 );
906 std::for_each( compressed.begin(), compressed.end(), [scaleFactor, dashWidthDiv]( qreal & element ) { element *= scaleFactor / dashWidthDiv; } );
907 adjustedPen.setDashPattern( compressed );
911 adjustedPen.setStyle( Qt::SolidLine );
914 painter->setPen( adjustedPen );
916 path.addPolygon( bufferedPoints );
917 painter->drawPath( path );
920 bufferedPoints.clear();
926 bufferedPoints << p2;
927 for ( ; ptIt != points.constEnd(); ++ptIt )
935 double remainingSegmentDistance = std::sqrt( std::pow( p2.x() - p1.x(), 2.0 ) + std::pow( p2.y() - p1.y(), 2.0 ) );
936 currentBufferLineLength += remainingSegmentDistance;
940 if ( currentRemainingDashLength > 0 )
943 if ( remainingSegmentDistance >= currentRemainingDashLength )
946 buffer << currentRemainingDashLength << 0.0;
947 totalBufferLength += currentRemainingDashLength;
948 remainingSegmentDistance -= currentRemainingDashLength;
950 currentRemainingDashLength = 0.0;
951 currentRemainingGapLength = sourcePattern.at( patternIndex );
956 buffer << remainingSegmentDistance << 0.0;
957 totalBufferLength += remainingSegmentDistance;
958 currentRemainingDashLength -= remainingSegmentDistance;
962 if ( currentRemainingGapLength > 0 )
965 if ( remainingSegmentDistance >= currentRemainingGapLength )
968 buffer << 0.0 << currentRemainingGapLength;
969 totalBufferLength += currentRemainingGapLength;
970 remainingSegmentDistance -= currentRemainingGapLength;
971 currentRemainingGapLength = 0.0;
977 buffer << 0.0 << remainingSegmentDistance;
978 totalBufferLength += remainingSegmentDistance;
979 currentRemainingGapLength -= remainingSegmentDistance;
984 if ( patternIndex >= sourcePattern.size() )
987 const double nextPatternDashLength = sourcePattern.at( patternIndex );
988 const double nextPatternGapLength = sourcePattern.at( patternIndex + 1 );
989 if ( nextPatternDashLength + nextPatternGapLength <= remainingSegmentDistance )
991 buffer << nextPatternDashLength << nextPatternGapLength;
992 remainingSegmentDistance -= nextPatternDashLength + nextPatternGapLength;
993 totalBufferLength += nextPatternDashLength + nextPatternGapLength;
996 else if ( nextPatternDashLength <= remainingSegmentDistance )
999 buffer << nextPatternDashLength << remainingSegmentDistance - nextPatternDashLength;
1000 totalBufferLength += remainingSegmentDistance;
1001 currentRemainingGapLength = nextPatternGapLength - ( remainingSegmentDistance - nextPatternDashLength );
1002 currentRemainingDashLength = 0;
1009 buffer << remainingSegmentDistance << 0.0;
1010 totalBufferLength += remainingSegmentDistance;
1011 currentRemainingGapLength = 0;
1012 currentRemainingDashLength = nextPatternDashLength - remainingSegmentDistance;
1017 bufferedPoints << p1;
1018 if ( mPatternCartographicTweakOnSharpCorners && ptIt + 1 != points.constEnd() )
1020 QPointF nextPoint = *( ptIt + 1 );
1026 flushBuffer( &nextPoint );
1027 bufferedPoints << p1;
1030 if ( patternIndex % 2 == 1 )
1034 currentRemainingDashLength = sourcePattern.at( patternIndex );
1041 flushBuffer(
nullptr );
1042 if ( !previousSegmentBuffer.empty() )
1044 QPen adjustedPen = pen;
1045 adjustedPen.setStyle( Qt::SolidLine );
1046 painter->setPen( adjustedPen );
1048 path.addPolygon( previousSegmentBuffer );
1049 painter->drawPath( path );
1050 previousSegmentBuffer.clear();
1056 if ( mDrawInsidePolygon )
1070 unit = mCustomDashPatternUnit;
1071 return mUseCustomDashPattern ? mCustomDashVector : QVector<qreal>();
1108 return mPenStyle != Qt::SolidLine || mUseCustomDashPattern;
1113 return mAlignDashPattern;
1123 return mPatternCartographicTweakOnSharpCorners;
1128 mPatternCartographicTweakOnSharpCorners =
enabled;
1157 MyLine( QPointF p1, QPointF p2 )
1158 : mVertical( false )
1159 , mIncreasing( false )
1171 mIncreasing = ( p2.y() > p1.y() );
1176 mT = ( p2.y() - p1.y() ) / ( p2.x() - p1.x() );
1177 mIncreasing = ( p2.x() > p1.x() );
1181 double x = ( p2.x() - p1.x() );
1182 double y = ( p2.y() - p1.y() );
1183 mLength = std::sqrt( x * x + y * y );
1189 double a = ( mVertical ? M_PI_2 : std::atan( mT ) );
1197 QPointF diffForInterval(
double interval )
1200 return ( mIncreasing ? QPointF( 0, interval ) : QPointF( 0, -interval ) );
1202 double alpha = std::atan( mT );
1203 double dx = std::cos( alpha ) * interval;
1204 double dy = std::sin( alpha ) * interval;
1205 return ( mIncreasing ? QPointF( dx, dy ) : QPointF( -dx, -dy ) );
1208 double length() {
return mLength; }
1223 : mRotateSymbols( rotateSymbol )
1224 , mInterval( interval )
1246 if ( !exprVal.isNull() )
1248 QString placementString = exprVal.toString();
1249 if ( placementString.compare( QLatin1String(
"interval" ), Qt::CaseInsensitive ) == 0 )
1253 else if ( placementString.compare( QLatin1String(
"vertex" ), Qt::CaseInsensitive ) == 0 )
1257 else if ( placementString.compare( QLatin1String(
"lastvertex" ), Qt::CaseInsensitive ) == 0 )
1261 else if ( placementString.compare( QLatin1String(
"firstvertex" ), Qt::CaseInsensitive ) == 0 )
1265 else if ( placementString.compare( QLatin1String(
"centerpoint" ), Qt::CaseInsensitive ) == 0 )
1269 else if ( placementString.compare( QLatin1String(
"curvepoint" ), Qt::CaseInsensitive ) == 0 )
1273 else if ( placementString.compare( QLatin1String(
"segmentcenter" ), Qt::CaseInsensitive ) == 0 )
1286 double averageOver = mAverageAngleLength;
1299 renderPolylineInterval( points, context, averageOver );
1303 renderPolylineCentral( points, context, averageOver );
1311 renderPolylineVertex( points, context,
placement );
1320 for (
int part = 0; part < mline.count(); ++part )
1322 const QPolygonF &points2 = mline[ part ];
1327 renderPolylineInterval( points2, context, averageOver );
1331 renderPolylineCentral( points2, context, averageOver );
1339 renderPolylineVertex( points2, context,
placement );
1356 std::unique_ptr< QgsExpressionContextScopePopper > scopePopper;
1386 for (
int i = 0; i < rings->size(); ++i )
1438 map[QStringLiteral(
"rotate" )] = (
rotateSymbols() ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
1439 map[QStringLiteral(
"interval" )] = QString::number(
interval() );
1440 map[QStringLiteral(
"offset" )] = QString::number(
mOffset );
1441 map[QStringLiteral(
"offset_along_line" )] = QString::number(
offsetAlongLine() );
1448 map[QStringLiteral(
"average_angle_length" )] = QString::number( mAverageAngleLength );
1452 switch ( mPlacement )
1455 map[QStringLiteral(
"placement" )] = QStringLiteral(
"vertex" );
1458 map[QStringLiteral(
"placement" )] = QStringLiteral(
"lastvertex" );
1461 map[QStringLiteral(
"placement" )] = QStringLiteral(
"firstvertex" );
1464 map[QStringLiteral(
"placement" )] = QStringLiteral(
"centralpoint" );
1467 map[QStringLiteral(
"placement" )] = QStringLiteral(
"curvepoint" );
1470 map[QStringLiteral(
"placement" )] = QStringLiteral(
"interval" );
1473 map[QStringLiteral(
"placement" )] = QStringLiteral(
"segmentcenter" );
1477 map[QStringLiteral(
"ring_filter" )] = QString::number(
static_cast< int >(
mRingFilter ) );
1483 switch ( mPlacement )
1521 if (
properties.contains( QStringLiteral(
"offset" ) ) )
1525 if (
properties.contains( QStringLiteral(
"offset_unit" ) ) )
1529 if (
properties.contains( QStringLiteral(
"interval_unit" ) ) )
1533 if (
properties.contains( QStringLiteral(
"offset_along_line" ) ) )
1537 if (
properties.contains( QStringLiteral(
"offset_along_line_unit" ) ) )
1541 if (
properties.contains( ( QStringLiteral(
"offset_along_line_map_unit_scale" ) ) ) )
1546 if (
properties.contains( QStringLiteral(
"offset_map_unit_scale" ) ) )
1550 if (
properties.contains( QStringLiteral(
"interval_map_unit_scale" ) ) )
1555 if (
properties.contains( QStringLiteral(
"average_angle_length" ) ) )
1559 if (
properties.contains( QStringLiteral(
"average_angle_unit" ) ) )
1563 if (
properties.contains( ( QStringLiteral(
"average_angle_map_unit_scale" ) ) ) )
1568 if (
properties.contains( QStringLiteral(
"placement" ) ) )
1570 if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"vertex" ) )
1572 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"lastvertex" ) )
1574 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"firstvertex" ) )
1576 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"centralpoint" ) )
1578 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"curvepoint" ) )
1580 else if (
properties[QStringLiteral(
"placement" )] == QLatin1String(
"segmentcenter" ) )
1586 if (
properties.contains( QStringLiteral(
"ring_filter" ) ) )
1594 void QgsTemplatedLineSymbolLayerBase::renderPolylineInterval(
const QPolygonF &points,
QgsSymbolRenderContext &context,
double averageOver )
1596 if ( points.isEmpty() )
1599 double lengthLeft = 0;
1631 if ( painterUnitInterval < 0 )
1642 lengthLeft = painterUnitInterval - painterUnitOffsetAlongLine;
1644 if ( averageOver > 0 && !
qgsDoubleNear( averageOver, 0.0 ) )
1646 QVector< QPointF > angleStartPoints;
1647 QVector< QPointF > symbolPoints;
1648 QVector< QPointF > angleEndPoints;
1656 collectOffsetPoints( points, symbolPoints, painterUnitInterval, lengthLeft );
1658 if ( symbolPoints.empty() )
1664 if ( symbolPoints.count() > 1 && symbolPoints.constFirst() == symbolPoints.constLast() )
1667 symbolPoints.pop_back();
1670 angleEndPoints.reserve( symbolPoints.size() );
1671 angleStartPoints.reserve( symbolPoints.size() );
1672 if ( averageOver <= painterUnitOffsetAlongLine )
1674 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, lengthLeft + averageOver, 0, symbolPoints.size() );
1678 collectOffsetPoints( points, angleStartPoints, painterUnitInterval, 0, averageOver - painterUnitOffsetAlongLine, symbolPoints.size() );
1680 collectOffsetPoints( points, angleEndPoints, painterUnitInterval, lengthLeft - averageOver, 0, symbolPoints.size() );
1683 for (
int i = 0; i < symbolPoints.size(); ++ i )
1688 const QPointF pt = symbolPoints[i];
1689 const QPointF startPt = angleStartPoints[i];
1690 const QPointF endPt = angleEndPoints[i];
1692 MyLine l( startPt, endPt );
1707 QPointF lastPt = points[0];
1708 for (
int i = 1; i < points.count(); ++i )
1713 const QPointF &pt = points[i];
1719 MyLine l( lastPt, pt );
1720 QPointF diff = l.diffForInterval( painterUnitInterval );
1724 double c = 1 - lengthLeft / painterUnitInterval;
1726 lengthLeft += l.length();
1735 while ( lengthLeft > painterUnitInterval )
1739 lengthLeft -= painterUnitInterval;
1751 static double _averageAngle( QPointF prevPt, QPointF pt, QPointF nextPt )
1754 double a1 = MyLine( prevPt, pt ).angle();
1755 double a2 = MyLine( pt, nextPt ).angle();
1756 double unitX = std::cos( a1 ) + std::cos( a2 ), unitY = std::sin( a1 ) + std::sin( a2 );
1758 return std::atan2( unitY, unitX );
1763 if ( points.isEmpty() )
1768 int i = -1, maxCount = 0;
1769 bool isRing =
false;
1842 i = points.count() - 1;
1843 maxCount = points.count();
1851 maxCount = points.count();
1852 if ( points.first() == points.last() )
1869 renderOffsetVertexAlongLine( points, i, distance, context );
1877 prevPoint = points.at( 0 );
1879 QPointF symbolPoint;
1880 for ( ; i < maxCount; ++i )
1891 QPointF currentPoint = points.at( i );
1892 symbolPoint = QPointF( 0.5 * ( currentPoint.x() + prevPoint.x() ),
1893 0.5 * ( currentPoint.y() + prevPoint.y() ) );
1896 double angle = std::atan2( currentPoint.y() - prevPoint.y(),
1897 currentPoint.x() - prevPoint.x() );
1900 prevPoint = currentPoint;
1904 symbolPoint = points.at( i );
1908 double angle = markerAngle( points, isRing, i );
1917 double QgsTemplatedLineSymbolLayerBase::markerAngle(
const QPolygonF &points,
bool isRing,
int vertex )
1920 const QPointF &pt = points[vertex];
1922 if ( isRing || ( vertex > 0 && vertex < points.count() - 1 ) )
1924 int prevIndex = vertex - 1;
1925 int nextIndex = vertex + 1;
1927 if ( isRing && ( vertex == 0 || vertex == points.count() - 1 ) )
1929 prevIndex = points.count() - 2;
1933 QPointF prevPoint, nextPoint;
1934 while ( prevIndex >= 0 )
1936 prevPoint = points[ prevIndex ];
1937 if ( prevPoint != pt )
1944 while ( nextIndex < points.count() )
1946 nextPoint = points[ nextIndex ];
1947 if ( nextPoint != pt )
1954 if ( prevIndex >= 0 && nextIndex < points.count() )
1956 angle = _averageAngle( prevPoint, pt, nextPoint );
1963 while ( vertex < points.size() - 1 )
1965 const QPointF &nextPt = points[vertex + 1];
1968 angle = MyLine( pt, nextPt ).angle();
1977 while ( vertex >= 1 )
1979 const QPointF &prevPt = points[vertex - 1];
1982 angle = MyLine( prevPt, pt ).angle();
1992 void QgsTemplatedLineSymbolLayerBase::renderOffsetVertexAlongLine(
const QPolygonF &points,
int vertex,
double distance,
QgsSymbolRenderContext &context )
1994 if ( points.isEmpty() )
2003 bool isRing =
false;
2004 if ( points.first() == points.last() )
2006 double angle = markerAngle( points, isRing, vertex );
2013 int pointIncrement = distance > 0 ? 1 : -1;
2014 QPointF previousPoint = points[vertex];
2015 int startPoint = distance > 0 ? std::min( vertex + 1,
static_cast<int>( points.count() ) - 1 ) : std::max( vertex - 1, 0 );
2016 int endPoint = distance > 0 ? points.count() - 1 : 0;
2017 double distanceLeft = std::fabs( distance );
2019 for (
int i = startPoint; pointIncrement > 0 ? i <= endPoint : i >= endPoint; i += pointIncrement )
2021 const QPointF &pt = points[i];
2023 if ( previousPoint == pt )
2027 MyLine l( previousPoint, pt );
2029 if ( distanceLeft < l.length() )
2032 QPointF markerPoint = previousPoint + l.diffForInterval( distanceLeft );
2042 distanceLeft -= l.length();
2049 void QgsTemplatedLineSymbolLayerBase::collectOffsetPoints(
const QVector<QPointF> &p, QVector<QPointF> &dest,
double intervalPainterUnits,
double initialOffset,
double initialLag,
int numberPointsRequired )
2054 QVector< QPointF > points = p;
2055 const bool closedRing = points.first() == points.last();
2057 double lengthLeft = initialOffset;
2059 double initialLagLeft = initialLag > 0 ? -initialLag : 1;
2060 if ( initialLagLeft < 0 && closedRing )
2063 QPointF lastPt = points.constLast();
2064 QVector< QPointF > pseudoPoints;
2065 for (
int i = points.count() - 2; i > 0; --i )
2067 if ( initialLagLeft >= 0 )
2072 const QPointF &pt = points[i];
2077 MyLine l( lastPt, pt );
2078 initialLagLeft += l.length();
2083 std::reverse( pseudoPoints.begin(), pseudoPoints.end() );
2085 points = pseudoPoints;
2090 while ( initialLagLeft < 0 )
2092 dest << points.constFirst();
2093 initialLagLeft += intervalPainterUnits;
2096 if ( initialLag > 0 )
2098 lengthLeft += intervalPainterUnits - initialLagLeft;
2101 QPointF lastPt = points[0];
2102 for (
int i = 1; i < points.count(); ++i )
2104 const QPointF &pt = points[i];
2108 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2117 MyLine l( lastPt, pt );
2118 QPointF diff = l.diffForInterval( intervalPainterUnits );
2122 double c = 1 - lengthLeft / intervalPainterUnits;
2124 lengthLeft += l.length();
2127 while ( lengthLeft > intervalPainterUnits ||
qgsDoubleNear( lengthLeft, intervalPainterUnits, 0.000000001 ) )
2131 lengthLeft -= intervalPainterUnits;
2134 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2139 if ( numberPointsRequired > 0 && dest.size() >= numberPointsRequired )
2143 if ( closedRing && i == points.count() - 1 && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2150 if ( !closedRing && numberPointsRequired > 0 && dest.size() < numberPointsRequired )
2153 while ( dest.size() < numberPointsRequired )
2154 dest << points.constLast();
2158 void QgsTemplatedLineSymbolLayerBase::renderPolylineCentral(
const QPolygonF &points,
QgsSymbolRenderContext &context,
double averageAngleOver )
2160 if ( !points.isEmpty() )
2164 QPolygonF::const_iterator it = points.constBegin();
2166 for ( ++it; it != points.constEnd(); ++it )
2168 length += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2169 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2175 const double midPoint = length / 2;
2178 double thisSymbolAngle = 0;
2180 if ( averageAngleOver > 0 && !
qgsDoubleNear( averageAngleOver, 0.0 ) )
2182 QVector< QPointF > angleStartPoints;
2183 QVector< QPointF > symbolPoints;
2184 QVector< QPointF > angleEndPoints;
2186 collectOffsetPoints( points, symbolPoints, midPoint, midPoint, 0.0, 2 );
2187 collectOffsetPoints( points, angleStartPoints, midPoint, 0, averageAngleOver, 2 );
2188 collectOffsetPoints( points, angleEndPoints, midPoint, midPoint - averageAngleOver, 0, 2 );
2190 pt = symbolPoints.at( 1 );
2191 MyLine l( angleStartPoints.at( 1 ), angleEndPoints.at( 1 ) );
2192 thisSymbolAngle = l.angle();
2197 it = points.constBegin();
2199 qreal last_at = 0, next_at = 0;
2202 for ( ++it; it != points.constEnd(); ++it )
2205 next_at += std::sqrt( ( last.x() - it->x() ) * ( last.x() - it->x() ) +
2206 ( last.y() - it->y() ) * ( last.y() - it->y() ) );
2207 if ( next_at >= midPoint )
2215 MyLine l( last, next );
2216 qreal k = ( length * 0.5 - last_at ) / ( next_at - last_at );
2217 pt = last + ( next - last ) * k;
2218 thisSymbolAngle = l.angle();
2270 if ( props.contains( QStringLiteral(
"interval" ) ) )
2271 interval = props[QStringLiteral(
"interval" )].toDouble();
2272 if ( props.contains( QStringLiteral(
"rotate" ) ) )
2273 rotate = ( props[QStringLiteral(
"rotate" )].toString() == QLatin1String(
"1" ) );
2275 std::unique_ptr< QgsMarkerLineSymbolLayer > x = std::make_unique< QgsMarkerLineSymbolLayer >( rotate,
interval );
2282 return QStringLiteral(
"MarkerLine" );
2299 Qgis::SymbolRenderHints hints = Qgis::SymbolRenderHints();
2302 mMarker->setRenderHints( hints );
2315 std::unique_ptr< QgsMarkerLineSymbolLayer > x = std::make_unique< QgsMarkerLineSymbolLayer >(
rotateSymbols(),
interval() );
2322 for (
int i = 0; i <
mMarker->symbolLayerCount(); i++ )
2324 QDomElement symbolizerElem = doc.createElement( QStringLiteral(
"se:LineSymbolizer" ) );
2325 if ( !props.value( QStringLiteral(
"uom" ), QString() ).toString().isEmpty() )
2326 symbolizerElem.setAttribute( QStringLiteral(
"uom" ), props.value( QStringLiteral(
"uom" ), QString() ).toString() );
2327 element.appendChild( symbolizerElem );
2362 QDomElement strokeElem = doc.createElement( QStringLiteral(
"se:Stroke" ) );
2363 symbolizerElem.appendChild( strokeElem );
2366 QDomElement graphicStrokeElem = doc.createElement( QStringLiteral(
"se:GraphicStroke" ) );
2367 strokeElem.appendChild( graphicStrokeElem );
2372 markerLayer->writeSldMarker( doc, graphicStrokeElem, props );
2376 graphicStrokeElem.appendChild( doc.createComment( QStringLiteral(
"QgsMarkerSymbolLayer expected, %1 found. Skip it." ).arg( layer->
layerType() ) ) );
2380 graphicStrokeElem.appendChild( doc.createComment( QStringLiteral(
"Missing marker line symbol layer. Skip it." ) ) );
2383 if ( !gap.isEmpty() )
2385 QDomElement gapElem = doc.createElement( QStringLiteral(
"se:Gap" ) );
2387 graphicStrokeElem.appendChild( gapElem );
2392 QDomElement perpOffsetElem = doc.createElement( QStringLiteral(
"se:PerpendicularOffset" ) );
2395 symbolizerElem.appendChild( perpOffsetElem );
2404 QDomElement strokeElem = element.firstChildElement( QStringLiteral(
"Stroke" ) );
2405 if ( strokeElem.isNull() )
2408 QDomElement graphicStrokeElem = strokeElem.firstChildElement( QStringLiteral(
"GraphicStroke" ) );
2409 if ( graphicStrokeElem.isNull() )
2417 for ( QgsStringMap::iterator it = vendorOptions.begin(); it != vendorOptions.end(); ++it )
2419 if ( it.key() == QLatin1String(
"placement" ) )
2421 if ( it.value() == QLatin1String(
"points" ) )
2423 else if ( it.value() == QLatin1String(
"firstPoint" ) )
2425 else if ( it.value() == QLatin1String(
"lastPoint" ) )
2427 else if ( it.value() == QLatin1String(
"centralPoint" ) )
2430 else if ( it.value() == QLatin1String(
"rotateMarker" ) )
2436 std::unique_ptr< QgsMarkerSymbol > marker;
2450 QDomElement gapElem = graphicStrokeElem.firstChildElement( QStringLiteral(
"Gap" ) );
2451 if ( !gapElem.isNull() )
2454 double d = gapElem.firstChild().nodeValue().toDouble( &ok );
2460 QDomElement perpOffsetElem = graphicStrokeElem.firstChildElement( QStringLiteral(
"PerpendicularOffset" ) );
2461 if ( !perpOffsetElem.isNull() )
2464 double d = perpOffsetElem.firstChild().nodeValue().toDouble( &ok );
2469 QString uom = element.attribute( QStringLiteral(
"uom" ) );
2491 mMarker->setDataDefinedSize( property );
2498 const double prevOpacity =
mMarker->opacity();
2501 mMarker->setOpacity( prevOpacity );
2524 mMarker->renderPoint( point, feature, context, layer, selected );
2536 return mMarker->size( context );
2542 mMarker->setOutputUnit( unit );
2562 attr.unite(
mMarker->usedAttributes( context ) );
2577 return (
mMarker->size( context ) / 2.0 ) +
2599 if ( props.contains( QStringLiteral(
"interval" ) ) )
2600 interval = props[QStringLiteral(
"interval" )].toDouble();
2601 if ( props.contains( QStringLiteral(
"rotate" ) ) )
2602 rotate = ( props[QStringLiteral(
"rotate" )] == QLatin1String(
"1" ) );
2604 std::unique_ptr< QgsHashedLineSymbolLayer > x = std::make_unique< QgsHashedLineSymbolLayer >( rotate,
interval );
2606 if ( props.contains( QStringLiteral(
"hash_angle" ) ) )
2608 x->setHashAngle( props[QStringLiteral(
"hash_angle" )].toDouble() );
2611 if ( props.contains( QStringLiteral(
"hash_length" ) ) )
2612 x->setHashLength( props[QStringLiteral(
"hash_length" )].toDouble() );
2614 if ( props.contains( QStringLiteral(
"hash_length_unit" ) ) )
2617 if ( props.contains( QStringLiteral(
"hash_length_map_unit_scale" ) ) )
2625 return QStringLiteral(
"HashLine" );
2631 Qgis::SymbolRenderHints hints = Qgis::SymbolRenderHints();
2634 mHashSymbol->setRenderHints( hints );
2647 map[ QStringLiteral(
"hash_angle" ) ] = QString::number( mHashAngle );
2649 map[QStringLiteral(
"hash_length" )] = QString::number( mHashLength );
2658 std::unique_ptr< QgsHashedLineSymbolLayer > x = std::make_unique< QgsHashedLineSymbolLayer >(
rotateSymbols(),
interval() );
2660 x->setHashAngle( mHashAngle );
2661 x->setHashLength( mHashLength );
2662 x->setHashLengthUnit( mHashLengthUnit );
2663 x->setHashLengthMapUnitScale( mHashLengthMapUnitScale );
2669 mHashSymbol->setColor(
color );
2675 return mHashSymbol ? mHashSymbol->color() :
mColor;
2680 return mHashSymbol.get();
2691 mHashSymbol.reset(
static_cast<QgsLineSymbol *
>( symbol ) );
2692 mColor = mHashSymbol->color();
2698 mHashLength =
width;
2713 return ( mHashSymbol->width( context ) / 2.0 )
2721 mHashSymbol->setOutputUnit( unit );
2731 attr.unite( mHashSymbol->usedAttributes( context ) );
2739 if ( mHashSymbol && mHashSymbol->hasDataDefinedProperties() )
2748 mHashSymbol->setDataDefinedWidth( property );
2761 || ( mHashSymbol && mHashSymbol->usesMapUnits() );
2766 mSymbolLineAngle =
angle;
2771 return mSymbolAngle;
2776 mSymbolAngle =
angle;
2781 double lineLength = mHashLength;
2787 const double w = context.
convertToPainterUnits( lineLength, mHashLengthUnit, mHashLengthMapUnitScale ) / 2.0;
2801 points << QPointF( start.
x(), start.
y() ) << QPointF( end.
x(), end.
y() );
2806 mHashSymbol->renderPolyline( points, feature, context, layer, selected );
2823 const double prevOpacity = mHashSymbol->opacity();
2824 mHashSymbol->setOpacity( mHashSymbol->opacity() * context.
opacity() );
2826 mHashSymbol->setOpacity( prevOpacity );
@ DynamicRotation
Rotation of symbol may be changed during rendering and symbol should not be cached.
@ RenderingSubSymbol
Set whenever a sub-symbol of a parent symbol is currently being rendered. Can be used during symbol a...
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
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 the 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...
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale(), Qgis::RenderSubcomponentProperty property=Qgis::RenderSubcomponentProperty::Generic) const
Converts a size from the specified units to painter units (pixels).
void setGeometry(const QgsAbstractGeometry *geometry)
Sets pointer to original (unsegmentized) geometry.
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
QColor selectionColor() const
Returns the color to use when rendering selected features.
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
const 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.
Qgis::VertexType type
Vertex type.