Skip to content

Commit d8db3ec

Browse files
committedSep 14, 2017
[FEATURE] New processing algorithm "extract/clip by extent"
Allows extract a subset of another layer using an extent, with optional setting to clip geometries to the extent
1 parent ba9cb87 commit d8db3ec

File tree

7 files changed

+250
-2
lines changed

7 files changed

+250
-2
lines changed
 
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>extract_by_extent</Name>
4+
<ElementPath>extract_by_extent</ElementPath>
5+
<!--POLYGON-->
6+
<GeometryType>3</GeometryType>
7+
<SRSName>EPSG:4326</SRSName>
8+
<DatasetSpecificInfo>
9+
<FeatureCount>3</FeatureCount>
10+
<ExtentXMin>-1.00000</ExtentXMin>
11+
<ExtentXMax>10.00000</ExtentXMax>
12+
<ExtentYMin>-3.00000</ExtentYMin>
13+
<ExtentYMax>3.00000</ExtentYMax>
14+
</DatasetSpecificInfo>
15+
<PropertyDefn>
16+
<Name>name</Name>
17+
<ElementPath>name</ElementPath>
18+
<Type>String</Type>
19+
<Width>5</Width>
20+
</PropertyDefn>
21+
<PropertyDefn>
22+
<Name>intval</Name>
23+
<ElementPath>intval</ElementPath>
24+
<Type>Integer</Type>
25+
</PropertyDefn>
26+
<PropertyDefn>
27+
<Name>floatval</Name>
28+
<ElementPath>floatval</ElementPath>
29+
<Type>String</Type>
30+
<Width>18</Width>
31+
</PropertyDefn>
32+
</GMLFeatureClass>
33+
</GMLFeatureClassList>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation=""
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
10+
<gml:coord><gml:X>6</gml:X><gml:Y>3</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:extract_by_extent fid="polys.0">
16+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
17+
<ogr:name>aaaaa</ogr:name>
18+
<ogr:intval>33</ogr:intval>
19+
<ogr:floatval>44.123456</ogr:floatval>
20+
</ogr:extract_by_extent>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:extract_by_extent fid="polys.5">
24+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 6,1 6,-3 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
25+
<ogr:name>elim</ogr:name>
26+
<ogr:intval>2</ogr:intval>
27+
<ogr:floatval>3.33</ogr:floatval>
28+
</ogr:extract_by_extent>
29+
</gml:featureMember>
30+
</ogr:FeatureCollection>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>extract_by_extent_clip</Name>
4+
<ElementPath>extract_by_extent_clip</ElementPath>
5+
<!--MULTIPOLYGON-->
6+
<GeometryType>6</GeometryType>
7+
<SRSName>EPSG:4326</SRSName>
8+
<DatasetSpecificInfo>
9+
<FeatureCount>2</FeatureCount>
10+
<ExtentXMin>-1.00000</ExtentXMin>
11+
<ExtentXMax>4.77500</ExtentXMax>
12+
<ExtentYMin>-2.38750</ExtentYMin>
13+
<ExtentYMax>3.00000</ExtentYMax>
14+
</DatasetSpecificInfo>
15+
<PropertyDefn>
16+
<Name>name</Name>
17+
<ElementPath>name</ElementPath>
18+
<Type>String</Type>
19+
<Width>5</Width>
20+
</PropertyDefn>
21+
<PropertyDefn>
22+
<Name>intval</Name>
23+
<ElementPath>intval</ElementPath>
24+
<Type>Integer</Type>
25+
</PropertyDefn>
26+
<PropertyDefn>
27+
<Name>floatval</Name>
28+
<ElementPath>floatval</ElementPath>
29+
<Type>Real</Type>
30+
</PropertyDefn>
31+
</GMLFeatureClass>
32+
</GMLFeatureClassList>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation=""
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>-1</gml:X><gml:Y>-2.3875</gml:Y></gml:coord>
10+
<gml:coord><gml:X>4.775</gml:X><gml:Y>3</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:extract_by_extent_clip fid="polys.0">
16+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 -1,3 3,3 3,2 2,2 2,-1 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
17+
<ogr:name>aaaaa</ogr:name>
18+
<ogr:intval>33</ogr:intval>
19+
<ogr:floatval>44.123456</ogr:floatval>
20+
</ogr:extract_by_extent_clip>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:extract_by_extent_clip fid="polys.5">
24+
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3,2 4.775,1.40833333333333 4.775,-2.3875 2,-1 2,2 3,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
25+
<ogr:name>elim</ogr:name>
26+
<ogr:intval>2</ogr:intval>
27+
<ogr:floatval>3.33</ogr:floatval>
28+
</ogr:extract_by_extent_clip>
29+
</gml:featureMember>
30+
</ogr:FeatureCollection>

‎python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

100644100755
Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3937,4 +3937,30 @@ tests:
39373937
- name
39383938
compare:
39393939
fields:
3940-
fid: skip
3940+
fid: skip
3941+
3942+
- algorithm: native:extractbyextent
3943+
name: Extract by extent
3944+
params:
3945+
CLIP: false
3946+
EXTENT: -1.1650000000000003,4.775,-2.444285714285715,3.4171428571428573
3947+
INPUT:
3948+
name: polys.gml
3949+
type: vector
3950+
results:
3951+
OUTPUT:
3952+
name: expected/extract_by_extent.gml
3953+
type: vector
3954+
3955+
- algorithm: native:extractbyextent
3956+
name: Extract by extent (clipped)
3957+
params:
3958+
CLIP: true
3959+
EXTENT: -1.1650000000000003,4.775,-2.444285714285715,3.4171428571428573
3960+
INPUT:
3961+
name: polys.gml
3962+
type: vector
3963+
results:
3964+
OUTPUT:
3965+
name: expected/extract_by_extent_clip.gml
3966+
type: vector

