-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
New class QgsMapClippingUtils with utility functions for helping
with map clipping
- Loading branch information
1 parent
b5ae078
commit b10b169
Showing
7 changed files
with
277 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
/************************************************************************ | ||
* This file has been generated automatically from * | ||
* * | ||
* src/core/qgsmapclippingutils.h * | ||
* * | ||
* Do not edit manually ! Edit header and run scripts/sipify.pl again * | ||
************************************************************************/ | ||
|
||
|
||
|
||
|
||
class QgsMapClippingUtils | ||
{ | ||
%Docstring | ||
|
||
Utility functions for use when clipping map renders. | ||
|
||
.. versionadded:: 3.16 | ||
%End | ||
|
||
%TypeHeaderCode | ||
#include "qgsmapclippingutils.h" | ||
%End | ||
public: | ||
|
||
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer( const QgsRenderContext &context, const QgsMapLayer *layer ); | ||
%Docstring | ||
Collects the list of map clipping regions from a ``context`` which apply to a map ``layer``. | ||
%End | ||
|
||
static QgsGeometry calculateFeatureRequestGeometry( const QList< QgsMapClippingRegion > ®ions, const QgsRenderContext &context, bool &shouldFilter ); | ||
%Docstring | ||
Returns the geometry representing the intersection of clipping ``regions`` from ``context``. | ||
|
||
The returned geometry will be automatically reprojected into the same CRS as the source layer, ready for use for filtering | ||
a feature request. | ||
|
||
:param regions: list of clip regions which apply to the layer | ||
:param context: a render context | ||
:param shouldFilter: will be set to ``True`` if layer's features should be filtered, i.e. one or more clipping regions applies to the layer | ||
|
||
:return: combined clipping region for use when filtering features to render | ||
%End | ||
|
||
}; | ||
|
||
/************************************************************************ | ||
* This file has been generated automatically from * | ||
* * | ||
* src/core/qgsmapclippingutils.h * | ||
* * | ||
* Do not edit manually ! Edit header and run scripts/sipify.pl again * | ||
************************************************************************/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
/*************************************************************************** | ||
qgsmapclippingutils.cpp | ||
-------------------------------------- | ||
Date : June 2020 | ||
Copyright : (C) 2020 by Nyall Dawson | ||
Email : nyall dot dawson at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#include "qgsmapclippingutils.h" | ||
#include "qgsgeometry.h" | ||
#include "qgsrendercontext.h" | ||
#include "qgsmapclippingregion.h" | ||
#include "qgslogger.h" | ||
#include <algorithm> | ||
|
||
QList<QgsMapClippingRegion> QgsMapClippingUtils::collectClippingRegionsForLayer( const QgsRenderContext &context, const QgsMapLayer *layer ) | ||
{ | ||
QList< QgsMapClippingRegion > res; | ||
const QList< QgsMapClippingRegion > regions = context.clippingRegions(); | ||
res.reserve( regions.size() ); | ||
|
||
std::copy_if( regions.begin(), regions.end(), std::back_inserter( res ), [layer]( const QgsMapClippingRegion & region ) | ||
{ | ||
return region.appliesToLayer( layer ); | ||
} ); | ||
|
||
return res; | ||
} | ||
|
||
QgsGeometry QgsMapClippingUtils::calculateFeatureRequestGeometry( const QList< QgsMapClippingRegion > ®ions, const QgsRenderContext &context, bool &shouldFilter ) | ||
{ | ||
QgsGeometry result; | ||
bool first = true; | ||
shouldFilter = false; | ||
for ( const QgsMapClippingRegion ®ion : regions ) | ||
{ | ||
if ( region.geometry().type() != QgsWkbTypes::PolygonGeometry ) | ||
continue; | ||
|
||
shouldFilter = true; | ||
if ( first ) | ||
{ | ||
result = region.geometry(); | ||
first = false; | ||
} | ||
else | ||
{ | ||
result = result.intersection( region.geometry() ); | ||
} | ||
} | ||
|
||
// filter out polygon parts from result only | ||
result.convertGeometryCollectionToSubclass( QgsWkbTypes::PolygonGeometry ); | ||
|
||
// lastly transform back to layer CRS | ||
try | ||
{ | ||
result.transform( context.coordinateTransform(), QgsCoordinateTransform::ReverseTransform ); | ||
} | ||
catch ( QgsCsException & ) | ||
{ | ||
QgsDebugMsg( QStringLiteral( "Could not transform clipping region to layer CRS" ) ); | ||
shouldFilter = false; | ||
return QgsGeometry(); | ||
} | ||
|
||
return result; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/*************************************************************************** | ||
qgsmapclippingutils.h | ||
-------------------------------------- | ||
Date : June 2020 | ||
Copyright : (C) 2020 by Nyall Dawson | ||
Email : nyall dot dawson at gmail dot com | ||
*************************************************************************** | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
***************************************************************************/ | ||
|
||
#ifndef QGSMAPCLIPPINGUTILS_H | ||
#define QGSMAPCLIPPINGUTILS_H | ||
|
||
#include "qgis_core.h" | ||
#include "qgis_sip.h" | ||
#include <QList> | ||
|
||
class QgsRenderContext; | ||
class QgsMapLayer; | ||
class QgsGeometry; | ||
class QgsMapClippingRegion; | ||
|
||
/** | ||
* \class QgsMapClippingUtils | ||
* \ingroup core | ||
* | ||
* Utility functions for use when clipping map renders. | ||
* | ||
* \since QGIS 3.16 | ||
*/ | ||
class CORE_EXPORT QgsMapClippingUtils | ||
{ | ||
public: | ||
|
||
/** | ||
* Collects the list of map clipping regions from a \a context which apply to a map \a layer. | ||
*/ | ||
static QList< QgsMapClippingRegion > collectClippingRegionsForLayer( const QgsRenderContext &context, const QgsMapLayer *layer ); | ||
|
||
/** | ||
* Returns the geometry representing the intersection of clipping \a regions from \a context. | ||
* | ||
* The returned geometry will be automatically reprojected into the same CRS as the source layer, ready for use for filtering | ||
* a feature request. | ||
* | ||
* \param regions list of clip regions which apply to the layer | ||
* \param context a render context | ||
* \param shouldFilter will be set to TRUE if layer's features should be filtered, i.e. one or more clipping regions applies to the layer | ||
* | ||
* \returns combined clipping region for use when filtering features to render | ||
*/ | ||
static QgsGeometry calculateFeatureRequestGeometry( const QList< QgsMapClippingRegion > ®ions, const QgsRenderContext &context, bool &shouldFilter ); | ||
|
||
}; | ||
|
||
#endif // QGSMAPCLIPPINGUTILS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# -*- coding: utf-8 -*- | ||
"""QGIS Unit tests for QgsMapClippingUtils. | ||
.. note:: This program is free software; you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation; either version 2 of the License, or | ||
(at your option) any later version. | ||
""" | ||
__author__ = 'Nyall Dawson' | ||
__date__ = '2020-06' | ||
__copyright__ = 'Copyright 2020, The QGIS Project' | ||
|
||
import qgis # NOQA | ||
|
||
from qgis.testing import unittest | ||
from qgis.core import ( | ||
QgsMapClippingRegion, | ||
QgsMapClippingUtils, | ||
QgsMapSettings, | ||
QgsRenderContext, | ||
QgsGeometry, | ||
QgsVectorLayer, | ||
QgsCoordinateTransform, | ||
QgsCoordinateReferenceSystem, | ||
QgsProject | ||
) | ||
|
||
|
||
class TestQgsMapClippingUtils(unittest.TestCase): | ||
|
||
def testClippingRegionsForLayer(self): | ||
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", | ||
"addfeat", "memory") | ||
layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", | ||
"addfeat", "memory") | ||
|
||
region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) | ||
region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) | ||
region2.setRestrictedLayers([layer]) | ||
ms = QgsMapSettings() | ||
ms.addClippingRegion(region) | ||
ms.addClippingRegion(region2) | ||
rc = QgsRenderContext.fromMapSettings(ms) | ||
|
||
regions = QgsMapClippingUtils.collectClippingRegionsForLayer(rc, layer) | ||
self.assertEqual(len(regions), 2) | ||
self.assertEqual(regions[0].geometry().asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') | ||
self.assertEqual(regions[1].geometry().asWkt(1), 'Polygon ((0 0, 0.1 0, 0.1 2, 0 2, 0 0))') | ||
|
||
regions = QgsMapClippingUtils.collectClippingRegionsForLayer(rc, layer2) | ||
self.assertEqual(len(regions), 1) | ||
self.assertEqual(regions[0].geometry().asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') | ||
|
||
def testCalculateFeatureRequestGeometry(self): | ||
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", | ||
"addfeat", "memory") | ||
layer2 = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", | ||
"addfeat", "memory") | ||
|
||
region = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 1 0, 1 1, 0 1, 0 0))')) | ||
region2 = QgsMapClippingRegion(QgsGeometry.fromWkt('Polygon((0 0, 0.1 0, 0.1 2, 0 2, 0 0))')) | ||
|
||
rc = QgsRenderContext() | ||
|
||
geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry([], rc) | ||
self.assertFalse(should_clip) | ||
self.assertTrue(geom.isNull()) | ||
|
||
geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry([region], rc) | ||
self.assertTrue(should_clip) | ||
self.assertEqual(geom.asWkt(1), 'Polygon ((0 0, 1 0, 1 1, 0 1, 0 0))') | ||
|
||
geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry([region, region2], rc) | ||
self.assertTrue(should_clip) | ||
self.assertEqual(geom.asWkt(1), 'Polygon ((0.1 0, 0 0, 0 1, 0.1 1, 0.1 0))') | ||
|
||
rc.setCoordinateTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:3857'), QgsCoordinateReferenceSystem('EPSG:4326'), QgsProject.instance())) | ||
geom, should_clip = QgsMapClippingUtils.calculateFeatureRequestGeometry([region, region2], rc) | ||
self.assertTrue(should_clip) | ||
self.assertEqual(geom.asWkt(0), 'Polygon ((11132 0, 0 0, 0 111325, 11132 111325, 11132 0))') | ||
|
||
|
||
if __name__ == '__main__': | ||
unittest.main() |