QGIS API Documentation 3.28.0-Firenze (ed3ad0430f)
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"
20#include "qgslogger.h"
21#include <algorithm>
22#include <QPointer>
23
24QList<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
38QgsGeometry 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
81QgsGeometry 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
127QPainterPath 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
182QgsGeometry 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
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}
virtual QPainterPath asQPainterPath() const =0
Returns the geometry represented as a QPainterPath.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:66
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
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.
void mapToPixel(const QgsMapToPixel &mtp)
Transforms the geometry from map units to pixels in place.
QgsGeometry intersection(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points shared by this geometry and other.
bool convertGeometryCollectionToSubclass(QgsWkbTypes::GeometryType geomType)
Converts geometry collection to a the desired geometry type subclass (multi-point,...
A map clipping region (in map coordinates and CRS).
@ ClipPainterOnly
Applying clipping on the painter only (i.e. feature boundaries will be unchanged, but may be invisibl...
@ ClipToIntersection
Clip the geometry of these features to the region prior to rendering (i.e. feature boundaries will fo...
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.
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...
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...
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...
static QgsGeometry calculateFeatureRequestGeometry(const QList< QgsMapClippingRegion > &regions, const QgsRenderContext &context, bool &shouldFilter)
Returns the geometry representing the intersection of clipping regions from context.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
Contains information about the context of a rendering operation.
QList< QgsMapClippingRegion > clippingRegions() const
Returns the list of clipping regions to apply during the render.
const QgsMapToPixel & mapToPixel() const
Returns the context's map to pixel transform, which transforms between map coordinates and device coo...
QgsCoordinateTransform coordinateTransform() const
Returns the current coordinate transform for the context.
QgsMapLayerType
Types of layers that can be added to a map.
Definition: qgis.h:47
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38