‎src/core/processing/qgsnativealgorithms.cpp

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
8282
addAlgorithm( new QgsMergeLinesAlgorithm() );
8383
addAlgorithm( new QgsSmoothAlgorithm() );
8484
addAlgorithm( new QgsSimplifyAlgorithm() );
85+
addAlgorithm( new QgsExtractByExtentAlgorithm() );
8586
}
8687

8788
void QgsCentroidAlgorithm::initAlgorithm( const QVariantMap & )
@@ -1811,7 +1812,77 @@ QgsFeature QgsSimplifyAlgorithm::processFeature( const QgsFeature &feature, QgsP
18111812
return f;
18121813
}
18131814

1814-
///@endcond
18151815

18161816

18171817

1818+
void QgsExtractByExtentAlgorithm::initAlgorithm( const QVariantMap & )
1819+
{
1820+
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
1821+
addParameter( new QgsProcessingParameterExtent( QStringLiteral( "EXTENT" ), QObject::tr( "Extent" ) ) );
1822+
addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "CLIP" ), QObject::tr( "Clip features to extent" ), false ) );
1823+
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Extracted" ) ) );
1824+
}
1825+
1826+
QString QgsExtractByExtentAlgorithm::shortHelpString() const
1827+
{
1828+
return QObject::tr( "This algorithm creates a new vector layer that only contains features which fall within a specified extent. "
1829+
"Any features which intersect the extent will be included.\n\n"
1830+
"Optionally, feature geometries can also be clipped to the extent. If this option is selected, then the output "
1831+
"geometries will automatically be converted to multi geometries to ensure uniform output geometry types." );
1832+
}
1833+
1834+
QgsExtractByExtentAlgorithm *QgsExtractByExtentAlgorithm::createInstance() const
1835+
{
1836+
return new QgsExtractByExtentAlgorithm();
1837+
}
1838+
1839+
QVariantMap QgsExtractByExtentAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
1840+
{
1841+
std::unique_ptr< QgsFeatureSource > featureSource( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
1842+
if ( !featureSource )
1843+
return QVariantMap();
1844+
1845+
QgsRectangle extent = parameterAsExtent( parameters, QStringLiteral( "EXTENT" ), context );
1846+
bool clip = parameterAsBool( parameters, QStringLiteral( "CLIP" ), context );
1847+
1848+
// if clipping, we force multi output
1849+
QgsWkbTypes::Type outType = clip ? QgsWkbTypes::multiType( featureSource->wkbType() ) : featureSource->wkbType();
1850+
1851+
QString dest;
1852+
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, featureSource->fields(), outType, featureSource->sourceCrs() ) );
1853+
1854+
if ( !sink )
1855+
return QVariantMap();
1856+
1857+
QgsGeometry clipGeom = QgsGeometry::fromRect( extent );
1858+
1859+
double step = featureSource->featureCount() > 0 ? 100.0 / featureSource->featureCount() : 1;
1860+
QgsFeatureIterator inputIt = featureSource->getFeatures( QgsFeatureRequest().setFilterRect( extent ).setFlags( QgsFeatureRequest::ExactIntersect ) );
1861+
QgsFeature f;
1862+
int i = -1;
1863+
while ( inputIt.nextFeature( f ) )
1864+
{
1865+
i++;
1866+
if ( feedback->isCanceled() )
1867+
{
1868+
break;
1869+
}
1870+
1871+
if ( clip )
1872+
{
1873+
QgsGeometry g = f.geometry().intersection( clipGeom );
1874+
g.convertToMultiType();
1875+
f.setGeometry( g );
1876+
}
1877+
1878+
sink->addFeature( f, QgsFeatureSink::FastInsert );
1879+
feedback->setProgress( i * step );
1880+
}
1881+
1882+
QVariantMap outputs;
1883+
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
1884+
return outputs;
1885+
}
1886+
1887+
///@endcond
1888+

‎src/core/processing/qgsnativealgorithms.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,32 @@ class QgsSimplifyAlgorithm : public QgsProcessingFeatureBasedAlgorithm
662662
std::unique_ptr< QgsMapToPixelSimplifier > mSimplifier;
663663

664664
};
665+
666+
667+
/**
668+
* Native extract/clip by extent algorithm.
669+
*/
670+
class QgsExtractByExtentAlgorithm : public QgsProcessingAlgorithm
671+
{
672+
673+
public:
674+
675+
QgsExtractByExtentAlgorithm() = default;
676+
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
677+
QString name() const override { return QStringLiteral( "extractbyextent" ); }
678+
QString displayName() const override { return QObject::tr( "Extract/clip by extent" ); }
679+
virtual QStringList tags() const override { return QObject::tr( "clip,extract,intersect,intersection,mask,extent" ).split( ',' ); }
680+
QString group() const override { return QObject::tr( "Vector overlay" ); }
681+
QString shortHelpString() const override;
682+
QgsExtractByExtentAlgorithm *createInstance() const override SIP_FACTORY;
683+
684+
protected:
685+
686+
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
687+
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
688+
689+
};
690+
665691
///@endcond PRIVATE
666692

667693
#endif // QGSNATIVEALGORITHMS_H

0 commit comments

Comments
 (0)
Please sign in to comment.