32 mSymbol.reset( static_cast<QgsFillSymbol *>( symbol ) );
43 if ( props.contains( QStringLiteral(
"arrow_width" ) ) )
44 l->
setArrowWidth( props[QStringLiteral(
"arrow_width" )].toDouble() );
46 if ( props.contains( QStringLiteral(
"arrow_width_unit" ) ) )
49 if ( props.contains( QStringLiteral(
"arrow_width_unit_scale" ) ) )
52 if ( props.contains( QStringLiteral(
"arrow_start_width" ) ) )
55 if ( props.contains( QStringLiteral(
"arrow_start_width_unit" ) ) )
58 if ( props.contains( QStringLiteral(
"arrow_start_width_unit_scale" ) ) )
61 if ( props.contains( QStringLiteral(
"is_curved" ) ) )
62 l->
setIsCurved( props[QStringLiteral(
"is_curved" )].toInt() == 1 );
64 if ( props.contains( QStringLiteral(
"is_repeated" ) ) )
65 l->
setIsRepeated( props[QStringLiteral(
"is_repeated" )].toInt() == 1 );
67 if ( props.contains( QStringLiteral(
"head_length" ) ) )
68 l->
setHeadLength( props[QStringLiteral(
"head_length" )].toDouble() );
70 if ( props.contains( QStringLiteral(
"head_length_unit" ) ) )
73 if ( props.contains( QStringLiteral(
"head_length_unit_scale" ) ) )
76 if ( props.contains( QStringLiteral(
"head_thickness" ) ) )
79 if ( props.contains( QStringLiteral(
"head_thickness_unit" ) ) )
82 if ( props.contains( QStringLiteral(
"head_thickness_unit_scale" ) ) )
85 if ( props.contains( QStringLiteral(
"head_type" ) ) )
86 l->
setHeadType( static_cast<HeadType>( props[QStringLiteral(
"head_type" )].toInt() ) );
88 if ( props.contains( QStringLiteral(
"arrow_type" ) ) )
89 l->
setArrowType( static_cast<ArrowType>( props[QStringLiteral(
"arrow_type" )].toInt() ) );
91 if ( props.contains( QStringLiteral(
"offset" ) ) )
92 l->
setOffset( props[QStringLiteral(
"offset" )].toDouble() );
94 if ( props.contains( QStringLiteral(
"offset_unit" ) ) )
97 if ( props.contains( QStringLiteral(
"offset_unit_scale" ) ) )
118 return QStringLiteral(
"ArrowLine" );
125 map[QStringLiteral(
"arrow_width" )] = QString::number(
arrowWidth() );
129 map[QStringLiteral(
"arrow_start_width" )] = QString::number(
arrowStartWidth() );
133 map[QStringLiteral(
"is_curved" )] = QString::number(
isCurved() ? 1 : 0 );
134 map[QStringLiteral(
"is_repeated" )] = QString::number(
isRepeated() ? 1 : 0 );
136 map[QStringLiteral(
"head_length" )] = QString::number(
headLength() );
140 map[QStringLiteral(
"head_thickness" )] = QString::number(
headThickness() );
144 map[QStringLiteral(
"head_type" )] = QString::number(
headType() );
145 map[QStringLiteral(
"arrow_type" )] = QString::number(
arrowType() );
147 map[QStringLiteral(
"offset" )] = QString::number(
offset() );
158 attributes.unite( mSymbol->usedAttributes( context ) );
185 return std::sqrt( ( po.x() - pd.x() ) * ( po.x() - pd.x() ) + ( po.y() - pd.y() ) * ( po.y() - pd.y() ) );
189 qreal startWidth, qreal
width,
190 qreal headWidth, qreal headHeight,
201 po = pd - ( pd - po ) / length * headWidth;
206 pd = po + ( pd - po ) / length * headWidth;
211 QPointF v = ( pd - po ) / length * headWidth;
212 QPointF npo = ( po + pd ) / 2.0 - v;
213 QPointF npd = ( po + pd ) / 2.0 + v;
216 length = 2 * headWidth;
219 qreal bodyLength = length - headWidth;
222 QPointF unitVec = ( pd - po ) / length;
224 QPointF perpVec( -unitVec.y(), unitVec.x() );
236 polygon << po + unitVec *headWidth + perpVec *headHeight;
237 polygon << po + unitVec *headWidth + perpVec * ( width * 0.5 );
239 polygon << po + unitVec *bodyLength + perpVec * ( width * 0.5 );
242 polygon << po + unitVec *bodyLength + perpVec *headHeight;
248 polygon << po + unitVec *bodyLength - perpVec *headHeight;
249 polygon << po + unitVec *bodyLength - perpVec * ( width * 0.5 );
252 polygon << po + unitVec *headWidth - perpVec * ( width * 0.5 );
253 polygon << po + unitVec *headWidth - perpVec *headHeight;
260 polygon << po + perpVec * ( startWidth * 0.5 );
261 polygon << po + unitVec *bodyLength + perpVec * ( width * 0.5 );
262 polygon << po + unitVec *bodyLength + perpVec *headHeight;
271 polygon << po + unitVec *bodyLength - perpVec *headHeight;
272 polygon << po + unitVec *bodyLength - perpVec * ( width * 0.5 );
273 polygon << po - perpVec * ( startWidth * 0.5 );
285 polygon << po + unitVec *headWidth + perpVec *headHeight;
286 polygon << po + unitVec *headWidth + perpVec * ( width * 0.5 );
288 polygon << pd + perpVec * ( startWidth * 0.5 );
296 polygon << pd - perpVec * ( startWidth * 0.5 );
298 polygon << po + unitVec *headWidth - perpVec * ( width * 0.5 );
299 polygon << po + unitVec *headWidth - perpVec *headHeight;
307 polygon << polygon.first();
326 bool pointsToCircle( QPointF a, QPointF b, QPointF
c, QPointF ¢er, qreal &radius )
335 QPointF ab2 = ( a + b ) / 2.0;
336 QPointF bc2 = ( b +
c ) / 2.0;
339 if ( std::fabs( ab.x() * bc.y() - ab.y() * bc.x() ) < 0.001 )
346 cy = bc2.y() - ( cx - bc2.x() ) * bc.x() / bc.y();
349 else if ( bc.y() == 0 )
352 cy = ab2.y() - ( cx - ab2.x() ) * ab.x() / ab.y();
357 cx = ( bc2.y() - ab2.y() + bc.x() * bc2.x() / bc.y() - ab.x() * ab2.x() / ab.y() ) / ( bc.x() / bc.y() - ab.x() / ab.y() );
358 cy = bc2.y() - ( cx - bc2.x() ) * bc.x() / bc.y();
361 radius = std::sqrt( ( a.x() - cx ) * ( a.x() - cx ) + ( a.y() - cy ) * ( a.y() - cy ) );
371 return QPointF( std::cos( -angle ) * radius + center.x(), std::sin( -angle ) * radius + center.y() );
374 void pathArcTo( QPainterPath &path, QPointF circleCenter, qreal circleRadius, qreal angle_o, qreal angle_d,
int direction )
376 QRectF circleRect( circleCenter - QPointF( circleRadius, circleRadius ), circleCenter + QPointF( circleRadius, circleRadius ) );
377 if ( direction == 1 )
379 if ( angle_o < angle_d )
380 path.arcTo( circleRect, angle_o / M_PI * 180.0, ( angle_d - angle_o ) / M_PI * 180.0 );
382 path.arcTo( circleRect, angle_o / M_PI * 180.0, 360.0 - ( angle_o - angle_d ) / M_PI * 180.0 );
386 if ( angle_o < angle_d )
387 path.arcTo( circleRect, angle_o / M_PI * 180.0, - ( 360.0 - ( angle_d - angle_o ) / M_PI * 180.0 ) );
389 path.arcTo( circleRect, angle_o / M_PI * 180.0, ( angle_d - angle_o ) / M_PI * 180.0 );
394 void spiralArcTo( QPainterPath &path, QPointF center, qreal startAngle, qreal startRadius, qreal endAngle, qreal endRadius,
int direction )
397 QPointF A =
circlePoint( center, startRadius, startAngle );
399 QPointF B =
circlePoint( center, endRadius, endAngle );
403 deltaAngle = endAngle - startAngle;
404 if ( direction * deltaAngle < 0.0 )
405 deltaAngle = deltaAngle + direction * 2 * M_PI;
407 QPointF I1 =
circlePoint( center, 0.75 * startRadius + 0.25 * endRadius, startAngle + 0.25 * deltaAngle );
408 QPointF I2 =
circlePoint( center, 0.50 * startRadius + 0.50 * endRadius, startAngle + 0.50 * deltaAngle );
409 QPointF I3 =
circlePoint( center, 0.25 * startRadius + 0.75 * endRadius, startAngle + 0.75 * deltaAngle );
422 qreal a1 = std::atan2( cCenter.y() - A.y(), A.x() - cCenter.x() );
423 qreal a2 = std::atan2( cCenter.y() - I2.y(), I2.x() - cCenter.x() );
424 pathArcTo( path, cCenter, cRadius, a1, a2, direction );
436 qreal a1 = std::atan2( cCenter.y() - I2.y(), I2.x() - cCenter.x() );
437 qreal a2 = std::atan2( cCenter.y() - B.y(), B.x() - cCenter.x() );
438 pathArcTo( path, cCenter, cRadius, a1, a2, direction );
443 qreal startWidth, qreal
width,
444 qreal headWidth, qreal headHeight,
449 QPointF circleCenter;
453 return straightArrow( po, pd, startWidth, width, headWidth, headHeight, headType, arrowType, offset );
457 qreal angle_o =
clampAngle( std::atan2( circleCenter.y() - po.y(), po.x() - circleCenter.x() ) );
458 qreal angle_m =
clampAngle( std::atan2( circleCenter.y() - pm.y(), pm.x() - circleCenter.x() ) );
459 qreal angle_d =
clampAngle( std::atan2( circleCenter.y() - pd.y(), pd.x() - circleCenter.x() ) );
471 qreal deltaAngle = angle_d - angle_o;
472 if ( direction * deltaAngle < 0.0 )
473 deltaAngle = deltaAngle + direction * 2 * M_PI;
481 return straightArrow( po, pd, startWidth, width, headWidth, headHeight, headType, arrowType, offset );
486 po =
circlePoint( circleCenter, circleRadius, angle_o );
487 pm =
circlePoint( circleCenter, circleRadius, angle_m );
488 pd =
circlePoint( circleCenter, circleRadius, angle_d );
490 qreal headAngle = direction * std::atan( headWidth / circleRadius );
500 path.lineTo(
circlePoint( circleCenter, circleRadius + direction * headHeight, angle_o + headAngle ) );
502 pathArcTo( path, circleCenter, circleRadius + direction * width / 2, angle_o + headAngle, angle_d - headAngle, direction );
505 path.lineTo(
circlePoint( circleCenter, circleRadius + direction * headHeight, angle_d - headAngle ) );
510 pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
514 path.lineTo(
circlePoint( circleCenter, circleRadius - direction * headHeight, angle_d - headAngle ) );
516 pathArcTo( path, circleCenter, circleRadius - direction * width / 2, angle_d - headAngle, angle_o + headAngle, -direction );
519 path.lineTo(
circlePoint( circleCenter, circleRadius - direction * headHeight, angle_o + headAngle ) );
524 pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
531 path.moveTo(
circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
533 spiralArcTo( path, circleCenter, angle_o, circleRadius + direction * startWidth / 2, angle_d - headAngle, circleRadius + direction * width / 2, direction );
536 path.lineTo(
circlePoint( circleCenter, circleRadius + direction * headHeight, angle_d - headAngle ) );
542 pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
546 path.lineTo(
circlePoint( circleCenter, circleRadius - direction * headHeight, angle_d - headAngle ) );
548 spiralArcTo( path, circleCenter, angle_d - headAngle, circleRadius - direction * width / 2, angle_o, circleRadius - direction * startWidth / 2, -direction );
550 path.lineTo(
circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
554 pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
555 path.lineTo(
circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
563 path.lineTo(
circlePoint( circleCenter, circleRadius + direction * headHeight, angle_o + headAngle ) );
564 path.lineTo(
circlePoint( circleCenter, circleRadius + direction * width / 2, angle_o + headAngle ) );
566 spiralArcTo( path, circleCenter, angle_o + headAngle, circleRadius + direction * width / 2, angle_d, circleRadius + direction * startWidth / 2, direction );
570 pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
574 path.lineTo(
circlePoint( circleCenter, circleRadius - direction * startWidth / 2, angle_d ) );
576 spiralArcTo( path, circleCenter, angle_d, circleRadius - direction * startWidth / 2, angle_o + headAngle, circleRadius - direction * width / 2, - direction );
578 path.lineTo(
circlePoint( circleCenter, circleRadius - direction * headHeight, angle_o + headAngle ) );
584 pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
588 return path.toSubpathPolygons().at( 0 );
601 double w = exprVal.toDouble( &ok );
611 double w = exprVal.toDouble( &ok );
621 double w = exprVal.toDouble( &ok );
631 double w = exprVal.toDouble( &ok );
641 double w = exprVal.toDouble( &ok );
655 mComputedHeadType = h;
666 mComputedArrowType = h;
685 _resolveDataDefined( context );
689 if ( points.size() >= 3 )
692 QPointF po( points.at( 0 ) );
694 QPointF pm( points.at( points.size() / 2 ) );
696 QPointF pd( points.back() );
698 QPolygonF poly =
curvedArrow( po, pm, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
702 else if ( points.size() == 2 )
705 QPointF po( points.at( 0 ) );
707 QPointF pd( points.at( 1 ) );
709 QPolygonF poly =
straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
715 for (
int pIdx = 0; pIdx < points.size() - 1; pIdx += 2 )
718 _resolveDataDefined( context );
720 if ( points.size() - pIdx >= 3 )
723 QPointF po( points.at( pIdx ) );
725 QPointF pm( points.at( pIdx + 1 ) );
727 QPointF pd( points.at( pIdx + 2 ) );
729 QPolygonF poly =
curvedArrow( po, pm, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
733 else if ( points.size() - pIdx == 2 )
736 QPointF po( points.at( pIdx ) );
738 QPointF pd( points.at( pIdx + 1 ) );
740 QPolygonF poly =
straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
750 _resolveDataDefined( context );
752 if ( !points.isEmpty() )
755 QPointF po( points.at( 0 ) );
757 QPointF pd( points.back() );
759 QPolygonF poly =
straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
766 for (
int pIdx = 0; pIdx < points.size() - 1; pIdx++ )
769 _resolveDataDefined( context );
772 QPointF po( points.at( pIdx ) );
774 QPointF pd( points.at( pIdx + 1 ) );
776 QPolygonF poly =
straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
787 mSymbol->setColor( c );
794 return mSymbol.get() ? mSymbol->color() :
mColor;
void setHeadThicknessUnitScale(const QgsMapUnitScale &scale)
Sets the scale for the head height.
void setHeadLengthUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the head length.
void stopRender(QgsSymbolRenderContext &context) override
Single variable definition for use within a QgsExpressionContextScope.
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
QgsUnitTypes::RenderUnit headThicknessUnit() const
Gets the unit for the head height.
static QgsArrowSymbolLayer::ArrowType decodeArrowType(const QVariant &value, bool *ok=nullptr)
Decodes a value representing an arrow type.
double arrowStartWidth() const
Gets current arrow start width. Only meaningful for single headed arrows.
double arrowWidth() const
Gets current arrow width.
void setArrowWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the arrow width.
const QgsMapUnitScale & offsetMapUnitScale() const
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
static QgsFillSymbol * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
QPolygonF straightArrow(QPointF po, QPointF pd, qreal startWidth, qreal width, qreal headWidth, qreal headHeight, QgsArrowSymbolLayer::HeadType headType, QgsArrowSymbolLayer::ArrowType arrowType, qreal offset)
QgsMapUnitScale arrowStartWidthUnitScale() const
Gets the scale for the arrow start width.
QgsMapUnitScale headLengthUnitScale() const
Gets the scale for the head length.
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
QString layerType() const override
Returns a string that represents this layer type.
void pathArcTo(QPainterPath &path, QPointF circleCenter, qreal circleRadius, qreal angle_o, qreal angle_d, int direction)
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
void setHeadThicknessUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the head height.
void restoreOldDataDefinedProperties(const QgsStringMap &stringMap)
Restores older data defined properties from string map.
void setColor(const QColor &c) override
The fill color.
qreal clampAngle(qreal a)
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units for the line's offset.
QPolygonF curvedArrow(QPointF po, QPointF pm, QPointF pd, qreal startWidth, qreal width, qreal headWidth, qreal headHeight, QgsArrowSymbolLayer::HeadType headType, QgsArrowSymbolLayer::ArrowType arrowType, qreal offset)
ArrowType arrowType() const
Gets the current arrow type.
static QgsArrowSymbolLayer::HeadType decodeArrowHeadType(const QVariant &value, bool *ok=nullptr)
Decodes a value representing an arrow head type.
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
QMap< QString, QString > QgsStringMap
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)
virtual double width() const
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
QPointF circlePoint(QPointF center, qreal radius, qreal angle)
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
bool isRepeated() const
Returns whether the arrow is repeated along the line or not.
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...
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
bool pointsToCircle(QPointF a, QPointF b, QPointF c, QPointF ¢er, qreal &radius)
Compute the circumscribed circle from three points.
QgsArrowSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
void setHeadLength(double length)
Sets the arrow head length.
void setHeadThickness(double thickness)
Sets the arrow head height.
QgsUnitTypes::RenderUnit arrowStartWidthUnit() const
Gets the unit for the arrow start width.
void spiralArcTo(QPainterPath &path, QPointF center, qreal startAngle, qreal startRadius, qreal endAngle, qreal endRadius, int direction)
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides...
void setArrowWidth(double width)
Sets the arrow width.
ArrowType
Possible arrow types.
bool isCurved() const
Returns whether it is a curved arrow or a straight one.
qreal euclidian_distance(QPointF po, QPointF pd)
double headLength() const
Gets the current arrow head length.
void setIsRepeated(bool isRepeated)
Sets whether the arrow is repeated along the line.
QgsArrowSymbolLayer()
Simple constructor.
QgsMapUnitScale arrowWidthUnitScale() const
Gets the scale for the arrow width.
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
Single scope for storing variables and functions for use within a QgsExpressionContext.
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsUnitTypes::RenderUnit arrowWidthUnit() const
Gets the unit for the arrow width.
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void setIsCurved(bool isCurved)
Sets whether it is a curved arrow or a straight one.
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
Contains information about the context of a rendering operation.
double convertToPainterUnits(double size, QgsUnitTypes::RenderUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale()) const
Converts a size from the specified units to painter units (pixels).
QPainter * painter()
Returns the destination QPainter for the render operation.
void setHeadLengthUnitScale(const QgsMapUnitScale &scale)
Sets the scale for the head length.
void setArrowType(ArrowType type)
Sets the arrow type.
void setArrowWidthUnitScale(const QgsMapUnitScale &scale)
Sets the scale for the arrow width.
QgsUnitTypes::RenderUnit headLengthUnit() const
Gets the unit for the head length.
void setHeadType(HeadType type)
Sets the head type.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
const QgsFeature * feature() const
Current feature being rendered - may be null.
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the line's offset.
static QgsSymbolLayer * create(const QgsStringMap &properties=QgsStringMap())
Create a new QgsArrowSymbolLayer.
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
QColor color() const override
The fill color.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QgsMapUnitScale headThicknessUnitScale() const
Gets the scale for the head height.
Line symbol layer used for representing lines as arrows.
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
HeadType
Possible head types.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
void setArrowStartWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the arrow start width.
HeadType headType() const
Gets the current head type.
QgsPropertyCollection mDataDefinedProperties
void setArrowStartWidth(double width)
Sets the arrow start width.
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
void setArrowStartWidthUnitScale(const QgsMapUnitScale &scale)
Sets the scale for the arrow start width.
void setOffset(double offset)
void startRender(QgsSymbolRenderContext &context) override
double headThickness() const
Gets the current arrow head height.