22 , mArrowStartWidth( 1.0 )
26 , mHeadThickness( 1.5 )
28 , mHeadType( HeadSingle )
29 , mArrowType( ArrowPlain )
32 , mScaledArrowWidth( 1.0 )
33 , mScaledArrowStartWidth( 1.0 )
34 , mScaledHeadLength( 1.5 )
35 , mScaledHeadThickness( 1.5 )
36 , mScaledOffset( 0.0 )
37 , mComputedHeadType( HeadSingle )
38 , mComputedArrowType( ArrowPlain )
51 mSymbol.
reset( static_cast<QgsFillSymbolV2*>( symbol ) );
62 if ( props.
contains(
"arrow_width" ) )
65 if ( props.
contains(
"arrow_width_unit" ) )
68 if ( props.
contains(
"arrow_width_unit_scale" ) )
71 if ( props.
contains(
"arrow_start_width" ) )
74 if ( props.
contains(
"arrow_start_width_unit" ) )
77 if ( props.
contains(
"arrow_start_width_unit_scale" ) )
83 if ( props.
contains(
"is_repeated" ) )
86 if ( props.
contains(
"head_length" ) )
89 if ( props.
contains(
"head_length_unit" ) )
92 if ( props.
contains(
"head_length_unit_scale" ) )
95 if ( props.
contains(
"head_thickness" ) )
98 if ( props.
contains(
"head_thickness_unit" ) )
101 if ( props.
contains(
"head_thickness_unit_scale" ) )
104 if ( props.
contains(
"head_type" ) )
105 l->
setHeadType( static_cast<HeadType>( props[
"head_type"].toInt() ) );
107 if ( props.
contains(
"arrow_type" ) )
108 l->
setArrowType( static_cast<ArrowType>( props[
"arrow_type"].toInt() ) );
111 l->
setOffset( props[
"offset"].toDouble() );
113 if ( props.
contains(
"offset_unit" ) )
116 if ( props.
contains(
"offset_unit_scale" ) )
178 attributes.
unite( mSymbol->usedAttributes() );
205 return sqrt(( po.
x() - pd.
x() ) * ( po.
x() - pd.
x() ) + ( po.
y() - pd.
y() ) * ( po.
y() - pd.
y() ) );
209 qreal startWidth, qreal
width,
210 qreal headWidth, qreal headHeight,
221 po = pd - ( pd - po ) / length * headWidth;
226 pd = po + ( pd - po ) / length * headWidth;
231 QPointF v = ( pd - po ) / length * headWidth;
232 QPointF npo = ( po + pd ) / 2.0 - v;
233 QPointF npd = ( po + pd ) / 2.0 + v;
236 length = 2 * headWidth;
239 qreal bodyLength = length - headWidth;
242 QPointF unitVec = ( pd - po ) / length;
244 QPointF perpVec( -unitVec.
y(), unitVec.
x() );
256 polygon << po + unitVec * headWidth + perpVec * headHeight;
257 polygon << po + unitVec * headWidth + perpVec * ( width * 0.5 );
259 polygon << po + unitVec * bodyLength + perpVec * ( width * 0.5 );
262 polygon << po + unitVec * bodyLength + perpVec * headHeight;
268 polygon << po + unitVec * bodyLength - perpVec * headHeight;
269 polygon << po + unitVec * bodyLength - perpVec * ( width * 0.5 );
272 polygon << po + unitVec * headWidth - perpVec * ( width * 0.5 );
273 polygon << po + unitVec * headWidth - perpVec * headHeight;
280 polygon << po + perpVec * ( startWidth * 0.5 );
281 polygon << po + unitVec * bodyLength + perpVec * ( width * 0.5 );
282 polygon << po + unitVec * bodyLength + perpVec * headHeight;
291 polygon << po + unitVec * bodyLength - perpVec * headHeight;
292 polygon << po + unitVec * bodyLength - perpVec * ( width * 0.5 );
293 polygon << po - perpVec * ( startWidth * 0.5 );
305 polygon << po + unitVec * headWidth + perpVec * headHeight;
306 polygon << po + unitVec * headWidth + perpVec * ( width * 0.5 );
308 polygon << pd + perpVec * ( startWidth * 0.5 );
316 polygon << pd - perpVec * ( startWidth * 0.5 );
318 polygon << po + unitVec * headWidth - perpVec * ( width * 0.5 );
319 polygon << po + unitVec * headWidth - perpVec * headHeight;
327 polygon << polygon.
first();
359 if ( fabs( ab.
x() * bc.
y() - ab.
y() * bc.
x() ) < 0.001 )
366 cy = bc2.
y() - ( cx - bc2.
x() ) * bc.
x() / bc.
y();
369 else if ( bc.
y() == 0 )
372 cy = ab2.
y() - ( cx - ab2.
x() ) * ab.
x() / ab.
y();
377 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() );
378 cy = bc2.
y() - ( cx - bc2.
x() ) * bc.
x() / bc.
y();
381 radius = sqrt(( a.x() - cx ) * ( a.x() - cx ) + ( a.y() - cy ) * ( a.y() - cy ) );
391 return QPointF( cos( -angle ) * radius + center.
x(), sin( -angle ) * radius + center.
y() );
396 QRectF circleRect( circleCenter -
QPointF( circleRadius, circleRadius ), circleCenter +
QPointF( circleRadius, circleRadius ) );
397 if ( direction == 1 )
399 if ( angle_o < angle_d )
400 path.
arcTo( circleRect, angle_o /
M_PI * 180.0, ( angle_d - angle_o ) /
M_PI * 180.0 );
402 path.
arcTo( circleRect, angle_o /
M_PI * 180.0, 360.0 - ( angle_o - angle_d ) /
M_PI * 180.0 );
406 if ( angle_o < angle_d )
407 path.
arcTo( circleRect, angle_o /
M_PI * 180.0, - ( 360.0 - ( angle_d - angle_o ) /
M_PI * 180.0 ) );
409 path.
arcTo( circleRect, angle_o /
M_PI * 180.0, ( angle_d - angle_o ) /
M_PI * 180.0 );
423 deltaAngle = endAngle - startAngle;
424 if ( direction * deltaAngle < 0.0 )
425 deltaAngle = deltaAngle + direction * 2 *
M_PI;
427 QPointF I1 =
circlePoint( center, 0.75 * startRadius + 0.25 * endRadius, startAngle + 0.25 * deltaAngle );
428 QPointF I2 =
circlePoint( center, 0.50 * startRadius + 0.50 * endRadius, startAngle + 0.50 * deltaAngle );
429 QPointF I3 =
circlePoint( center, 0.25 * startRadius + 0.75 * endRadius, startAngle + 0.75 * deltaAngle );
442 qreal a1 = atan2( cCenter.
y() - A.
y(), A.
x() - cCenter.
x() );
443 qreal a2 = atan2( cCenter.
y() - I2.
y(), I2.
x() - cCenter.
x() );
444 pathArcTo( path, cCenter, cRadius, a1, a2, direction );
456 qreal a1 = atan2( cCenter.
y() - I2.
y(), I2.
x() - cCenter.
x() );
457 qreal a2 = atan2( cCenter.
y() - B.
y(), B.
x() - cCenter.
x() );
458 pathArcTo( path, cCenter, cRadius, a1, a2, direction );
463 qreal startWidth, qreal
width,
464 qreal headWidth, qreal headHeight,
473 return straightArrow( po, pd, startWidth, width, headWidth, headHeight, headType, arrowType, offset );
477 qreal angle_o =
clampAngle( atan2( circleCenter.
y() - po.
y(), po.
x() - circleCenter.
x() ) );
478 qreal angle_m =
clampAngle( atan2( circleCenter.
y() - pm.
y(), pm.
x() - circleCenter.
x() ) );
479 qreal angle_d =
clampAngle( atan2( circleCenter.
y() - pd.
y(), pd.
x() - circleCenter.
x() ) );
491 qreal deltaAngle = angle_d - angle_o;
492 if ( direction * deltaAngle < 0.0 )
493 deltaAngle = deltaAngle + direction * 2 *
M_PI;
501 return straightArrow( po, pd, startWidth, width, headWidth, headHeight, headType, arrowType, offset );
506 po =
circlePoint( circleCenter, circleRadius, angle_o );
507 pm =
circlePoint( circleCenter, circleRadius, angle_m );
508 pd =
circlePoint( circleCenter, circleRadius, angle_d );
510 qreal headAngle = direction * atan( headWidth / circleRadius );
520 path.
lineTo(
circlePoint( circleCenter, circleRadius + direction * headHeight, angle_o + headAngle ) );
522 pathArcTo( path, circleCenter, circleRadius + direction * width / 2, angle_o + headAngle, angle_d - headAngle, direction );
525 path.
lineTo(
circlePoint( circleCenter, circleRadius + direction * headHeight, angle_d - headAngle ) );
530 pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
534 path.
lineTo(
circlePoint( circleCenter, circleRadius - direction * headHeight, angle_d - headAngle ) );
536 pathArcTo( path, circleCenter, circleRadius - direction * width / 2, angle_d - headAngle, angle_o + headAngle, -direction );
539 path.
lineTo(
circlePoint( circleCenter, circleRadius - direction * headHeight, angle_o + headAngle ) );
544 pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
551 path.
moveTo(
circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
553 spiralArcTo( path, circleCenter, angle_o, circleRadius + direction * startWidth / 2, angle_d - headAngle, circleRadius + direction * width / 2, direction );
556 path.
lineTo(
circlePoint( circleCenter, circleRadius + direction * headHeight, angle_d - headAngle ) );
562 pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
566 path.
lineTo(
circlePoint( circleCenter, circleRadius - direction * headHeight, angle_d - headAngle ) );
568 spiralArcTo( path, circleCenter, angle_d - headAngle, circleRadius - direction * width / 2, angle_o, circleRadius - direction * startWidth / 2, -direction );
570 path.
lineTo(
circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
574 pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
575 path.
lineTo(
circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
583 path.
lineTo(
circlePoint( circleCenter, circleRadius + direction * headHeight, angle_o + headAngle ) );
584 path.
lineTo(
circlePoint( circleCenter, circleRadius + direction * width / 2, angle_o + headAngle ) );
586 spiralArcTo( path, circleCenter, angle_o + headAngle, circleRadius + direction * width / 2, angle_d, circleRadius + direction * startWidth / 2, direction );
590 pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
594 path.
lineTo(
circlePoint( circleCenter, circleRadius - direction * startWidth / 2, angle_d ) );
596 spiralArcTo( path, circleCenter, angle_d, circleRadius - direction * startWidth / 2, angle_o + headAngle, circleRadius - direction * width / 2, - direction );
598 path.
lineTo(
circlePoint( circleCenter, circleRadius - direction * headHeight, angle_o + headAngle ) );
604 pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
669 mComputedHeadType =
static_cast<HeadType>( h );
679 mComputedArrowType =
static_cast<ArrowType>( h );
698 _resolveDataDefined( context );
702 if ( points.
size() >= 3 )
711 QPolygonF poly =
curvedArrow( po, pm, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
715 else if ( points.
size() == 2 )
722 QPolygonF poly =
straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
728 for (
int pIdx = 0; pIdx < points.
size() - 1; pIdx += 2 )
731 _resolveDataDefined( context );
733 if ( points.
size() - pIdx >= 3 )
742 QPolygonF poly =
curvedArrow( po, pm, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
746 else if ( points.
size() - pIdx == 2 )
753 QPolygonF poly =
straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
763 _resolveDataDefined( context );
772 QPolygonF poly =
straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
779 for (
int pIdx = 0; pIdx < points.
size() - 1; pIdx++ )
782 _resolveDataDefined( context );
789 QPolygonF poly =
straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
799 if ( mSymbol.
data() )
800 mSymbol->setColor( c );
807 return mSymbol.
data() ? mSymbol->color() :
mColor;
static QString encodeOutputUnit(QgsSymbolV2::OutputUnit unit)
void setHeadThicknessUnitScale(const QgsMapUnitScale &scale)
Set the scale for the head height.
Single variable definition for use within a QgsExpressionContextScope.
void startRender(QgsSymbolV2RenderContext &context) override
Prepare the rendering.
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
bool contains(const Key &key) const
double arrowStartWidth() const
Get current arrow start width.
double arrowWidth() const
Get current arrow width.
QgsSymbolV2::OutputUnit headThicknessUnit() const
Get the unit for the head height.
virtual QSet< QString > usedAttributes() const
Returns the set of attributes referenced by the layer.
qreal euclidian_distance(const QPointF &po, const QPointF &pd)
static QgsFillSymbolV2 * 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
Get the scale for the arrow start width.
virtual bool hasDataDefinedProperties() const
Checks whether the layer has any associated data defined properties.
QgsMapUnitScale headLengthUnitScale() const
Get the scale for the head length.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
QString layerType() const override
Returns a string that represents this layer type.
void moveTo(const QPointF &point)
void setColor(const QColor &c) override
The fill color.
void pathArcTo(QPainterPath &path, const QPointF &circleCenter, qreal circleRadius, qreal angle_o, qreal angle_d, int direction)
const QgsFeature * feature() const
Current feature being rendered - may be null.
void setArrowWidthUnit(QgsSymbolV2::OutputUnit unit)
Set the unit for the arrow width.
const QgsMapUnitScale & offsetMapUnitScale() const
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
qreal clampAngle(qreal a)
void renderPolyline(const QPolygonF &points, QgsSymbolV2RenderContext &context) override
Main drawing method.
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
Get the current arrow type.
QMap< QString, QString > QgsStringMap
static const QString EXPR_OFFSET
virtual Q_DECL_DEPRECATED QVariant evaluateDataDefinedProperty(const QString &property, const QgsFeature *feature, const QVariant &defaultVal=QVariant(), bool *ok=nullptr) const
Evaluates the matching data defined property and returns the calculated value.
void stopRender(QgsSymbolV2RenderContext &context) override
End of the rendering.
static QgsSymbolV2::OutputUnit decodeOutputUnit(const QString &str)
bool isRepeated() const
Return whether the arrow is repeated along the line or not.
virtual double width() const
The output shall be in millimeters.
QString number(int n, int base)
void setOffset(double offset)
int toInt(bool *ok) const
virtual QgsArrowSymbolLayer * clone() const override
Virtual constructor.
static double convertToPainterUnits(const QgsRenderContext &c, double size, QgsSymbolV2::OutputUnit unit, const QgsMapUnitScale &scale=QgsMapUnitScale())
Converts a size from the specied units to painter units.
void setHeadLength(double length)
Set the arrow head length.
void setHeadThickness(double thickness)
Set the arrow head height.
static QgsSymbolLayerV2 * create(const QgsStringMap &properties=QgsStringMap())
Create a new QgsArrowSymbolLayer.
void lineTo(const QPointF &endPoint)
QList< QPolygonF > toSubpathPolygons(const QMatrix &matrix) const
void spiralArcTo(QPainterPath &path, const QPointF ¢er, qreal startAngle, qreal startRadius, qreal endAngle, qreal endRadius, int direction)
void setHeadThicknessUnit(QgsSymbolV2::OutputUnit unit)
Set the unit for the head height.
void setArrowWidth(double width)
Set the arrow width.
ArrowType
Possible arrow types.
bool isCurved() const
Return whether it is a curved arrow or a straight one.
virtual QSet< QString > usedAttributes() const override
Return a list of attributes required to render this feature.
double headLength() const
Get the current arrow head length.
void setIsRepeated(bool isRepeated)
Set whether the arrow is repeated along the line.
QgsArrowSymbolLayer()
Simple constructor.
QgsMapUnitScale arrowWidthUnitScale() const
Get the scale for the arrow width.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void copyDataDefinedProperties(QgsSymbolLayerV2 *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
void saveDataDefinedProperties(QgsStringMap &stringMap) const
Saves all data defined properties to a string map.
void setOffsetUnit(QgsSymbolV2::OutputUnit unit)
QgsExpressionContext & expressionContext()
Gets the expression context.
QgsStringMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void copyPaintEffect(QgsSymbolLayerV2 *destLayer) const
Copies paint effect of this layer to another symbol layer.
void setIsCurved(bool isCurved)
Set whether it is a curved arrow or a straight one.
const T & at(int i) const
void setHeadLengthUnitScale(const QgsMapUnitScale &scale)
Set the scale for the head length.
QSet< T > & unite(const QSet< T > &other)
void setArrowType(ArrowType type)
Set the arrow type.
QgsSymbolV2::OutputUnit offsetUnit() const
virtual bool hasDataDefinedProperty(const QString &property) const
Checks whether the layer has a matching data defined property and if that property is currently activ...
QgsSymbolV2::OutputUnit headLengthUnit() const
Get the unit for the head length.
void setArrowWidthUnitScale(const QgsMapUnitScale &scale)
Set the scale for the arrow width.
void setArrowStartWidthUnit(QgsSymbolV2::OutputUnit unit)
Set the unit for the arrow start width.
void setHeadType(HeadType type)
Set the head type.
QgsRenderContext & renderContext()
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
bool pointsToCircle(const QPointF &a, const QPointF &b, const QPointF &c, QPointF ¢er, qreal &radius)
Compute the circumscribed circle from three points.
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
virtual QColor color() const override
The fill color.
double toDouble(bool *ok) const
QgsSymbolV2::OutputUnit arrowStartWidthUnit() const
Get the unit for the arrow start width.
void setHeadLengthUnit(QgsSymbolV2::OutputUnit unit)
Set the unit for the head length.
QgsMapUnitScale headThicknessUnitScale() const
Get the scale for the head height.
Line symbol layer used for representing lines as arrows.
void restoreDataDefinedProperties(const QgsStringMap &stringMap)
Restores all data defined properties from string map.
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
virtual bool setSubSymbol(QgsSymbolV2 *symbol) override
Set the sub symbol used for filling.
HeadType
Possible head types.
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolV2::OutputUnit arrowWidthUnit() const
Get the unit for the arrow width.
void arcTo(const QRectF &rectangle, qreal startAngle, qreal sweepLength)
HeadType headType() const
Get the current head type.
void setArrowStartWidth(double width)
Set the arrow start width.
QPointF circlePoint(const QPointF ¢er, qreal radius, qreal angle)
void setArrowStartWidthUnitScale(const QgsMapUnitScale &scale)
Set the scale for the arrow start width.
double headThickness() const
Get the current arrow head height.