QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsrendereditemresults.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrendereditemresults.cpp
3  -------------------
4  begin : August 2021
5  copyright : (C) Nyall Dawson
6  email : nyall dot dawson at gmail dot com
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 
16 #include "qgsrendereditemresults.h"
17 #include "qgsrendereditemdetails.h"
18 #include "qgsrendercontext.h"
19 #include "qgslogger.h"
21 #include "RTree.h"
22 
23 
25 class QgsRenderedItemResultsSpatialIndex : public RTree<const QgsRenderedItemDetails *, float, 2, float>
26 {
27  public:
28 
29  explicit QgsRenderedItemResultsSpatialIndex( const QgsRectangle &maxBounds )
30  : mXMin( maxBounds.xMinimum() )
31  , mYMin( maxBounds.yMinimum() )
32  , mXRes( ( std::numeric_limits< float >::max() - 1 ) / ( maxBounds.xMaximum() - maxBounds.xMinimum() ) )
33  , mYRes( ( std::numeric_limits< float >::max() - 1 ) / ( maxBounds.yMaximum() - maxBounds.yMinimum() ) )
34  , mMaxBounds( maxBounds )
35  , mUseScale( !maxBounds.isNull() )
36  {}
37 
38  void insert( const QgsRenderedItemDetails *details, const QgsRectangle &bounds )
39  {
40  std::array< float, 4 > scaledBounds = scaleBounds( bounds );
41  this->Insert(
42  {
43  scaledBounds[0], scaledBounds[ 1]
44  },
45  {
46  scaledBounds[2], scaledBounds[3]
47  },
48  details );
49  }
50 
56  bool intersects( const QgsRectangle &bounds, const std::function< bool( const QgsRenderedItemDetails *details )> &callback ) const
57  {
58  std::array< float, 4 > scaledBounds = scaleBounds( bounds );
59  this->Search(
60  {
61  scaledBounds[0], scaledBounds[ 1]
62  },
63  {
64  scaledBounds[2], scaledBounds[3]
65  },
66  callback );
67  return true;
68  }
69 
70  private:
71  double mXMin = 0;
72  double mYMin = 0;
73  double mXRes = 1;
74  double mYRes = 1;
75  QgsRectangle mMaxBounds;
76  bool mUseScale = false;
77 
78  std::array<float, 4> scaleBounds( const QgsRectangle &bounds ) const
79  {
80  if ( mUseScale )
81  return
82  {
83  static_cast< float >( ( std::max( bounds.xMinimum(), mMaxBounds.xMinimum() ) - mXMin ) / mXRes ),
84  static_cast< float >( ( std::max( bounds.yMinimum(), mMaxBounds.yMinimum() ) - mYMin ) / mYRes ),
85  static_cast< float >( ( std::min( bounds.xMaximum(), mMaxBounds.xMaximum() ) - mXMin ) / mXRes ),
86  static_cast< float >( ( std::min( bounds.yMaximum(), mMaxBounds.yMaximum() ) - mYMin ) / mYRes )
87  };
88  else
89  return
90  {
91  static_cast< float >( bounds.xMinimum() ),
92  static_cast< float >( bounds.yMinimum() ),
93  static_cast< float >( bounds.xMaximum() ),
94  static_cast< float >( bounds.yMaximum() )
95  };
96  }
97 };
99 
101  : mExtent( extent.buffered( std::max( extent.width(), extent.height() ) * 1000 ) ) // RTree goes crazy if we insert geometries outside the bounds, so buffer them right out to be safe
102  , mAnnotationItemsIndex( std::make_unique< QgsRenderedItemResultsSpatialIndex >( mExtent ) )
103 {
104 
105 }
106 
108 
109 QList<QgsRenderedItemDetails *> QgsRenderedItemResults::renderedItems() const
110 {
111  QList< QgsRenderedItemDetails * > res;
112  for ( const auto &it : mDetails )
113  {
114  std::transform( it.second.begin(), it.second.end(), std::back_inserter( res ), []( const auto & detail )
115  {
116  return detail.get();
117  } );
118  }
119  return res;
120 }
121 
122 QList<const QgsRenderedAnnotationItemDetails *> QgsRenderedItemResults::renderedAnnotationItemsInBounds( const QgsRectangle &bounds ) const
123 {
124  QList<const QgsRenderedAnnotationItemDetails *> res;
125 
126  mAnnotationItemsIndex->intersects( bounds, [&res]( const QgsRenderedItemDetails * details )->bool
127  {
128  res << qgis::down_cast< const QgsRenderedAnnotationItemDetails * >( details );
129  return true;
130  } );
131  return res;
132 }
133 
134 void QgsRenderedItemResults::appendResults( const QList<QgsRenderedItemDetails *> &results, const QgsRenderContext &context )
135 {
136  QgsCoordinateTransform layerToMapTransform = context.coordinateTransform();
137  layerToMapTransform.setBallparkTransformsAreAppropriate( true );
138  for ( QgsRenderedItemDetails *details : results )
139  {
140  try
141  {
142  const QgsRectangle transformedBounds = layerToMapTransform.transformBoundingBox( details->boundingBox() );
143  details->setBoundingBox( transformedBounds );
144  }
145  catch ( QgsCsException & )
146  {
147  QgsDebugMsg( QStringLiteral( "Could not transform rendered item's bounds to map CRS" ) );
148  }
149 
150  if ( QgsRenderedAnnotationItemDetails *annotationDetails = dynamic_cast< QgsRenderedAnnotationItemDetails * >( details ) )
151  mAnnotationItemsIndex->insert( annotationDetails, annotationDetails->boundingBox() );
152 
153 
154  mDetails[ details->layerId() ].emplace_back( std::unique_ptr< QgsRenderedItemDetails >( details ) );
155  }
156 }
157 
158 void QgsRenderedItemResults::transferResults( QgsRenderedItemResults *other, const QStringList &layerIds )
159 {
160  for ( const QString &layerId : layerIds )
161  {
162  auto otherLayerIt = other->mDetails.find( layerId );
163  if ( otherLayerIt == other->mDetails.end() )
164  continue;
165 
166  std::vector< std::unique_ptr< QgsRenderedItemDetails > > &source = otherLayerIt->second;
167 
168  for ( std::unique_ptr< QgsRenderedItemDetails > &details : source )
169  {
170  if ( QgsRenderedAnnotationItemDetails *annotationDetails = dynamic_cast< QgsRenderedAnnotationItemDetails * >( details.get() ) )
171  mAnnotationItemsIndex->insert( annotationDetails, annotationDetails->boundingBox() );
172 
173  mDetails[layerId].emplace_back( std::move( details ) );
174  }
175 
176  other->mDetails.erase( otherLayerIt );
177  }
178 }
179 
181 {
182  for ( auto layerIt = other->mDetails.begin(); layerIt != other->mDetails.end(); ++layerIt )
183  {
184  std::vector< std::unique_ptr< QgsRenderedItemDetails > > &dest = mDetails[layerIt->first];
185  dest.reserve( layerIt->second.size() );
186  for ( auto it = layerIt->second.begin(); it != layerIt->second.end(); ++it )
187  {
188  if ( QgsRenderedAnnotationItemDetails *annotationDetails = dynamic_cast< QgsRenderedAnnotationItemDetails * >( ( *it ).get() ) )
189  mAnnotationItemsIndex->insert( annotationDetails, annotationDetails->boundingBox() );
190 
191  dest.emplace_back( std::move( *it ) );
192  }
193  }
194  other->mDetails.clear();
195 }
196 
197 void QgsRenderedItemResults::eraseResultsFromLayers( const QStringList &layerIds )
198 {
199  for ( const QString &layerId : layerIds )
200  {
201  auto it = mDetails.find( layerId );
202  if ( it != mDetails.end() )
203  mDetails.erase( it );
204  }
205 }
206 
207 
QgsRenderedItemDetails::boundingBox
QgsRectangle boundingBox() const
Returns the bounding box of the item (in map units).
Definition: qgsrendereditemdetails.h:78
qgsrenderedannotationitemdetails.h
QgsRenderedItemResults::renderedItems
QList< QgsRenderedItemDetails * > renderedItems() const
Returns a list of all rendered items.
Definition: qgsrendereditemresults.cpp:109
QgsRectangle::yMinimum
double yMinimum() const SIP_HOLDGIL
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:198
QgsCoordinateTransform::transformBoundingBox
QgsRectangle transformBoundingBox(const QgsRectangle &rectangle, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool handle180Crossover=false) const SIP_THROW(QgsCsException)
Transforms a rectangle from the source CRS to the destination CRS.
Definition: qgscoordinatetransform.cpp:560
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsRectangle
A rectangle specified with double values.
Definition: qgsrectangle.h:41
QgsRectangle::xMaximum
double xMaximum() const SIP_HOLDGIL
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:183
QgsRenderContext::coordinateTransform
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
Definition: qgsrendercontext.h:178
QgsCsException
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
QgsCoordinateTransform::setBallparkTransformsAreAppropriate
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
Definition: qgscoordinatetransform.cpp:939
QgsRenderedItemDetails
Base class for detailed information about a rendered item.
Definition: qgsrendereditemdetails.h:36
QgsRenderedItemDetails::layerId
QString layerId() const
Returns the layer ID of the associated map layer.
Definition: qgsrendereditemdetails.h:71
QgsRenderedItemResults::~QgsRenderedItemResults
~QgsRenderedItemResults()
qgsrendercontext.h
QgsRenderedAnnotationItemDetails
Contains information about a rendered annotation item.
Definition: qgsrenderedannotationitemdetails.h:29
QgsRenderedItemDetails::setBoundingBox
void setBoundingBox(const QgsRectangle &bounds)
Sets the bounding box of the item (in map units).
Definition: qgsrendereditemdetails.h:85
qgsrendereditemdetails.h
QgsRectangle::xMinimum
double xMinimum() const SIP_HOLDGIL
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:188
QgsRenderedItemResults::transferResults
void transferResults(QgsRenderedItemResults *other, const QStringList &layerIds)
Transfers all results from an other QgsRenderedItemResults object where the items have layer IDs matc...
Definition: qgsrendereditemresults.cpp:158
QgsRenderedItemResults::eraseResultsFromLayers
void eraseResultsFromLayers(const QStringList &layerIds)
Erases results from layers matching those in the specified list of layers IDs.
Definition: qgsrendereditemresults.cpp:197
QgsRectangle::yMaximum
double yMaximum() const SIP_HOLDGIL
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:193
QgsRenderedItemResults::renderedAnnotationItemsInBounds
QList< const QgsRenderedAnnotationItemDetails * > renderedAnnotationItemsInBounds(const QgsRectangle &bounds) const
Returns a list with details of the rendered annotation items within the specified bounds.
Definition: qgsrendereditemresults.cpp:122
QgsRenderedItemResults
Stores collated details of rendered items during a map rendering operation.
Definition: qgsrendereditemresults.h:42
qgslogger.h
QgsCoordinateTransform
Class for doing transforms between two map coordinate systems.
Definition: qgscoordinatetransform.h:57
QgsRenderedItemResults::QgsRenderedItemResults
QgsRenderedItemResults(const QgsRectangle &extent=QgsRectangle())
Constructor for QgsRenderedItemResults.
Definition: qgsrendereditemresults.cpp:100
QgsRenderedItemResults::appendResults
void appendResults(const QList< QgsRenderedItemDetails * > &results, const QgsRenderContext &context)
Appends rendered item details to the results object.
Definition: qgsrendereditemresults.cpp:134
qgsrendereditemresults.h