Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgscallout.h
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 : : #ifndef QGSCALLOUT_H
18 : : #define QGSCALLOUT_H
19 : :
20 : : #include "qgis_core.h"
21 : : #include "qgis_sip.h"
22 : : #include "qgsexpressioncontext.h"
23 : : #include "qgsreadwritecontext.h"
24 : : #include "qgspropertycollection.h"
25 : : #include "qgsmapunitscale.h"
26 : : #include "qgscalloutposition.h"
27 : : #include "qgsmargins.h"
28 : : #include <QString>
29 : : #include <QRectF>
30 : : #include <memory>
31 : :
32 : : class QgsLineSymbol;
33 : : class QgsFillSymbol;
34 : : class QgsGeometry;
35 : : class QgsRenderContext;
36 : :
37 : : class QgsCalloutWidget; //stop sip breaking
38 : :
39 : : /**
40 : : * \ingroup core
41 : : * \brief Abstract base class for callout renderers.
42 : : *
43 : : * Implementations of QgsCallout are responsible for performing the actual render of
44 : : * callouts, including determining the desired shape of the callout and using any
45 : : * relevant symbology elements to render them.
46 : : *
47 : : * \since QGIS 3.10
48 : : */
49 : 0 : class CORE_EXPORT QgsCallout
50 : : {
51 : :
52 : : #ifdef SIP_RUN
53 : : SIP_CONVERT_TO_SUBCLASS_CODE
54 : : if ( sipCpp->type() == "simple" && dynamic_cast<QgsSimpleLineCallout *>( sipCpp ) != NULL )
55 : : {
56 : : sipType = sipType_QgsSimpleLineCallout;
57 : : }
58 : : else if ( sipCpp->type() == "manhattan" && dynamic_cast<QgsManhattanLineCallout *>( sipCpp ) != NULL )
59 : : {
60 : : sipType = sipType_QgsManhattanLineCallout;
61 : : }
62 : : else if ( sipCpp->type() == "curved" && dynamic_cast<QgsCurvedLineCallout *>( sipCpp ) != NULL )
63 : : {
64 : : sipType = sipType_QgsCurvedLineCallout;
65 : : }
66 : : else if ( sipCpp->type() == "balloon" && dynamic_cast<QgsBalloonCallout *>( sipCpp ) != NULL )
67 : : {
68 : : sipType = sipType_QgsBalloonCallout;
69 : : }
70 : : else
71 : : {
72 : : sipType = 0;
73 : : }
74 : : SIP_END
75 : : #endif
76 : :
77 : : public:
78 : :
79 : : //! Data definable properties.
80 : : enum Property
81 : : {
82 : : MinimumCalloutLength, //!< Minimum length of callouts
83 : : OffsetFromAnchor, //!< Distance to offset lines from anchor points
84 : : OffsetFromLabel, //!< Distance to offset lines from label area
85 : : DrawCalloutToAllParts, //!< Whether callout lines should be drawn to all feature parts
86 : : AnchorPointPosition, //!< Feature's anchor point position
87 : : LabelAnchorPointPosition, //!< Label's anchor point position
88 : : OriginX, //!< X-coordinate of callout origin (label anchor) (since QGIS 3.20)
89 : : OriginY, //!< Y-coordinate of callout origin (label anchor) (since QGIS 3.20)
90 : : DestinationX, //!< X-coordinate of callout destination (feature anchor) (since QGIS 3.20)
91 : : DestinationY, //!< Y-coordinate of callout destination (feature anchor) (since QGIS 3.20)
92 : : Curvature, //!< Curvature of curved line callouts (since QGIS 3.20)
93 : : Orientation, //!< Orientation of curved line callouts (since QGIS 3.20)
94 : : Margins, //!< Margin from text (since QGIS 3.20)
95 : : WedgeWidth, //!< Balloon callout wedge width (since QGIS 3.20)
96 : : CornerRadius, //!< Balloon callout corner radius (since QGIS 3.20)
97 : : };
98 : :
99 : : //! Options for draw order (stacking) of callouts
100 : : enum DrawOrder
101 : : {
102 : : OrderBelowAllLabels, //!< Render callouts below all labels
103 : : OrderBelowIndividualLabels, //!< Render callouts below their individual associated labels, some callouts may be drawn over other labels
104 : : };
105 : :
106 : : //! Feature's anchor point position
107 : : enum AnchorPoint
108 : : {
109 : : PoleOfInaccessibility = 0, //!< The surface's pole of inaccessibility used as anchor for polygon geometries
110 : : PointOnExterior, //!< A point on the surface's outline closest to the label is used as anchor for polygon geometries
111 : : PointOnSurface, //!< A point guaranteed to be on the surface is used as anchor for polygon geometries
112 : : Centroid, //!< The surface's centroid is used as anchor for polygon geometries
113 : : };
114 : :
115 : : /**
116 : : * Label's anchor point position.
117 : : * \since QGIS 3.14
118 : : */
119 : : enum LabelAnchorPoint
120 : : {
121 : : LabelPointOnExterior, //!< The point on the label's boundary closest to the feature
122 : : LabelCentroid, //!< The labe's centroid
123 : : LabelTopLeft, //!< Top left corner of the label's boundary
124 : : LabelTopMiddle, //!< Top middle of the label's boundary
125 : : LabelTopRight, //!< Top right corner of the label's boundary
126 : : LabelMiddleLeft, //!< Middle left of the label's boundary
127 : : LabelMiddleRight, //!< Middle right of the label's boundary
128 : : LabelBottomLeft, //!< Bottom left corner of the label's boundary
129 : : LabelBottomMiddle, //!< Bottom middle of the label's boundary
130 : : LabelBottomRight, //!< Bottom right corner of the label's boundary
131 : : };
132 : :
133 : : /**
134 : : * Constructor for QgsCallout.
135 : : */
136 : : QgsCallout();
137 : 0 : virtual ~QgsCallout() = default;
138 : :
139 : : /**
140 : : * Returns a unique string representing the callout type.
141 : : */
142 : : virtual QString type() const = 0;
143 : :
144 : : /**
145 : : * Duplicates a callout by creating a deep copy of the callout.
146 : : *
147 : : * Caller takes ownership of the returned object.
148 : : */
149 : : virtual QgsCallout *clone() const = 0 SIP_FACTORY;
150 : :
151 : : /**
152 : : * Returns the properties describing the callout encoded in a
153 : : * string format.
154 : : *
155 : : * Subclasses must ensure that they include the base class' properties()
156 : : * in their returned value.
157 : : *
158 : : * \see readProperties()
159 : : * \see saveProperties()
160 : : */
161 : : virtual QVariantMap properties( const QgsReadWriteContext &context ) const;
162 : :
163 : : /**
164 : : * Reads a string map of an callout's properties and restores the callout
165 : : * to the state described by the properties map.
166 : : *
167 : : * Subclasses must ensure that they call the base class' readProperties()
168 : : * method.
169 : : *
170 : : * \see properties()
171 : : */
172 : : virtual void readProperties( const QVariantMap &props, const QgsReadWriteContext &context );
173 : :
174 : : /**
175 : : * Saves the current state of the callout to a DOM \a element. The default
176 : : * behavior is to save the properties string map returned by
177 : : * properties().
178 : : * \returns TRUE if save was successful
179 : : * \see readProperties()
180 : : */
181 : : virtual bool saveProperties( QDomDocument &doc, QDomElement &element, const QgsReadWriteContext &context ) const;
182 : :
183 : : /**
184 : : * Restores the callout's properties from a DOM element.
185 : : *
186 : : * The default behavior is the read the DOM contents and call readProperties() on the subclass.
187 : : *
188 : : * \see readProperties()
189 : : */
190 : : virtual void restoreProperties( const QDomElement &element, const QgsReadWriteContext &context );
191 : :
192 : : /**
193 : : * Prepares the callout for rendering on the specified render \a context.
194 : : *
195 : : * \warning This MUST be called prior to calling render() on the callout, and must always
196 : : * be accompanied by a corresponding call to stopRender().
197 : : *
198 : : * \see stopRender()
199 : : */
200 : : virtual void startRender( QgsRenderContext &context );
201 : :
202 : : /**
203 : : * Finalises the callout after a set of rendering operations on the specified render \a context.
204 : : *
205 : : * \warning This MUST be called after to after render() operations on the callout, and must always
206 : : * be accompanied by a corresponding prior call to startRender().
207 : : *
208 : : * \see startRender()
209 : : */
210 : : virtual void stopRender( QgsRenderContext &context );
211 : :
212 : : /**
213 : : * Returns the set of attributes referenced by the callout. This includes attributes
214 : : * required by any data defined properties associated with the callout.
215 : : *
216 : : * \warning This must only be called after a corresponding call to startRender() with
217 : : * the same render \a context.
218 : : */
219 : : virtual QSet< QString > referencedFields( const QgsRenderContext &context ) const;
220 : :
221 : : /**
222 : : * Returns the desired drawing order (stacking) to use while rendering this callout.
223 : : *
224 : : * The default order is QgsCallout::OrderBelowIndividualLabels.
225 : : */
226 : : virtual DrawOrder drawOrder() const;
227 : :
228 : : /**
229 : : * \brief Contains additional contextual information about the context in which a callout is
230 : : * being rendered.
231 : : * \ingroup core
232 : : * \since QGIS 3.10
233 : : */
234 : 0 : class CORE_EXPORT QgsCalloutContext
235 : : {
236 : : public:
237 : : //! TRUE if all parts of associated feature were labeled
238 : 0 : bool allFeaturePartsLabeled = false;
239 : :
240 : : /**
241 : : * Contains the CRS of the original feature associated with this callout.
242 : : *
243 : : * \since QGIS 3.20
244 : : */
245 : : QgsCoordinateReferenceSystem originalFeatureCrs;
246 : :
247 : : /**
248 : : * Returns the coordinate transform to convert from the original layer associated with
249 : : * the callout to the destination map CRS.
250 : : *
251 : : * \since QGIS 3.20
252 : : */
253 : : QgsCoordinateTransform originalFeatureToMapTransform( const QgsRenderContext &renderContext ) const;
254 : :
255 : : /**
256 : : * Adds a rendered callout position.
257 : : *
258 : : * The position details such as the callout line origin and destination should be populated by the
259 : : * callout subclass during rendering operations.
260 : : *
261 : : * \note the feature ID, layer ID and provider ID of the QgsCalloutPosition will be automatically populated.
262 : : *
263 : : * \since QGIS 3.20
264 : : */
265 : 0 : void addCalloutPosition( const QgsCalloutPosition &position ) { return mPositions.push_back( position ); }
266 : :
267 : : /**
268 : : * Returns the list of rendered callout positions.
269 : : *
270 : : * \since QGIS 3.20
271 : : */
272 : 0 : QList< QgsCalloutPosition > positions() const { return mPositions; }
273 : :
274 : : private:
275 : : //! Lazy initialized coordinate transform from original feature CRS to map CRS
276 : : mutable QgsCoordinateTransform mOriginalFeatureToMapTransform;
277 : :
278 : : QList< QgsCalloutPosition > mPositions;
279 : : };
280 : :
281 : : /**
282 : : * Renders the callout onto the specified render \a context.
283 : : *
284 : : * The \a rect argument gives the desired size and position of the body of the callout (e.g. the
285 : : * actual label geometry). The \a angle argument specifies the rotation of the callout body
286 : : * (in degrees clockwise from horizontal). It is assumed that angle rotation specified via \a angle
287 : : * is applied around the center of \a rect.
288 : : *
289 : : * The \a anchor argument dictates the geometry which the callout should connect to. Depending on the
290 : : * callout subclass and anchor geometry type, the actual shape of the rendered callout may vary.
291 : : * E.g. a subclass may prefer to attach to the centroid of the \a anchor, while another subclass may
292 : : * prefer to attach to the closest point on \a anchor instead.
293 : : *
294 : : * Both \a rect and \a anchor must be specified in painter coordinates (i.e. pixels).
295 : : *
296 : : * The \a calloutContext argument is used to specify additional contextual information about
297 : : * how a callout is being rendered.
298 : : *
299 : : * \warning A prior call to startRender() must have been made before calling this method, and
300 : : * after all render() operations are complete a call to stopRender() must be made.
301 : : */
302 : : void render( QgsRenderContext &context, const QRectF &rect, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext );
303 : :
304 : : /**
305 : : * Returns TRUE if the the callout is enabled.
306 : : * \see setEnabled()
307 : : */
308 : 0 : bool enabled() const { return mEnabled; }
309 : :
310 : : /**
311 : : * Sets whether the callout is \a enabled.
312 : : * \see enabled()
313 : : */
314 : : void setEnabled( bool enabled );
315 : :
316 : : /**
317 : : * Returns a reference to the callout's property collection, used for data defined overrides.
318 : : * \see setDataDefinedProperties()
319 : : */
320 : 0 : QgsPropertyCollection &dataDefinedProperties() { return mDataDefinedProperties; }
321 : :
322 : : /**
323 : : * Returns a reference to the callout's property collection, used for data defined overrides.
324 : : * \see setDataDefinedProperties()
325 : : * \see Property
326 : : * \note not available in Python bindings
327 : : */
328 : 0 : const QgsPropertyCollection &dataDefinedProperties() const SIP_SKIP { return mDataDefinedProperties; }
329 : :
330 : : /**
331 : : * Sets the callout's property \a collection, used for data defined overrides.
332 : : *
333 : : * Any existing properties will be discarded.
334 : : *
335 : : * \see dataDefinedProperties()
336 : : * \see Property
337 : : */
338 : 0 : void setDataDefinedProperties( const QgsPropertyCollection &collection ) { mDataDefinedProperties = collection; }
339 : :
340 : : /**
341 : : * Returns the definitions for data defined properties available for use in callouts.
342 : : */
343 : : static QgsPropertiesDefinition propertyDefinitions();
344 : :
345 : : /**
346 : : * Returns the feature's anchor point position.
347 : : *
348 : : * \see setAnchorPoint()
349 : : */
350 : 0 : AnchorPoint anchorPoint() const { return mAnchorPoint; }
351 : :
352 : : /**
353 : : * Sets the feature's \a anchor point position.
354 : : *
355 : : * \see anchorPoint()
356 : : */
357 : : void setAnchorPoint( AnchorPoint anchor ) { mAnchorPoint = anchor; }
358 : :
359 : : /**
360 : : * Encodes an \a anchor point to its string representation.
361 : : * \returns encoded string
362 : : * \see decodeAnchorPoint()
363 : : */
364 : : static QString encodeAnchorPoint( AnchorPoint anchor );
365 : :
366 : : /**
367 : : * Attempts to decode a string representation of an anchor point name to the corresponding
368 : : * anchor point.
369 : : * \param name encoded anchor point name
370 : : * \param ok if specified, will be set to TRUE if the anchor point was successfully decoded
371 : : * \returns decoded name
372 : : * \see encodeAnchorPoint()
373 : : */
374 : : static QgsCallout::AnchorPoint decodeAnchorPoint( const QString &name, bool *ok = nullptr );
375 : :
376 : :
377 : : /**
378 : : * Returns the label's anchor point position.
379 : : *
380 : : * \see setLabelAnchorPoint()
381 : : * \since QGIS 3.14
382 : : */
383 : 0 : LabelAnchorPoint labelAnchorPoint() const { return mLabelAnchorPoint; }
384 : :
385 : : /**
386 : : * Sets the label's \a anchor point position.
387 : : *
388 : : * \see labelAnchorPoint()
389 : : * \since QGIS 3.14
390 : : */
391 : : void setLabelAnchorPoint( LabelAnchorPoint anchor ) { mLabelAnchorPoint = anchor; }
392 : :
393 : : /**
394 : : * Encodes a label \a anchor point to its string representation.
395 : : * \returns encoded string
396 : : * \see decodeLabelAnchorPoint()
397 : : * \since QGIS 3.14
398 : : */
399 : : static QString encodeLabelAnchorPoint( LabelAnchorPoint anchor );
400 : :
401 : : /**
402 : : * Attempts to decode a string representation of a label anchor point name to the corresponding
403 : : * anchor point.
404 : : * \param name encoded label anchor point name
405 : : * \param ok if specified, will be set to TRUE if the anchor point was successfully decoded
406 : : * \returns decoded name
407 : : * \see encodeLabelAnchorPoint()
408 : : * \since QGIS 3.14
409 : : */
410 : : static QgsCallout::LabelAnchorPoint decodeLabelAnchorPoint( const QString &name, bool *ok = nullptr );
411 : :
412 : : protected:
413 : :
414 : : /**
415 : : * Performs the actual rendering of the callout implementation onto the specified render \a context.
416 : : *
417 : : * The \a bodyBoundingBox argument gives the desired size and position of the body of the callout (e.g. the
418 : : * actual label geometry). The \a angle argument specifies the rotation of the callout body
419 : : * (in degrees clockwise from horizontal). It is assumed that angle rotation specified via \a angle
420 : : * is applied around the center of \a rect.
421 : : *
422 : : * The \a anchor argument dictates the geometry which the callout should connect to. Depending on the
423 : : * callout subclass and anchor geometry type, the actual shape of the rendered callout may vary.
424 : : * E.g. a subclass may prefer to attach to the centroid of the \a anchor, while another subclass may
425 : : * prefer to attach to the closest point on \a anchor instead.
426 : : *
427 : : * Both \a rect and \a anchor are specified in painter coordinates (i.e. pixels).
428 : : *
429 : : * The \a calloutContext argument is used to specify additional contextual information about
430 : : * how a callout is being rendered.
431 : : */
432 : : virtual void draw( QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext ) = 0;
433 : :
434 : : /**
435 : : * Returns the anchor point geometry for a label with the given bounding box and \a anchor point mode.
436 : : * \deprecated QGIS 3.20 use calloutLabelPoint() instead
437 : : */
438 : : Q_DECL_DEPRECATED QgsGeometry labelAnchorGeometry( const QRectF &bodyBoundingBox, const double angle, LabelAnchorPoint anchor ) const SIP_DEPRECATED;
439 : :
440 : : /**
441 : : * Returns the anchor point geometry for a label with the given bounding box and \a anchor point mode.
442 : : *
443 : : * The \a pinned argument will be set to TRUE if the callout label point is pinned (manually placed).
444 : : *
445 : : * \since QGIS 3.20
446 : : */
447 : : QgsGeometry calloutLabelPoint( const QRectF &bodyBoundingBox, double angle, LabelAnchorPoint anchor, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned ) const;
448 : :
449 : : /**
450 : : * Calculates the direct line from a label geometry to an anchor geometry part, respecting the various
451 : : * callout settings which influence how the callout end should be placed in the anchor geometry.
452 : : *
453 : : * Returns a null geometry if the callout line cannot be calculated.
454 : : *
455 : : * The \a pinned argument will be set to TRUE if the callout anchor point is pinned (manually placed).
456 : : *
457 : : * \since QGIS 3.20
458 : : */
459 : : QgsGeometry calloutLineToPart( const QgsGeometry &labelGeometry, const QgsAbstractGeometry *partGeometry, QgsRenderContext &context, const QgsCalloutContext &calloutContext, bool &pinned ) const;
460 : :
461 : : private:
462 : :
463 : : bool mEnabled = false;
464 : :
465 : : AnchorPoint mAnchorPoint = PoleOfInaccessibility;
466 : : LabelAnchorPoint mLabelAnchorPoint = LabelPointOnExterior;
467 : :
468 : : //! Property collection for data defined callout settings
469 : : QgsPropertyCollection mDataDefinedProperties;
470 : :
471 : : //! Property definitions
472 : : static QgsPropertiesDefinition sPropertyDefinitions;
473 : :
474 : : static void initPropertyDefinitions();
475 : : };
476 : :
477 : : /**
478 : : * \ingroup core
479 : : * \brief A simple direct line callout style.
480 : : *
481 : : * \since QGIS 3.10
482 : : */
483 : : class CORE_EXPORT QgsSimpleLineCallout : public QgsCallout
484 : : {
485 : : public:
486 : :
487 : : QgsSimpleLineCallout();
488 : : ~QgsSimpleLineCallout() override;
489 : :
490 : : #ifndef SIP_RUN
491 : :
492 : : /**
493 : : * Copy constructor.
494 : : */
495 : : QgsSimpleLineCallout( const QgsSimpleLineCallout &other );
496 : : QgsSimpleLineCallout &operator=( const QgsSimpleLineCallout & ) = delete;
497 : : #endif
498 : :
499 : : /**
500 : : * Creates a new QgsSimpleLineCallout, using the settings
501 : : * serialized in the \a properties map (corresponding to the output from
502 : : * QgsSimpleLineCallout::properties() ).
503 : : */
504 : : static QgsCallout *create( const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext &context = QgsReadWriteContext() ) SIP_FACTORY;
505 : :
506 : : QString type() const override;
507 : : QgsSimpleLineCallout *clone() const override;
508 : : QVariantMap properties( const QgsReadWriteContext &context ) const override;
509 : : void readProperties( const QVariantMap &props, const QgsReadWriteContext &context ) override;
510 : : void startRender( QgsRenderContext &context ) override;
511 : : void stopRender( QgsRenderContext &context ) override;
512 : : QSet< QString > referencedFields( const QgsRenderContext &context ) const override;
513 : :
514 : : /**
515 : : * Returns the line symbol used to render the callout line.
516 : : *
517 : : * Ownership is not transferred.
518 : : *
519 : : * \see setLineSymbol()
520 : : */
521 : : QgsLineSymbol *lineSymbol();
522 : :
523 : : /**
524 : : * Sets the line \a symbol used to render the callout line. Ownership of \a symbol is
525 : : * transferred to the callout.
526 : : *
527 : : * \see lineSymbol()
528 : : */
529 : : void setLineSymbol( QgsLineSymbol *symbol SIP_TRANSFER );
530 : :
531 : : /**
532 : : * Returns the minimum length of callout lines. Units are specified through minimumLengthUnits().
533 : : * \see setMinimumLength()
534 : : * \see minimumLengthUnit()
535 : : */
536 : : double minimumLength() const { return mMinCalloutLength; }
537 : :
538 : : /**
539 : : * Sets the minimum \a length of callout lines. Units are specified through setMinimumLengthUnit().
540 : : * \see minimumLength()
541 : : * \see setMinimumLengthUnit()
542 : : */
543 : : void setMinimumLength( double length ) { mMinCalloutLength = length; }
544 : :
545 : : /**
546 : : * Sets the \a unit for the minimum length of callout lines.
547 : : * \see minimumLengthUnit()
548 : : * \see setMinimumLength()
549 : : */
550 : : void setMinimumLengthUnit( QgsUnitTypes::RenderUnit unit ) { mMinCalloutLengthUnit = unit; }
551 : :
552 : : /**
553 : : * Returns the units for the minimum length of callout lines.
554 : : * \see setMinimumLengthUnit()
555 : : * \see minimumLength()
556 : : */
557 : : QgsUnitTypes::RenderUnit minimumLengthUnit() const { return mMinCalloutLengthUnit; }
558 : :
559 : : /**
560 : : * Sets the map unit \a scale for the minimum callout length.
561 : : * \see minimumLengthMapUnitScale()
562 : : * \see setMinimumLengthUnit()
563 : : * \see setMinimumLength()
564 : : */
565 : : void setMinimumLengthMapUnitScale( const QgsMapUnitScale &scale ) { mMinCalloutLengthScale = scale; }
566 : :
567 : : /**
568 : : * Returns the map unit scale for the minimum callout length.
569 : : * \see setMinimumLengthMapUnitScale()
570 : : * \see minimumLengthUnit()
571 : : * \see minimumLength()
572 : : */
573 : : const QgsMapUnitScale &minimumLengthMapUnitScale() const { return mMinCalloutLengthScale; }
574 : :
575 : :
576 : : /**
577 : : * Returns the offset distance from the anchor point at which to start the line. Units are specified through offsetFromAnchorUnit().
578 : : * \see setOffsetFromAnchor()
579 : : * \see offsetFromAnchorUnit()
580 : : */
581 : : double offsetFromAnchor() const { return mOffsetFromAnchorDistance; }
582 : :
583 : : /**
584 : : * Sets the offset \a distance from the anchor point at which to start the line. Units are specified through setOffsetFromAnchorUnit().
585 : : * \see offsetFromAnchor()
586 : : * \see setOffsetFromAnchorUnit()
587 : : */
588 : : void setOffsetFromAnchor( double distance ) { mOffsetFromAnchorDistance = distance; }
589 : :
590 : : /**
591 : : * Sets the \a unit for the offset from anchor distance.
592 : : * \see offsetFromAnchor()
593 : : * \see setOffsetFromAnchor()
594 : : */
595 : : void setOffsetFromAnchorUnit( QgsUnitTypes::RenderUnit unit ) { mOffsetFromAnchorUnit = unit; }
596 : :
597 : : /**
598 : : * Returns the units for the offset from anchor point.
599 : : * \see setOffsetFromAnchorUnit()
600 : : * \see offsetFromAnchor()
601 : : */
602 : : QgsUnitTypes::RenderUnit offsetFromAnchorUnit() const { return mOffsetFromAnchorUnit; }
603 : :
604 : : /**
605 : : * Sets the map unit \a scale for the offset from anchor.
606 : : * \see offsetFromAnchorMapUnitScale()
607 : : * \see setOffsetFromAnchorUnit()
608 : : * \see setOffsetFromAnchor()
609 : : */
610 : : void setOffsetFromAnchorMapUnitScale( const QgsMapUnitScale &scale ) { mOffsetFromAnchorScale = scale; }
611 : :
612 : : /**
613 : : * Returns the map unit scale for the offset from anchor.
614 : : * \see setOffsetFromAnchorMapUnitScale()
615 : : * \see offsetFromAnchorUnit()
616 : : * \see offsetFromAnchor()
617 : : */
618 : : const QgsMapUnitScale &offsetFromAnchorMapUnitScale() const { return mOffsetFromAnchorScale; }
619 : :
620 : : /**
621 : : * Returns the offset distance from label area at which to end the line. Units are specified through offsetFromLabelUnit().
622 : : * \see setOffsetFromLabel()
623 : : * \see offsetFromLabelUnit()
624 : : */
625 : : double offsetFromLabel() const { return mOffsetFromLabelDistance; }
626 : :
627 : : /**
628 : : * Sets the offset \a distance from label area at which to end the line. Units are specified through setOffsetFromLabelUnit().
629 : : * \see offsetFromLabel()
630 : : * \see setOffsetFromLabelUnit()
631 : : */
632 : : void setOffsetFromLabel( double distance ) { mOffsetFromLabelDistance = distance; }
633 : :
634 : : /**
635 : : * Sets the \a unit for the offset from label area distance.
636 : : * \see offsetFromLabel()
637 : : * \see setOffsetFromLabel()
638 : : */
639 : : void setOffsetFromLabelUnit( QgsUnitTypes::RenderUnit unit ) { mOffsetFromLabelUnit = unit; }
640 : :
641 : : /**
642 : : * Returns the units for the offset from label area.
643 : : * \see setOffsetFromLabelUnit()
644 : : * \see offsetFromLabel()
645 : : */
646 : : QgsUnitTypes::RenderUnit offsetFromLabelUnit() const { return mOffsetFromLabelUnit; }
647 : :
648 : : /**
649 : : * Sets the map unit \a scale for the offset from label area.
650 : : * \see offsetFromLabelMapUnitScale()
651 : : * \see setOffsetFromLabelUnit()
652 : : * \see setOffsetFromLabel()
653 : : */
654 : : void setOffsetFromLabelMapUnitScale( const QgsMapUnitScale &scale ) { mOffsetFromLabelScale = scale; }
655 : :
656 : : /**
657 : : * Returns the map unit scale for the minimum callout length.
658 : : * \see setOffsetFromLabelMapUnitScale()
659 : : * \see offsetFromLabelUnit()
660 : : * \see offsetFromLabel()
661 : : */
662 : : const QgsMapUnitScale &offsetFromLabelMapUnitScale() const { return mOffsetFromLabelScale; }
663 : :
664 : : /**
665 : : * Returns TRUE if callout lines should be drawn to all feature parts.
666 : : *
667 : : * \see setDrawCalloutToAllParts()
668 : : */
669 : : bool drawCalloutToAllParts() const { return mDrawCalloutToAllParts; }
670 : :
671 : : /**
672 : : * Sets whether callout lines should be drawn to all feature parts.
673 : : *
674 : : * \see drawCalloutToAllParts()
675 : : */
676 : : void setDrawCalloutToAllParts( bool drawToAllParts ) { mDrawCalloutToAllParts = drawToAllParts; }
677 : :
678 : : protected:
679 : : void draw( QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext ) override;
680 : :
681 : : /**
682 : : * Creates a callout line between \a start and \a end in the desired style.
683 : : *
684 : : * The base class method returns a straight line.
685 : : *
686 : : * \since QGIS 3.20
687 : : */
688 : : virtual QgsCurve *createCalloutLine( const QgsPoint &start, const QgsPoint &end, QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext ) const SIP_FACTORY;
689 : :
690 : : private:
691 : :
692 : : #ifdef SIP_RUN
693 : : QgsSimpleLineCallout( const QgsSimpleLineCallout &other );
694 : : QgsSimpleLineCallout &operator=( const QgsSimpleLineCallout & );
695 : : #endif
696 : :
697 : : std::unique_ptr< QgsLineSymbol > mLineSymbol;
698 : : double mMinCalloutLength = 0;
699 : : QgsUnitTypes::RenderUnit mMinCalloutLengthUnit = QgsUnitTypes::RenderMillimeters;
700 : : QgsMapUnitScale mMinCalloutLengthScale;
701 : :
702 : : double mOffsetFromAnchorDistance = 0;
703 : : QgsUnitTypes::RenderUnit mOffsetFromAnchorUnit = QgsUnitTypes::RenderMillimeters;
704 : : QgsMapUnitScale mOffsetFromAnchorScale;
705 : :
706 : : double mOffsetFromLabelDistance = 0;
707 : : QgsUnitTypes::RenderUnit mOffsetFromLabelUnit = QgsUnitTypes::RenderMillimeters;
708 : : QgsMapUnitScale mOffsetFromLabelScale;
709 : :
710 : : bool mDrawCalloutToAllParts = false;
711 : : };
712 : :
713 : :
714 : : /**
715 : : * \ingroup core
716 : : * \brief Draws straight (right angled) lines as callouts.
717 : : *
718 : : * \since QGIS 3.10
719 : : */
720 : 0 : class CORE_EXPORT QgsManhattanLineCallout : public QgsSimpleLineCallout
721 : : {
722 : : public:
723 : :
724 : : QgsManhattanLineCallout();
725 : :
726 : : #ifndef SIP_RUN
727 : :
728 : : /**
729 : : * Copy constructor.
730 : : */
731 : : QgsManhattanLineCallout( const QgsManhattanLineCallout &other );
732 : :
733 : : QgsManhattanLineCallout &operator=( const QgsManhattanLineCallout & ) = delete;
734 : : #endif
735 : :
736 : : /**
737 : : * Creates a new QgsManhattanLineCallout, using the settings
738 : : * serialized in the \a properties map (corresponding to the output from
739 : : * QgsManhattanLineCallout::properties() ).
740 : : */
741 : : static QgsCallout *create( const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext &context = QgsReadWriteContext() ) SIP_FACTORY;
742 : :
743 : : QString type() const override;
744 : : QgsManhattanLineCallout *clone() const override;
745 : :
746 : : protected:
747 : : QgsCurve *createCalloutLine( const QgsPoint &start, const QgsPoint &end, QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext ) const override SIP_FACTORY;
748 : :
749 : : private:
750 : : #ifdef SIP_RUN
751 : : QgsManhattanLineCallout( const QgsManhattanLineCallout &other );
752 : : QgsManhattanLineCallout &operator=( const QgsManhattanLineCallout & );
753 : : #endif
754 : : };
755 : :
756 : :
757 : : /**
758 : : * \ingroup core
759 : : * \brief Draws curved lines as callouts.
760 : : *
761 : : * \since QGIS 3.20
762 : : */
763 : 0 : class CORE_EXPORT QgsCurvedLineCallout : public QgsSimpleLineCallout
764 : : {
765 : : public:
766 : :
767 : : /**
768 : : * Curve orientation
769 : : */
770 : : enum Orientation
771 : : {
772 : : Automatic, //!< Automatically choose most cartographically pleasing orientation based on label and callout arrangement
773 : : Clockwise, //!< Curve lines in a clockwise direction
774 : : CounterClockwise, //!< Curve lines in a counter-clockwise direction
775 : : };
776 : :
777 : : QgsCurvedLineCallout();
778 : :
779 : : #ifndef SIP_RUN
780 : :
781 : : /**
782 : : * Copy constructor.
783 : : */
784 : : QgsCurvedLineCallout( const QgsCurvedLineCallout &other );
785 : :
786 : : QgsCurvedLineCallout &operator=( const QgsCurvedLineCallout & ) = delete;
787 : : #endif
788 : :
789 : : /**
790 : : * Creates a new QgsCurvedLineCallout, using the settings
791 : : * serialized in the \a properties map (corresponding to the output from
792 : : * QgsCurvedLineCallout::properties() ).
793 : : */
794 : : static QgsCallout *create( const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext &context = QgsReadWriteContext() ) SIP_FACTORY;
795 : :
796 : : QString type() const override;
797 : : QgsCurvedLineCallout *clone() const override;
798 : : QVariantMap properties( const QgsReadWriteContext &context ) const override;
799 : :
800 : : /**
801 : : * Returns the callout line's curvature.
802 : : *
803 : : * The curvature is a percentage value (with typical ranges between 0.0 and 1.0), representing the overall curvature of the line.
804 : : *
805 : : * \see setCurvature()
806 : : */
807 : : double curvature() const;
808 : :
809 : : /**
810 : : * Sets the callout line's \a curvature.
811 : : *
812 : : * The \a curvature is a percentage value (with typical ranges between 0.0 and 1.0), representing the overall curvature of the line.
813 : : *
814 : : * \see curvature()
815 : : */
816 : : void setCurvature( double curvature );
817 : :
818 : : /**
819 : : * Returns the callout line's curve orientation.
820 : : *
821 : : * \see setOrientation()
822 : : */
823 : : Orientation orientation() const;
824 : :
825 : : /**
826 : : * Sets the callout line's curve \a orientation.
827 : : *
828 : : * \see orientation()
829 : : */
830 : : void setOrientation( Orientation orientation );
831 : :
832 : : protected:
833 : : QgsCurve *createCalloutLine( const QgsPoint &start, const QgsPoint &end, QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCalloutContext &calloutContext ) const override SIP_FACTORY;
834 : :
835 : : private:
836 : : #ifdef SIP_RUN
837 : : QgsCurvedLineCallout( const QgsCurvedLineCallout &other );
838 : : QgsCurvedLineCallout &operator=( const QgsCurvedLineCallout & );
839 : : #endif
840 : :
841 : : /**
842 : : * Decodes a string to an orientation value
843 : : */
844 : : static Orientation decodeOrientation( const QString &string );
845 : :
846 : : /**
847 : : * Encodes an orientation string
848 : : */
849 : : static QString encodeOrientation( Orientation orientation );
850 : :
851 : :
852 : : Orientation mOrientation = Automatic;
853 : : double mCurvature = 0.1;
854 : : };
855 : :
856 : :
857 : : /**
858 : : * \ingroup core
859 : : * \brief A cartoon talking bubble callout style.
860 : : *
861 : : * \since QGIS 3.20
862 : : */
863 : : class CORE_EXPORT QgsBalloonCallout : public QgsCallout
864 : : {
865 : : public:
866 : :
867 : : QgsBalloonCallout();
868 : : ~QgsBalloonCallout() override;
869 : :
870 : : #ifndef SIP_RUN
871 : :
872 : : /**
873 : : * Copy constructor.
874 : : */
875 : : QgsBalloonCallout( const QgsBalloonCallout &other );
876 : : QgsBalloonCallout &operator=( const QgsBalloonCallout & ) = delete;
877 : : #endif
878 : :
879 : : /**
880 : : * Creates a new QgsBalloonCallout, using the settings
881 : : * serialized in the \a properties map (corresponding to the output from
882 : : * QgsBalloonCallout::properties() ).
883 : : */
884 : : static QgsCallout *create( const QVariantMap &properties = QVariantMap(), const QgsReadWriteContext &context = QgsReadWriteContext() ) SIP_FACTORY;
885 : :
886 : : QString type() const override;
887 : : QgsBalloonCallout *clone() const override;
888 : : QVariantMap properties( const QgsReadWriteContext &context ) const override;
889 : : void readProperties( const QVariantMap &props, const QgsReadWriteContext &context ) override;
890 : : void startRender( QgsRenderContext &context ) override;
891 : : void stopRender( QgsRenderContext &context ) override;
892 : : QSet< QString > referencedFields( const QgsRenderContext &context ) const override;
893 : :
894 : : /**
895 : : * Returns the fill symbol used to render the callout.
896 : : *
897 : : * Ownership is not transferred.
898 : : *
899 : : * \see setFillSymbol()
900 : : */
901 : : QgsFillSymbol *fillSymbol();
902 : :
903 : : /**
904 : : * Sets the fill \a symbol used to render the callout. Ownership of \a symbol is
905 : : * transferred to the callout.
906 : : *
907 : : * \see fillSymbol()
908 : : */
909 : : void setFillSymbol( QgsFillSymbol *symbol SIP_TRANSFER );
910 : :
911 : : /**
912 : : * Returns the offset distance from the anchor point at which to start the line. Units are specified through offsetFromAnchorUnit().
913 : : * \see setOffsetFromAnchor()
914 : : * \see offsetFromAnchorUnit()
915 : : */
916 : : double offsetFromAnchor() const { return mOffsetFromAnchorDistance; }
917 : :
918 : : /**
919 : : * Sets the offset \a distance from the anchor point at which to start the line. Units are specified through setOffsetFromAnchorUnit().
920 : : * \see offsetFromAnchor()
921 : : * \see setOffsetFromAnchorUnit()
922 : : */
923 : : void setOffsetFromAnchor( double distance ) { mOffsetFromAnchorDistance = distance; }
924 : :
925 : : /**
926 : : * Sets the \a unit for the offset from anchor distance.
927 : : * \see offsetFromAnchor()
928 : : * \see setOffsetFromAnchor()
929 : : */
930 : : void setOffsetFromAnchorUnit( QgsUnitTypes::RenderUnit unit ) { mOffsetFromAnchorUnit = unit; }
931 : :
932 : : /**
933 : : * Returns the units for the offset from anchor point.
934 : : * \see setOffsetFromAnchorUnit()
935 : : * \see offsetFromAnchor()
936 : : */
937 : : QgsUnitTypes::RenderUnit offsetFromAnchorUnit() const { return mOffsetFromAnchorUnit; }
938 : :
939 : : /**
940 : : * Sets the map unit \a scale for the offset from anchor.
941 : : * \see offsetFromAnchorMapUnitScale()
942 : : * \see setOffsetFromAnchorUnit()
943 : : * \see setOffsetFromAnchor()
944 : : */
945 : : void setOffsetFromAnchorMapUnitScale( const QgsMapUnitScale &scale ) { mOffsetFromAnchorScale = scale; }
946 : :
947 : : /**
948 : : * Returns the map unit scale for the offset from anchor.
949 : : * \see setOffsetFromAnchorMapUnitScale()
950 : : * \see offsetFromAnchorUnit()
951 : : * \see offsetFromAnchor()
952 : : */
953 : : const QgsMapUnitScale &offsetFromAnchorMapUnitScale() const { return mOffsetFromAnchorScale; }
954 : :
955 : : /**
956 : : * Returns the margins between the outside of the callout frame and the label's bounding rectangle.
957 : : *
958 : : * Units are retrieved via marginsUnit()
959 : : *
960 : : * \note Negative margins are acceptable.
961 : : *
962 : : * \see setMargins()
963 : : * \see marginsUnit()
964 : : */
965 : : const QgsMargins &margins() const { return mMargins; }
966 : :
967 : : /**
968 : : * Sets the \a margins between the outside of the callout frame and the label's bounding rectangle.
969 : : *
970 : : * Units are set via setMarginsUnit()
971 : : *
972 : : * \note Negative margins are acceptable.
973 : : *
974 : : * \see margins()
975 : : * \see setMarginsUnit()
976 : : */
977 : : void setMargins( const QgsMargins &margins ) { mMargins = margins; }
978 : :
979 : : /**
980 : : * Sets the \a unit for the margins between the outside of the callout frame and the label's bounding rectangle.
981 : : *
982 : : * \see margins()
983 : : * \see marginsUnit()
984 : : */
985 : : void setMarginsUnit( QgsUnitTypes::RenderUnit unit ) { mMarginUnit = unit; }
986 : :
987 : : /**
988 : : * Returns the units for the margins between the outside of the callout frame and the label's bounding rectangle.
989 : : *
990 : : * \see setMarginsUnit()
991 : : * \see margins()
992 : : */
993 : : QgsUnitTypes::RenderUnit marginsUnit() const { return mMarginUnit; }
994 : :
995 : : /**
996 : : * Returns the width of the wedge shape at the side it connects with the label.
997 : : *
998 : : * Units are specified through wedgeWidthUnit().
999 : : *
1000 : : * \see setWedgeWidth()
1001 : : * \see wedgeWidthUnit()
1002 : : */
1003 : : double wedgeWidth() const { return mWedgeWidth; }
1004 : :
1005 : : /**
1006 : : * Sets the \a width of the wedge shape at the side it connects with the label.
1007 : : *
1008 : : * Units are specified through setWedgeWidthUnit().
1009 : : *
1010 : : * \see wedgeWidth()
1011 : : * \see setWedgeWidthUnit()
1012 : : */
1013 : : void setWedgeWidth( double width ) { mWedgeWidth = width; }
1014 : :
1015 : : /**
1016 : : * Sets the \a unit for the wedge width.
1017 : : *
1018 : : * \see wedgeWidthUnit()
1019 : : * \see setWedgeWidth()
1020 : : */
1021 : : void setWedgeWidthUnit( QgsUnitTypes::RenderUnit unit ) { mWedgeWidthUnit = unit; }
1022 : :
1023 : : /**
1024 : : * Returns the units for the wedge width.
1025 : : *
1026 : : * \see setWedgeWidthUnit()
1027 : : * \see wedgeWidth()
1028 : : */
1029 : : QgsUnitTypes::RenderUnit wedgeWidthUnit() const { return mWedgeWidthUnit; }
1030 : :
1031 : : /**
1032 : : * Sets the map unit \a scale for the wedge width.
1033 : : *
1034 : : * \see wedgeWidthMapUnitScale()
1035 : : * \see setWedgeWidthUnit()
1036 : : * \see setWedgeWidth()
1037 : : */
1038 : : void setWedgeWidthMapUnitScale( const QgsMapUnitScale &scale ) { mWedgeWidthScale = scale; }
1039 : :
1040 : : /**
1041 : : * Returns the map unit scale for the wedge width.
1042 : : *
1043 : : * \see setWedgeWidthMapUnitScale()
1044 : : * \see wedgeWidthUnit()
1045 : : * \see wedgeWidth()
1046 : : */
1047 : : const QgsMapUnitScale &wedgeWidthMapUnitScale() const { return mWedgeWidthScale; }
1048 : :
1049 : : /**
1050 : : * Returns the corner radius of the balloon shapes.
1051 : : *
1052 : : * Units are specified through wedgeWidthUnit().
1053 : : *
1054 : : * \see setCornerRadius()
1055 : : * \see cornerRadiusUnit()
1056 : : */
1057 : : double cornerRadius() const { return mCornerRadius; }
1058 : :
1059 : : /**
1060 : : * Sets the \a radius of the corners for the balloon shapes.
1061 : : *
1062 : : * Units are specified through setCornerRadiusUnit().
1063 : : *
1064 : : * \see cornerRadius()
1065 : : * \see setCornerRadiusUnit()
1066 : : */
1067 : : void setCornerRadius( double radius ) { mCornerRadius = radius; }
1068 : :
1069 : : /**
1070 : : * Sets the \a unit for the corner radius.
1071 : : *
1072 : : * \see cornerRadiusUnit()
1073 : : * \see setCornerRadius()
1074 : : */
1075 : : void setCornerRadiusUnit( QgsUnitTypes::RenderUnit unit ) { mCornerRadiusUnit = unit; }
1076 : :
1077 : : /**
1078 : : * Returns the units for the corner radius.
1079 : : *
1080 : : * \see setCornerRadiusUnit()
1081 : : * \see cornerRadius()
1082 : : */
1083 : : QgsUnitTypes::RenderUnit cornerRadiusUnit() const { return mCornerRadiusUnit; }
1084 : :
1085 : : /**
1086 : : * Sets the map unit \a scale for the corner radius.
1087 : : *
1088 : : * \see cornerRadiusMapUnitScale()
1089 : : * \see setCornerRadiusUnit()
1090 : : * \see setCornerRadius()
1091 : : */
1092 : : void setCornerRadiusMapUnitScale( const QgsMapUnitScale &scale ) { mCornerRadiusScale = scale; }
1093 : :
1094 : : /**
1095 : : * Returns the map unit scale for the corner radius.
1096 : : *
1097 : : * \see setCornerRadiusMapUnitScale()
1098 : : * \see cornerRadiusUnit()
1099 : : * \see cornerRadius()
1100 : : */
1101 : : const QgsMapUnitScale &cornerRadiusMapUnitScale() const { return mCornerRadiusScale; }
1102 : :
1103 : :
1104 : : protected:
1105 : : void draw( QgsRenderContext &context, const QRectF &bodyBoundingBox, const double angle, const QgsGeometry &anchor, QgsCallout::QgsCalloutContext &calloutContext ) override;
1106 : :
1107 : : private:
1108 : :
1109 : : QPolygonF getPoints( QgsRenderContext &context, QgsPointXY origin, QRectF rect ) const;
1110 : :
1111 : : #ifdef SIP_RUN
1112 : : QgsBalloonCallout( const QgsBalloonCallout &other );
1113 : : QgsBalloonCallout &operator=( const QgsBalloonCallout & );
1114 : : #endif
1115 : :
1116 : : std::unique_ptr< QgsFillSymbol > mFillSymbol;
1117 : :
1118 : : double mOffsetFromAnchorDistance = 0;
1119 : : QgsUnitTypes::RenderUnit mOffsetFromAnchorUnit = QgsUnitTypes::RenderMillimeters;
1120 : : QgsMapUnitScale mOffsetFromAnchorScale;
1121 : :
1122 : : QgsMargins mMargins;
1123 : : QgsUnitTypes::RenderUnit mMarginUnit = QgsUnitTypes::RenderMillimeters;
1124 : :
1125 : : double mWedgeWidth = 2.64;
1126 : : QgsUnitTypes::RenderUnit mWedgeWidthUnit = QgsUnitTypes::RenderMillimeters;
1127 : : QgsMapUnitScale mWedgeWidthScale;
1128 : :
1129 : : double mCornerRadius = 0.0;
1130 : : QgsUnitTypes::RenderUnit mCornerRadiusUnit = QgsUnitTypes::RenderMillimeters;
1131 : : QgsMapUnitScale mCornerRadiusScale;
1132 : :
1133 : : };
1134 : :
1135 : :
1136 : :
1137 : : #endif // QGSCALLOUT_H
1138 : :
|