mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-08 00:05:09 -04:00
New class QgsMapClippingUtils with utility functions for helping
with map clipping
This commit is contained in:
parent
b5ae07869e
commit
b10b16941b
53
python/core/auto_generated/qgsmapclippingutils.sip.in
Normal file
53
python/core/auto_generated/qgsmapclippingutils.sip.in
Normal file
@ -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 *
|
||||
************************************************************************/
|
@ -102,6 +102,7 @@
|
||||
%Include auto_generated/qgslocalizeddatapathregistry.sip
|
||||
%Include auto_generated/qgslogger.sip
|
||||
%Include auto_generated/qgsmapclippingregion.sip
|
||||
%Include auto_generated/qgsmapclippingutils.sip
|
||||
%Include auto_generated/qgsmapdecoration.sip
|
||||
%Include auto_generated/qgsmaphittest.sip
|
||||
%Include auto_generated/qgsmaplayer.sip
|
||||
|
@ -312,6 +312,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgslocalizeddatapathregistry.cpp
|
||||
qgslogger.cpp
|
||||
qgsmapclippingregion.cpp
|
||||
qgsmapclippingutils.cpp
|
||||
qgsmapdecoration.cpp
|
||||
qgsmaphittest.cpp
|
||||
qgsmaplayer.cpp
|
||||
@ -861,6 +862,7 @@ SET(QGIS_CORE_HDRS
|
||||
qgslocalizeddatapathregistry.h
|
||||
qgslogger.h
|
||||
qgsmapclippingregion.h
|
||||
qgsmapclippingutils.h
|
||||
qgsmapdecoration.h
|
||||
qgsmaphittest.h
|
||||
qgsmaplayer.h
|
||||
|
75
src/core/qgsmapclippingutils.cpp
Normal file
75
src/core/qgsmapclippingutils.cpp
Normal file
@ -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;
|
||||
}
|
61
src/core/qgsmapclippingutils.h
Normal file
61
src/core/qgsmapclippingutils.h
Normal file
@ -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
|
@ -149,6 +149,7 @@ ADD_PYTHON_TEST(PyQgsLocator test_qgslocator.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapCanvas test_qgsmapcanvas.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapCanvasAnnotationItem test_qgsmapcanvasannotationitem.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapClippingRegion test_qgsmapclippingregion.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapClippingUtils test_qgsmapclippingutils.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapLayer test_qgsmaplayer.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapLayerAction test_qgsmaplayeraction.py)
|
||||
ADD_PYTHON_TEST(PyQgsMapLayerComboBox test_qgsmaplayercombobox.py)
|
||||
|
84
tests/src/python/test_qgsmapclippingutils.py
Normal file
84
tests/src/python/test_qgsmapclippingutils.py
Normal file
@ -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()
|
Loading…
x
Reference in New Issue
Block a user