QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsmapclippingutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmapclippingutils.cpp
3  --------------------------------------
4  Date : June 2020
5  Copyright : (C) 2020 by 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 "qgsmapclippingutils.h"
17 #include "qgsgeometry.h"
18 #include "qgsrendercontext.h"
19 #include "qgsmapclippingregion.h"
20 #include "qgslogger.h"
21 #include <algorithm>
22 #include <QPointer>
23 
24 QList<QgsMapClippingRegion> QgsMapClippingUtils::collectClippingRegionsForLayer( const QgsRenderContext &context, const QgsMapLayer *layer )
25 {
26  QList< QgsMapClippingRegion > res;
27  const QList< QgsMapClippingRegion > regions = context.clippingRegions();
28  res.reserve( regions.size() );
29 
30  std::copy_if( regions.begin(), regions.end(), std::back_inserter( res ), [layer]( const QgsMapClippingRegion & region )
31  {
32  return region.appliesToLayer( layer );
33  } );
34 
35  return res;
36 }
37 
38 QgsGeometry QgsMapClippingUtils::calculateFeatureRequestGeometry( const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, bool &shouldFilter )
39 {
40  QgsGeometry result;
41  bool first = true;
42  shouldFilter = false;
43  for ( const QgsMapClippingRegion &region : regions )
44  {
45  if ( region.geometry().type() != QgsWkbTypes::PolygonGeometry )
46  continue;
47 
48  shouldFilter = true;
49  if ( first )
50  {
51  result = region.geometry();
52  first = false;
53  }
54  else
55  {
56  result = result.intersection( region.geometry() );
57  }
58  }
59 
60  if ( !shouldFilter )
61  return QgsGeometry();
62 
63  // filter out polygon parts from result only
65 
66  // lastly transform back to layer CRS
67  try
68  {
69  result.transform( context.coordinateTransform(), Qgis::TransformDirection::Reverse );
70  }
71  catch ( QgsCsException & )
72  {
73  QgsDebugMsg( QStringLiteral( "Could not transform clipping region to layer CRS" ) );
74  shouldFilter = false;
75  return QgsGeometry();
76  }
77 
78  return result;
79 }
80 
81 QgsGeometry QgsMapClippingUtils::calculateFeatureIntersectionGeometry( const QList<QgsMapClippingRegion> &regions, const QgsRenderContext &context, bool &shouldClip )
82 {
83  QgsGeometry result;
84  bool first = true;
85  shouldClip = false;
86  for ( const QgsMapClippingRegion &region : regions )
87  {
88  if ( region.geometry().type() != QgsWkbTypes::PolygonGeometry )
89  continue;
90 
92  continue;
93 
94  shouldClip = true;
95  if ( first )
96  {
97  result = region.geometry();
98  first = false;
99  }
100  else
101  {
102  result = result.intersection( region.geometry() );
103  }
104  }
105 
106  if ( !shouldClip )
107  return QgsGeometry();
108 
109  // filter out polygon parts from result only
111 
112  // lastly transform back to layer CRS
113  try
114  {
115  result.transform( context.coordinateTransform(), Qgis::TransformDirection::Reverse );
116  }
117  catch ( QgsCsException & )
118  {
119  QgsDebugMsg( QStringLiteral( "Could not transform clipping region to layer CRS" ) );
120  shouldClip = false;
121  return QgsGeometry();
122  }
123 
124  return result;
125 }
126 
127 QPainterPath QgsMapClippingUtils::calculatePainterClipRegion( const QList<QgsMapClippingRegion> &regions, const QgsRenderContext &context, QgsMapLayerType layerType, bool &shouldClip )
128 {
129  QgsGeometry result;
130  bool first = true;
131  shouldClip = false;
132  for ( const QgsMapClippingRegion &region : regions )
133  {
134  if ( region.geometry().type() != QgsWkbTypes::PolygonGeometry )
135  continue;
136 
137  switch ( layerType )
138  {
141  continue;
142  break;
143 
145  // for now, we ignore the region's featureClip behavior when rendering vector tiles
146  // TODO: ideally we should apply this during rendering, just like we do for normal
147  // vector layers
148  break;
149 
156  // for these layer types, we ignore the region's featureClip behavior.
157  break;
158 
159  }
160 
161  shouldClip = true;
162  if ( first )
163  {
164  result = region.geometry();
165  first = false;
166  }
167  else
168  {
169  result = result.intersection( region.geometry() );
170  }
171  }
172 
173  if ( !shouldClip )
174  return QPainterPath();
175 
176  // transform to painter coordinates
177  result.mapToPixel( context.mapToPixel() );
178 
179  return result.constGet()->asQPainterPath();
180 }
181 
182 QgsGeometry QgsMapClippingUtils::calculateLabelIntersectionGeometry( const QList<QgsMapClippingRegion> &regions, const QgsRenderContext &context, bool &shouldClip )
183 {
184  QgsGeometry result;
185  bool first = true;
186  shouldClip = false;
187  for ( const QgsMapClippingRegion &region : regions )
188  {
189  if ( region.geometry().type() != QgsWkbTypes::PolygonGeometry )
190  continue;
191 
192  // for labeling, we clip using either painter clip regions or intersects type regions.
193  // unlike feature rendering, we clip features to painter clip regions for labeling, because
194  // we want the label to sit within the clip region if possible
195  if ( region.featureClip() != QgsMapClippingRegion::FeatureClippingType::ClipPainterOnly &&
197  continue;
198 
199  shouldClip = true;
200  if ( first )
201  {
202  result = region.geometry();
203  first = false;
204  }
205  else
206  {
207  result = result.intersection( region.geometry() );
208  }
209  }
210 
211  if ( !shouldClip )
212  return QgsGeometry();
213 
214  // filter out polygon parts from result only
216 
217  // lastly transform back to layer CRS
218  try
219  {
220  result.transform( context.coordinateTransform(), Qgis::TransformDirection::Reverse );
221  }
222  catch ( QgsCsException & )
223  {
224  QgsDebugMsg( QStringLiteral( "Could not transform clipping region to layer CRS" ) );
225  shouldClip = false;
226  return QgsGeometry();
227  }
228 
229  return result;
230 }
QgsMapClippingUtils::collectClippingRegionsForLayer
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer(const QgsRenderContext &context, const QgsMapLayer *layer)
Collects the list of map clipping regions from a context which apply to a map layer.
Definition: qgsmapclippingutils.cpp:24
QgsGeometry::convertGeometryCollectionToSubclass
bool convertGeometryCollectionToSubclass(QgsWkbTypes::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
Definition: qgsgeometry.cpp:1625
QgsRenderContext::mapToPixel
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
Definition: qgsrendercontext.h:258
QgsMapClippingRegion
A map clipping region (in map coordinates and CRS).
Definition: qgsmapclippingregion.h:33
QgsMapClippingUtils::calculateFeatureIntersectionGeometry
static QgsGeometry calculateFeatureIntersectionGeometry(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, bool &shouldClip)
Returns the geometry representing the intersection of clipping regions from context which should be u...
Definition: qgsmapclippingutils.cpp:81
QgsMapLayerType::MeshLayer
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
QgsAbstractGeometry::asQPainterPath
virtual QPainterPath asQPainterPath() const =0
Returns the geometry represented as a QPainterPath.
QgsMapLayerType::VectorLayer
@ VectorLayer
Vector layer.
QgsGeometry::transform
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
Definition: qgsgeometry.cpp:3128
QgsMapLayerType::AnnotationLayer
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
QgsMapLayerType
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:46
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsWkbTypes::PolygonGeometry
@ PolygonGeometry
Definition: qgswkbtypes.h:144
QgsGeometry::intersection
QgsGeometry intersection(const QgsGeometry &geometry) const
Returns a geometry representing the points shared by this geometry and other.
Definition: qgsgeometry.cpp:2616
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
QgsMapLayerType::GroupLayer
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
QgsMapClippingUtils::calculatePainterClipRegion
static QPainterPath calculatePainterClipRegion(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, QgsMapLayerType layerType, bool &shouldClip)
Returns a QPainterPath representing the intersection of clipping regions from context which should be...
Definition: qgsmapclippingutils.cpp:127
QgsMapClippingRegion::FeatureClippingType::ClipToIntersection
@ ClipToIntersection
Clip the geometry of these features to the region prior to rendering (i.e. feature boundaries will fo...
QgsMapLayerType::RasterLayer
@ RasterLayer
Raster layer.
QgsMapClippingUtils::calculateLabelIntersectionGeometry
static QgsGeometry calculateLabelIntersectionGeometry(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, bool &shouldClip)
Returns the geometry representing the intersection of clipping regions from context which should be u...
Definition: qgsmapclippingutils.cpp:182
qgsrendercontext.h
QgsMapClippingUtils::calculateFeatureRequestGeometry
static QgsGeometry calculateFeatureRequestGeometry(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, bool &shouldFilter)
Returns the geometry representing the intersection of clipping regions from context.
Definition: qgsmapclippingutils.cpp:38
QgsGeometry::constGet
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
Definition: qgsgeometry.cpp:136
qgsgeometry.h
QgsGeometry
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:124
QgsMapClippingRegion::FeatureClippingType::ClipPainterOnly
@ ClipPainterOnly
Applying clipping on the painter only (i.e. feature boundaries will be unchanged, but may be invisibl...
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
qgsmapclippingutils.h
QgsGeometry::mapToPixel
void mapToPixel(const QgsMapToPixel &mtp)
Transforms the geometry from map units to pixels in place.
Definition: qgsgeometry.cpp:3152
QgsRenderContext::clippingRegions
QList< QgsMapClippingRegion > clippingRegions() const
Returns the list of clipping regions to apply during the render.
Definition: qgsrendercontext.cpp:625
qgslogger.h
QgsMapLayerType::PointCloudLayer
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
QgsMapLayerType::PluginLayer
@ PluginLayer
Plugin based layer.
qgsmapclippingregion.h