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