QGIS API Documentation 4.3.0-Master (2b7e6c9893e)
Loading...
Searching...
No Matches
qgslabelingresults.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslabelingresults.cpp
3 -------------------
4 begin : February 2021
5 copyright : (C) Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include "qgslabelingresults.h"
17
18#include "feature.h"
19#include "labelposition.h"
20#include "qgslabelsearchtree.h"
21#include "qgslinestring.h"
22#include "qgsmapsettings.h"
23#include "qgspolygon.h"
24
26 : mLabelSearchTree( enableSearchTree ? std::make_unique< QgsLabelSearchTree >() : nullptr )
27{}
28
30
32{
33 return static_cast< bool >( mLabelSearchTree );
34}
35
37 pal::LabelPosition *labelPos,
38 QgsFeatureId featureId,
39 const QString &layerName,
40 const QString &labeltext,
41 const QFont &labelfont,
42 bool diagram,
43 bool pinned,
44 const QString &providerId,
45 bool isUnplaced,
46 long long linkedId,
47 long long linkedPositionIndex,
48 long long subPartId
49)
50{
51 if ( !labelPos )
52 {
53 return false;
54 }
55
56 QVector<QgsPointXY> cornerPoints;
57 QVector< double > cornerPointsX;
58 QVector< double > cornerPointsY;
59 cornerPoints.resize( 4 );
60 cornerPointsX.resize( 5 );
61 cornerPointsY.resize( 5 );
62 double xMin = std::numeric_limits< double >::max();
63 double yMin = std::numeric_limits< double >::max();
64 double xMax = std::numeric_limits< double >::lowest();
65 double yMax = std::numeric_limits< double >::lowest();
66 for ( int i = 0; i < 4; ++i )
67 {
68 // we have to transform the bounding box to convert pre-rotated label positions back to real world locations
69 const QPointF res = mTransform.map( QPointF( labelPos->getX( i ), labelPos->getY( i ) ) );
70 cornerPoints[i] = QgsPointXY( res );
71 cornerPointsX[i] = res.x();
72 cornerPointsY[i] = res.y();
73 xMin = std::min( xMin, res.x() );
74 xMax = std::max( xMax, res.x() );
75 yMin = std::min( yMin, res.y() );
76 yMax = std::max( yMax, res.y() );
77 }
78 cornerPointsX[4] = cornerPointsX[0];
79 cornerPointsY[4] = cornerPointsY[0];
80
81 pal::LabelPosition *next = labelPos->nextPart();
82 long long uniqueLinkedId = 0;
83 if ( linkedId != 0 )
84 uniqueLinkedId = linkedId;
85 else if ( next )
86 uniqueLinkedId = mNextFeatureId++;
87
88 const QgsRectangle bounds( xMin, yMin, xMax, yMax );
89 const QgsGeometry labelGeometry( std::make_unique< QgsPolygon >( new QgsLineString( cornerPointsX, cornerPointsY ) ) );
90 auto newEntry = std::make_unique< QgsLabelPosition >(
91 featureId,
92 -labelPos->getAlpha() * 180 / M_PI + mMapSettings.rotation(),
93 cornerPoints,
94 bounds,
95 labelPos->getWidth(),
96 labelPos->getHeight(),
97 layerName,
98 labeltext,
99 labelfont,
100 labelPos->getUpsideDown(),
101 diagram,
102 pinned,
103 providerId,
104 labelGeometry,
105 isUnplaced
106 );
107 newEntry->groupedLabelId = uniqueLinkedId;
108 newEntry->groupedPositionIndex = linkedPositionIndex;
109 newEntry->subPartId = subPartId;
110
111 if ( uniqueLinkedId != 0 )
112 {
113 mLinkedLabelHash[uniqueLinkedId].append( newEntry.get() );
114 }
115
116 if ( mLabelSearchTree )
117 {
118 mLabelSearchTree->mSpatialIndex.insert( newEntry.get(), bounds );
119 }
120 mOwnedPositions.emplace_back( std::move( newEntry ) );
121
122 if ( next )
123 {
124 return insertLabel( next, featureId, layerName, labeltext, labelfont, diagram, pinned, providerId, isUnplaced, uniqueLinkedId, linkedPositionIndex + 1, subPartId );
125 }
126 return true;
127}
128
130{
131 const QPointF origin = position.origin();
132 const QPointF destination = position.destination();
133
134 auto newEntry = std::make_unique< QgsCalloutPosition >( position );
135
136 if ( mLabelSearchTree )
137 {
138 mLabelSearchTree->mCalloutIndex.insert( newEntry.get(), QgsRectangle( origin.x(), origin.y(), origin.x(), origin.y() ) );
139 mLabelSearchTree->mCalloutIndex.insert( newEntry.get(), QgsRectangle( destination.x(), destination.y(), destination.x(), destination.y() ) );
140 }
141
142 mOwnedCalloutPositions.emplace_back( std::move( newEntry ) );
143
144 return true;
145}
146
147QList<QgsLabelPosition> QgsLabelingResults::allLabels() const
148{
149 QList<QgsLabelPosition> res;
150 res.reserve( static_cast< qsizetype>( mOwnedPositions.size() ) );
151 for ( const std::unique_ptr< QgsLabelPosition > &pos : mOwnedPositions )
152 {
153 res.append( *pos );
154 }
155 return res;
156}
157
158QList<QgsLabelPosition> QgsLabelingResults::labelsAtPosition( const QgsPointXY &p ) const
159{
160 QList<QgsLabelPosition> positions;
161
162 QList<QgsLabelPosition *> positionPointers;
163 if ( mLabelSearchTree )
164 {
165 mLabelSearchTree->label( p, positionPointers );
166 QList<QgsLabelPosition *>::const_iterator pointerIt = positionPointers.constBegin();
167 for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
168 {
169 positions.push_back( QgsLabelPosition( **pointerIt ) );
170 }
171 }
172
173 return positions;
174}
175
176QList<QgsLabelPosition> QgsLabelingResults::labelsWithinRect( const QgsRectangle &r ) const
177{
178 QList<QgsLabelPosition> positions;
179
180 QList<QgsLabelPosition *> positionPointers;
181 if ( mLabelSearchTree )
182 {
183 mLabelSearchTree->labelsInRect( r, positionPointers );
184 QList<QgsLabelPosition *>::const_iterator pointerIt = positionPointers.constBegin();
185 for ( ; pointerIt != positionPointers.constEnd(); ++pointerIt )
186 {
187 positions.push_back( QgsLabelPosition( **pointerIt ) );
188 }
189 }
190
191 return positions;
192}
193
194QList<QgsLabelPosition> QgsLabelingResults::groupedLabelPositions( long long groupId ) const
195{
196 QList<QgsLabelPosition> positions;
197 if ( mLabelSearchTree )
198 {
199 const QList<QgsLabelPosition *> positionPointers = mLinkedLabelHash.value( groupId );
200 positions.reserve( positionPointers.size() );
201 for ( const QgsLabelPosition *pos : positionPointers )
202 positions.push_back( QgsLabelPosition( *pos ) );
203 }
204 return positions;
205}
206
207QList<QgsCalloutPosition> QgsLabelingResults::calloutsWithinRectangle( const QgsRectangle &rectangle ) const
208{
209 QList<QgsCalloutPosition> positions;
210
211 if ( mLabelSearchTree )
212 {
213 const QList<const QgsCalloutPosition *> positionPointers = mLabelSearchTree->calloutsInRectangle( rectangle );
214 for ( const QgsCalloutPosition *pos : positionPointers )
215 {
216 positions.push_back( QgsCalloutPosition( *pos ) );
217 }
218 }
219
220 return positions;
221}
222
224{
225 mMapSettings = settings;
226 if ( !qgsDoubleNear( settings.rotation(), 0.0 ) )
227 {
228 // build a transform to convert points from real world to pre-rotated label positions
229 const QgsPointXY center = settings.visibleExtent().center();
230 mTransform = QTransform::fromTranslate( center.x(), center.y() );
231 mTransform.rotate( mMapSettings.rotation() );
232 mTransform.translate( -center.x(), -center.y() );
233 }
234 else
235 {
236 mTransform = QTransform();
237 }
238}
Represents the calculated placement of a map label callout line.
QPointF origin() const
Returns the origin of the callout line, in map coordinates.
QPointF destination() const
Returns the destination of the callout line, in map coordinates.
A geometry is the spatial representation of a feature.
Represents the calculated placement of a map label.
Queries the labeling structure at a given point.
bool insertCallout(const QgsCalloutPosition &position)
Inserts a rendered callout position.
bool hasSearchTree() const
Returns true if the results were constructed with search tree enabled.
QList< QgsCalloutPosition > calloutsWithinRectangle(const QgsRectangle &rectangle) const
Returns a list of callouts with origins or destinations inside the given rectangle.
QgsLabelingResults(bool enableSearchTree=true)
Constructor for QgsLabelingResults.
bool insertLabel(pal::LabelPosition *labelPos, QgsFeatureId featureId, const QString &layerName, const QString &labeltext, const QFont &labelfont, bool diagram=false, bool pinned=false, const QString &providerId=QString(), bool isUnplaced=false, long long linkedId=0, long long linkedPositionIndex=0, long long subPartId=0)
Inserts label position.
void setMapSettings(const QgsMapSettings &settings)
Sets the map settings associated with the labeling run.
QList< QgsLabelPosition > allLabels() const
Returns a list of all labels generated by the labeling run.
QList< QgsLabelPosition > labelsAtPosition(const QgsPointXY &p) const
Returns the details of any labels placed at the specified point (in map coordinates).
QList< QgsLabelPosition > groupedLabelPositions(long long groupId) const
Returns a list of all label positions sharing the same group ID (i.e.
QList< QgsLabelPosition > labelsWithinRect(const QgsRectangle &r) const
Returns the details of any labels placed within the specified rectangle (in map coordinates).
Line string geometry type, with support for z-dimension and m-values.
Contains configuration for rendering maps.
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
Represents a 2D point.
Definition qgspointxy.h:62
double y
Definition qgspointxy.h:66
double x
Definition qgspointxy.h:65
A rectangle specified with double values.
QgsPointXY center
LabelPosition is a candidate feature label position.
double getAlpha() const
Returns the angle to rotate text (in radians).
double getHeight() const
double getWidth() const
double getX(int i=0) const
Returns the down-left x coordinate.
double getY(int i=0) const
Returns the down-left y coordinate.
bool getUpsideDown() const
LabelPosition * nextPart() const
Returns the next part of this label position (i.e.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
Definition qgis.h:7624
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features