QGIS API Documentation  3.27.0-Master (e113457133)
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 }
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.
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.
bool insert(T *data, const QgsRectangle &bounds)
Inserts new data into the spatial index, with the specified bounds.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:125
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.
QgsLabelSearchTree()
Constructor for QgsLabelSearchTree.
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.
The QgsMapSettings class contains configuration for rendering of the map.
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.
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:251
LabelPosition is a candidate feature label position.
Definition: labelposition.h:56
double getAlpha() const
Returns the angle to rotate text (in rad).
double getHeight() const
double getWidth() const
LabelPosition * nextPart() const
Returns the next part of this label position (i.e.
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
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:2260
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
Definition: qgsfeatureid.h:28