QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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, int featureId, const QString &layerName, const QString &labeltext, const QFont &labelfont, bool diagram, bool pinned, const QString &providerId )
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 );
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 );
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:40
double getWidth() const
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:171
double y
Definition: qgspointxy.h:48
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:278
QgsRectangle visibleExtent() const
Returns the actual extent derived from requested extent that takes takes output image size into accou...
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
bool insertLabel(pal::LabelPosition *labelPos, int featureId, const QString &layerName, const QString &labeltext, const QFont &labelfont, bool diagram=false, bool pinned=false, const QString &providerId=QString())
Inserts label position.
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
The QgsMapSettings class contains configuration for rendering of the map.
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:176
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:161
double getY(int i=0) const
Returns the down-left y coordinate.
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:229
bool searchCallback(QgsLabelPosition *pos, void *context)
LabelPosition * getNextPart() const
double getX(int i=0) const
Returns the down-left x coordinate.
double x
Definition: qgspointxy.h:47
bool getUpsideDown() const
double getAlpha() const
Returns the angle to rotate text (in rad).
static QgsGeometry fromPolygonXY(const QgsPolygonXY &polygon)
Creates a new geometry from a QgsPolygon.
void label(const QgsPointXY &p, QList< QgsLabelPosition * > &posList) const
Returns label position(s) at a given point.
double getHeight() const
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
void labelsInRect(const QgsRectangle &r, QList< QgsLabelPosition * > &posList) const
Returns label position(s) in given rectangle.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:166