QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsarrowsymbollayer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsarrowsymbollayer.cpp
3  ---------------------
4  begin : January 2016
5  copyright : (C) 2016 by Hugo Mercier
6  email : hugo dot mercier at oslandia dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsarrowsymbollayer.h"
17 #include "qgssymbollayerutils.h"
18 #include "qgsfillsymbol.h"
19 #include "qgsrendercontext.h"
20 
22 {
23  /* default values */
24  setOffset( 0.0 );
26 
27  mSymbol.reset( static_cast<QgsFillSymbol *>( QgsFillSymbol::createSimple( QVariantMap() ) ) );
28 }
29 
31 
33 {
34  if ( symbol && symbol->type() == Qgis::SymbolType::Fill )
35  {
36  mSymbol.reset( static_cast<QgsFillSymbol *>( symbol ) );
37  return true;
38  }
39  delete symbol;
40  return false;
41 }
42 
43 QgsSymbolLayer *QgsArrowSymbolLayer::create( const QVariantMap &props )
44 {
46 
47  if ( props.contains( QStringLiteral( "arrow_width" ) ) )
48  l->setArrowWidth( props[QStringLiteral( "arrow_width" )].toDouble() );
49 
50  if ( props.contains( QStringLiteral( "arrow_width_unit" ) ) )
51  l->setArrowWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "arrow_width_unit" )].toString() ) );
52 
53  if ( props.contains( QStringLiteral( "arrow_width_unit_scale" ) ) )
54  l->setArrowWidthUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "arrow_width_unit_scale" )].toString() ) );
55 
56  if ( props.contains( QStringLiteral( "arrow_start_width" ) ) )
57  l->setArrowStartWidth( props[QStringLiteral( "arrow_start_width" )].toDouble() );
58 
59  if ( props.contains( QStringLiteral( "arrow_start_width_unit" ) ) )
60  l->setArrowStartWidthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "arrow_start_width_unit" )].toString() ) );
61 
62  if ( props.contains( QStringLiteral( "arrow_start_width_unit_scale" ) ) )
63  l->setArrowStartWidthUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "arrow_start_width_unit_scale" )].toString() ) );
64 
65  if ( props.contains( QStringLiteral( "is_curved" ) ) )
66  l->setIsCurved( props[QStringLiteral( "is_curved" )].toInt() == 1 );
67 
68  if ( props.contains( QStringLiteral( "is_repeated" ) ) )
69  l->setIsRepeated( props[QStringLiteral( "is_repeated" )].toInt() == 1 );
70 
71  if ( props.contains( QStringLiteral( "head_length" ) ) )
72  l->setHeadLength( props[QStringLiteral( "head_length" )].toDouble() );
73 
74  if ( props.contains( QStringLiteral( "head_length_unit" ) ) )
75  l->setHeadLengthUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "head_length_unit" )].toString() ) );
76 
77  if ( props.contains( QStringLiteral( "head_length_unit_scale" ) ) )
78  l->setHeadLengthUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "head_length_unit_scale" )].toString() ) );
79 
80  if ( props.contains( QStringLiteral( "head_thickness" ) ) )
81  l->setHeadThickness( props[QStringLiteral( "head_thickness" )].toDouble() );
82 
83  if ( props.contains( QStringLiteral( "head_thickness_unit" ) ) )
84  l->setHeadThicknessUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "head_thickness_unit" )].toString() ) );
85 
86  if ( props.contains( QStringLiteral( "head_thickness_unit_scale" ) ) )
87  l->setHeadThicknessUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "head_thickness_unit_scale" )].toString() ) );
88 
89  if ( props.contains( QStringLiteral( "head_type" ) ) )
90  l->setHeadType( static_cast<HeadType>( props[QStringLiteral( "head_type" )].toInt() ) );
91 
92  if ( props.contains( QStringLiteral( "arrow_type" ) ) )
93  l->setArrowType( static_cast<ArrowType>( props[QStringLiteral( "arrow_type" )].toInt() ) );
94 
95  if ( props.contains( QStringLiteral( "offset" ) ) )
96  l->setOffset( props[QStringLiteral( "offset" )].toDouble() );
97 
98  if ( props.contains( QStringLiteral( "offset_unit" ) ) )
99  l->setOffsetUnit( QgsUnitTypes::decodeRenderUnit( props[QStringLiteral( "offset_unit" )].toString() ) );
100 
101  if ( props.contains( QStringLiteral( "offset_unit_scale" ) ) )
102  l->setOffsetMapUnitScale( QgsSymbolLayerUtils::decodeMapUnitScale( props[QStringLiteral( "offset_unit_scale" )].toString() ) );
103 
104  if ( props.contains( QStringLiteral( "ring_filter" ) ) )
105  l->setRingFilter( static_cast< RenderRingFilter>( props[QStringLiteral( "ring_filter" )].toInt() ) );
106 
108 
110 
111  return l;
112 }
113 
115 {
116  QgsArrowSymbolLayer *l = static_cast<QgsArrowSymbolLayer *>( create( properties() ) );
117  l->setSubSymbol( mSymbol->clone() );
119  copyPaintEffect( l );
120  return l;
121 }
122 
124 {
125  return mSymbol.get();
126 }
127 
129 {
130  return QStringLiteral( "ArrowLine" );
131 }
132 
134 {
135  QVariantMap map;
136 
137  map[QStringLiteral( "arrow_width" )] = QString::number( arrowWidth() );
138  map[QStringLiteral( "arrow_width_unit" )] = QgsUnitTypes::encodeUnit( arrowWidthUnit() );
139  map[QStringLiteral( "arrow_width_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( arrowWidthUnitScale() );
140 
141  map[QStringLiteral( "arrow_start_width" )] = QString::number( arrowStartWidth() );
142  map[QStringLiteral( "arrow_start_width_unit" )] = QgsUnitTypes::encodeUnit( arrowStartWidthUnit() );
143  map[QStringLiteral( "arrow_start_width_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( arrowStartWidthUnitScale() );
144 
145  map[QStringLiteral( "is_curved" )] = QString::number( isCurved() ? 1 : 0 );
146  map[QStringLiteral( "is_repeated" )] = QString::number( isRepeated() ? 1 : 0 );
147 
148  map[QStringLiteral( "head_length" )] = QString::number( headLength() );
149  map[QStringLiteral( "head_length_unit" )] = QgsUnitTypes::encodeUnit( headLengthUnit() );
150  map[QStringLiteral( "head_length_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( headLengthUnitScale() );
151 
152  map[QStringLiteral( "head_thickness" )] = QString::number( headThickness() );
153  map[QStringLiteral( "head_thickness_unit" )] = QgsUnitTypes::encodeUnit( headThicknessUnit() );
154  map[QStringLiteral( "head_thickness_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( headThicknessUnitScale() );
155 
156  map[QStringLiteral( "head_type" )] = QString::number( headType() );
157  map[QStringLiteral( "arrow_type" )] = QString::number( arrowType() );
158 
159  map[QStringLiteral( "offset" )] = QString::number( offset() );
160  map[QStringLiteral( "offset_unit" )] = QgsUnitTypes::encodeUnit( offsetUnit() );
161  map[QStringLiteral( "offset_unit_scale" )] = QgsSymbolLayerUtils::encodeMapUnitScale( offsetMapUnitScale() );
162 
163  map[QStringLiteral( "ring_filter" )] = QString::number( static_cast< int >( mRingFilter ) );
164 
165  return map;
166 }
167 
168 QSet<QString> QgsArrowSymbolLayer::usedAttributes( const QgsRenderContext &context ) const
169 {
170  QSet<QString> attributes = QgsLineSymbolLayer::usedAttributes( context );
171 
172  attributes.unite( mSymbol->usedAttributes( context ) );
173 
174  return attributes;
175 }
176 
178 {
180  return true;
181  if ( mSymbol && mSymbol->hasDataDefinedProperties() )
182  return true;
183  return false;
184 }
185 
187 {
188  return mArrowWidthUnit == QgsUnitTypes::RenderMapUnits || mArrowWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
189  || mArrowStartWidthUnit == QgsUnitTypes::RenderMapUnits || mArrowStartWidthUnit == QgsUnitTypes::RenderMetersInMapUnits
190  || mHeadLengthUnit == QgsUnitTypes::RenderMapUnits || mHeadLengthUnit == QgsUnitTypes::RenderMetersInMapUnits
191  || mHeadThicknessUnit == QgsUnitTypes::RenderMapUnits || mHeadThicknessUnit == QgsUnitTypes::RenderMetersInMapUnits
194 }
195 
197 {
199  mArrowWidthUnit = unit;
200  mArrowStartWidthUnit = unit;
201  mHeadLengthUnit = unit;
202  mHeadThicknessUnit = unit;
203 }
204 
206 {
207  mExpressionScope.reset( new QgsExpressionContextScope() );
208  mScaledArrowWidth = context.renderContext().convertToPainterUnits( arrowWidth(), arrowWidthUnit(), arrowWidthUnitScale() );
210  mScaledHeadLength = context.renderContext().convertToPainterUnits( headLength(), headLengthUnit(), headLengthUnitScale() );
212  mScaledOffset = context.renderContext().convertToPainterUnits( offset(), offsetUnit(), offsetMapUnitScale() );
213  mComputedHeadType = headType();
214  mComputedArrowType = arrowType();
215 
216  mSymbol->startRender( context.renderContext() );
217 }
218 
220 {
221  mSymbol->stopRender( context.renderContext() );
222 }
223 
224 inline qreal euclidean_distance( QPointF po, QPointF pd )
225 {
226  return std::sqrt( ( po.x() - pd.x() ) * ( po.x() - pd.x() ) + ( po.y() - pd.y() ) * ( po.y() - pd.y() ) );
227 }
228 
229 QPolygonF straightArrow( QPointF po, QPointF pd,
230  qreal startWidth, qreal width,
231  qreal headWidth, qreal headHeight,
233  qreal offset )
234 {
235  QPolygonF polygon; // implicitly shared
236  // vector length
237  qreal length = euclidean_distance( po, pd );
238 
239  // shift points if there is not enough room for the head(s)
240  if ( ( headType == QgsArrowSymbolLayer::HeadSingle ) && ( length < headWidth ) )
241  {
242  po = pd - ( pd - po ) / length * headWidth;
243  length = headWidth;
244  }
245  else if ( ( headType == QgsArrowSymbolLayer::HeadReversed ) && ( length < headWidth ) )
246  {
247  pd = po + ( pd - po ) / length * headWidth;
248  length = headWidth;
249  }
250  else if ( ( headType == QgsArrowSymbolLayer::HeadDouble ) && ( length < 2 * headWidth ) )
251  {
252  const QPointF v = ( pd - po ) / length * headWidth;
253  const QPointF npo = ( po + pd ) / 2.0 - v;
254  const QPointF npd = ( po + pd ) / 2.0 + v;
255  po = npo;
256  pd = npd;
257  length = 2 * headWidth;
258  }
259 
260  const qreal bodyLength = length - headWidth;
261 
262  // unit vector
263  const QPointF unitVec = ( pd - po ) / length;
264  // perpendicular vector
265  const QPointF perpVec( -unitVec.y(), unitVec.x() );
266 
267  // set offset
268  po += perpVec * offset;
269  pd += perpVec * offset;
270 
271  if ( headType == QgsArrowSymbolLayer::HeadDouble )
272  {
273  // first head
274  polygon << po;
275  if ( arrowType == QgsArrowSymbolLayer::ArrowPlain || arrowType == QgsArrowSymbolLayer::ArrowRightHalf )
276  {
277  polygon << po + unitVec *headWidth + perpVec *headHeight;
278  polygon << po + unitVec *headWidth + perpVec * ( width * 0.5 );
279 
280  polygon << po + unitVec *bodyLength + perpVec * ( width * 0.5 );
281 
282  // second head
283  polygon << po + unitVec *bodyLength + perpVec *headHeight;
284  }
285  polygon << pd;
286 
287  if ( arrowType == QgsArrowSymbolLayer::ArrowPlain || arrowType == QgsArrowSymbolLayer::ArrowLeftHalf )
288  {
289  polygon << po + unitVec *bodyLength - perpVec *headHeight;
290  polygon << po + unitVec *bodyLength - perpVec * ( width * 0.5 );
291 
292  // end of the first head
293  polygon << po + unitVec *headWidth - perpVec * ( width * 0.5 );
294  polygon << po + unitVec *headWidth - perpVec *headHeight;
295  }
296  }
297  else if ( headType == QgsArrowSymbolLayer::HeadSingle )
298  {
299  if ( arrowType == QgsArrowSymbolLayer::ArrowPlain || arrowType == QgsArrowSymbolLayer::ArrowRightHalf )
300  {
301  polygon << po + perpVec * ( startWidth * 0.5 );
302  polygon << po + unitVec *bodyLength + perpVec * ( width * 0.5 );
303  polygon << po + unitVec *bodyLength + perpVec *headHeight;
304  }
305  else
306  {
307  polygon << po;
308  }
309  polygon << pd;
310  if ( arrowType == QgsArrowSymbolLayer::ArrowPlain || arrowType == QgsArrowSymbolLayer::ArrowLeftHalf )
311  {
312  polygon << po + unitVec *bodyLength - perpVec *headHeight;
313  polygon << po + unitVec *bodyLength - perpVec * ( width * 0.5 );
314  polygon << po - perpVec * ( startWidth * 0.5 );
315  }
316  else
317  {
318  polygon << po;
319  }
320  }
321  else if ( headType == QgsArrowSymbolLayer::HeadReversed )
322  {
323  polygon << po;
324  if ( arrowType == QgsArrowSymbolLayer::ArrowPlain || arrowType == QgsArrowSymbolLayer::ArrowRightHalf )
325  {
326  polygon << po + unitVec *headWidth + perpVec *headHeight;
327  polygon << po + unitVec *headWidth + perpVec * ( width * 0.5 );
328 
329  polygon << pd + perpVec * ( startWidth * 0.5 );
330  }
331  else
332  {
333  polygon << pd;
334  }
335  if ( arrowType == QgsArrowSymbolLayer::ArrowPlain || arrowType == QgsArrowSymbolLayer::ArrowLeftHalf )
336  {
337  polygon << pd - perpVec * ( startWidth * 0.5 );
338 
339  polygon << po + unitVec *headWidth - perpVec * ( width * 0.5 );
340  polygon << po + unitVec *headWidth - perpVec *headHeight;
341  }
342  else
343  {
344  polygon << pd;
345  }
346  }
347  // close the polygon
348  polygon << polygon.first();
349 
350  return polygon;
351 }
352 
353 // Make sure a given angle is between 0 and 2 pi
354 inline qreal clampAngle( qreal a )
355 {
356  if ( a > 2 * M_PI )
357  return a - 2 * M_PI;
358  if ( a < 0.0 )
359  return a + 2 * M_PI;
360  return a;
361 }
362 
367 bool pointsToCircle( QPointF a, QPointF b, QPointF c, QPointF &center, qreal &radius )
368 {
369  qreal cx, cy;
370 
371  // AB and BC vectors
372  const QPointF ab = b - a;
373  const QPointF bc = c - b;
374 
375  // AB and BC middles
376  const QPointF ab2 = ( a + b ) / 2.0;
377  const QPointF bc2 = ( b + c ) / 2.0;
378 
379  // Aligned points
380  if ( std::fabs( ab.x() * bc.y() - ab.y() * bc.x() ) < 0.001 ) // Empirical threshold for nearly aligned points
381  return false;
382 
383  // in case AB is horizontal
384  if ( ab.y() == 0 )
385  {
386  cx = ab2.x();
387  cy = bc2.y() - ( cx - bc2.x() ) * bc.x() / bc.y();
388  }
389  //# BC horizontal
390  else if ( bc.y() == 0 )
391  {
392  cx = bc2.x();
393  cy = ab2.y() - ( cx - ab2.x() ) * ab.x() / ab.y();
394  }
395  // Otherwise
396  else
397  {
398  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() );
399  cy = bc2.y() - ( cx - bc2.x() ) * bc.x() / bc.y();
400  }
401  // Radius
402  radius = std::sqrt( ( a.x() - cx ) * ( a.x() - cx ) + ( a.y() - cy ) * ( a.y() - cy ) );
403  // Center
404  center.setX( cx );
405  center.setY( cy );
406  return true;
407 }
408 
409 QPointF circlePoint( QPointF center, qreal radius, qreal angle )
410 {
411  // Y is oriented downward
412  return QPointF( std::cos( -angle ) * radius + center.x(), std::sin( -angle ) * radius + center.y() );
413 }
414 
415 void pathArcTo( QPainterPath &path, QPointF circleCenter, qreal circleRadius, qreal angle_o, qreal angle_d, int direction )
416 {
417  const QRectF circleRect( circleCenter - QPointF( circleRadius, circleRadius ), circleCenter + QPointF( circleRadius, circleRadius ) );
418  if ( direction == 1 )
419  {
420  if ( angle_o < angle_d )
421  path.arcTo( circleRect, angle_o / M_PI * 180.0, ( angle_d - angle_o ) / M_PI * 180.0 );
422  else
423  path.arcTo( circleRect, angle_o / M_PI * 180.0, 360.0 - ( angle_o - angle_d ) / M_PI * 180.0 );
424  }
425  else
426  {
427  if ( angle_o < angle_d )
428  path.arcTo( circleRect, angle_o / M_PI * 180.0, - ( 360.0 - ( angle_d - angle_o ) / M_PI * 180.0 ) );
429  else
430  path.arcTo( circleRect, angle_o / M_PI * 180.0, ( angle_d - angle_o ) / M_PI * 180.0 );
431  }
432 }
433 
434 // Draw a "spiral" arc defined by circle arcs around a center, a start and an end radius
435 void spiralArcTo( QPainterPath &path, QPointF center, qreal startAngle, qreal startRadius, qreal endAngle, qreal endRadius, int direction )
436 {
437  // start point
438  const QPointF A = circlePoint( center, startRadius, startAngle );
439  // end point
440  const QPointF B = circlePoint( center, endRadius, endAngle );
441  // middle points
442  qreal deltaAngle;
443 
444  deltaAngle = endAngle - startAngle;
445  if ( direction * deltaAngle < 0.0 )
446  deltaAngle = deltaAngle + direction * 2 * M_PI;
447 
448  const QPointF I1 = circlePoint( center, 0.75 * startRadius + 0.25 * endRadius, startAngle + 0.25 * deltaAngle );
449  const QPointF I2 = circlePoint( center, 0.50 * startRadius + 0.50 * endRadius, startAngle + 0.50 * deltaAngle );
450  const QPointF I3 = circlePoint( center, 0.25 * startRadius + 0.75 * endRadius, startAngle + 0.75 * deltaAngle );
451 
452  qreal cRadius;
453  QPointF cCenter;
454  // first circle arc
455  if ( ! pointsToCircle( A, I1, I2, cCenter, cRadius ) )
456  {
457  // aligned points => draw a straight line
458  path.lineTo( I2 );
459  }
460  else
461  {
462  // angles in the new circle
463  const qreal a1 = std::atan2( cCenter.y() - A.y(), A.x() - cCenter.x() );
464  const qreal a2 = std::atan2( cCenter.y() - I2.y(), I2.x() - cCenter.x() );
465  pathArcTo( path, cCenter, cRadius, a1, a2, direction );
466  }
467 
468  // second circle arc
469  if ( ! pointsToCircle( I2, I3, B, cCenter, cRadius ) )
470  {
471  // aligned points => draw a straight line
472  path.lineTo( B );
473  }
474  else
475  {
476  // angles in the new circle
477  const qreal a1 = std::atan2( cCenter.y() - I2.y(), I2.x() - cCenter.x() );
478  const qreal a2 = std::atan2( cCenter.y() - B.y(), B.x() - cCenter.x() );
479  pathArcTo( path, cCenter, cRadius, a1, a2, direction );
480  }
481 }
482 
483 QPolygonF curvedArrow( QPointF po, QPointF pm, QPointF pd,
484  qreal startWidth, qreal width,
485  qreal headWidth, qreal headHeight,
487  qreal offset )
488 {
489  qreal circleRadius;
490  QPointF circleCenter;
491  if ( ! pointsToCircle( po, pm, pd, circleCenter, circleRadius ) )
492  {
493  // aligned points => draw a straight arrow
494  return straightArrow( po, pd, startWidth, width, headWidth, headHeight, headType, arrowType, offset );
495  }
496 
497  // angles of each point
498  const qreal angle_o = clampAngle( std::atan2( circleCenter.y() - po.y(), po.x() - circleCenter.x() ) );
499  const qreal angle_m = clampAngle( std::atan2( circleCenter.y() - pm.y(), pm.x() - circleCenter.x() ) );
500  const qreal angle_d = clampAngle( std::atan2( circleCenter.y() - pd.y(), pd.x() - circleCenter.x() ) );
501 
502  // arc direction : 1 = counter-clockwise, -1 = clockwise
503  const int direction = clampAngle( angle_m - angle_o ) < clampAngle( angle_m - angle_d ) ? 1 : -1;
504 
505  // arrow type, independent of the direction
506  int aType = 0;
507  if ( arrowType == QgsArrowSymbolLayer::ArrowRightHalf )
508  aType = direction;
509  else if ( arrowType == QgsArrowSymbolLayer::ArrowLeftHalf )
510  aType = -direction;
511 
512  qreal deltaAngle = angle_d - angle_o;
513  if ( direction * deltaAngle < 0.0 )
514  deltaAngle = deltaAngle + direction * 2 * M_PI;
515 
516  const qreal length = euclidean_distance( po, pd );
517  // for close points and deltaAngle < 180, draw a straight line
518  if ( std::fabs( deltaAngle ) < M_PI && ( ( ( headType == QgsArrowSymbolLayer::HeadSingle ) && ( length < headWidth ) ) ||
519  ( ( headType == QgsArrowSymbolLayer::HeadReversed ) && ( length < headWidth ) ) ||
520  ( ( headType == QgsArrowSymbolLayer::HeadDouble ) && ( length < 2 * headWidth ) ) ) )
521  {
522  return straightArrow( po, pd, startWidth, width, headWidth, headHeight, headType, arrowType, offset );
523  }
524 
525  // adjust coordinates to include offset
526  circleRadius += offset;
527  po = circlePoint( circleCenter, circleRadius, angle_o );
528  pm = circlePoint( circleCenter, circleRadius, angle_m );
529  pd = circlePoint( circleCenter, circleRadius, angle_d );
530 
531  const qreal headAngle = direction * std::atan( headWidth / circleRadius );
532 
533  QPainterPath path;
534 
535  if ( headType == QgsArrowSymbolLayer::HeadDouble )
536  {
537  // the first head
538  path.moveTo( po );
539  if ( aType <= 0 )
540  {
541  path.lineTo( circlePoint( circleCenter, circleRadius + direction * headHeight, angle_o + headAngle ) );
542 
543  pathArcTo( path, circleCenter, circleRadius + direction * width / 2, angle_o + headAngle, angle_d - headAngle, direction );
544 
545  // the second head
546  path.lineTo( circlePoint( circleCenter, circleRadius + direction * headHeight, angle_d - headAngle ) );
547  path.lineTo( pd );
548  }
549  else
550  {
551  pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
552  }
553  if ( aType >= 0 )
554  {
555  path.lineTo( circlePoint( circleCenter, circleRadius - direction * headHeight, angle_d - headAngle ) );
556 
557  pathArcTo( path, circleCenter, circleRadius - direction * width / 2, angle_d - headAngle, angle_o + headAngle, -direction );
558 
559  // the end of the first head
560  path.lineTo( circlePoint( circleCenter, circleRadius - direction * headHeight, angle_o + headAngle ) );
561  path.lineTo( po );
562  }
563  else
564  {
565  pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
566  }
567  }
568  else if ( headType == QgsArrowSymbolLayer::HeadSingle )
569  {
570  if ( aType <= 0 )
571  {
572  path.moveTo( circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
573 
574  spiralArcTo( path, circleCenter, angle_o, circleRadius + direction * startWidth / 2, angle_d - headAngle, circleRadius + direction * width / 2, direction );
575 
576  // the arrow head
577  path.lineTo( circlePoint( circleCenter, circleRadius + direction * headHeight, angle_d - headAngle ) );
578  path.lineTo( pd );
579  }
580  else
581  {
582  path.moveTo( po );
583  pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
584  }
585  if ( aType >= 0 )
586  {
587  path.lineTo( circlePoint( circleCenter, circleRadius - direction * headHeight, angle_d - headAngle ) );
588 
589  spiralArcTo( path, circleCenter, angle_d - headAngle, circleRadius - direction * width / 2, angle_o, circleRadius - direction * startWidth / 2, -direction );
590 
591  path.lineTo( circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
592  }
593  else
594  {
595  pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
596  path.lineTo( circlePoint( circleCenter, circleRadius + direction * startWidth / 2, angle_o ) );
597  }
598  }
599  else if ( headType == QgsArrowSymbolLayer::HeadReversed )
600  {
601  path.moveTo( po );
602  if ( aType <= 0 )
603  {
604  path.lineTo( circlePoint( circleCenter, circleRadius + direction * headHeight, angle_o + headAngle ) );
605  path.lineTo( circlePoint( circleCenter, circleRadius + direction * width / 2, angle_o + headAngle ) );
606 
607  spiralArcTo( path, circleCenter, angle_o + headAngle, circleRadius + direction * width / 2, angle_d, circleRadius + direction * startWidth / 2, direction );
608  }
609  else
610  {
611  pathArcTo( path, circleCenter, circleRadius, angle_o, angle_d, direction );
612  }
613  if ( aType >= 0 )
614  {
615  path.lineTo( circlePoint( circleCenter, circleRadius - direction * startWidth / 2, angle_d ) );
616 
617  spiralArcTo( path, circleCenter, angle_d, circleRadius - direction * startWidth / 2, angle_o + headAngle, circleRadius - direction * width / 2, - direction );
618 
619  path.lineTo( circlePoint( circleCenter, circleRadius - direction * headHeight, angle_o + headAngle ) );
620  path.lineTo( po );
621  }
622  else
623  {
624  path.lineTo( pd );
625  pathArcTo( path, circleCenter, circleRadius, angle_d, angle_o, -direction );
626  }
627  }
628 
629  return path.toSubpathPolygons().at( 0 );
630 }
631 
632 void QgsArrowSymbolLayer::_resolveDataDefined( QgsSymbolRenderContext &context )
633 {
634  if ( !dataDefinedProperties().hasActiveProperties() )
635  return; // shortcut if case there is no data defined properties at all
636 
637  QVariant exprVal;
638  bool ok;
640  {
642  if ( !exprVal.isNull() )
643  {
644  const double w = exprVal.toDouble( &ok );
645  if ( ok )
646  {
647  mScaledArrowWidth = context.renderContext().convertToPainterUnits( w, arrowWidthUnit(), arrowWidthUnitScale() );
648  }
649  }
650  }
652  {
655  if ( !exprVal.isNull() )
656  {
657  const double w = exprVal.toDouble( &ok );
658  if ( ok )
659  {
660  mScaledArrowStartWidth = context.renderContext().convertToPainterUnits( w, arrowStartWidthUnit(), arrowStartWidthUnitScale() );
661  }
662  }
663  }
665  {
668  if ( !exprVal.isNull() )
669  {
670  const double w = exprVal.toDouble( &ok );
671  if ( ok )
672  {
673  mScaledHeadLength = context.renderContext().convertToPainterUnits( w, headLengthUnit(), headLengthUnitScale() );
674  }
675  }
676  }
678  {
681  if ( !exprVal.isNull() )
682  {
683  const double w = exprVal.toDouble( &ok );
684  if ( ok )
685  {
686  mScaledHeadThickness = context.renderContext().convertToPainterUnits( w, headThicknessUnit(), headThicknessUnitScale() );
687  }
688  }
689  }
691  {
692  context.setOriginalValueVariable( offset() );
694  const double w = exprVal.toDouble( &ok );
695  if ( ok )
696  {
697  mScaledOffset = context.renderContext().convertToPainterUnits( w, offsetUnit(), offsetMapUnitScale() );
698  }
699  }
700 
702  {
703  context.setOriginalValueVariable( headType() );
705  if ( !exprVal.isNull() )
706  {
707  const HeadType h = QgsSymbolLayerUtils::decodeArrowHeadType( exprVal, &ok );
708  if ( ok )
709  {
710  mComputedHeadType = h;
711  }
712  }
713  }
714 
716  {
717  context.setOriginalValueVariable( arrowType() );
719  if ( !exprVal.isNull() )
720  {
721  const ArrowType h = QgsSymbolLayerUtils::decodeArrowType( exprVal, &ok );
722  if ( ok )
723  {
724  mComputedArrowType = h;
725  }
726  }
727  }
728 }
729 
730 void QgsArrowSymbolLayer::renderPolyline( const QPolygonF &points, QgsSymbolRenderContext &context )
731 {
732  Q_UNUSED( points )
733 
734  if ( !context.renderContext().painter() )
735  {
736  return;
737  }
738 
739  context.renderContext().expressionContext().appendScope( mExpressionScope.get() );
740  mExpressionScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_POINT_COUNT, points.size() + 1, true ) );
742 
743  const bool prevIsSubsymbol = context.renderContext().flags() & Qgis::RenderContextFlag::RenderingSubSymbol;
745 
746  const double prevOpacity = mSymbol->opacity();
747  mSymbol->setOpacity( prevOpacity * context.opacity() );
748 
749  if ( isCurved() )
750  {
751  _resolveDataDefined( context );
752 
753  if ( ! isRepeated() )
754  {
755  if ( points.size() >= 3 )
756  {
757  // origin point
758  const QPointF po( points.at( 0 ) );
759  // middle point
760  const QPointF pm( points.at( points.size() / 2 ) );
761  // destination point
762  const QPointF pd( points.back() );
763 
764  const QPolygonF poly = curvedArrow( po, pm, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
765  mSymbol->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
766  }
767  // straight arrow
768  else if ( points.size() == 2 )
769  {
770  // origin point
771  const QPointF po( points.at( 0 ) );
772  // destination point
773  const QPointF pd( points.at( 1 ) );
774 
775  const QPolygonF poly = straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
776  mSymbol->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
777  }
778  }
779  else
780  {
781  for ( int pIdx = 0; pIdx < points.size() - 1; pIdx += 2 )
782  {
783  if ( context.renderContext().renderingStopped() )
784  break;
785 
786  mExpressionScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM, pIdx + 1, true ) );
787  _resolveDataDefined( context );
788 
789  if ( points.size() - pIdx >= 3 )
790  {
791  // origin point
792  const QPointF po( points.at( pIdx ) );
793  // middle point
794  const QPointF pm( points.at( pIdx + 1 ) );
795  // destination point
796  const QPointF pd( points.at( pIdx + 2 ) );
797 
798  const QPolygonF poly = curvedArrow( po, pm, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
799  mSymbol->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
800  }
801  // straight arrow
802  else if ( points.size() - pIdx == 2 )
803  {
804  // origin point
805  const QPointF po( points.at( pIdx ) );
806  // destination point
807  const QPointF pd( points.at( pIdx + 1 ) );
808 
809  const QPolygonF poly = straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
810  mSymbol->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
811  }
812  }
813  }
814  }
815  else
816  {
817  if ( !isRepeated() )
818  {
819  _resolveDataDefined( context );
820 
821  if ( !points.isEmpty() )
822  {
823  // origin point
824  const QPointF po( points.at( 0 ) );
825  // destination point
826  const QPointF pd( points.back() );
827 
828  const QPolygonF poly = straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
829  mSymbol->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
830  }
831  }
832  else
833  {
834  // only straight arrows
835  for ( int pIdx = 0; pIdx < points.size() - 1; pIdx++ )
836  {
837  if ( context.renderContext().renderingStopped() )
838  break;
839 
840  mExpressionScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM, pIdx + 1, true ) );
841  _resolveDataDefined( context );
842 
843  // origin point
844  const QPointF po( points.at( pIdx ) );
845  // destination point
846  const QPointF pd( points.at( pIdx + 1 ) );
847 
848  const QPolygonF poly = straightArrow( po, pd, mScaledArrowStartWidth, mScaledArrowWidth, mScaledHeadLength, mScaledHeadThickness, mComputedHeadType, mComputedArrowType, mScaledOffset );
849 
850  mSymbol->renderPolygon( poly, /* rings */ nullptr, context.feature(), context.renderContext(), -1, context.selected() );
851  }
852  }
853  }
854 
856 
857  mSymbol->setOpacity( prevOpacity );
859 }
860 
861 void QgsArrowSymbolLayer::setColor( const QColor &c )
862 {
863  if ( mSymbol )
864  mSymbol->setColor( c );
865 
866  mColor = c;
867 }
868 
870 {
871  return mSymbol.get() ? mSymbol->color() : mColor;
872 }
873 
875 {
876  return true;
877 }
878 
QgsArrowSymbolLayer::headThicknessUnitScale
QgsMapUnitScale headThicknessUnitScale() const
Gets the scale for the head height.
Definition: qgsarrowsymbollayer.h:105
QgsSymbolLayer::PropertyArrowHeadType
@ PropertyArrowHeadType
Arrow head type.
Definition: qgssymbollayer.h:193
QgsSymbolRenderContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for data defined symbology.
Definition: qgssymbolrendercontext.cpp:36
QgsArrowSymbolLayer::ArrowType
ArrowType
Possible arrow types.
Definition: qgsarrowsymbollayer.h:133
curvedArrow
QPolygonF curvedArrow(QPointF po, QPointF pm, QPointF pd, qreal startWidth, qreal width, qreal headWidth, qreal headHeight, QgsArrowSymbolLayer::HeadType headType, QgsArrowSymbolLayer::ArrowType arrowType, qreal offset)
Definition: qgsarrowsymbollayer.cpp:483
QgsSymbolLayer::PropertyArrowHeadThickness
@ PropertyArrowHeadThickness
Arrow head thickness.
Definition: qgssymbollayer.h:192
clampAngle
qreal clampAngle(qreal a)
Definition: qgsarrowsymbollayer.cpp:354
QgsLineSymbolLayer::RenderRingFilter
RenderRingFilter
Options for filtering rings when the line symbol layer is being used to render a polygon's rings.
Definition: qgssymbollayer.h:1029
QgsSymbolLayer::mColor
QColor mColor
Definition: qgssymbollayer.h:648
QgsArrowSymbolLayer::headType
HeadType headType() const
Gets the current head type.
Definition: qgsarrowsymbollayer.h:128
QgsArrowSymbolLayer::HeadSingle
@ HeadSingle
Definition: qgsarrowsymbollayer.h:122
QgsSymbolLayer::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer's property collection, used for data defined overrides.
Definition: qgssymbollayer.h:595
QgsUnitTypes::RenderUnit
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:167
Qgis::SymbolType::Fill
@ Fill
Fill symbol.
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsExpressionContext::popScope
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
Definition: qgsexpressioncontext.cpp:504
QgsLineSymbolLayer::setRingFilter
void setRingFilter(QgsLineSymbolLayer::RenderRingFilter filter)
Sets the line symbol layer's ring filter, which controls which rings are rendered when the line symbo...
Definition: qgssymbollayer.cpp:518
QgsArrowSymbolLayer::setColor
void setColor(const QColor &c) override
Sets the "representative" color for the symbol layer.
Definition: qgsarrowsymbollayer.cpp:861
pathArcTo
void pathArcTo(QPainterPath &path, QPointF circleCenter, qreal circleRadius, qreal angle_o, qreal angle_d, int direction)
Definition: qgsarrowsymbollayer.cpp:415
QgsSymbolLayer::PropertyArrowStartWidth
@ PropertyArrowStartWidth
Arrow tail start width.
Definition: qgssymbollayer.h:190
QgsArrowSymbolLayer::arrowStartWidthUnit
QgsUnitTypes::RenderUnit arrowStartWidthUnit() const
Gets the unit for the arrow start width.
Definition: qgsarrowsymbollayer.h:75
QgsArrowSymbolLayer::stopRender
void stopRender(QgsSymbolRenderContext &context) override
Called after a set of rendering operations has finished on the supplied render context.
Definition: qgsarrowsymbollayer.cpp:219
QgsSymbolLayerUtils::encodeMapUnitScale
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Definition: qgssymbollayerutils.cpp:666
QgsArrowSymbolLayer::setArrowStartWidth
void setArrowStartWidth(double width)
Sets the arrow start width.
Definition: qgsarrowsymbollayer.h:73
QgsSymbolRenderContext::feature
const QgsFeature * feature() const
Returns the current feature being rendered.
Definition: qgssymbolrendercontext.h:143
QgsArrowSymbolLayer::usesMapUnits
bool usesMapUnits() const override
Returns true if the symbol layer has any components which use map unit based sizes.
Definition: qgsarrowsymbollayer.cpp:186
QgsArrowSymbolLayer::subSymbol
QgsSymbol * subSymbol() override
Returns the symbol's sub symbol, if present.
Definition: qgsarrowsymbollayer.cpp:123
QgsArrowSymbolLayer::create
static QgsSymbolLayer * create(const QVariantMap &properties=QVariantMap())
Create a new QgsArrowSymbolLayer.
Definition: qgsarrowsymbollayer.cpp:43
QgsArrowSymbolLayer::setHeadThicknessUnit
void setHeadThicknessUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the head height.
Definition: qgsarrowsymbollayer.h:103
QgsArrowSymbolLayer::layerType
QString layerType() const override
Returns a string that represents this layer type.
Definition: qgsarrowsymbollayer.cpp:128
QgsExpressionContext::EXPR_GEOMETRY_POINT_COUNT
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
Definition: qgsexpressioncontext.h:821
QgsExpressionContext::EXPR_GEOMETRY_POINT_NUM
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
Definition: qgsexpressioncontext.h:823
qgssymbollayerutils.h
QgsLineSymbolLayer::mRingFilter
RenderRingFilter mRingFilter
Definition: qgssymbollayer.h:1210
QgsArrowSymbolLayer::setHeadLengthUnit
void setHeadLengthUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the head length.
Definition: qgsarrowsymbollayer.h:90
QgsArrowSymbolLayer::arrowWidthUnit
QgsUnitTypes::RenderUnit arrowWidthUnit() const
Gets the unit for the arrow width.
Definition: qgsarrowsymbollayer.h:62
QgsSymbolRenderContext::opacity
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbolrendercontext.h:105
QgsArrowSymbolLayer::HeadReversed
@ HeadReversed
Definition: qgsarrowsymbollayer.h:123
QgsSymbolLayer::hasDataDefinedProperties
virtual bool hasDataDefinedProperties() const
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgssymbollayer.cpp:287
QgsRenderContext::flags
Qgis::RenderContextFlags flags() const
Returns combination of flags used for rendering.
Definition: qgsrendercontext.cpp:224
QgsLineSymbolLayer::offsetUnit
QgsUnitTypes::RenderUnit offsetUnit() const
Returns the units for the line's offset.
Definition: qgssymbollayer.h:1139
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsArrowSymbolLayer::headLengthUnit
QgsUnitTypes::RenderUnit headLengthUnit() const
Gets the unit for the head length.
Definition: qgsarrowsymbollayer.h:88
QgsUnitTypes::RenderMillimeters
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
QgsSymbol
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:92
QgsArrowSymbolLayer::setArrowStartWidthUnitScale
void setArrowStartWidthUnitScale(const QgsMapUnitScale &scale)
Sets the scale for the arrow start width.
Definition: qgsarrowsymbollayer.h:81
euclidean_distance
qreal euclidean_distance(QPointF po, QPointF pd)
Definition: qgsarrowsymbollayer.cpp:224
QgsArrowSymbolLayer::clone
QgsArrowSymbolLayer * clone() const override
Shall be reimplemented by subclasses to create a deep copy of the instance.
Definition: qgsarrowsymbollayer.cpp:114
QgsArrowSymbolLayer::headLength
double headLength() const
Gets the current arrow head length.
Definition: qgsarrowsymbollayer.h:84
QgsArrowSymbolLayer::setIsRepeated
void setIsRepeated(bool isRepeated)
Sets whether the arrow is repeated along the line.
Definition: qgsarrowsymbollayer.h:117
QgsArrowSymbolLayer::setHeadThicknessUnitScale
void setHeadThicknessUnitScale(const QgsMapUnitScale &scale)
Sets the scale for the head height.
Definition: qgsarrowsymbollayer.h:107
QgsLineSymbolLayer::setOffset
void setOffset(double offset)
Sets the line's offset.
Definition: qgssymbollayer.h:1123
QgsLineSymbolLayer::setOffsetMapUnitScale
void setOffsetMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the line's offset.
Definition: qgssymbollayer.h:1147
QgsSymbolLayer::PropertyArrowHeadLength
@ PropertyArrowHeadLength
Arrow head length.
Definition: qgssymbollayer.h:191
QgsSymbolRenderContext::selected
bool selected() const
Returns true if symbols should be rendered using the selected symbol coloring and style.
Definition: qgssymbolrendercontext.h:118
QgsArrowSymbolLayer::setSubSymbol
bool setSubSymbol(QgsSymbol *symbol) override
Sets layer's subsymbol. takes ownership of the passed symbol.
Definition: qgsarrowsymbollayer.cpp:32
QgsUnitTypes::decodeRenderUnit
static Q_INVOKABLE QgsUnitTypes::RenderUnit decodeRenderUnit(const QString &string, bool *ok=nullptr)
Decodes a render unit from a string.
Definition: qgsunittypes.cpp:2948
QgsSymbolRenderContext
Definition: qgssymbolrendercontext.h:35
QgsLineSymbolLayer::mOffsetUnit
QgsUnitTypes::RenderUnit mOffsetUnit
Definition: qgssymbollayer.h:1207
QgsArrowSymbolLayer::setHeadThickness
void setHeadThickness(double thickness)
Sets the arrow head height.
Definition: qgsarrowsymbollayer.h:99
QgsArrowSymbolLayer::HeadDouble
@ HeadDouble
Definition: qgsarrowsymbollayer.h:124
QgsArrowSymbolLayer
Line symbol layer used for representing lines as arrows.
Definition: qgsarrowsymbollayer.h:33
QgsRenderContext::renderingStopped
bool renderingStopped() const
Returns true if the rendering operation has been stopped and any ongoing rendering should be canceled...
Definition: qgsrendercontext.h:285
QgsSymbolLayer::PropertyOffset
@ PropertyOffset
Symbol offset.
Definition: qgssymbollayer.h:151
QgsArrowSymbolLayer::renderPolyline
void renderPolyline(const QPolygonF &points, QgsSymbolRenderContext &context) override
Renders the line symbol layer along the line joining points, using the given render context.
Definition: qgsarrowsymbollayer.cpp:730
QgsSymbolLayer
Definition: qgssymbollayer.h:54
QgsArrowSymbolLayer::HeadType
HeadType
Possible head types.
Definition: qgsarrowsymbollayer.h:120
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
QgsSymbolLayer::PropertyArrowWidth
@ PropertyArrowWidth
Arrow tail width.
Definition: qgssymbollayer.h:189
qgsarrowsymbollayer.h
QgsSymbol::type
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:152
QgsArrowSymbolLayer::arrowStartWidth
double arrowStartWidth() const
Gets current arrow start width. Only meaningful for single headed arrows.
Definition: qgsarrowsymbollayer.h:71
QgsArrowSymbolLayer::ArrowPlain
@ ArrowPlain
Definition: qgsarrowsymbollayer.h:135
QgsArrowSymbolLayer::headThickness
double headThickness() const
Gets the current arrow head height.
Definition: qgsarrowsymbollayer.h:97
QgsArrowSymbolLayer::setHeadLengthUnitScale
void setHeadLengthUnitScale(const QgsMapUnitScale &scale)
Sets the scale for the head length.
Definition: qgsarrowsymbollayer.h:94
QgsRenderContext::setFlag
void setFlag(Qgis::RenderContextFlag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
Definition: qgsrendercontext.cpp:216
QgsArrowSymbolLayer::ArrowRightHalf
@ ArrowRightHalf
Definition: qgsarrowsymbollayer.h:137
QgsLineSymbolLayer::setOffsetUnit
void setOffsetUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the line's offset.
Definition: qgssymbollayer.h:1131
circlePoint
QPointF circlePoint(QPointF center, qreal radius, qreal angle)
Definition: qgsarrowsymbollayer.cpp:409
QgsLineSymbolLayer::mWidthUnit
QgsUnitTypes::RenderUnit mWidthUnit
Definition: qgssymbollayer.h:1204
QgsSymbolLayer::copyPaintEffect
void copyPaintEffect(QgsSymbolLayer *destLayer) const
Copies paint effect of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:491
qgsrendercontext.h
QgsArrowSymbolLayer::properties
QVariantMap properties() const override
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
Definition: qgsarrowsymbollayer.cpp:133
QgsArrowSymbolLayer::canCauseArtifactsBetweenAdjacentTiles
bool canCauseArtifactsBetweenAdjacentTiles() const override
Returns true if the symbol layer rendering can cause visible artifacts across a single feature when t...
Definition: qgsarrowsymbollayer.cpp:874
QgsArrowSymbolLayer::arrowStartWidthUnitScale
QgsMapUnitScale arrowStartWidthUnitScale() const
Gets the scale for the arrow start width.
Definition: qgsarrowsymbollayer.h:79
QgsArrowSymbolLayer::headThicknessUnit
QgsUnitTypes::RenderUnit headThicknessUnit() const
Gets the unit for the head height.
Definition: qgsarrowsymbollayer.h:101
QgsSymbolLayer::restoreOldDataDefinedProperties
void restoreOldDataDefinedProperties(const QVariantMap &stringMap)
Restores older data defined properties from string map.
Definition: qgssymbollayer.cpp:362
QgsSymbolLayerUtils::decodeArrowHeadType
static QgsArrowSymbolLayer::HeadType decodeArrowHeadType(const QVariant &value, bool *ok=nullptr)
Decodes a value representing an arrow head type.
Definition: qgssymbollayerutils.cpp:420
QgsSymbolLayer::mDataDefinedProperties
QgsPropertyCollection mDataDefinedProperties
Definition: qgssymbollayer.h:651
QgsFillSymbol::createSimple
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
Definition: qgsfillsymbol.cpp:20
QgsArrowSymbolLayer::arrowWidthUnitScale
QgsMapUnitScale arrowWidthUnitScale() const
Gets the scale for the arrow width.
Definition: qgsarrowsymbollayer.h:66
QgsArrowSymbolLayer::setHeadType
void setHeadType(HeadType type)
Sets the head type.
Definition: qgsarrowsymbollayer.h:130
QgsArrowSymbolLayer::usedAttributes
QSet< QString > usedAttributes(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the layer.
Definition: qgsarrowsymbollayer.cpp:168
QgsArrowSymbolLayer::ArrowLeftHalf
@ ArrowLeftHalf
Definition: qgsarrowsymbollayer.h:136
QgsArrowSymbolLayer::QgsArrowSymbolLayer
QgsArrowSymbolLayer()
Simple constructor.
Definition: qgsarrowsymbollayer.cpp:21
straightArrow
QPolygonF straightArrow(QPointF po, QPointF pd, qreal startWidth, qreal width, qreal headWidth, qreal headHeight, QgsArrowSymbolLayer::HeadType headType, QgsArrowSymbolLayer::ArrowType arrowType, qreal offset)
Definition: qgsarrowsymbollayer.cpp:229
QgsExpressionContextScope
Single scope for storing variables and functions for use within a QgsExpressionContext....
Definition: qgsexpressioncontext.h:113
QgsSymbolLayer::usedAttributes
virtual QSet< QString > usedAttributes(const QgsRenderContext &context) const
Returns the set of attributes referenced by the layer.
Definition: qgssymbollayer.cpp:328
QgsArrowSymbolLayer::setArrowWidthUnitScale
void setArrowWidthUnitScale(const QgsMapUnitScale &scale)
Sets the scale for the arrow width.
Definition: qgsarrowsymbollayer.h:68
QgsExpressionContext::appendScope
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
Definition: qgsexpressioncontext.cpp:494
QgsRenderContext::convertToPainterUnits
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).
Definition: qgsrendercontext.cpp:367
QgsArrowSymbolLayer::isCurved
bool isCurved() const
Returns whether it is a curved arrow or a straight one.
Definition: qgsarrowsymbollayer.h:110
QgsArrowSymbolLayer::setArrowType
void setArrowType(ArrowType type)
Sets the arrow type.
Definition: qgsarrowsymbollayer.h:143
QgsLineSymbolLayer::offsetMapUnitScale
const QgsMapUnitScale & offsetMapUnitScale() const
Returns the map unit scale for the line's offset.
Definition: qgssymbollayer.h:1155
QgsPropertyCollection::value
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.
Definition: qgspropertycollection.cpp:228
c
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
Definition: porting_processing.dox:1
QgsArrowSymbolLayer::hasDataDefinedProperties
bool hasDataDefinedProperties() const override
Returns true if the symbol layer (or any of its sub-symbols) contains data defined properties.
Definition: qgsarrowsymbollayer.cpp:177
QgsArrowSymbolLayer::startRender
void startRender(QgsSymbolRenderContext &context) override
Called before a set of rendering operations commences on the supplied render context.
Definition: qgsarrowsymbollayer.cpp:205
QgsArrowSymbolLayer::setArrowStartWidthUnit
void setArrowStartWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the arrow start width.
Definition: qgsarrowsymbollayer.h:77
QgsFillSymbol
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:29
QgsUnitTypes::RenderMetersInMapUnits
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:176
QgsSymbolLayer::PropertyArrowType
@ PropertyArrowType
Arrow type.
Definition: qgssymbollayer.h:194
QgsLineSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgssymbollayer.cpp:721
QgsSymbolLayerUtils::decodeArrowType
static QgsArrowSymbolLayer::ArrowType decodeArrowType(const QVariant &value, bool *ok=nullptr)
Decodes a value representing an arrow type.
Definition: qgssymbollayerutils.cpp:445
QgsArrowSymbolLayer::~QgsArrowSymbolLayer
~QgsArrowSymbolLayer() override
QgsArrowSymbolLayer::setArrowWidthUnit
void setArrowWidthUnit(QgsUnitTypes::RenderUnit unit)
Sets the unit for the arrow width.
Definition: qgsarrowsymbollayer.h:64
QgsSymbolRenderContext::renderContext
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgssymbolrendercontext.h:62
QgsLineSymbolLayer::offset
double offset() const
Returns the line's offset.
Definition: qgssymbollayer.h:1112
QgsArrowSymbolLayer::setArrowWidth
void setArrowWidth(double width)
Sets the arrow width.
Definition: qgsarrowsymbollayer.h:60
spiralArcTo
void spiralArcTo(QPainterPath &path, QPointF center, qreal startAngle, qreal startRadius, qreal endAngle, qreal endRadius, int direction)
Definition: qgsarrowsymbollayer.cpp:435
Qgis::RenderContextFlag::RenderingSubSymbol
@ RenderingSubSymbol
Set whenever a sub-symbol of a parent symbol is currently being rendered. Can be used during symbol a...
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsArrowSymbolLayer::isRepeated
bool isRepeated() const
Returns whether the arrow is repeated along the line or not.
Definition: qgsarrowsymbollayer.h:115
QgsExpressionContextScope::StaticVariable
Single variable definition for use within a QgsExpressionContextScope.
Definition: qgsexpressioncontext.h:120
QgsPropertyCollection::isActive
bool isActive(int key) const override
Returns true if the collection contains an active property with the specified key.
Definition: qgspropertycollection.cpp:268
QgsArrowSymbolLayer::setOutputUnit
void setOutputUnit(QgsUnitTypes::RenderUnit unit) override
Sets the units to use for sizes and widths within the symbol layer.
Definition: qgsarrowsymbollayer.cpp:196
MathUtils::angle
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)
Definition: MathUtils.cpp:786
QgsSymbolLayer::copyDataDefinedProperties
void copyDataDefinedProperties(QgsSymbolLayer *destLayer) const
Copies all data defined properties of this layer to another symbol layer.
Definition: qgssymbollayer.cpp:483
qgsfillsymbol.h
QgsArrowSymbolLayer::arrowType
ArrowType arrowType() const
Gets the current arrow type.
Definition: qgsarrowsymbollayer.h:141
QgsUnitTypes::RenderMapUnits
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:676
QgsArrowSymbolLayer::setHeadLength
void setHeadLength(double length)
Sets the arrow head length.
Definition: qgsarrowsymbollayer.h:86
QgsArrowSymbolLayer::color
QColor color() const override
Returns the "representative" color of the symbol layer.
Definition: qgsarrowsymbollayer.cpp:869
QgsArrowSymbolLayer::arrowWidth
double arrowWidth() const
Gets current arrow width.
Definition: qgsarrowsymbollayer.h:58
QgsArrowSymbolLayer::setIsCurved
void setIsCurved(bool isCurved)
Sets whether it is a curved arrow or a straight one.
Definition: qgsarrowsymbollayer.h:112
QgsArrowSymbolLayer::headLengthUnitScale
QgsMapUnitScale headLengthUnitScale() const
Gets the scale for the head length.
Definition: qgsarrowsymbollayer.h:92
pointsToCircle
bool pointsToCircle(QPointF a, QPointF b, QPointF c, QPointF &center, qreal &radius)
Compute the circumscribed circle from three points.
Definition: qgsarrowsymbollayer.cpp:367