QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
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 #include "labelposition.h"
17 
19 
21 
22 void QgsLabelSearchTree::label( const QgsPointXY &point, QList<QgsLabelPosition *> &posList ) const
23 {
24  const QgsPointXY p( point );
25 
26  QList<QgsLabelPosition *> searchResults;
27  mSpatialIndex.intersects( QgsRectangle( p.x() - 0.1, p.y() - 0.1, p.x() + 0.1, p.y() + 0.1 ), [&searchResults]( const QgsLabelPosition * pos ) -> bool
28  {
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 
45 QList<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 
56 void QgsLabelSearchTree::labelsInRect( const QgsRectangle &r, QList<QgsLabelPosition *> &posList ) const
57 {
58  QList<QgsLabelPosition *> searchResults;
59  mSpatialIndex.intersects( r, [&searchResults]( const QgsLabelPosition * pos )->bool
60  {
61  searchResults.push_back( const_cast< QgsLabelPosition * >( pos ) );
62  return true;
63  } );
64 
65  posList.clear();
66  QList<QgsLabelPosition *>::const_iterator resultIt = searchResults.constBegin();
67  for ( ; resultIt != searchResults.constEnd(); ++resultIt )
68  {
69  if ( ( *resultIt )->labelGeometry.intersects( r ) )
70  {
71  posList.push_back( *resultIt );
72  }
73  }
74 }
75 
76 bool QgsLabelSearchTree::insertLabel( pal::LabelPosition *labelPos, QgsFeatureId featureId, const QString &layerName, const QString &labeltext, const QFont &labelfont, bool diagram, bool pinned, const QString &providerId, bool isUnplaced, long long linkedId )
77 {
78  if ( !labelPos )
79  {
80  return false;
81  }
82 
83  QVector<QgsPointXY> cornerPoints;
84  cornerPoints.reserve( 4 );
85  double xMin = std::numeric_limits< double >::max();
86  double yMin = std::numeric_limits< double >::max();
87  double xMax = std::numeric_limits< double >::lowest();
88  double yMax = std::numeric_limits< double >::lowest();
89  for ( int i = 0; i < 4; ++i )
90  {
91  // we have to transform the bounding box to convert pre-rotated label positions back to real world locations
92  const QPointF res = mTransform.map( QPointF( labelPos->getX( i ), labelPos->getY( i ) ) );
93  cornerPoints.push_back( QgsPointXY( res ) );
94  xMin = std::min( xMin, res.x() );
95  xMax = std::max( xMax, res.x() );
96  yMin = std::min( yMin, res.y() );
97  yMax = std::max( yMax, res.y() );
98  }
99 
100  pal::LabelPosition *next = labelPos->nextPart();
101  long long uniqueLinkedId = 0;
102  if ( linkedId != 0 )
103  uniqueLinkedId = linkedId;
104  else if ( next )
105  uniqueLinkedId = mNextFeatureId++;
106 
107  const QgsRectangle bounds( xMin, yMin, xMax, yMax );
108  const QgsGeometry labelGeometry( QgsGeometry::fromPolygonXY( QVector<QgsPolylineXY>() << cornerPoints ) );
109  std::unique_ptr< QgsLabelPosition > newEntry = std::make_unique< QgsLabelPosition >( featureId, labelPos->getAlpha() + mMapSettings.rotation(), cornerPoints, bounds,
110  labelPos->getWidth(), labelPos->getHeight(), layerName, labeltext, labelfont, labelPos->getUpsideDown(), diagram, pinned, providerId, labelGeometry, isUnplaced );
111  newEntry->groupedLabelId = uniqueLinkedId;
112  mSpatialIndex.insert( newEntry.get(), bounds );
113 
114  if ( uniqueLinkedId != 0 )
115  {
116  mLinkedLabelHash[ uniqueLinkedId ].append( newEntry.get() );
117  }
118 
119  mOwnedPositions.emplace_back( std::move( newEntry ) );
120 
121  if ( next )
122  {
123  return insertLabel( next, featureId, layerName, labeltext, labelfont, diagram, pinned, providerId, isUnplaced, uniqueLinkedId );
124  }
125  return true;
126 }
127 
129 {
130  const QPointF origin = position.origin();
131  const QPointF destination = position.destination();
132 
133  std::unique_ptr< QgsCalloutPosition > newEntry = std::make_unique< QgsCalloutPosition >( position );
134 
135  mCalloutIndex.insert( newEntry.get(), QgsRectangle( origin.x(), origin.y(), origin.x(), origin.y() ) );
136  mCalloutIndex.insert( newEntry.get(), QgsRectangle( destination.x(), destination.y(), destination.x(), destination.y() ) );
137 
138  mOwnedCalloutPositions.emplace_back( std::move( newEntry ) );
139 
140  return true;
141 }
142 
143 QList<const QgsCalloutPosition *> QgsLabelSearchTree::calloutsInRectangle( const QgsRectangle &rectangle ) const
144 {
145  QList<const QgsCalloutPosition *> searchResults;
146  mCalloutIndex.intersects( rectangle, [&searchResults]( const QgsCalloutPosition * pos )->bool
147  {
148  searchResults.push_back( pos );
149  return true;
150  } );
151 
152  std::sort( searchResults.begin(), searchResults.end() );
153  searchResults.erase( std::unique( searchResults.begin(), searchResults.end() ), searchResults.end() );
154 
155  return searchResults;
156 }
157 
158 QList<QgsLabelPosition *> QgsLabelSearchTree::groupedLabelPositions( long long groupId ) const
159 {
160  return mLinkedLabelHash.value( groupId );
161 }
162 
164 {
165  mMapSettings = settings;
166 
167  if ( !qgsDoubleNear( mMapSettings.rotation(), 0.0 ) )
168  {
169  // build a transform to convert points from real world to pre-rotated label positions
170  const QgsPointXY center = mMapSettings.visibleExtent().center();
171  mTransform = QTransform::fromTranslate( center.x(), center.y() );
172  mTransform.rotate( mMapSettings.rotation() );
173  mTransform.translate( -center.x(), -center.y() );
174  }
175  else
176  {
177  mTransform = QTransform();
178  }
179 }
180 
181 
183 {
184 
185 }
pal::LabelPosition::getY
double getY(int i=0) const
Returns the down-left y coordinate.
Definition: labelposition.cpp:343
QgsPointXY::y
double y
Definition: qgspointxy.h:63
qgslabelsearchtree.h
QgsCalloutPosition::destination
QPointF destination() const
Returns the destination of the callout line, in map coordinates.
Definition: qgscalloutposition.h:94
labelposition.h
QgsRectangle::center
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:251
pal::LabelPosition
LabelPosition is a candidate feature label position.
Definition: labelposition.h:55
QgsLabelSearchTree::calloutsInRectangle
QList< const QgsCalloutPosition * > calloutsInRectangle(const QgsRectangle &rectangle) const
Returns the list of callouts with origins or destinations inside the given rectangle.
Definition: qgslabelsearchtree.cpp:143
QgsLabelSearchTree::label
void label(const QgsPointXY &p, QList< QgsLabelPosition * > &posList) const
Returns label position(s) at a given point.
Definition: qgslabelsearchtree.cpp:22
pal::LabelPosition::nextPart
LabelPosition * nextPart() const
Returns the next part of this label position (i.e.
Definition: labelposition.h:277
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsLabelSearchTree::labelsInRect
void labelsInRect(const QgsRectangle &r, QList< QgsLabelPosition * > &posList) const
Returns label position(s) in given rectangle.
Definition: qgslabelsearchtree.cpp:56
QgsCalloutPosition::origin
QPointF origin() const
Returns the origin of the callout line, in map coordinates.
Definition: qgscalloutposition.h:74
QgsLabelPosition
Represents the calculated placement of a map label.
Definition: qgslabelposition.h:33
QgsLabelSearchTree::allLabels
QList< QgsLabelPosition > allLabels() const
Returns a list of all labels generated by the labeling run.
Definition: qgslabelsearchtree.cpp:45
QgsLabelSearchTree::clear
Q_DECL_DEPRECATED void clear()
Removes and deletes all the entries.
Definition: qgslabelsearchtree.cpp:182
QgsLabelSearchTree::insertCallout
bool insertCallout(const QgsCalloutPosition &position)
Inserts a rendered callout position.
Definition: qgslabelsearchtree.cpp:128
QgsMapSettings::rotation
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
Definition: qgsmapsettings.cpp:102
QgsLabelSearchTree::QgsLabelSearchTree
QgsLabelSearchTree()
Constructor for QgsLabelSearchTree.
QgsGenericSpatialIndex::intersects
bool intersects(const QgsRectangle &bounds, const std::function< bool(T *data)> &callback) const
Performs an intersection check against the index, for data intersecting the specified bounds.
Definition: qgsgenericspatialindex.h:123
QgsCalloutPosition
Represents the calculated placement of a map label callout line.
Definition: qgscalloutposition.h:32
qgsDoubleNear
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2265
QgsLabelSearchTree::insertLabel
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.
Definition: qgslabelsearchtree.cpp:76
QgsGenericSpatialIndex::insert
bool insert(T *data, const QgsRectangle &bounds)
Inserts new data into the spatial index, with the specified bounds.
Definition: qgsgenericspatialindex.h:63
pal::LabelPosition::getUpsideDown
bool getUpsideDown() const
Definition: labelposition.h:268
QgsLabelSearchTree::setMapSettings
void setMapSettings(const QgsMapSettings &settings)
Sets the map settings associated with the labeling run.
Definition: qgslabelsearchtree.cpp:163
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsLabelSearchTree::~QgsLabelSearchTree
~QgsLabelSearchTree()
QgsGeometry::fromPolygonXY
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygonXY.
Definition: qgsgeometry.cpp:201
pal::LabelPosition::getHeight
double getHeight() const
Definition: labelposition.h:261
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsPointXY::x
double x
Definition: qgspointxy.h:62
pal::LabelPosition::getX
double getX(int i=0) const
Returns the down-left x coordinate.
Definition: labelposition.cpp:338
pal::LabelPosition::getAlpha
double getAlpha() const
Returns the angle to rotate text (in rad).
Definition: labelposition.cpp:348
QgsMapSettings
The QgsMapSettings class contains configuration for rendering of the map. The rendering itself is don...
Definition: qgsmapsettings.h:88
QgsMapSettings::visibleExtent
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes output image size into account.
Definition: qgsmapsettings.cpp:411
QgsLabelSearchTree::groupedLabelPositions
QList< QgsLabelPosition * > groupedLabelPositions(long long groupId) const
Returns a list of all label positions sharing the same group ID (i.e.
Definition: qgslabelsearchtree.cpp:158
QgsFeatureId
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28
pal::LabelPosition::getWidth
double getWidth() const
Definition: labelposition.h:260