QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 
18 bool searchCallback( QgsLabelPosition *pos, void *context )
19 {
20  QList<QgsLabelPosition *> *list = static_cast< QList<QgsLabelPosition *>* >( context );
21  list->push_back( pos );
22  return true;
23 }
24 
26 {
27  clear();
28 }
29 
30 void QgsLabelSearchTree::label( const QgsPointXY &point, QList<QgsLabelPosition *> &posList ) const
31 {
32  QgsPointXY p( point );
33  double c_min[2];
34  c_min[0] = p.x() - 0.1;
35  c_min[1] = p.y() - 0.1;
36  double c_max[2];
37  c_max[0] = p.x() + 0.1;
38  c_max[1] = p.y() + 0.1;
39 
40  QList<QgsLabelPosition *> searchResults;
41  mSpatialIndex.Search( c_min, c_max, searchCallback, &searchResults );
42 
43  //tolerance +-0.1 could be high in case of degree crs, so check if p is really contained in the results
44  posList.clear();
45  QList<QgsLabelPosition *>::const_iterator resultIt = searchResults.constBegin();
46  for ( ; resultIt != searchResults.constEnd(); ++resultIt )
47  {
48  if ( ( *resultIt )->labelGeometry.contains( &p ) )
49  {
50  posList.push_back( *resultIt );
51  }
52  }
53 }
54 
55 void QgsLabelSearchTree::labelsInRect( const QgsRectangle &r, QList<QgsLabelPosition *> &posList ) const
56 {
57  double c_min[2];
58  c_min[0] = r.xMinimum();
59  c_min[1] = r.yMinimum();
60  double c_max[2];
61  c_max[0] = r.xMaximum();
62  c_max[1] = r.yMaximum();
63 
64  QList<QgsLabelPosition *> searchResults;
65  mSpatialIndex.Search( c_min, c_max, searchCallback, &searchResults );
66 
67  posList.clear();
68  QList<QgsLabelPosition *>::const_iterator resultIt = searchResults.constBegin();
69  for ( ; resultIt != searchResults.constEnd(); ++resultIt )
70  {
71  if ( ( *resultIt )->labelGeometry.intersects( r ) )
72  {
73  posList.push_back( *resultIt );
74  }
75  }
76 }
77 
78 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 )
79 {
80  if ( !labelPos )
81  {
82  return false;
83  }
84 
85  QVector<QgsPointXY> cornerPoints;
86  cornerPoints.reserve( 4 );
87  double xMin = std::numeric_limits< double >::max();
88  double yMin = std::numeric_limits< double >::max();
89  double xMax = std::numeric_limits< double >::lowest();
90  double yMax = std::numeric_limits< double >::lowest();
91  for ( int i = 0; i < 4; ++i )
92  {
93  // we have to transform the bounding box to convert pre-rotated label positions back to real world locations
94  QPointF res = mTransform.map( QPointF( labelPos->getX( i ), labelPos->getY( i ) ) );
95  cornerPoints.push_back( QgsPointXY( res ) );
96  xMin = std::min( xMin, res.x() );
97  xMax = std::max( xMax, res.x() );
98  yMin = std::min( yMin, res.y() );
99  yMax = std::max( yMax, res.y() );
100  }
101  double c_min[2];
102  double c_max[2];
103  c_min[0] = xMin;
104  c_min[1] = yMin;
105  c_max[0] = xMax;
106  c_max[1] = yMax;
107 
108  QgsGeometry labelGeometry( QgsGeometry::fromPolygonXY( QVector<QgsPolylineXY>() << cornerPoints ) );
109  std::unique_ptr< QgsLabelPosition > newEntry = qgis::make_unique< QgsLabelPosition >( featureId, labelPos->getAlpha() + mMapSettings.rotation(), cornerPoints, QgsRectangle( c_min[0], c_min[1], c_max[0], c_max[1] ),
110  labelPos->getWidth(), labelPos->getHeight(), layerName, labeltext, labelfont, labelPos->getUpsideDown(), diagram, pinned, providerId, labelGeometry, isUnplaced );
111  mSpatialIndex.Insert( c_min, c_max, newEntry.get() );
112  mOwnedPositions.emplace_back( std::move( newEntry ) );
113 
114  if ( pal::LabelPosition *next = labelPos->getNextPart() )
115  {
116  return insertLabel( next, featureId, layerName, labeltext, labelfont, diagram, pinned, providerId, isUnplaced );
117  }
118  return true;
119 }
120 
122 {
123  mMapSettings = settings;
124 
125  if ( !qgsDoubleNear( mMapSettings.rotation(), 0.0 ) )
126  {
127  // build a transform to convert points from real world to pre-rotated label positions
128  const QgsPointXY center = mMapSettings.visibleExtent().center();
129  mTransform = QTransform::fromTranslate( center.x(), center.y() );
130  mTransform.rotate( mMapSettings.rotation() );
131  mTransform.translate( -center.x(), -center.y() );
132  }
133  else
134  {
135  mTransform = QTransform();
136  }
137 }
138 
140 {
141  mSpatialIndex.RemoveAll();
142 
143  //PAL rtree iterator is buggy and doesn't iterate over all items, so we can't iterate through the tree to delete positions
144  mOwnedPositions.clear();
145 }
A rectangle specified with double values.
Definition: qgsrectangle.h:41
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
double getY(int i=0) const
Returns the down-left y coordinate.
double y
Definition: qgspointxy.h:48
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)
Inserts label position.
A class to represent a 2D point.
Definition: qgspointxy.h:43
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:280
qint64 QgsFeatureId
Definition: qgsfeatureid.h:25
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:122
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
void labelsInRect(const QgsRectangle &r, QList< QgsLabelPosition *> &posList) const
Returns label position(s) in given rectangle.
The QgsMapSettings class contains configuration for rendering of the map.
double getHeight() const
LabelPosition * getNextPart() const
bool searchCallback(QgsLabelPosition *pos, void *context)
double x
Definition: qgspointxy.h:47
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:177
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygon.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:162
double getAlpha() const
Returns the angle to rotate text (in rad).
double getWidth() const
double getX(int i=0) const
Returns the down-left x coordinate.
void clear()
Removes and deletes all the entries.
void setMapSettings(const QgsMapSettings &settings)
Sets the map settings associated with the labeling run.
LabelPosition is a candidate feature label position.
Definition: labelposition.h:55
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:167
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:172
bool getUpsideDown() const
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:230
void label(const QgsPointXY &p, QList< QgsLabelPosition *> &posList) const
Returns label position(s) at a given point.