QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
Loading...
Searching...
No Matches
qgslabelsearchtree.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslabelsearchtree.cpp
3 ---------------------
4 begin : November 2010
5 copyright : (C) 2010 by Marco Hugentobler
6 email : marco dot hugentobler at sourcepole dot ch
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#include "qgslabelsearchtree.h"
16
17#include "labelposition.h"
18
20
22
23void QgsLabelSearchTree::label( const QgsPointXY &point, QList<QgsLabelPosition *> &posList ) const
24{
25 const QgsPointXY p( point );
26
27 QList<QgsLabelPosition *> searchResults;
28 mSpatialIndex.intersects( QgsRectangle( p.x() - 0.1, p.y() - 0.1, p.x() + 0.1, p.y() + 0.1 ), [&searchResults]( const QgsLabelPosition *pos ) -> bool {
29 searchResults.push_back( const_cast< QgsLabelPosition * >( pos ) );
30 return true;
31 } );
32
33 //tolerance +-0.1 could be high in case of degree crs, so check if p is really contained in the results
34 posList.clear();
35 QList<QgsLabelPosition *>::const_iterator resultIt = searchResults.constBegin();
36 for ( ; resultIt != searchResults.constEnd(); ++resultIt )
37 {
38 if ( ( *resultIt )->labelGeometry.contains( &p ) )
39 {
40 posList.push_back( *resultIt );
41 }
42 }
43}
44
45QList<QgsLabelPosition> QgsLabelSearchTree::allLabels() const
46{
47 QList<QgsLabelPosition> res;
48 res.reserve( mOwnedPositions.size() );
49 for ( const std::unique_ptr< QgsLabelPosition > &pos : mOwnedPositions )
50 {
51 res.append( *pos );
52 }
53 return res;
54}
55
56void QgsLabelSearchTree::labelsInRect( const QgsRectangle &r, QList<QgsLabelPosition *> &posList ) const
57{
58 QList<QgsLabelPosition *> searchResults;
59 mSpatialIndex.intersects( r, [&searchResults]( const QgsLabelPosition *pos ) -> bool {
60 searchResults.push_back( const_cast< QgsLabelPosition * >( pos ) );
61 return true;
62 } );
63
64 posList.clear();
65 QList<QgsLabelPosition *>::const_iterator resultIt = searchResults.constBegin();
66 for ( ; resultIt != searchResults.constEnd(); ++resultIt )
67 {
68 if ( ( *resultIt )->labelGeometry.intersects( r ) )
69 {
70 posList.push_back( *resultIt );
71 }
72 }
73}
74
76 pal::LabelPosition *labelPos,
77 QgsFeatureId featureId,
78 const QString &layerName,
79 const QString &labeltext,
80 const QFont &labelfont,
81 bool diagram,
82 bool pinned,
83 const QString &providerId,
84 bool isUnplaced,
85 long long linkedId
86)
87{
88 if ( !labelPos )
89 {
90 return false;
91 }
92
93 QVector<QgsPointXY> cornerPoints;
94 cornerPoints.reserve( 4 );
95 double xMin = std::numeric_limits< double >::max();
96 double yMin = std::numeric_limits< double >::max();
97 double xMax = std::numeric_limits< double >::lowest();
98 double yMax = std::numeric_limits< double >::lowest();
99 for ( int i = 0; i < 4; ++i )
100 {
101 // we have to transform the bounding box to convert pre-rotated label positions back to real world locations
102 const QPointF res = mTransform.map( QPointF( labelPos->getX( i ), labelPos->getY( i ) ) );
103 cornerPoints.push_back( QgsPointXY( res ) );
104 xMin = std::min( xMin, res.x() );
105 xMax = std::max( xMax, res.x() );
106 yMin = std::min( yMin, res.y() );
107 yMax = std::max( yMax, res.y() );
108 }
109
110 pal::LabelPosition *next = labelPos->nextPart();
111 long long uniqueLinkedId = 0;
112 if ( linkedId != 0 )
113 uniqueLinkedId = linkedId;
114 else if ( next )
115 uniqueLinkedId = mNextFeatureId++;
116
117 const QgsRectangle bounds( xMin, yMin, xMax, yMax );
118 const QgsGeometry labelGeometry( QgsGeometry::fromPolygonXY( QVector<QgsPolylineXY>() << cornerPoints ) );
119 auto newEntry = std::make_unique< QgsLabelPosition >(
120 featureId,
121 -labelPos->getAlpha() * 180 / M_PI + mMapSettings.rotation(),
122 cornerPoints,
123 bounds,
124 labelPos->getWidth(),
125 labelPos->getHeight(),
126 layerName,
127 labeltext,
128 labelfont,
129 labelPos->getUpsideDown(),
130 diagram,
131 pinned,
132 providerId,
133 labelGeometry,
134 isUnplaced
135 );
136 newEntry->groupedLabelId = uniqueLinkedId;
137 mSpatialIndex.insert( newEntry.get(), bounds );
138
139 if ( uniqueLinkedId != 0 )
140 {
141 mLinkedLabelHash[uniqueLinkedId].append( newEntry.get() );
142 }
143
144 mOwnedPositions.emplace_back( std::move( newEntry ) );
145
146 if ( next )
147 {
148 return insertLabel( next, featureId, layerName, labeltext, labelfont, diagram, pinned, providerId, isUnplaced, uniqueLinkedId );
149 }
150 return true;
151}
152
154{
155 const QPointF origin = position.origin();
156 const QPointF destination = position.destination();
157
158 auto newEntry = std::make_unique< QgsCalloutPosition >( position );
159
160 mCalloutIndex.insert( newEntry.get(), QgsRectangle( origin.x(), origin.y(), origin.x(), origin.y() ) );
161 mCalloutIndex.insert( newEntry.get(), QgsRectangle( destination.x(), destination.y(), destination.x(), destination.y() ) );
162
163 mOwnedCalloutPositions.emplace_back( std::move( newEntry ) );
164
165 return true;
166}
167
168QList<const QgsCalloutPosition *> QgsLabelSearchTree::calloutsInRectangle( const QgsRectangle &rectangle ) const
169{
170 QList<const QgsCalloutPosition *> searchResults;
171 mCalloutIndex.intersects( rectangle, [&searchResults]( const QgsCalloutPosition *pos ) -> bool {
172 searchResults.push_back( pos );
173 return true;
174 } );
175
176 std::sort( searchResults.begin(), searchResults.end() );
177 searchResults.erase( std::unique( searchResults.begin(), searchResults.end() ), searchResults.end() );
178
179 return searchResults;
180}
181
182QList<QgsLabelPosition *> QgsLabelSearchTree::groupedLabelPositions( long long groupId ) const
183{
184 return mLinkedLabelHash.value( groupId );
185}
186
188{
189 mMapSettings = settings;
190
191 if ( !qgsDoubleNear( mMapSettings.rotation(), 0.0 ) )
192 {
193 // build a transform to convert points from real world to pre-rotated label positions
194 const QgsPointXY center = mMapSettings.visibleExtent().center();
195 mTransform = QTransform::fromTranslate( center.x(), center.y() );
196 mTransform.rotate( mMapSettings.rotation() );
197 mTransform.translate( -center.x(), -center.y() );
198 }
199 else
200 {
201 mTransform = QTransform();
202 }
203}
204
205
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.
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygonXY.
Represents the calculated placement of a map label.
QList< QgsLabelPosition * > groupedLabelPositions(long long groupId) const
Returns a list of all label positions sharing the same group ID (i.e.
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)
Inserts label position.
Q_DECL_DEPRECATED void clear()
Removes and deletes all the entries.
void label(const QgsPointXY &p, QList< QgsLabelPosition * > &posList) const
Returns label position(s) at a given point.
void labelsInRect(const QgsRectangle &r, QList< QgsLabelPosition * > &posList) const
Returns label position(s) in given rectangle.
QList< const QgsCalloutPosition * > calloutsInRectangle(const QgsRectangle &rectangle) const
Returns the list of callouts with origins or destinations inside the given rectangle.
bool insertCallout(const QgsCalloutPosition &position)
Inserts a rendered callout 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.
Contains configuration for rendering maps.
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.
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:6975
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features