mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-09 00:08:52 -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/qgslocalizeddatapathregistry.sip
|
||||||
%Include auto_generated/qgslogger.sip
|
%Include auto_generated/qgslogger.sip
|
||||||
%Include auto_generated/qgsmapclippingregion.sip
|
%Include auto_generated/qgsmapclippingregion.sip
|
||||||
|
%Include auto_generated/qgsmapclippingutils.sip
|
||||||
%Include auto_generated/qgsmapdecoration.sip
|
%Include auto_generated/qgsmapdecoration.sip
|
||||||
%Include auto_generated/qgsmaphittest.sip
|
%Include auto_generated/qgsmaphittest.sip
|
||||||
%Include auto_generated/qgsmaplayer.sip
|
%Include auto_generated/qgsmaplayer.sip
|
||||||
|
@ -312,6 +312,7 @@ SET(QGIS_CORE_SRCS
|
|||||||
qgslocalizeddatapathregistry.cpp
|
qgslocalizeddatapathregistry.cpp
|
||||||
qgslogger.cpp
|
qgslogger.cpp
|
||||||
qgsmapclippingregion.cpp
|
qgsmapclippingregion.cpp
|
||||||
|
qgsmapclippingutils.cpp
|
||||||
qgsmapdecoration.cpp
|
qgsmapdecoration.cpp
|
||||||
qgsmaphittest.cpp
|
qgsmaphittest.cpp
|
||||||
qgsmaplayer.cpp
|
qgsmaplayer.cpp
|
||||||
@ -861,6 +862,7 @@ SET(QGIS_CORE_HDRS
|
|||||||
qgslocalizeddatapathregistry.h
|
qgslocalizeddatapathregistry.h
|
||||||
qgslogger.h
|
qgslogger.h
|
||||||
qgsmapclippingregion.h
|
qgsmapclippingregion.h
|
||||||
|
qgsmapclippingutils.h
|
||||||
qgsmapdecoration.h
|
qgsmapdecoration.h
|
||||||
qgsmaphittest.h
|
qgsmaphittest.h
|
||||||
qgsmaplayer.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(PyQgsMapCanvas test_qgsmapcanvas.py)
|
||||||
ADD_PYTHON_TEST(PyQgsMapCanvasAnnotationItem test_qgsmapcanvasannotationitem.py)
|
ADD_PYTHON_TEST(PyQgsMapCanvasAnnotationItem test_qgsmapcanvasannotationitem.py)
|
||||||
ADD_PYTHON_TEST(PyQgsMapClippingRegion test_qgsmapclippingregion.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(PyQgsMapLayer test_qgsmaplayer.py)
|
||||||
ADD_PYTHON_TEST(PyQgsMapLayerAction test_qgsmaplayeraction.py)
|
ADD_PYTHON_TEST(PyQgsMapLayerAction test_qgsmaplayeraction.py)
|
||||||
ADD_PYTHON_TEST(PyQgsMapLayerComboBox test_qgsmaplayercombobox.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