QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgscallout.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscallout.cpp
3  ----------------
4  begin : July 2019
5  copyright : (C) 2019 Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgscallout.h"
19 #include "qgsrendercontext.h"
20 #include "qgssymbol.h"
21 #include "qgslinesymbollayer.h"
22 #include "qgsfillsymbollayer.h"
23 #include "qgssymbollayerutils.h"
24 #include "qgsxmlutils.h"
25 #include "qgslinestring.h"
26 #include "qgslogger.h"
27 #include "qgsgeos.h"
28 #include "qgsgeometryutils.h"
29 #include "qgscircularstring.h"
30 #include "qgsshapegenerator.h"
31 #include "qgspainting.h"
32 #include "qgsfillsymbol.h"
33 #include "qgslinesymbol.h"
34 
35 #include <mutex>
36 
37 QgsPropertiesDefinition QgsCallout::sPropertyDefinitions;
38 
39 void QgsCallout::initPropertyDefinitions()
40 {
41  const QString origin = QStringLiteral( "callouts" );
42 
43  sPropertyDefinitions = QgsPropertiesDefinition
44  {
45  { QgsCallout::MinimumCalloutLength, QgsPropertyDefinition( "MinimumCalloutLength", QObject::tr( "Minimum callout length" ), QgsPropertyDefinition::DoublePositive, origin ) },
46  { QgsCallout::OffsetFromAnchor, QgsPropertyDefinition( "OffsetFromAnchor", QObject::tr( "Offset from feature" ), QgsPropertyDefinition::DoublePositive, origin ) },
47  { QgsCallout::OffsetFromLabel, QgsPropertyDefinition( "OffsetFromLabel", QObject::tr( "Offset from label" ), QgsPropertyDefinition::DoublePositive, origin ) },
48  { QgsCallout::DrawCalloutToAllParts, QgsPropertyDefinition( "DrawCalloutToAllParts", QObject::tr( "Draw lines to all feature parts" ), QgsPropertyDefinition::Boolean, origin ) },
49  { QgsCallout::AnchorPointPosition, QgsPropertyDefinition( "AnchorPointPosition", QgsPropertyDefinition::DataTypeString, QObject::tr( "Feature's anchor point position" ), QObject::tr( "string " ) + "[<b>pole_of_inaccessibility</b>|<b>point_on_exterior</b>|<b>point_on_surface</b>|<b>centroid</b>]", origin ) },
50  {
51  QgsCallout::LabelAnchorPointPosition, QgsPropertyDefinition( "LabelAnchorPointPosition", QgsPropertyDefinition::DataTypeString, QObject::tr( "Label's anchor point position" ), QObject::tr( "string " ) + "[<b>point_on_exterior</b>|<b>centroid</b>|<b>TL</b>=Top left|<b>T</b>=Top middle|"
52  "<b>TR</b>=Top right|<br>"
53  "<b>L</b>=Left|<b>R</b>=Right|<br>"
54  "<b>BL</b>=Bottom left|<b>B</b>=Bottom middle|"
55  "<b>BR</b>=Bottom right]", origin )
56  },
57  { QgsCallout::OriginX, QgsPropertyDefinition( "OriginX", QObject::tr( "Callout origin (X)" ), QgsPropertyDefinition::Double, origin ) },
58  { QgsCallout::OriginY, QgsPropertyDefinition( "OriginY", QObject::tr( "Callout origin (Y)" ), QgsPropertyDefinition::Double, origin ) },
59  { QgsCallout::DestinationX, QgsPropertyDefinition( "DestinationX", QObject::tr( "Callout destination (X)" ), QgsPropertyDefinition::Double, origin ) },
60  { QgsCallout::DestinationY, QgsPropertyDefinition( "DestinationY", QObject::tr( "Callout destination (Y)" ), QgsPropertyDefinition::Double, origin ) },
61  { QgsCallout::Curvature, QgsPropertyDefinition( "Curvature", QObject::tr( "Callout line curvature" ), QgsPropertyDefinition::Double, origin ) },
62  {
63  QgsCallout::Orientation, QgsPropertyDefinition( "Orientation", QgsPropertyDefinition::DataTypeString, QObject::tr( "Callout curve orientation" ), QObject::tr( "string " ) + "[<b>auto</b>|<b>clockwise</b>|<b>counterclockwise</b>]", origin )
64  },
65  {
66  QgsCallout::Margins, QgsPropertyDefinition( "Margins", QgsPropertyDefinition::DataTypeString, QObject::tr( "Margins" ), QObject::tr( "string of four doubles '<b>top,right,bottom,left</b>' or array of doubles <b>[top, right, bottom, left]</b>" ) )
67  },
68  { QgsCallout::WedgeWidth, QgsPropertyDefinition( "WedgeWidth", QObject::tr( "Wedge width" ), QgsPropertyDefinition::DoublePositive, origin ) },
69  { QgsCallout::CornerRadius, QgsPropertyDefinition( "CornerRadius", QObject::tr( "Corner radius" ), QgsPropertyDefinition::DoublePositive, origin ) },
70  { QgsCallout::BlendMode, QgsPropertyDefinition( "BlendMode", QObject::tr( "Callout blend mode" ), QgsPropertyDefinition::BlendMode, origin ) },
71  };
72 }
73 
74 
76 {
77 }
78 
79 QVariantMap QgsCallout::properties( const QgsReadWriteContext & ) const
80 {
81  QVariantMap props;
82  props.insert( QStringLiteral( "enabled" ), mEnabled ? "1" : "0" );
83  props.insert( QStringLiteral( "anchorPoint" ), encodeAnchorPoint( mAnchorPoint ) );
84  props.insert( QStringLiteral( "labelAnchorPoint" ), encodeLabelAnchorPoint( mLabelAnchorPoint ) );
85  props.insert( QStringLiteral( "blendMode" ), QgsPainting::getBlendModeEnum( mBlendMode ) );
86  props.insert( QStringLiteral( "ddProperties" ), mDataDefinedProperties.toVariant( propertyDefinitions() ) );
87  return props;
88 }
89 
90 void QgsCallout::readProperties( const QVariantMap &props, const QgsReadWriteContext & )
91 {
92  mEnabled = props.value( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();
93  mAnchorPoint = decodeAnchorPoint( props.value( QStringLiteral( "anchorPoint" ), QString() ).toString() );
94  mLabelAnchorPoint = decodeLabelAnchorPoint( props.value( QStringLiteral( "labelAnchorPoint" ), QString() ).toString() );
96  static_cast< QgsPainting::BlendMode >( props.value( QStringLiteral( "blendMode" ), QString::number( QgsPainting::BlendNormal ) ).toUInt() ) );
97  mDataDefinedProperties.loadVariant( props.value( QStringLiteral( "ddProperties" ) ), propertyDefinitions() );
98 }
99 
100 bool QgsCallout::saveProperties( QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context ) const
101 {
102  if ( element.isNull() )
103  {
104  return false;
105  }
106 
107  const QDomElement calloutPropsElement = QgsXmlUtils::writeVariant( properties( context ), doc );
108 
109  QDomElement calloutElement = doc.createElement( QStringLiteral( "callout" ) );
110  calloutElement.setAttribute( QStringLiteral( "type" ), type() );
111  calloutElement.appendChild( calloutPropsElement );
112 
113  element.appendChild( calloutElement );
114  return true;
115 }
116 
117 void QgsCallout::restoreProperties( const QDomElement &element, const QgsReadWriteContext &context )
118 {
119  const QVariantMap props = QgsXmlUtils::readVariant( element.firstChildElement() ).toMap();
120  readProperties( props, context );
121 }
122 
124 {
125 
126 }
128 {
129 
130 }
131 
133 {
134  return mBlendMode != QPainter::CompositionMode_SourceOver || dataDefinedProperties().isActive( QgsCallout::BlendMode );
135 }
136 
137 QSet<QString> QgsCallout::referencedFields( const QgsRenderContext &context ) const
138 {
139  mDataDefinedProperties.prepare( context.expressionContext() );
140  return mDataDefinedProperties.referencedFields( context.expressionContext() );
141 }
142 
144 {
145  return OrderBelowAllLabels;
146 }
147 
148 void QgsCallout::render( QgsRenderContext &context, const QRectF &rect, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext )
149 {
150  QPainter *painter = context.painter();
151  if ( context.useAdvancedEffects() )
152  {
153 
154  const QPainter::CompositionMode blendMode = mBlendMode;
155  if ( dataDefinedProperties().isActive( QgsCallout::BlendMode ) )
156  {
157  context.expressionContext().setOriginalValueVariable( QString() );
158  mBlendMode = QgsSymbolLayerUtils::decodeBlendMode( dataDefinedProperties().valueAsString( QgsCallout::BlendMode, context.expressionContext(), QString() ) );
159  }
160 
161  painter->setCompositionMode( blendMode );
162  }
163 
164 #if 0 // for debugging
165  painter->save();
166  painter->setRenderHint( QPainter::Antialiasing, false );
167  painter->translate( rect.center() );
168  painter->rotate( -angle );
169 
170  painter->setBrush( QColor( 255, 0, 0, 100 ) );
171  painter->setPen( QColor( 255, 0, 0, 150 ) );
172 
173  painter->drawRect( rect.width() * -0.5, rect.height() * -0.5, rect.width(), rect.height() );
174  painter->restore();
175 
176  painter->setBrush( QColor( 0, 255, 0, 100 ) );
177  painter->setPen( QColor( 0, 255, 0, 150 ) );
178 
179  painter->drawRect( anchor.boundingBox( ).buffered( 30 ).toRectF() );
180 #endif
181 
182  draw( context, rect, angle, anchor, calloutContext );
183 
184  painter->setCompositionMode( QPainter::CompositionMode_SourceOver ); // just to be sure
185 }
186 
187 void QgsCallout::setEnabled( bool enabled )
188 {
189  mEnabled = enabled;
190 }
191 
193 {
194  static std::once_flag initialized;
195  std::call_once( initialized, [ = ]( )
196  {
197  initPropertyDefinitions();
198  } );
199  return sPropertyDefinitions;
200 }
201 
203 {
204  if ( ok )
205  *ok = true;
206  const QString cleaned = name.toLower().trimmed();
207 
208  if ( cleaned == QLatin1String( "pole_of_inaccessibility" ) )
209  return PoleOfInaccessibility;
210  else if ( cleaned == QLatin1String( "point_on_exterior" ) )
211  return PointOnExterior;
212  else if ( cleaned == QLatin1String( "point_on_surface" ) )
213  return PointOnSurface;
214  else if ( cleaned == QLatin1String( "centroid" ) )
215  return Centroid;
216 
217  if ( ok )
218  *ok = false;
219  return PoleOfInaccessibility;
220 }
221 
223 {
224  switch ( anchor )
225  {
227  return QStringLiteral( "pole_of_inaccessibility" );
228  case PointOnExterior:
229  return QStringLiteral( "point_on_exterior" );
230  case PointOnSurface:
231  return QStringLiteral( "point_on_surface" );
232  case Centroid:
233  return QStringLiteral( "centroid" );
234  }
235  return QString();
236 }
237 
239 {
240  switch ( anchor )
241  {
243  return QStringLiteral( "point_on_exterior" );
244  case LabelCentroid:
245  return QStringLiteral( "centroid" );
246  case LabelTopLeft:
247  return QStringLiteral( "tl" );
248  case LabelTopMiddle:
249  return QStringLiteral( "t" );
250  case LabelTopRight:
251  return QStringLiteral( "tr" );
252  case LabelMiddleLeft:
253  return QStringLiteral( "l" );
254  case LabelMiddleRight:
255  return QStringLiteral( "r" );
256  case LabelBottomLeft:
257  return QStringLiteral( "bl" );
258  case LabelBottomMiddle:
259  return QStringLiteral( "b" );
260  case LabelBottomRight:
261  return QStringLiteral( "br" );
262  }
263 
264  return QString();
265 }
266 
268 {
269  if ( ok )
270  *ok = true;
271  const QString cleaned = name.toLower().trimmed();
272 
273  if ( cleaned == QLatin1String( "point_on_exterior" ) )
274  return LabelPointOnExterior;
275  else if ( cleaned == QLatin1String( "centroid" ) )
276  return LabelCentroid;
277  else if ( cleaned == QLatin1String( "tl" ) )
278  return LabelTopLeft;
279  else if ( cleaned == QLatin1String( "t" ) )
280  return LabelTopMiddle;
281  else if ( cleaned == QLatin1String( "tr" ) )
282  return LabelTopRight;
283  else if ( cleaned == QLatin1String( "l" ) )
284  return LabelMiddleLeft;
285  else if ( cleaned == QLatin1String( "r" ) )
286  return LabelMiddleRight;
287  else if ( cleaned == QLatin1String( "bl" ) )
288  return LabelBottomLeft;
289  else if ( cleaned == QLatin1String( "b" ) )
290  return LabelBottomMiddle;
291  else if ( cleaned == QLatin1String( "br" ) )
292  return LabelBottomRight;
293 
294  if ( ok )
295  *ok = false;
296  return LabelPointOnExterior;
297 }
298 
299 QgsGeometry QgsCallout::labelAnchorGeometry( const QRectF &rect, const double angle, LabelAnchorPoint anchor ) const
300 {
301  QgsGeometry label;
302  switch ( anchor )
303  {
305  label = QgsGeometry::fromRect( rect );
306  break;
307 
308  case LabelCentroid:
309  label = QgsGeometry::fromRect( rect ).centroid();
310  break;
311 
312  case LabelTopLeft:
313  label = QgsGeometry::fromPointXY( QgsPointXY( rect.bottomLeft() ) );
314  break;
315 
316  case LabelTopMiddle:
317  label = QgsGeometry::fromPointXY( QgsPointXY( ( rect.left() + rect.right() ) / 2.0, rect.bottom() ) );
318  break;
319 
320  case LabelTopRight:
321  label = QgsGeometry::fromPointXY( QgsPointXY( rect.bottomRight() ) );
322  break;
323 
324  case LabelMiddleLeft:
325  label = QgsGeometry::fromPointXY( QgsPointXY( rect.left(), ( rect.top() + rect.bottom() ) / 2.0 ) );
326  break;
327 
328  case LabelMiddleRight:
329  label = QgsGeometry::fromPointXY( QgsPointXY( rect.right(), ( rect.top() + rect.bottom() ) / 2.0 ) );
330  break;
331 
332  case LabelBottomLeft:
333  label = QgsGeometry::fromPointXY( QgsPointXY( rect.topLeft() ) );
334  break;
335 
336  case LabelBottomMiddle:
337  label = QgsGeometry::fromPointXY( QgsPointXY( ( rect.left() + rect.right() ) / 2.0, rect.top() ) );
338  break;
339 
340  case LabelBottomRight:
341  label = QgsGeometry::fromPointXY( QgsPointXY( rect.topRight() ) );
342  break;
343  }
344 
345  label.rotate( angle, rect.topLeft() );
346  return label;
347 }
348 
349 QgsGeometry QgsCallout::calloutLabelPoint( const QRectF &rect, const double angle, QgsCallout::LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCallout::QgsCalloutContext &calloutContext, bool &pinned ) const
350 {
351  pinned = false;
353  {
354  bool ok = false;
355  const double x = dataDefinedProperties().valueAsDouble( QgsCallout::OriginX, context.expressionContext(), 0, &ok );
356  if ( ok )
357  {
358  const double y = dataDefinedProperties().valueAsDouble( QgsCallout::OriginY, context.expressionContext(), 0, &ok );
359  if ( ok )
360  {
361  pinned = true;
362  // data defined label point, use it directly
363  QgsGeometry labelPoint = QgsGeometry::fromPointXY( QgsPointXY( x, y ) );
364  try
365  {
366  labelPoint.transform( calloutContext.originalFeatureToMapTransform( context ) );
367  labelPoint.transform( context.mapToPixel().transform() );
368  }
369  catch ( QgsCsException & )
370  {
371  return QgsGeometry();
372  }
373  return labelPoint;
374  }
375  }
376  }
377 
378  QgsGeometry label;
379  switch ( anchor )
380  {
382  label = QgsGeometry::fromRect( rect );
383  break;
384 
385  case LabelCentroid:
386  label = QgsGeometry::fromRect( rect ).centroid();
387  break;
388 
389  case LabelTopLeft:
390  label = QgsGeometry::fromPointXY( QgsPointXY( rect.bottomLeft() ) );
391  break;
392 
393  case LabelTopMiddle:
394  label = QgsGeometry::fromPointXY( QgsPointXY( ( rect.left() + rect.right() ) / 2.0, rect.bottom() ) );
395  break;
396 
397  case LabelTopRight:
398  label = QgsGeometry::fromPointXY( QgsPointXY( rect.bottomRight() ) );
399  break;
400 
401  case LabelMiddleLeft:
402  label = QgsGeometry::fromPointXY( QgsPointXY( rect.left(), ( rect.top() + rect.bottom() ) / 2.0 ) );
403  break;
404 
405  case LabelMiddleRight:
406  label = QgsGeometry::fromPointXY( QgsPointXY( rect.right(), ( rect.top() + rect.bottom() ) / 2.0 ) );
407  break;
408 
409  case LabelBottomLeft:
410  label = QgsGeometry::fromPointXY( QgsPointXY( rect.topLeft() ) );
411  break;
412 
413  case LabelBottomMiddle:
414  label = QgsGeometry::fromPointXY( QgsPointXY( ( rect.left() + rect.right() ) / 2.0, rect.top() ) );
415  break;
416 
417  case LabelBottomRight:
418  label = QgsGeometry::fromPointXY( QgsPointXY( rect.topRight() ) );
419  break;
420  }
421 
422  label.rotate( angle, rect.topLeft() );
423  return label;
424 }
425 
426 QgsGeometry QgsCallout::calloutLineToPart( const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned ) const
427 {
428  pinned = false;
429  AnchorPoint anchor = anchorPoint();
430  const QgsAbstractGeometry *evaluatedPartAnchor = partGeometry;
431  std::unique_ptr< QgsAbstractGeometry > tempPartAnchor;
432 
434  {
435  bool ok = false;
436  const double x = dataDefinedProperties().valueAsDouble( QgsCallout::DestinationX, context.expressionContext(), 0, &ok );
437  if ( ok )
438  {
439  const double y = dataDefinedProperties().valueAsDouble( QgsCallout::DestinationY, context.expressionContext(), 0, &ok );
440  if ( ok )
441  {
442  pinned = true;
443  tempPartAnchor = std::make_unique< QgsPoint >( QgsWkbTypes::Point, x, y );
444  evaluatedPartAnchor = tempPartAnchor.get();
445  try
446  {
447  tempPartAnchor->transform( calloutContext.originalFeatureToMapTransform( context ) );
448  tempPartAnchor->transform( context.mapToPixel().transform() );
449  }
450  catch ( QgsCsException & )
451  {
452  evaluatedPartAnchor = partGeometry;
453  }
454  }
455  }
456  }
457 
459  {
460  const QString encodedAnchor = encodeAnchorPoint( anchor );
461  context.expressionContext().setOriginalValueVariable( encodedAnchor );
462  anchor = decodeAnchorPoint( dataDefinedProperties().valueAsString( QgsCallout::AnchorPointPosition, context.expressionContext(), encodedAnchor ) );
463  }
464 
465  QgsGeometry line;
466  const QgsGeos labelGeos( labelGeometry.constGet() );
467 
468  switch ( QgsWkbTypes::geometryType( evaluatedPartAnchor->wkbType() ) )
469  {
472  {
473  line = labelGeos.shortestLine( evaluatedPartAnchor );
474  break;
475  }
476 
478  {
479  if ( labelGeos.intersects( evaluatedPartAnchor ) )
480  return QgsGeometry();
481 
482  // ideally avoid this unwanted clone in future. For now we need it because poleOfInaccessibility/pointOnSurface are
483  // only available to QgsGeometry objects
484  const QgsGeometry evaluatedPartAnchorGeom( evaluatedPartAnchor->clone() );
485  switch ( anchor )
486  {
488  line = labelGeos.shortestLine( evaluatedPartAnchorGeom.poleOfInaccessibility( std::max( evaluatedPartAnchor->boundingBox().width(), evaluatedPartAnchor->boundingBox().height() ) / 20.0 ) ); // really rough (but quick) pole of inaccessibility
489  break;
491  line = labelGeos.shortestLine( evaluatedPartAnchorGeom.pointOnSurface() );
492  break;
494  line = labelGeos.shortestLine( evaluatedPartAnchor );
495  break;
497  line = labelGeos.shortestLine( evaluatedPartAnchorGeom.centroid() );
498  break;
499  }
500  break;
501  }
502 
505  return QgsGeometry(); // shouldn't even get here..
506  }
507  return line;
508 }
509 
510 //
511 // QgsCallout::QgsCalloutContext
512 //
513 
515 {
516  if ( !mOriginalFeatureToMapTransform.isValid() )
517  {
518  // lazy initialization, only create if needed...
519  mOriginalFeatureToMapTransform = QgsCoordinateTransform( originalFeatureCrs, renderContext.coordinateTransform().destinationCrs(), renderContext.transformContext() );
520  }
521  return mOriginalFeatureToMapTransform;
522 }
523 
524 
525 //
526 // QgsSimpleLineCallout
527 //
528 
530 {
531  mLineSymbol = std::make_unique< QgsLineSymbol >( QgsSymbolLayerList() << new QgsSimpleLineSymbolLayer( QColor( 60, 60, 60 ), .3 ) );
532 
533 }
534 
536 
538  : QgsCallout( other )
539  , mLineSymbol( other.mLineSymbol ? other.mLineSymbol->clone() : nullptr )
540  , mMinCalloutLength( other.mMinCalloutLength )
541  , mMinCalloutLengthUnit( other.mMinCalloutLengthUnit )
542  , mMinCalloutLengthScale( other.mMinCalloutLengthScale )
543  , mOffsetFromAnchorDistance( other.mOffsetFromAnchorDistance )
544  , mOffsetFromAnchorUnit( other.mOffsetFromAnchorUnit )
545  , mOffsetFromAnchorScale( other.mOffsetFromAnchorScale )
546  , mOffsetFromLabelDistance( other.mOffsetFromLabelDistance )
547  , mOffsetFromLabelUnit( other.mOffsetFromLabelUnit )
548  , mOffsetFromLabelScale( other.mOffsetFromLabelScale )
549  , mDrawCalloutToAllParts( other.mDrawCalloutToAllParts )
550 {
551 
552 }
553 
554 QgsCallout *QgsSimpleLineCallout::create( const QVariantMap &properties, const QgsReadWriteContext &context )
555 {
556  std::unique_ptr< QgsSimpleLineCallout > callout = std::make_unique< QgsSimpleLineCallout >();
557  callout->readProperties( properties, context );
558  return callout.release();
559 }
560 
562 {
563  return QStringLiteral( "simple" );
564 }
565 
567 {
568  return new QgsSimpleLineCallout( *this );
569 }
570 
571 QVariantMap QgsSimpleLineCallout::properties( const QgsReadWriteContext &context ) const
572 {
573  QVariantMap props = QgsCallout::properties( context );
574 
575  if ( mLineSymbol )
576  {
577  props[ QStringLiteral( "lineSymbol" ) ] = QgsSymbolLayerUtils::symbolProperties( mLineSymbol.get() );
578  }
579  props[ QStringLiteral( "minLength" ) ] = mMinCalloutLength;
580  props[ QStringLiteral( "minLengthUnit" ) ] = QgsUnitTypes::encodeUnit( mMinCalloutLengthUnit );
581  props[ QStringLiteral( "minLengthMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mMinCalloutLengthScale );
582 
583  props[ QStringLiteral( "offsetFromAnchor" ) ] = mOffsetFromAnchorDistance;
584  props[ QStringLiteral( "offsetFromAnchorUnit" ) ] = QgsUnitTypes::encodeUnit( mOffsetFromAnchorUnit );
585  props[ QStringLiteral( "offsetFromAnchorMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetFromAnchorScale );
586  props[ QStringLiteral( "offsetFromLabel" ) ] = mOffsetFromLabelDistance;
587  props[ QStringLiteral( "offsetFromLabelUnit" ) ] = QgsUnitTypes::encodeUnit( mOffsetFromLabelUnit );
588  props[ QStringLiteral( "offsetFromLabelMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetFromLabelScale );
589 
590  props[ QStringLiteral( "drawToAllParts" ) ] = mDrawCalloutToAllParts;
591 
592  return props;
593 }
594 
595 void QgsSimpleLineCallout::readProperties( const QVariantMap &props, const QgsReadWriteContext &context )
596 {
597  QgsCallout::readProperties( props, context );
598 
599  const QString lineSymbolDef = props.value( QStringLiteral( "lineSymbol" ) ).toString();
600  QDomDocument doc( QStringLiteral( "symbol" ) );
601  doc.setContent( lineSymbolDef );
602  const QDomElement symbolElem = doc.firstChildElement( QStringLiteral( "symbol" ) );
603  std::unique_ptr< QgsLineSymbol > lineSymbol( QgsSymbolLayerUtils::loadSymbol< QgsLineSymbol >( symbolElem, context ) );
604  if ( lineSymbol )
605  mLineSymbol = std::move( lineSymbol );
606 
607  mMinCalloutLength = props.value( QStringLiteral( "minLength" ), 0 ).toDouble();
608  mMinCalloutLengthUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "minLengthUnit" ) ).toString() );
609  mMinCalloutLengthScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "minLengthMapUnitScale" ) ).toString() );
610 
611  mOffsetFromAnchorDistance = props.value( QStringLiteral( "offsetFromAnchor" ), 0 ).toDouble();
612  mOffsetFromAnchorUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "offsetFromAnchorUnit" ) ).toString() );
613  mOffsetFromAnchorScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "offsetFromAnchorMapUnitScale" ) ).toString() );
614  mOffsetFromLabelDistance = props.value( QStringLiteral( "offsetFromLabel" ), 0 ).toDouble();
615  mOffsetFromLabelUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "offsetFromLabelUnit" ) ).toString() );
616  mOffsetFromLabelScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "offsetFromLabelMapUnitScale" ) ).toString() );
617 
618  mDrawCalloutToAllParts = props.value( QStringLiteral( "drawToAllParts" ), false ).toBool();
619 }
620 
622 {
623  QgsCallout::startRender( context );
624  if ( mLineSymbol )
625  mLineSymbol->startRender( context );
626 }
627 
629 {
630  QgsCallout::stopRender( context );
631  if ( mLineSymbol )
632  mLineSymbol->stopRender( context );
633 }
634 
635 QSet<QString> QgsSimpleLineCallout::referencedFields( const QgsRenderContext &context ) const
636 {
637  QSet<QString> fields = QgsCallout::referencedFields( context );
638  if ( mLineSymbol )
639  fields.unite( mLineSymbol->usedAttributes( context ) );
640  return fields;
641 }
642 
644 {
645  return mLineSymbol.get();
646 }
647 
649 {
650  mLineSymbol.reset( symbol );
651 }
652 
653 void QgsSimpleLineCallout::draw( QgsRenderContext &context, const QRectF &rect, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext )
654 {
655  LabelAnchorPoint labelAnchor = labelAnchorPoint();
657  {
658  const QString encodedAnchor = encodeLabelAnchorPoint( labelAnchor );
659  context.expressionContext().setOriginalValueVariable( encodedAnchor );
660  labelAnchor = decodeLabelAnchorPoint( dataDefinedProperties().valueAsString( QgsCallout::LabelAnchorPointPosition, context.expressionContext(), encodedAnchor ) );
661  }
662 
663  bool originPinned = false;
664  const QgsGeometry label = calloutLabelPoint( rect, angle, labelAnchor, context, calloutContext, originPinned );
665  if ( label.isNull() )
666  return;
667 
668  auto drawCalloutLine = [this, &context, &calloutContext, &label, &rect, angle, &anchor, originPinned]( const QgsAbstractGeometry * partAnchor )
669  {
670  bool destinationPinned = false;
671  const QgsGeometry line = calloutLineToPart( label, partAnchor, context, calloutContext, destinationPinned );
672  if ( line.isEmpty() )
673  return;
674 
675  const double lineLength = line.length();
676  if ( qgsDoubleNear( lineLength, 0 ) )
677  return;
678 
679  double minLength = mMinCalloutLength;
681  {
682  context.expressionContext().setOriginalValueVariable( minLength );
684  }
685  const double minLengthPixels = context.convertToPainterUnits( minLength, mMinCalloutLengthUnit, mMinCalloutLengthScale );
686  if ( minLengthPixels > 0 && lineLength < minLengthPixels )
687  return; // too small!
688 
689  std::unique_ptr< QgsCurve > calloutCurve( createCalloutLine( qgsgeometry_cast< const QgsLineString * >( line.constGet() )->startPoint(),
690  qgsgeometry_cast< const QgsLineString * >( line.constGet() )->endPoint(), context, rect, angle, anchor, calloutContext ) );
691 
692  double offsetFromAnchor = mOffsetFromAnchorDistance;
694  {
697  }
698  const double offsetFromAnchorPixels = context.convertToPainterUnits( offsetFromAnchor, mOffsetFromAnchorUnit, mOffsetFromAnchorScale );
699 
700  double offsetFromLabel = mOffsetFromLabelDistance;
702  {
705  }
706  const double offsetFromLabelPixels = context.convertToPainterUnits( offsetFromLabel, mOffsetFromLabelUnit, mOffsetFromLabelScale );
707  if ( offsetFromAnchorPixels > 0 || offsetFromLabelPixels > 0 )
708  {
709  calloutCurve.reset( calloutCurve->curveSubstring( offsetFromLabelPixels, calloutCurve->length() - offsetFromAnchorPixels ) );
710  }
711 
712  const QPolygonF points = calloutCurve->asQPolygonF();
713 
714  if ( points.empty() )
715  return;
716 
717  QgsCalloutPosition position;
718  position.setOrigin( context.mapToPixel().toMapCoordinates( points.at( 0 ).x(), points.at( 0 ).y() ).toQPointF() );
719  position.setOriginIsPinned( originPinned );
720  position.setDestination( context.mapToPixel().toMapCoordinates( points.constLast().x(), points.constLast().y() ).toQPointF() );
721  position.setDestinationIsPinned( destinationPinned );
722  calloutContext.addCalloutPosition( position );
723 
724  mLineSymbol->renderPolyline( points, nullptr, context );
725  };
726 
727  bool toAllParts = mDrawCalloutToAllParts;
729  {
730  context.expressionContext().setOriginalValueVariable( toAllParts );
732  }
733 
734  if ( calloutContext.allFeaturePartsLabeled || !toAllParts )
735  drawCalloutLine( anchor.constGet() );
736  else
737  {
738  for ( auto it = anchor.const_parts_begin(); it != anchor.const_parts_end(); ++it )
739  drawCalloutLine( *it );
740  }
741 }
742 
743 QgsCurve *QgsSimpleLineCallout::createCalloutLine( const QgsPoint &start, const QgsPoint &end, QgsRenderContext &, const QRectF &, const double, const QgsGeometry &, QgsCallout::QgsCalloutContext & ) const
744 {
745  return new QgsLineString( start, end );
746 }
747 
748 //
749 // QgsManhattanLineCallout
750 //
751 
753 {
754 }
755 
757  : QgsSimpleLineCallout( other )
758 {
759 
760 }
761 
762 
763 QgsCallout *QgsManhattanLineCallout::create( const QVariantMap &properties, const QgsReadWriteContext &context )
764 {
765  std::unique_ptr< QgsManhattanLineCallout > callout = std::make_unique< QgsManhattanLineCallout >();
766  callout->readProperties( properties, context );
767  return callout.release();
768 }
769 
771 {
772  return QStringLiteral( "manhattan" );
773 }
774 
776 {
777  return new QgsManhattanLineCallout( *this );
778 }
779 
780 QgsCurve *QgsManhattanLineCallout::createCalloutLine( const QgsPoint &start, const QgsPoint &end, QgsRenderContext &, const QRectF &, const double, const QgsGeometry &, QgsCallout::QgsCalloutContext & ) const
781 {
782  const QgsPoint mid1 = QgsPoint( start.x(), end.y() );
783  return new QgsLineString( QVector< QgsPoint >() << start << mid1 << end );
784 }
785 
786 
787 //
788 // QgsCurvedLineCallout
789 //
790 
792 {
793 }
794 
796  : QgsSimpleLineCallout( other )
797  , mOrientation( other.mOrientation )
798  , mCurvature( other.mCurvature )
799 {
800 
801 }
802 
803 QgsCallout *QgsCurvedLineCallout::create( const QVariantMap &properties, const QgsReadWriteContext &context )
804 {
805  std::unique_ptr< QgsCurvedLineCallout > callout = std::make_unique< QgsCurvedLineCallout >();
806  callout->readProperties( properties, context );
807 
808  callout->setCurvature( properties.value( QStringLiteral( "curvature" ), 0.1 ).toDouble() );
809  callout->setOrientation( decodeOrientation( properties.value( QStringLiteral( "orientation" ), QStringLiteral( "auto" ) ).toString() ) );
810 
811  return callout.release();
812 }
813 
815 {
816  return QStringLiteral( "curved" );
817 }
818 
820 {
821  return new QgsCurvedLineCallout( *this );
822 }
823 
824 QVariantMap QgsCurvedLineCallout::properties( const QgsReadWriteContext &context ) const
825 {
826  QVariantMap props = QgsSimpleLineCallout::properties( context );
827  props.insert( QStringLiteral( "curvature" ), mCurvature );
828  props.insert( QStringLiteral( "orientation" ), encodeOrientation( mOrientation ) );
829  return props;
830 }
831 
832 QgsCurve *QgsCurvedLineCallout::createCalloutLine( const QgsPoint &start, const QgsPoint &end, QgsRenderContext &context, const QRectF &rect, const double, const QgsGeometry &, QgsCallout::QgsCalloutContext & ) const
833 {
834  double curvature = mCurvature * 100;
835  if ( dataDefinedProperties().isActive( QgsCallout::Curvature ) )
836  {
839  }
840 
841  Orientation orientation = mOrientation;
843  {
844  bool ok = false;
845  const QString orientationString = dataDefinedProperties().property( QgsCallout::Orientation ).valueAsString( context.expressionContext(), QString(), &ok );
846  if ( ok )
847  {
848  orientation = decodeOrientation( orientationString );
849  }
850  }
851 
852  if ( orientation == Automatic )
853  {
854  // to calculate automatically the best curve orientation, we first check which side of the label bounding box
855  // the callout origin is nearest to
856  switch ( QgsGeometryUtils::closestSideOfRectangle( rect.right(), rect.bottom(), rect.left(), rect.top(), start.x(), start.y() ) )
857  {
858  case 1:
859  // closest to bottom
860  if ( qgsDoubleNear( end.x(), start.x() ) )
861  {
862  // if vertical line, we bend depending on whether the line sits towards the left or right side of the label
863  if ( start.x() < ( rect.left() + 0.5 * rect.width() ) )
865  else
867  }
868  else if ( end.x() > start.x() )
870  else
872  break;
873 
874  case 2:
875  // closest to bottom-right
876  if ( end.x() < start.x() )
878  else if ( end.y() < start.y() )
880  else if ( end.x() - start.x() < end.y() - start.y() )
882  else
884  break;
885 
886  case 3:
887  // closest to right
888  if ( qgsDoubleNear( end.y(), start.y() ) )
889  {
890  // if horizontal line, we bend depending on whether the line sits towards the top or bottom side of the label
891  if ( start.y() < ( rect.top() + 0.5 * rect.height() ) )
893  else
895  }
896  else if ( end.y() < start.y() )
898  else
900  break;
901 
902  case 4:
903  // closest to top-right
904  if ( end.x() < start.x() )
906  else if ( end.y() > start.y() )
908  else if ( end.x() - start.x() < start.y() - end.y() )
910  else
912  break;
913 
914  case 5:
915  // closest to top
916  if ( qgsDoubleNear( end.x(), start.x() ) )
917  {
918  // if vertical line, we bend depending on whether the line sits towards the left or right side of the label
919  if ( start.x() < ( rect.left() + 0.5 * rect.width() ) )
921  else
923  }
924  else if ( end.x() < start.x() )
926  else
928  break;
929 
930  case 6:
931  // closest to top-left
932  if ( end.x() > start.x() )
934  else if ( end.y() > start.y() )
936  else if ( start.x() - end.x() < start.y() - end.y() )
938  else
940  break;
941 
942  case 7:
943  //closest to left
944  if ( qgsDoubleNear( end.y(), start.y() ) )
945  {
946  // if horizontal line, we bend depending on whether the line sits towards the top or bottom side of the label
947  if ( start.y() < ( rect.top() + 0.5 * rect.height() ) )
949  else
951  }
952  else if ( end.y() > start.y() )
954  else
956  break;
957 
958  case 8:
959  //closest to bottom-left
960  if ( end.x() > start.x() )
962  else if ( end.y() < start.y() )
964  else if ( start.x() - end.x() < end.y() - start.y() )
966  else
968  break;
969  }
970  }
971 
972  // turn the line into a curved line. We do this by creating a circular string from the callout line's
973  // start to end point, where the curve point is in the middle of the callout line and perpendicularly offset
974  // by a proportion of the overall callout line length
975  const double distance = ( orientation == Clockwise ? 1 : -1 ) * start.distance( end ) * curvature / 100.0;
976  double midX, midY;
977  QgsGeometryUtils::perpendicularOffsetPointAlongSegment( start.x(), start.y(), end.x(), end.y(), 0.5, distance, &midX, &midY );
978 
979  return new QgsCircularString( start, QgsPoint( midX, midY ), end );
980 }
981 
982 QgsCurvedLineCallout::Orientation QgsCurvedLineCallout::decodeOrientation( const QString &string )
983 {
984  const QString cleaned = string.toLower().trimmed();
985  if ( cleaned == QLatin1String( "auto" ) )
986  return Automatic;
987  if ( cleaned == QLatin1String( "clockwise" ) )
988  return Clockwise;
989  if ( cleaned == QLatin1String( "counterclockwise" ) )
990  return CounterClockwise;
991  return Automatic;
992 }
993 
994 QString QgsCurvedLineCallout::encodeOrientation( QgsCurvedLineCallout::Orientation orientation )
995 {
996  switch ( orientation )
997  {
999  return QStringLiteral( "auto" );
1001  return QStringLiteral( "clockwise" );
1003  return QStringLiteral( "counterclockwise" );
1004  }
1005  return QString();
1006 }
1007 
1009 {
1010  return mOrientation;
1011 }
1012 
1014 {
1015  mOrientation = orientation;
1016 }
1017 
1019 {
1020  return mCurvature;
1021 }
1022 
1023 void QgsCurvedLineCallout::setCurvature( double curvature )
1024 {
1025  mCurvature = curvature;
1026 }
1027 
1028 
1029 
1030 //
1031 // QgsBalloonCallout
1032 //
1033 
1035 {
1036  mFillSymbol = std::make_unique< QgsFillSymbol >( QgsSymbolLayerList() << new QgsSimpleFillSymbolLayer( QColor( 255, 200, 60 ) ) );
1037 }
1038 
1040 
1042  : QgsCallout( other )
1043  , mFillSymbol( other.mFillSymbol ? other.mFillSymbol->clone() : nullptr )
1044  , mOffsetFromAnchorDistance( other.mOffsetFromAnchorDistance )
1045  , mOffsetFromAnchorUnit( other.mOffsetFromAnchorUnit )
1046  , mOffsetFromAnchorScale( other.mOffsetFromAnchorScale )
1047  , mMargins( other.mMargins )
1048  , mMarginUnit( other.mMarginUnit )
1049  , mWedgeWidth( other.mWedgeWidth )
1050  , mWedgeWidthUnit( other.mWedgeWidthUnit )
1051  , mWedgeWidthScale( other.mWedgeWidthScale )
1052  , mCornerRadius( other.mCornerRadius )
1053  , mCornerRadiusUnit( other.mCornerRadiusUnit )
1054  , mCornerRadiusScale( other.mCornerRadiusScale )
1055 {
1056 
1057 }
1058 
1059 QgsCallout *QgsBalloonCallout::create( const QVariantMap &properties, const QgsReadWriteContext &context )
1060 {
1061  std::unique_ptr< QgsBalloonCallout > callout = std::make_unique< QgsBalloonCallout >();
1062  callout->readProperties( properties, context );
1063  return callout.release();
1064 }
1065 
1067 {
1068  return QStringLiteral( "balloon" );
1069 }
1070 
1072 {
1073  return new QgsBalloonCallout( *this );
1074 }
1075 
1076 QVariantMap QgsBalloonCallout::properties( const QgsReadWriteContext &context ) const
1077 {
1078  QVariantMap props = QgsCallout::properties( context );
1079 
1080  if ( mFillSymbol )
1081  {
1082  props[ QStringLiteral( "fillSymbol" ) ] = QgsSymbolLayerUtils::symbolProperties( mFillSymbol.get() );
1083  }
1084 
1085  props[ QStringLiteral( "offsetFromAnchor" ) ] = mOffsetFromAnchorDistance;
1086  props[ QStringLiteral( "offsetFromAnchorUnit" ) ] = QgsUnitTypes::encodeUnit( mOffsetFromAnchorUnit );
1087  props[ QStringLiteral( "offsetFromAnchorMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mOffsetFromAnchorScale );
1088 
1089  props[ QStringLiteral( "margins" ) ] = mMargins.toString();
1090  props[ QStringLiteral( "marginsUnit" ) ] = QgsUnitTypes::encodeUnit( mMarginUnit );
1091 
1092  props[ QStringLiteral( "wedgeWidth" ) ] = mWedgeWidth;
1093  props[ QStringLiteral( "wedgeWidthUnit" ) ] = QgsUnitTypes::encodeUnit( mWedgeWidthUnit );
1094  props[ QStringLiteral( "wedgeWidthMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mWedgeWidthScale );
1095 
1096  props[ QStringLiteral( "cornerRadius" ) ] = mCornerRadius;
1097  props[ QStringLiteral( "cornerRadiusUnit" ) ] = QgsUnitTypes::encodeUnit( mCornerRadiusUnit );
1098  props[ QStringLiteral( "cornerRadiusMapUnitScale" ) ] = QgsSymbolLayerUtils::encodeMapUnitScale( mCornerRadiusScale );
1099 
1100  return props;
1101 }
1102 
1103 void QgsBalloonCallout::readProperties( const QVariantMap &props, const QgsReadWriteContext &context )
1104 {
1105  QgsCallout::readProperties( props, context );
1106 
1107  const QString fillSymbolDef = props.value( QStringLiteral( "fillSymbol" ) ).toString();
1108  QDomDocument doc( QStringLiteral( "symbol" ) );
1109  doc.setContent( fillSymbolDef );
1110  const QDomElement symbolElem = doc.firstChildElement( QStringLiteral( "symbol" ) );
1111  std::unique_ptr< QgsFillSymbol > fillSymbol( QgsSymbolLayerUtils::loadSymbol< QgsFillSymbol >( symbolElem, context ) );
1112  if ( fillSymbol )
1113  mFillSymbol = std::move( fillSymbol );
1114 
1115  mOffsetFromAnchorDistance = props.value( QStringLiteral( "offsetFromAnchor" ), 0 ).toDouble();
1116  mOffsetFromAnchorUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "offsetFromAnchorUnit" ) ).toString() );
1117  mOffsetFromAnchorScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "offsetFromAnchorMapUnitScale" ) ).toString() );
1118 
1119  mMargins = QgsMargins::fromString( props.value( QStringLiteral( "margins" ) ).toString() );
1120  mMarginUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "marginsUnit" ) ).toString() );
1121 
1122  mWedgeWidth = props.value( QStringLiteral( "wedgeWidth" ), 2.64 ).toDouble();
1123  mWedgeWidthUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "wedgeWidthUnit" ) ).toString() );
1124  mWedgeWidthScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "wedgeWidthMapUnitScale" ) ).toString() );
1125 
1126  mCornerRadius = props.value( QStringLiteral( "cornerRadius" ), 0 ).toDouble();
1127  mCornerRadiusUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "cornerRadiusUnit" ) ).toString() );
1128  mCornerRadiusScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "cornerRadiusMapUnitScale" ) ).toString() );
1129 }
1130 
1132 {
1133  QgsCallout::startRender( context );
1134  if ( mFillSymbol )
1135  mFillSymbol->startRender( context );
1136 }
1137 
1139 {
1140  QgsCallout::stopRender( context );
1141  if ( mFillSymbol )
1142  mFillSymbol->stopRender( context );
1143 }
1144 
1145 QSet<QString> QgsBalloonCallout::referencedFields( const QgsRenderContext &context ) const
1146 {
1147  QSet<QString> fields = QgsCallout::referencedFields( context );
1148  if ( mFillSymbol )
1149  fields.unite( mFillSymbol->usedAttributes( context ) );
1150  return fields;
1151 }
1152 
1154 {
1155  return mFillSymbol.get();
1156 }
1157 
1159 {
1160  mFillSymbol.reset( symbol );
1161 }
1162 
1163 void QgsBalloonCallout::draw( QgsRenderContext &context, const QRectF &rect, const double, const QgsGeometry &anchor, QgsCalloutContext &calloutContext )
1164 {
1165  bool destinationIsPinned = false;
1166  QgsGeometry line = calloutLineToPart( QgsGeometry::fromRect( rect ), anchor.constGet(), context, calloutContext, destinationIsPinned );
1167 
1168  double offsetFromAnchor = mOffsetFromAnchorDistance;
1170  {
1173  }
1174  const double offsetFromAnchorPixels = context.convertToPainterUnits( offsetFromAnchor, mOffsetFromAnchorUnit, mOffsetFromAnchorScale );
1175 
1176  if ( offsetFromAnchorPixels > 0 )
1177  {
1178  if ( const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( line.constGet() ) )
1179  {
1180  line = QgsGeometry( ls->curveSubstring( 0, ls->length() - offsetFromAnchorPixels ) );
1181  }
1182  }
1183 
1184  QgsPointXY destination;
1185  QgsPointXY origin;
1186  if ( const QgsLineString *ls = qgsgeometry_cast< const QgsLineString * >( line.constGet() ) )
1187  {
1188  origin = ls->startPoint();
1189  destination = ls->endPoint();
1190  }
1191  else
1192  {
1193  destination = QgsPointXY( rect.center() );
1194  }
1195 
1196  const QPolygonF points = getPoints( context, destination, rect );
1197  if ( points.empty() )
1198  return;
1199 
1200  if ( !origin.isEmpty() )
1201  {
1202  QgsCalloutPosition position;
1203  position.setOrigin( context.mapToPixel().toMapCoordinates( origin.x(), origin.y() ).toQPointF() );
1204  position.setOriginIsPinned( false );
1205  position.setDestination( context.mapToPixel().toMapCoordinates( destination.x(), destination.y() ).toQPointF() );
1206  position.setDestinationIsPinned( destinationIsPinned );
1207  calloutContext.addCalloutPosition( position );
1208  }
1209 
1210  mFillSymbol->renderPolygon( points, nullptr, nullptr, context );
1211 }
1212 
1213 QPolygonF QgsBalloonCallout::getPoints( QgsRenderContext &context, QgsPointXY origin, QRectF rect ) const
1214 {
1215  double segmentPointWidth = mWedgeWidth;
1216  if ( dataDefinedProperties().isActive( QgsCallout::WedgeWidth ) )
1217  {
1218  context.expressionContext().setOriginalValueVariable( segmentPointWidth );
1219  segmentPointWidth = dataDefinedProperties().valueAsDouble( QgsCallout::WedgeWidth, context.expressionContext(), segmentPointWidth );
1220  }
1221  segmentPointWidth = context.convertToPainterUnits( segmentPointWidth, mWedgeWidthUnit, mWedgeWidthScale );
1222 
1223  double cornerRadius = mCornerRadius;
1224  if ( dataDefinedProperties().isActive( QgsCallout::CornerRadius ) )
1225  {
1228  }
1229  cornerRadius = context.convertToPainterUnits( cornerRadius, mCornerRadiusUnit, mCornerRadiusScale );
1230 
1231  double left = mMargins.left();
1232  double right = mMargins.right();
1233  double top = mMargins.top();
1234  double bottom = mMargins.bottom();
1235 
1236  if ( dataDefinedProperties().isActive( QgsCallout::Margins ) )
1237  {
1238  const QVariant value = dataDefinedProperties().value( QgsCallout::Margins, context.expressionContext() );
1239  if ( !value.isNull() )
1240  {
1241  if ( value.type() == QVariant::List )
1242  {
1243  const QVariantList list = value.toList();
1244  if ( list.size() == 4 )
1245  {
1246  bool topOk = false;
1247  bool rightOk = false;
1248  bool bottomOk = false;
1249  bool leftOk = false;
1250  const double evaluatedTop = list.at( 0 ).toDouble( &topOk );
1251  const double evaluatedRight = list.at( 1 ).toDouble( &rightOk );
1252  const double evaluatedBottom = list.at( 2 ).toDouble( &bottomOk );
1253  const double evaluatedLeft = list.at( 3 ).toDouble( &leftOk );
1254  if ( topOk && rightOk && bottomOk && leftOk )
1255  {
1256  left = evaluatedLeft;
1257  top = evaluatedTop;
1258  right = evaluatedRight;
1259  bottom = evaluatedBottom;
1260  }
1261  }
1262  }
1263  else
1264  {
1265  const QStringList list = value.toString().trimmed().split( ',' );
1266  if ( list.count() == 4 )
1267  {
1268  bool topOk = false;
1269  bool rightOk = false;
1270  bool bottomOk = false;
1271  bool leftOk = false;
1272  const double evaluatedTop = list.at( 0 ).toDouble( &topOk );
1273  const double evaluatedRight = list.at( 1 ).toDouble( &rightOk );
1274  const double evaluatedBottom = list.at( 2 ).toDouble( &bottomOk );
1275  const double evaluatedLeft = list.at( 3 ).toDouble( &leftOk );
1276  if ( topOk && rightOk && bottomOk && leftOk )
1277  {
1278  left = evaluatedLeft;
1279  top = evaluatedTop;
1280  right = evaluatedRight;
1281  bottom = evaluatedBottom;
1282  }
1283  }
1284  }
1285  }
1286  }
1287 
1288  const double marginLeft = context.convertToPainterUnits( left, mMarginUnit );
1289  const double marginRight = context.convertToPainterUnits( right, mMarginUnit );
1290  const double marginTop = context.convertToPainterUnits( top, mMarginUnit );
1291  const double marginBottom = context.convertToPainterUnits( bottom, mMarginUnit );
1292 
1293  const QRectF expandedRect = rect.height() < 0 ?
1294  QRectF( rect.left() - marginLeft, rect.top() + marginBottom,
1295  rect.width() + marginLeft + marginRight,
1296  rect.height() - marginTop - marginBottom ) :
1297  QRectF( rect.left() - marginLeft, rect.top() - marginTop,
1298  rect.width() + marginLeft + marginRight,
1299  rect.height() + marginTop + marginBottom );
1300 
1301  // IMPORTANT -- check for degenerate height is sometimes >=0, because QRectF are not normalized and we are using painter
1302  // coordinates with descending vertical axis!
1303  if ( expandedRect.width() <= 0 || ( rect.height() < 0 && expandedRect.height() >= 0 ) || ( rect.height() > 0 && expandedRect.height() <= 0 ) )
1304  return QPolygonF();
1305 
1306  const QPainterPath path = QgsShapeGenerator::createBalloon( origin, expandedRect, segmentPointWidth, cornerRadius );
1307  const QTransform t = QTransform::fromScale( 100, 100 );
1308  const QTransform ti = t.inverted();
1309  const QPolygonF poly = path.toFillPolygon( t );
1310  return ti.map( poly );
1311 }
QgsMargins::bottom
double bottom() const
Returns the bottom margin.
Definition: qgsmargins.h:90
QgsCurve
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QgsBalloonCallout::~QgsBalloonCallout
~QgsBalloonCallout() override
QgsCallout::LabelPointOnExterior
@ LabelPointOnExterior
The point on the label's boundary closest to the feature.
Definition: qgscallout.h:125
QgsPainting::BlendNormal
@ BlendNormal
Definition: qgspainting.h:64
QgsSimpleLineCallout::lineSymbol
QgsLineSymbol * lineSymbol()
Returns the line symbol used to render the callout line.
Definition: qgscallout.cpp:643
QgsRectangle::height
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
QgsPropertyCollection::prepare
bool prepare(const QgsExpressionContext &context=QgsExpressionContext()) const override
Prepares the collection against a specified expression context.
Definition: qgspropertycollection.cpp:240
QgsCurvedLineCallout::Clockwise
@ Clockwise
Curve lines in a clockwise direction.
Definition: qgscallout.h:800
QgsAbstractPropertyCollection::valueAsDouble
double valueAsDouble(int key, const QgsExpressionContext &context, double defaultValue=0.0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a double.
Definition: qgspropertycollection.cpp:66
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsSymbolLayerUtils::decodeBlendMode
static QPainter::CompositionMode decodeBlendMode(const QString &s)
Definition: qgssymbollayerutils.cpp:854
QgsCallout::BlendMode
@ BlendMode
Callout blend mode (since QGIS 3.20)
Definition: qgscallout.h:100
QgsCallout::OffsetFromAnchor
@ OffsetFromAnchor
Distance to offset lines from anchor points.
Definition: qgscallout.h:86
QgsRenderContext::mapToPixel
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Definition: qgsrendercontext.h:258
QgsMargins::top
double top() const
Returns the top margin.
Definition: qgsmargins.h:78
QgsSimpleLineCallout::offsetFromAnchor
double offsetFromAnchor() const
Returns the offset distance from the anchor point at which to start the line.
Definition: qgscallout.h:608
QgsCallout::QgsCalloutContext::originalFeatureCrs
QgsCoordinateReferenceSystem originalFeatureCrs
Contains the CRS of the original feature associated with this callout.
Definition: qgscallout.h:256
QgsWkbTypes::Point
@ Point
Definition: qgswkbtypes.h:72
QgsSimpleLineCallout::~QgsSimpleLineCallout
~QgsSimpleLineCallout() override
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
QgsPainting::BlendMode
BlendMode
Blending modes enum defining the available composition modes that can be used when rendering a layer.
Definition: qgspainting.h:49
qgslinestring.h
QgsCallout::AnchorPoint
AnchorPoint
Feature's anchor point position.
Definition: qgscallout.h:111
QgsReadWriteContext
The class is used as a container of context for various read/write operations on other objects.
Definition: qgsreadwritecontext.h:34
QgsPoint::distance
double distance(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D distance between this point and a specified x, y coordinate.
Definition: qgspoint.h:360
QgsWkbTypes::NullGeometry
@ NullGeometry
Definition: qgswkbtypes.h:146
QgsCallout
Abstract base class for callout renderers.
Definition: qgscallout.h:52
QgsPropertyDefinition::BlendMode
@ BlendMode
Blend mode.
Definition: qgsproperty.h:67
QgsCallout::CornerRadius
@ CornerRadius
Balloon callout corner radius (since QGIS 3.20)
Definition: qgscallout.h:99
QgsCallout::Curvature
@ Curvature
Curvature of curved line callouts (since QGIS 3.20)
Definition: qgscallout.h:95
QgsSymbolLayerUtils::encodeMapUnitScale
static QString encodeMapUnitScale(const QgsMapUnitScale &mapUnitScale)
Definition: qgssymbollayerutils.cpp:666
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsGeos::shortestLine
QgsGeometry shortestLine(const QgsGeometry &other, QString *errorMsg=nullptr) const
Returns the shortest line joining this geometry to the other geometry.
Definition: qgsgeos.cpp:2676
QgsGeometry::transform
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Definition: qgsgeometry.cpp:3128
QgsPropertyDefinition::DataTypeString
@ DataTypeString
Property requires a string value.
Definition: qgsproperty.h:92
QgsExpressionContext::setOriginalValueVariable
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
Definition: qgsexpressioncontext.cpp:600
qgssymbollayerutils.h
QgsCallout::WedgeWidth
@ WedgeWidth
Balloon callout wedge width (since QGIS 3.20)
Definition: qgscallout.h:98
QgsCallout::propertyDefinitions
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in callouts.
Definition: qgscallout.cpp:192
QgsGeometry::fromPointXY
static QgsGeometry fromPointXY(const QgsPointXY &point) SIP_HOLDGIL
Creates a new geometry from a QgsPointXY object.
Definition: qgsgeometry.cpp:176
QgsGeometry::centroid
QgsGeometry centroid() const
Returns the center of mass of a geometry.
Definition: qgsgeometry.cpp:2284
QgsRectangle::toRectF
QRectF toRectF() const
Returns a QRectF with same coordinates as the rectangle.
Definition: qgsrectangle.h:500
QgsPropertyCollection::loadVariant
bool loadVariant(const QVariant &configuration, const QgsPropertiesDefinition &definitions) override
Loads this property collection from a QVariantMap, wrapped in a QVariant.
Definition: qgspropertycollection.cpp:341
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsCallout::OriginY
@ OriginY
Y-coordinate of callout origin (label anchor) (since QGIS 3.20)
Definition: qgscallout.h:92
QgsPointXY::toQPointF
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:169
QgsPropertyDefinition::Double
@ Double
Double value (including negative values)
Definition: qgsproperty.h:57
QgsCallout::anchorPoint
AnchorPoint anchorPoint() const
Returns the feature's anchor point position.
Definition: qgscallout.h:361
QgsGeometryUtils::perpendicularOffsetPointAlongSegment
static void perpendicularOffsetPointAlongSegment(double x1, double y1, double x2, double y2, double proportion, double offset, double *x, double *y)
Calculates a point a certain proportion of the way along the segment from (x1, y1) to (x2,...
Definition: qgsgeometryutils.cpp:650
QgsPointXY::isEmpty
bool isEmpty() const SIP_HOLDGIL
Returns true if the geometry is empty.
Definition: qgspointxy.h:249
QgsCallout::LabelCentroid
@ LabelCentroid
The labe's centroid.
Definition: qgscallout.h:126
QgsSimpleLineCallout::setLineSymbol
void setLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol used to render the callout line.
Definition: qgscallout.cpp:648
QgsCallout::PoleOfInaccessibility
@ PoleOfInaccessibility
The surface's pole of inaccessibility used as anchor for polygon geometries.
Definition: qgscallout.h:113
QgsSimpleLineCallout::create
static QgsCallout * create(const QVariantMap &properties=QVariantMap(), const QgsReadWriteContext &context=QgsReadWriteContext())
Creates a new QgsSimpleLineCallout, using the settings serialized in the properties map (correspondin...
Definition: qgscallout.cpp:554
QgsCallout::LabelBottomMiddle
@ LabelBottomMiddle
Bottom middle of the label's boundary.
Definition: qgscallout.h:133
QgsManhattanLineCallout::clone
QgsManhattanLineCallout * clone() const override
Duplicates a callout by creating a deep copy of the callout.
Definition: qgscallout.cpp:775
QgsLineString
Line string geometry type, with support for z-dimension and m-values.
Definition: qgslinestring.h:44
QgsCallout::Margins
@ Margins
Margin from text (since QGIS 3.20)
Definition: qgscallout.h:97
QgsMapToPixel::toMapCoordinates
QgsPointXY toMapCoordinates(int x, int y) const
Transforms device coordinates to map (world) coordinates.
Definition: qgsmaptopixel.h:173
QgsSimpleLineCallout::clone
QgsSimpleLineCallout * clone() const override
Duplicates a callout by creating a deep copy of the callout.
Definition: qgscallout.cpp:566
QgsCurvedLineCallout::create
static QgsCallout * create(const QVariantMap &properties=QVariantMap(), const QgsReadWriteContext &context=QgsReadWriteContext())
Creates a new QgsCurvedLineCallout, using the settings serialized in the properties map (correspondin...
Definition: qgscallout.cpp:803
QgsCoordinateTransform::isValid
bool isValid() const
Returns true if the coordinate transform is valid, ie both the source and destination CRS have been s...
Definition: qgscoordinatetransform.cpp:900
QgsManhattanLineCallout::QgsManhattanLineCallout
QgsManhattanLineCallout()
Definition: qgscallout.cpp:752
QgsCallout::type
virtual QString type() const =0
Returns a unique string representing the callout type.
QgsCallout::blendMode
QPainter::CompositionMode blendMode() const
Returns the blending mode used for drawing callouts.
Definition: qgscallout.h:428
QgsCurvedLineCallout::CounterClockwise
@ CounterClockwise
Curve lines in a counter-clockwise direction.
Definition: qgscallout.h:801
QgsBalloonCallout::type
QString type() const override
Returns a unique string representing the callout type.
Definition: qgscallout.cpp:1066
QgsCurvedLineCallout::type
QString type() const override
Returns a unique string representing the callout type.
Definition: qgscallout.cpp:814
QgsCallout::AnchorPointPosition
@ AnchorPointPosition
Feature's anchor point position.
Definition: qgscallout.h:89
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsCallout::PointOnExterior
@ PointOnExterior
A point on the surface's outline closest to the label is used as anchor for polygon geometries.
Definition: qgscallout.h:114
QgsCallout::LabelMiddleRight
@ LabelMiddleRight
Middle right of the label's boundary.
Definition: qgscallout.h:131
QgsPropertyCollection::property
QgsProperty property(int key) const override
Returns a matching property from the collection, if one exists.
Definition: qgspropertycollection.cpp:214
QgsSimpleLineCallout::referencedFields
QSet< QString > referencedFields(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the callout.
Definition: qgscallout.cpp:635
QgsSymbolLayerUtils::symbolProperties
static QString symbolProperties(QgsSymbol *symbol)
Returns a string representing the symbol.
Definition: qgssymbollayerutils.cpp:1454
QgsCallout::LabelTopLeft
@ LabelTopLeft
Top left corner of the label's boundary.
Definition: qgscallout.h:127
QgsSimpleLineCallout::createCalloutLine
virtual QgsCurve * createCalloutLine(const QgsPoint &start, const QgsPoint &end, QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext) const
Creates a callout line between start and end in the desired style.
Definition: qgscallout.cpp:743
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
QgsPainting::getBlendModeEnum
static QgsPainting::BlendMode getBlendModeEnum(QPainter::CompositionMode blendMode)
Returns a BlendMode corresponding to a QPainter::CompositionMode.
Definition: qgspainting.cpp:80
QgsBalloonCallout::startRender
void startRender(QgsRenderContext &context) override
Prepares the callout for rendering on the specified render context.
Definition: qgscallout.cpp:1131
QgsCoordinateTransform::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system, which the transform will transform coordinates t...
Definition: qgscoordinatetransform.cpp:267
QgsSimpleLineCallout::properties
QVariantMap properties(const QgsReadWriteContext &context) const override
Returns the properties describing the callout encoded in a string format.
Definition: qgscallout.cpp:571
QgsMargins::fromString
static QgsMargins fromString(const QString &string)
Returns a QgsMargins object decoded from a string, or a null QgsMargins if the string could not be in...
Definition: qgsmargins.cpp:27
QgsCalloutPosition::setDestination
void setDestination(const QPointF &destination)
Sets the destination of the callout line, in map coordinates.
Definition: qgscalloutposition.h:104
QgsAbstractGeometry::transform
virtual void transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection d=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)=0
Transforms the geometry using a coordinate transform.
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:178
QgsPoint::y
double y
Definition: qgspoint.h:70
QgsMargins::left
double left() const
Returns the left margin.
Definition: qgsmargins.h:72
QgsPropertiesDefinition
QMap< int, QgsPropertyDefinition > QgsPropertiesDefinition
Definition of available properties.
Definition: qgspropertycollection.h:29
AnchorPoint
record about vertex coordinates and index of anchor to which it is snapped
Definition: qgsgeometrysnappersinglesource.cpp:29
QgsGeometry::poleOfInaccessibility
QgsGeometry poleOfInaccessibility(double precision, double *distanceToBoundary=nullptr) const
Calculates the approximate pole of inaccessibility for a surface, which is the most distant internal ...
Definition: qgsgeometry.cpp:2323
QgsCallout::restoreProperties
virtual void restoreProperties(const QDomElement &element, const QgsReadWriteContext &context)
Restores the callout's properties from a DOM element.
Definition: qgscallout.cpp:117
QgsSimpleLineCallout::offsetFromLabel
double offsetFromLabel() const
Returns the offset distance from label area at which to end the line.
Definition: qgscallout.h:652
QgsCallout::QgsCalloutContext::originalFeatureToMapTransform
QgsCoordinateTransform originalFeatureToMapTransform(const QgsRenderContext &renderContext) const
Returns the coordinate transform to convert from the original layer associated with the callout to th...
Definition: qgscallout.cpp:514
QgsCurvedLineCallout::properties
QVariantMap properties(const QgsReadWriteContext &context) const override
Returns the properties describing the callout encoded in a string format.
Definition: qgscallout.cpp:824
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsRenderContext::useAdvancedEffects
bool useAdvancedEffects() const
Returns true if advanced effects such as blend modes such be used.
Definition: qgsrendercontext.cpp:300
QgsMargins::toString
QString toString() const
Returns the margins encoded to a string.
Definition: qgsmargins.cpp:18
QgsCircularString
Circular string geometry type.
Definition: qgscircularstring.h:34
QgsBalloonCallout::cornerRadius
double cornerRadius() const
Returns the corner radius of the balloon shapes.
Definition: qgscallout.h:1084
QgsUnitTypes::encodeUnit
static Q_INVOKABLE QString encodeUnit(QgsUnitTypes::DistanceUnit unit)
Encodes a distance unit to a string.
Definition: qgsunittypes.cpp:122
QgsAbstractGeometry::wkbType
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
Definition: qgsabstractgeometry.h:206
QgsCallout::DestinationX
@ DestinationX
X-coordinate of callout destination (feature anchor) (since QGIS 3.20)
Definition: qgscallout.h:93
QgsCallout::LabelAnchorPointPosition
@ LabelAnchorPointPosition
Label's anchor point position.
Definition: qgscallout.h:90
QgsSimpleLineCallout::readProperties
void readProperties(const QVariantMap &props, const QgsReadWriteContext &context) override
Reads a string map of an callout's properties and restores the callout to the state described by the ...
Definition: qgscallout.cpp:595
QgsXmlUtils::readVariant
static QVariant readVariant(const QDomElement &element)
Read a QVariant from a QDomElement.
Definition: qgsxmlutils.cpp:251
QgsCalloutPosition
Represents the calculated placement of a map label callout line.
Definition: qgscalloutposition.h:32
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsSimpleLineSymbolLayer
A simple line symbol layer, which renders lines using a line in a variety of styles (e....
Definition: qgslinesymbollayer.h:43
QgsPainting::getCompositionMode
static QPainter::CompositionMode getCompositionMode(QgsPainting::BlendMode blendMode)
Returns a QPainter::CompositionMode corresponding to a BlendMode.
Definition: qgspainting.cpp:20
QgsAbstractGeometry::clone
virtual QgsAbstractGeometry * clone() const =0
Clones the geometry by performing a deep copy.
QgsGeos
Does vector analysis using the geos library and handles import, export, exception handling*.
Definition: qgsgeos.h:103
QgsCallout::decodeAnchorPoint
static QgsCallout::AnchorPoint decodeAnchorPoint(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of an anchor point name to the corresponding anchor point.
Definition: qgscallout.cpp:202
QgsGeometry::rotate
Qgis::GeometryOperationResult rotate(double rotation, const QgsPointXY &center)
Rotate this geometry around the Z axis.
Definition: qgsgeometry.cpp:910
QgsCallout::labelAnchorPoint
LabelAnchorPoint labelAnchorPoint() const
Returns the label's anchor point position.
Definition: qgscallout.h:394
QgsCurvedLineCallout::createCalloutLine
QgsCurve * createCalloutLine(const QgsPoint &start, const QgsPoint &end, QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext) const override
Creates a callout line between start and end in the desired style.
Definition: qgscallout.cpp:832
qgsrendercontext.h
QgsLineSymbol
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:29
QgsCallout::DrawCalloutToAllParts
@ DrawCalloutToAllParts
Whether callout lines should be drawn to all feature parts.
Definition: qgscallout.h:88
qgspainting.h
QgsCallout::encodeLabelAnchorPoint
static QString encodeLabelAnchorPoint(LabelAnchorPoint anchor)
Encodes a label anchor point to its string representation.
Definition: qgscallout.cpp:238
QgsCallout::drawOrder
virtual DrawOrder drawOrder() const
Returns the desired drawing order (stacking) to use while rendering this callout.
Definition: qgscallout.cpp:143
QgsPropertyDefinition
Definition for a property.
Definition: qgsproperty.h:46
QgsCallout::Centroid
@ Centroid
The surface's centroid is used as anchor for polygon geometries.
Definition: qgscallout.h:116
QgsGeometry::length
double length() const
Returns the planar, 2-dimensional length of geometry.
Definition: qgsgeometry.cpp:1890
QgsProperty::valueAsString
QString valueAsString(const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property and interprets it as a string.
Definition: qgsproperty.cpp:640
QgsGeometry::isEmpty
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Definition: qgsgeometry.cpp:379
QgsMargins::right
double right() const
Returns the right margin.
Definition: qgsmargins.h:84
QgsGeometry::isNull
bool isNull
Definition: qgsgeometry.h:127
QgsSimpleLineCallout
A simple direct line callout style.
Definition: qgscallout.h:510
QgsCallout::QgsCallout
QgsCallout()
Constructor for QgsCallout.
Definition: qgscallout.cpp:75
QgsCalloutPosition::setDestinationIsPinned
void setDestinationIsPinned(bool pinned)
Sets whether the destination of the callout has pinned (manually placed).
Definition: qgscalloutposition.h:144
QgsRectangle::buffered
QgsRectangle buffered(double width) const
Gets rectangle enlarged by buffer.
Definition: qgsrectangle.h:325
qgsfillsymbollayer.h
QgsSimpleLineCallout::QgsSimpleLineCallout
QgsSimpleLineCallout()
Definition: qgscallout.cpp:529
QgsPropertyCollection::referencedFields
QSet< QString > referencedFields(const QgsExpressionContext &context=QgsExpressionContext(), bool ignoreContext=false) const override
Returns the set of any fields referenced by the active properties from the collection.
Definition: qgspropertycollection.cpp:254
QgsBalloonCallout::properties
QVariantMap properties(const QgsReadWriteContext &context) const override
Returns the properties describing the callout encoded in a string format.
Definition: qgscallout.cpp:1076
QgsGeometry::pointOnSurface
QgsGeometry pointOnSurface() const
Returns a point guaranteed to lie on the surface of a geometry.
Definition: qgsgeometry.cpp:2308
QgsBalloonCallout::fillSymbol
QgsFillSymbol * fillSymbol()
Returns the fill symbol used to render the callout.
Definition: qgscallout.cpp:1153
QgsBalloonCallout::clone
QgsBalloonCallout * clone() const override
Duplicates a callout by creating a deep copy of the callout.
Definition: qgscallout.cpp:1071
QgsCallout::setEnabled
void setEnabled(bool enabled)
Sets whether the callout is enabled.
Definition: qgscallout.cpp:187
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:136
qgscircularstring.h
QgsCallout::QgsCalloutContext::addCalloutPosition
void addCalloutPosition(const QgsCalloutPosition &position)
Adds a rendered callout position.
Definition: qgscallout.h:276
QgsCallout::encodeAnchorPoint
static QString encodeAnchorPoint(AnchorPoint anchor)
Encodes an anchor point to its string representation.
Definition: qgscallout.cpp:222
QgsCallout::readProperties
virtual void readProperties(const QVariantMap &props, const QgsReadWriteContext &context)
Reads a string map of an callout's properties and restores the callout to the state described by the ...
Definition: qgscallout.cpp:90
QgsBalloonCallout::draw
void draw(QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext) override
Performs the actual rendering of the callout implementation onto the specified render context.
Definition: qgscallout.cpp:1163
QgsMapToPixel::transform
QgsPointXY transform(const QgsPointXY &p) const
Transforms a point p from map (world) coordinates to device coordinates.
Definition: qgsmaptopixel.h:90
QgsCallout::OriginX
@ OriginX
X-coordinate of callout origin (label anchor) (since QGIS 3.20)
Definition: qgscallout.h:91
QgsAbstractGeometry
Abstract base class for all geometries.
Definition: qgsabstractgeometry.h:79
QgsCalloutPosition::setOrigin
void setOrigin(const QPointF &origin)
Sets the origin of the callout line, in map coordinates.
Definition: qgscalloutposition.h:84
QgsCallout::decodeLabelAnchorPoint
static QgsCallout::LabelAnchorPoint decodeLabelAnchorPoint(const QString &name, bool *ok=nullptr)
Attempts to decode a string representation of a label anchor point name to the corresponding anchor p...
Definition: qgscallout.cpp:267
qgsxmlutils.h
QgsCallout::render
void render(QgsRenderContext &context, const QRectF &rect, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext)
Renders the callout onto the specified render context.
Definition: qgscallout.cpp:148
qgsgeometryutils.h
QgsCurvedLineCallout::orientation
Orientation orientation() const
Returns the callout line's curve orientation.
Definition: qgscallout.cpp:1008
QgsCallout::Orientation
@ Orientation
Orientation of curved line callouts (since QGIS 3.20)
Definition: qgscallout.h:96
QgsCallout::DrawOrder
DrawOrder
Options for draw order (stacking) of callouts.
Definition: qgscallout.h:104
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
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
QgsCallout::properties
virtual QVariantMap properties(const QgsReadWriteContext &context) const
Returns the properties describing the callout encoded in a string format.
Definition: qgscallout.cpp:79
QgsAbstractGeometry::boundingBox
virtual QgsRectangle boundingBox() const =0
Returns the minimal bounding box for the geometry.
QgsCallout::LabelBottomLeft
@ LabelBottomLeft
Bottom left corner of the label's boundary.
Definition: qgscallout.h:132
QgsCurvedLineCallout::QgsCurvedLineCallout
QgsCurvedLineCallout()
Definition: qgscallout.cpp:791
QgsSimpleLineCallout::startRender
void startRender(QgsRenderContext &context) override
Prepares the callout for rendering on the specified render context.
Definition: qgscallout.cpp:621
QgsManhattanLineCallout::type
QString type() const override
Returns a unique string representing the callout type.
Definition: qgscallout.cpp:770
QgsBalloonCallout::stopRender
void stopRender(QgsRenderContext &context) override
Finalises the callout after a set of rendering operations on the specified render context.
Definition: qgscallout.cpp:1138
QgsWkbTypes::LineGeometry
@ LineGeometry
Definition: qgswkbtypes.h:143
QgsManhattanLineCallout
Draws straight (right angled) lines as callouts.
Definition: qgscallout.h:747
QgsShapeGenerator::createBalloon
static QPolygonF createBalloon(const QgsPointXY &origin, const QRectF &rect, double wedgeWidth)
Generates a "balloon"/"talking bubble" style shape (as a QPolygonF).
Definition: qgsshapegenerator.cpp:55
QgsWkbTypes::PointGeometry
@ PointGeometry
Definition: qgswkbtypes.h:142
qgscallout.h
QgsCurvedLineCallout::clone
QgsCurvedLineCallout * clone() const override
Duplicates a callout by creating a deep copy of the callout.
Definition: qgscallout.cpp:819
qgslinesymbollayer.h
QgsPropertyDefinition::Boolean
@ Boolean
Boolean value.
Definition: qgsproperty.h:53
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
QgsSimpleLineCallout::draw
void draw(QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext) override
Performs the actual rendering of the callout implementation onto the specified render context.
Definition: qgscallout.cpp:653
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsAbstractPropertyCollection::valueAsBool
bool valueAsBool(int key, const QgsExpressionContext &context, bool defaultValue=false, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an boolean.
Definition: qgspropertycollection.cpp:88
QgsCallout::draw
virtual void draw(QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext)=0
Performs the actual rendering of the callout implementation onto the specified render context.
QgsRectangle::width
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
QgsRenderContext::transformContext
QgsCoordinateTransformContext transformContext() const
Returns the context's coordinate transform context, which stores various information regarding which ...
Definition: qgsrendercontext.cpp:184
QgsCurvedLineCallout
Draws curved lines as callouts.
Definition: qgscallout.h:790
QgsSymbolLayerList
QList< QgsSymbolLayer * > QgsSymbolLayerList
Definition: qgssymbol.h:27
QgsGeometryUtils::closestSideOfRectangle
static int closestSideOfRectangle(double right, double bottom, double left, double top, double x, double y)
Returns a number representing the closest side of a rectangle defined by /a right,...
Definition: qgsgeometryutils.cpp:1423
QgsCallout::referencedFields
virtual QSet< QString > referencedFields(const QgsRenderContext &context) const
Returns the set of attributes referenced by the callout.
Definition: qgscallout.cpp:137
QgsCurvedLineCallout::setOrientation
void setOrientation(Orientation orientation)
Sets the callout line's curve orientation.
Definition: qgscallout.cpp:1013
QgsBalloonCallout
A cartoon talking bubble callout style.
Definition: qgscallout.h:890
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsBalloonCallout::readProperties
void readProperties(const QVariantMap &props, const QgsReadWriteContext &context) override
Reads a string map of an callout's properties and restores the callout to the state described by the ...
Definition: qgscallout.cpp:1103
QgsCallout::MinimumCalloutLength
@ MinimumCalloutLength
Minimum length of callouts.
Definition: qgscallout.h:85
QgsGeometry::fromRect
static QgsGeometry fromRect(const QgsRectangle &rect) SIP_HOLDGIL
Creates a new geometry from a QgsRectangle.
Definition: qgsgeometry.cpp:241
QgsSimpleFillSymbolLayer
Definition: qgsfillsymbollayer.h:43
QgsFillSymbol
A fill symbol type, for rendering Polygon and MultiPolygon geometries.
Definition: qgsfillsymbol.h:29
QgsCallout::calloutLineToPart
QgsGeometry calloutLineToPart(const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned) const
Calculates the direct line from a label geometry to an anchor geometry part, respecting the various c...
Definition: qgscallout.cpp:426
QgsWkbTypes::UnknownGeometry
@ UnknownGeometry
Definition: qgswkbtypes.h:145
QgsCallout::LabelMiddleLeft
@ LabelMiddleLeft
Middle left of the label's boundary.
Definition: qgscallout.h:130
QgsWkbTypes::geometryType
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:968
QgsCallout::LabelBottomRight
@ LabelBottomRight
Bottom right corner of the label's boundary.
Definition: qgscallout.h:134
QgsCallout::calloutLabelPoint
QgsGeometry calloutLabelPoint(const QRectF &bodyBoundingBox, double angle, LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned) const
Returns the anchor point geometry for a label with the given bounding box and anchor point mode.
Definition: qgscallout.cpp:349
QgsCallout::DestinationY
@ DestinationY
Y-coordinate of callout destination (feature anchor) (since QGIS 3.20)
Definition: qgscallout.h:94
QgsCallout::containsAdvancedEffects
bool containsAdvancedEffects() const
Returns true if the callout requires advanced effects such as blend modes, which require output in ra...
Definition: qgscallout.cpp:132
QgsCallout::QgsCalloutContext
Contains additional contextual information about the context in which a callout is being rendered.
Definition: qgscallout.h:245
QgsGeometry::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Definition: qgsgeometry.cpp:1080
QgsCallout::LabelTopMiddle
@ LabelTopMiddle
Top middle of the label's boundary.
Definition: qgscallout.h:128
QgsCallout::labelAnchorGeometry
Q_DECL_DEPRECATED QgsGeometry labelAnchorGeometry(const QRectF &bodyBoundingBox, const double angle, LabelAnchorPoint anchor) const
Returns the anchor point geometry for a label with the given bounding box and anchor point mode.
Definition: qgscallout.cpp:299
QgsSimpleLineCallout::type
QString type() const override
Returns a unique string representing the callout type.
Definition: qgscallout.cpp:561
QgsCallout::startRender
virtual void startRender(QgsRenderContext &context)
Prepares the callout for rendering on the specified render context.
Definition: qgscallout.cpp:123
QgsCallout::stopRender
virtual void stopRender(QgsRenderContext &context)
Finalises the callout after a set of rendering operations on the specified render context.
Definition: qgscallout.cpp:127
QgsBalloonCallout::referencedFields
QSet< QString > referencedFields(const QgsRenderContext &context) const override
Returns the set of attributes referenced by the callout.
Definition: qgscallout.cpp:1145
QgsCurvedLineCallout::curvature
double curvature() const
Returns the callout line's curvature.
Definition: qgscallout.cpp:1018
QgsPropertyCollection::toVariant
QVariant toVariant(const QgsPropertiesDefinition &definitions) const override
Saves this property collection to a QVariantMap, wrapped in a QVariant.
Definition: qgspropertycollection.cpp:320
QgsCallout::saveProperties
virtual bool saveProperties(QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context) const
Saves the current state of the callout to a DOM element.
Definition: qgscallout.cpp:100
qgslogger.h
QgsRenderContext::painter
QPainter * painter()
Returns the destination QPainter for the render operation.
Definition: qgsrendercontext.h:112
QgsManhattanLineCallout::create
static QgsCallout * create(const QVariantMap &properties=QVariantMap(), const QgsReadWriteContext &context=QgsReadWriteContext())
Creates a new QgsManhattanLineCallout, using the settings serialized in the properties map (correspon...
Definition: qgscallout.cpp:763
QgsBalloonCallout::create
static QgsCallout * create(const QVariantMap &properties=QVariantMap(), const QgsReadWriteContext &context=QgsReadWriteContext())
Creates a new QgsBalloonCallout, using the settings serialized in the properties map (corresponding t...
Definition: qgscallout.cpp:1059
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
QgsSimpleLineCallout::stopRender
void stopRender(QgsRenderContext &context) override
Finalises the callout after a set of rendering operations on the specified render context.
Definition: qgscallout.cpp:628
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsXmlUtils::writeVariant
static QDomElement writeVariant(const QVariant &value, QDomDocument &doc)
Write a QVariant to a QDomElement.
Definition: qgsxmlutils.cpp:106
QgsGeos::intersects
bool intersects(const QgsAbstractGeometry *geom, QString *errorMsg=nullptr) const override
Checks if geom intersects this.
Definition: qgsgeos.cpp:691
QgsCallout::OrderBelowAllLabels
@ OrderBelowAllLabels
Render callouts below all labels.
Definition: qgscallout.h:106
QgsBalloonCallout::QgsBalloonCallout
QgsBalloonCallout()
Definition: qgscallout.cpp:1034
QgsCallout::clone
virtual QgsCallout * clone() const =0
Duplicates a callout by creating a deep copy of the callout.
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
qgsfillsymbol.h
QgsCurvedLineCallout::setCurvature
void setCurvature(double curvature)
Sets the callout line's curvature.
Definition: qgscallout.cpp:1023
QgsCallout::LabelAnchorPoint
LabelAnchorPoint
Label's anchor point position.
Definition: qgscallout.h:123
qgssymbol.h
QgsBalloonCallout::setFillSymbol
void setFillSymbol(QgsFillSymbol *symbol)
Sets the fill symbol used to render the callout.
Definition: qgscallout.cpp:1158
QgsPoint::x
double x
Definition: qgspoint.h:69
QgsSymbolLayerUtils::decodeMapUnitScale
static QgsMapUnitScale decodeMapUnitScale(const QString &str)
Definition: qgssymbollayerutils.cpp:676
QgsCallout::OffsetFromLabel
@ OffsetFromLabel
Distance to offset lines from label area.
Definition: qgscallout.h:87
QgsBalloonCallout::offsetFromAnchor
double offsetFromAnchor() const
Returns the offset distance from the anchor point at which to start the line.
Definition: qgscallout.h:943
qgsshapegenerator.h
QgsCallout::dataDefinedProperties
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the callout's property collection, used for data defined overrides.
Definition: qgscallout.h:331
QgsCallout::enabled
bool enabled() const
Returns true if the the callout is enabled.
Definition: qgscallout.h:319
QgsCallout::PointOnSurface
@ PointOnSurface
A point guaranteed to be on the surface is used as anchor for polygon geometries.
Definition: qgscallout.h:115
qgsgeos.h
QgsCurvedLineCallout::Orientation
Orientation
Curve orientation.
Definition: qgscallout.h:797
QgsCallout::LabelTopRight
@ LabelTopRight
Top right corner of the label's boundary.
Definition: qgscallout.h:129
qgslinesymbol.h
QgsCurvedLineCallout::Automatic
@ Automatic
Automatically choose most cartographically pleasing orientation based on label and callout arrangemen...
Definition: qgscallout.h:799
QgsPropertyDefinition::DoublePositive
@ DoublePositive
Positive double value (including 0)
Definition: qgsproperty.h:58
QgsManhattanLineCallout::createCalloutLine
QgsCurve * createCalloutLine(const QgsPoint &start, const QgsPoint &end, QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext) const override
Creates a callout line between start and end in the desired style.
Definition: qgscallout.cpp:780
QgsCalloutPosition::setOriginIsPinned
void setOriginIsPinned(bool pinned)
Sets whether the origin of the callout has pinned (manually placed).
Definition: qgscalloutposition.h:124