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