mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-04 00:04:03 -04:00
[processing] Add algorithms to filter parts by length/area
These new algorithms "Remove parts by length" and "Remove parts by area" filter out parts of geometries from a vector layer, by checking their area or length vs a minimum size parameter. If the input geometry is a multipart geometry, then the parts will be filtered by their individual sizes. If no parts match the required minimum size, then the feature will be skipped and omitted from the output layer. If the input geometry is a singlepart geometry, then the feature will be skipped if the geometry's size is below the required size and omitted from the output layer. Attributes are not modified.
This commit is contained in:
parent
51df526a40
commit
4fe72dd84f
34
python/plugins/processing/tests/testdata/expected/remove_line_parts_by_length.gml
vendored
Normal file
34
python/plugins/processing/tests/testdata/expected/remove_line_parts_by_length.gml
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
gml:id="aFeatureCollection"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ remove_line_parts_by_length.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>-170142.279029556 -368051.169570389</gml:lowerCorner><gml:upperCorner>1198122.33141201 455636.648094066</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_line_parts_by_length gml:id="remove_line_parts_by_length.0">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>-170142.279029556 -309175.468327608</gml:lowerCorner><gml:upperCorner>193303.008118985 455636.648094066</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
<ogr:geometryProperty><gml:LineString srsName="urn:ogc:def:crs:EPSG::3857" gml:id="remove_line_parts_by_length.geom.0"><gml:posList>193303.008118985 455636.648094066 67700.5927073567 337822.202907407 40976.6745346706 33011.8416339877 -44539.8636179277 -303824.512095835 -170142.279029556 -309175.468327608</gml:posList></gml:LineString></ogr:geometryProperty>
|
||||
<ogr:fid>line_3857.0</ogr:fid>
|
||||
<ogr:val>5</ogr:val>
|
||||
</ogr:remove_line_parts_by_length>
|
||||
</ogr:featureMember>
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_line_parts_by_length gml:id="remove_line_parts_by_length.1">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>67700.5927073567 -368051.169570389</gml:lowerCorner><gml:upperCorner>628902.874333781 254888.031682493</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
<ogr:geometryProperty><gml:LineString srsName="urn:ogc:def:crs:EPSG::3857" gml:id="remove_line_parts_by_length.geom.1"><gml:posList>67700.5927073567 -368051.169570389 78390.1599764311 -23108.5844752597 300198.680809733 -47160.4899983067 628902.874333781 254888.031682493</gml:posList></gml:LineString></ogr:geometryProperty>
|
||||
<ogr:fid>line_3857.2</ogr:fid>
|
||||
<ogr:val>8</ogr:val>
|
||||
</ogr:remove_line_parts_by_length>
|
||||
</ogr:featureMember>
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_line_parts_by_length gml:id="remove_line_parts_by_length.2">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::3857"><gml:lowerCorner>992348.161482323 -263698.89064191</gml:lowerCorner><gml:upperCorner>1198122.33141201 262911.813488384</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
<ogr:geometryProperty><gml:LineString srsName="urn:ogc:def:crs:EPSG::3857" gml:id="remove_line_parts_by_length.geom.2"><gml:posList>992348.161482323 262911.813488384 1198122.33141201 -263698.89064191</gml:posList></gml:LineString></ogr:geometryProperty>
|
||||
<ogr:fid>line_3857.4</ogr:fid>
|
||||
<ogr:val>2</ogr:val>
|
||||
</ogr:remove_line_parts_by_length>
|
||||
</ogr:featureMember>
|
||||
</ogr:FeatureCollection>
|
60
python/plugins/processing/tests/testdata/expected/remove_line_parts_by_length.xsd
vendored
Normal file
60
python/plugins/processing/tests/testdata/expected/remove_line_parts_by_length.xsd
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema
|
||||
targetNamespace="http://ogr.maptools.org/"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2"
|
||||
xmlns:gmlsf="http://www.opengis.net/gmlsf/2.0"
|
||||
elementFormDefault="qualified"
|
||||
version="1.0">
|
||||
<xs:annotation>
|
||||
<xs:appinfo source="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd">
|
||||
<gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>
|
||||
</xs:appinfo>
|
||||
</xs:annotation>
|
||||
<xs:import namespace="http://www.opengis.net/gml/3.2" schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd"/>
|
||||
<xs:import namespace="http://www.opengis.net/gmlsf/2.0" schemaLocation="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:AbstractFeature"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="featureMember">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureMemberType">
|
||||
<xs:sequence>
|
||||
<xs:element ref="gml:AbstractFeature"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="remove_line_parts_by_length" type="ogr:remove_line_parts_by_length_Type" substitutionGroup="gml:AbstractFeature"/>
|
||||
<xs:complexType name="remove_line_parts_by_length_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:CurvePropertyType" nillable="true" minOccurs="0" maxOccurs="1"/> <!-- restricted to LineString --><!-- srsName="urn:ogc:def:crs:EPSG::3857" -->
|
||||
<xs:element name="fid" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="val" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:totalDigits value="10"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
22
python/plugins/processing/tests/testdata/expected/remove_multiline_parts_by_length.gml
vendored
Normal file
22
python/plugins/processing/tests/testdata/expected/remove_multiline_parts_by_length.gml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
gml:id="aFeatureCollection"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ remove_multiline_parts_by_length.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326"><gml:lowerCorner>0 2</gml:lowerCorner><gml:upperCorner>3 3</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_multiline_parts_by_length gml:id="remove_multiline_parts_by_length.0">
|
||||
<ogr:fid>lines.3</ogr:fid>
|
||||
</ogr:remove_multiline_parts_by_length>
|
||||
</ogr:featureMember>
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_multiline_parts_by_length gml:id="remove_multiline_parts_by_length.1">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326"><gml:lowerCorner>0 2</gml:lowerCorner><gml:upperCorner>3 3</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
<ogr:geometryProperty><gml:MultiCurve srsName="urn:ogc:def:crs:EPSG::4326" gml:id="remove_multiline_parts_by_length.geom.1"><gml:curveMember><gml:LineString gml:id="remove_multiline_parts_by_length.geom.1.0"><gml:posList>0 2 2 2 2 3 3 3</gml:posList></gml:LineString></gml:curveMember></gml:MultiCurve></ogr:geometryProperty>
|
||||
<ogr:fid>lines.4</ogr:fid>
|
||||
</ogr:remove_multiline_parts_by_length>
|
||||
</ogr:featureMember>
|
||||
</ogr:FeatureCollection>
|
53
python/plugins/processing/tests/testdata/expected/remove_multiline_parts_by_length.xsd
vendored
Normal file
53
python/plugins/processing/tests/testdata/expected/remove_multiline_parts_by_length.xsd
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema
|
||||
targetNamespace="http://ogr.maptools.org/"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2"
|
||||
xmlns:gmlsf="http://www.opengis.net/gmlsf/2.0"
|
||||
elementFormDefault="qualified"
|
||||
version="1.0">
|
||||
<xs:annotation>
|
||||
<xs:appinfo source="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd">
|
||||
<gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>
|
||||
</xs:appinfo>
|
||||
</xs:annotation>
|
||||
<xs:import namespace="http://www.opengis.net/gml/3.2" schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd"/>
|
||||
<xs:import namespace="http://www.opengis.net/gmlsf/2.0" schemaLocation="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:AbstractFeature"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="featureMember">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureMemberType">
|
||||
<xs:sequence>
|
||||
<xs:element ref="gml:AbstractFeature"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="remove_multiline_parts_by_length" type="ogr:remove_multiline_parts_by_length_Type" substitutionGroup="gml:AbstractFeature"/>
|
||||
<xs:complexType name="remove_multiline_parts_by_length_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:MultiCurvePropertyType" nillable="true" minOccurs="0" maxOccurs="1"/> <!-- restricted to MultiLineString --><!-- srsName="urn:ogc:def:crs:EPSG::4326" -->
|
||||
<xs:element name="fid" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
28
python/plugins/processing/tests/testdata/expected/remove_multipolygon_parts_by_area.gml
vendored
Normal file
28
python/plugins/processing/tests/testdata/expected/remove_multipolygon_parts_by_area.gml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
gml:id="aFeatureCollection"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ remove_multipolygon_parts_by_area.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326"><gml:lowerCorner>-1 7</gml:lowerCorner><gml:upperCorner>3 8</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_multipolygon_parts_by_area gml:id="remove_multipolygon_parts_by_area.0">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::4326"><gml:lowerCorner>-1 7</gml:lowerCorner><gml:upperCorner>3 8</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
<ogr:geometryProperty><gml:MultiSurface srsName="urn:ogc:def:crs:EPSG::4326" gml:id="remove_multipolygon_parts_by_area.geom.0"><gml:surfaceMember><gml:Polygon gml:id="remove_multipolygon_parts_by_area.geom.0.0"><gml:exterior><gml:LinearRing><gml:posList>-1 7 -1 8 3 8 3 7 -1 7</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface></ogr:geometryProperty>
|
||||
<ogr:fid>multipolys.1</ogr:fid>
|
||||
<ogr:Bname xsi:nil="true"/>
|
||||
<ogr:Bintval xsi:nil="true"/>
|
||||
<ogr:Bfloatval xsi:nil="true"/>
|
||||
</ogr:remove_multipolygon_parts_by_area>
|
||||
</ogr:featureMember>
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_multipolygon_parts_by_area gml:id="remove_multipolygon_parts_by_area.1">
|
||||
<ogr:fid>multipolys.3</ogr:fid>
|
||||
<ogr:Bname>Test</ogr:Bname>
|
||||
<ogr:Bintval>3</ogr:Bintval>
|
||||
<ogr:Bfloatval>0</ogr:Bfloatval>
|
||||
</ogr:remove_multipolygon_parts_by_area>
|
||||
</ogr:featureMember>
|
||||
</ogr:FeatureCollection>
|
73
python/plugins/processing/tests/testdata/expected/remove_multipolygon_parts_by_area.xsd
vendored
Normal file
73
python/plugins/processing/tests/testdata/expected/remove_multipolygon_parts_by_area.xsd
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema
|
||||
targetNamespace="http://ogr.maptools.org/"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2"
|
||||
xmlns:gmlsf="http://www.opengis.net/gmlsf/2.0"
|
||||
elementFormDefault="qualified"
|
||||
version="1.0">
|
||||
<xs:annotation>
|
||||
<xs:appinfo source="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd">
|
||||
<gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>
|
||||
</xs:appinfo>
|
||||
</xs:annotation>
|
||||
<xs:import namespace="http://www.opengis.net/gml/3.2" schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd"/>
|
||||
<xs:import namespace="http://www.opengis.net/gmlsf/2.0" schemaLocation="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:AbstractFeature"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="featureMember">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureMemberType">
|
||||
<xs:sequence>
|
||||
<xs:element ref="gml:AbstractFeature"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="remove_multipolygon_parts_by_area" type="ogr:remove_multipolygon_parts_by_area_Type" substitutionGroup="gml:AbstractFeature"/>
|
||||
<xs:complexType name="remove_multipolygon_parts_by_area_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:MultiSurfacePropertyType" nillable="true" minOccurs="0" maxOccurs="1"/> <!-- restricted to MultiPolygon --><!-- srsName="urn:ogc:def:crs:EPSG::4326" -->
|
||||
<xs:element name="fid" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="Bname" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="4"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="Bintval" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:integer">
|
||||
<xs:totalDigits value="10"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
<xs:element name="Bfloatval" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:decimal">
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
24
python/plugins/processing/tests/testdata/expected/remove_polygon_parts_by_area.gml
vendored
Normal file
24
python/plugins/processing/tests/testdata/expected/remove_polygon_parts_by_area.gml
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ogr:FeatureCollection
|
||||
gml:id="aFeatureCollection"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://ogr.maptools.org/ remove_polygon_parts_by_area.xsd"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::31256"><gml:lowerCorner>-5447984.1499324 -1696611.72536999</gml:lowerCorner><gml:upperCorner>-4968240.45365551 -812597.646423635</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_polygon_parts_by_area gml:id="remove_polygon_parts_by_area.0">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::31256"><gml:lowerCorner>-5082679.00301049 -1696611.72536999</gml:lowerCorner><gml:upperCorner>-4968240.45365551 -1536872.40598013</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
<ogr:geometryProperty><gml:MultiSurface srsName="urn:ogc:def:crs:EPSG::31256" gml:id="remove_polygon_parts_by_area.geom.0"><gml:surfaceMember><gml:Polygon gml:id="remove_polygon_parts_by_area.geom.0.0"><gml:exterior><gml:LinearRing><gml:posList>-5046793.84388864 -1696611.72536999 -4998860.79192466 -1686316.7671871 -5005696.1429675 -1639845.87197112 -4968240.45365551 -1543713.48564309 -5022688.65205912 -1536872.40598013 -5060223.52298557 -1584812.75072525 -5082679.00301049 -1677567.90939181 -5046793.84388864 -1696611.72536999</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface></ogr:geometryProperty>
|
||||
<ogr:testattr>a</ogr:testattr>
|
||||
</ogr:remove_polygon_parts_by_area>
|
||||
</ogr:featureMember>
|
||||
<ogr:featureMember>
|
||||
<ogr:remove_polygon_parts_by_area gml:id="remove_polygon_parts_by_area.1">
|
||||
<gml:boundedBy><gml:Envelope srsName="urn:ogc:def:crs:EPSG::31256"><gml:lowerCorner>-5447984.1499324 -1360816.09576364</gml:lowerCorner><gml:upperCorner>-5179666.180385 -812597.646423635</gml:upperCorner></gml:Envelope></gml:boundedBy>
|
||||
<ogr:geometryProperty><gml:MultiSurface srsName="urn:ogc:def:crs:EPSG::31256" gml:id="remove_polygon_parts_by_area.geom.1"><gml:surfaceMember><gml:Polygon gml:id="remove_polygon_parts_by_area.geom.1.0"><gml:exterior><gml:LinearRing><gml:posList>-5340262.55811533 -1360816.09576364 -5179666.180385 -1343487.40838446 -5201113.62674451 -1263539.81063555 -5295898.32956886 -1122417.3150334 -5191026.76572497 -941120.6948349 -5278830.75393966 -826514.145092787 -5358635.00834848 -812597.646423635 -5379879.24143519 -1287359.99466885 -5447984.1499324 -1340734.64008444 -5340262.55811533 -1360816.09576364</gml:posList></gml:LinearRing></gml:exterior></gml:Polygon></gml:surfaceMember></gml:MultiSurface></ogr:geometryProperty>
|
||||
<ogr:testattr>b</ogr:testattr>
|
||||
</ogr:remove_polygon_parts_by_area>
|
||||
</ogr:featureMember>
|
||||
</ogr:FeatureCollection>
|
54
python/plugins/processing/tests/testdata/expected/remove_polygon_parts_by_area.xsd
vendored
Normal file
54
python/plugins/processing/tests/testdata/expected/remove_polygon_parts_by_area.xsd
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema
|
||||
targetNamespace="http://ogr.maptools.org/"
|
||||
xmlns:ogr="http://ogr.maptools.org/"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:gml="http://www.opengis.net/gml/3.2"
|
||||
xmlns:gmlsf="http://www.opengis.net/gmlsf/2.0"
|
||||
elementFormDefault="qualified"
|
||||
version="1.0">
|
||||
<xs:annotation>
|
||||
<xs:appinfo source="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd">
|
||||
<gmlsf:ComplianceLevel>0</gmlsf:ComplianceLevel>
|
||||
</xs:appinfo>
|
||||
</xs:annotation>
|
||||
<xs:import namespace="http://www.opengis.net/gml/3.2" schemaLocation="http://schemas.opengis.net/gml/3.2.1/gml.xsd"/>
|
||||
<xs:import namespace="http://www.opengis.net/gmlsf/2.0" schemaLocation="http://schemas.opengis.net/gmlsfProfile/2.0/gmlsfLevels.xsd"/>
|
||||
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:AbstractFeature"/>
|
||||
<xs:complexType name="FeatureCollectionType">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||
<xs:element name="featureMember">
|
||||
<xs:complexType>
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureMemberType">
|
||||
<xs:sequence>
|
||||
<xs:element ref="gml:AbstractFeature"/>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
<xs:element name="remove_polygon_parts_by_area" type="ogr:remove_polygon_parts_by_area_Type" substitutionGroup="gml:AbstractFeature"/>
|
||||
<xs:complexType name="remove_polygon_parts_by_area_Type">
|
||||
<xs:complexContent>
|
||||
<xs:extension base="gml:AbstractFeatureType">
|
||||
<xs:sequence>
|
||||
<xs:element name="geometryProperty" type="gml:MultiSurfacePropertyType" nillable="true" minOccurs="0" maxOccurs="1"/> <!-- restricted to MultiPolygon --><!-- srsName="urn:ogc:def:crs:EPSG::31256" -->
|
||||
<xs:element name="testattr" nillable="true" minOccurs="0" maxOccurs="1">
|
||||
<xs:simpleType>
|
||||
<xs:restriction base="xs:string">
|
||||
<xs:maxLength value="10"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:extension>
|
||||
</xs:complexContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
@ -373,3 +373,51 @@ tests:
|
||||
OUTPUT:
|
||||
name: expected/concave_hull_by_feature.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:removepartsbylength
|
||||
name: Remove line parts by length
|
||||
params:
|
||||
INPUT:
|
||||
name: custom/line_3857.gml|layername=line_3857
|
||||
type: vector
|
||||
MIN_LENGTH: 550000.0
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/remove_line_parts_by_length.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:removepartsbylength
|
||||
name: Remove multiline parts by length
|
||||
params:
|
||||
INPUT:
|
||||
name: multilines.gml|layername=multilines
|
||||
type: vector
|
||||
MIN_LENGTH: 3.0
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/remove_multiline_parts_by_length.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:removepartsbyarea
|
||||
name: Remove polygon parts by area
|
||||
params:
|
||||
INPUT:
|
||||
name: custom/polys_epsg31256.shp
|
||||
type: vector
|
||||
MIN_AREA: 9999000000.0
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/remove_polygon_parts_by_area.gml
|
||||
type: vector
|
||||
|
||||
- algorithm: native:removepartsbyarea
|
||||
name: Remove multipolygon parts by area
|
||||
params:
|
||||
INPUT:
|
||||
name: multipolys.gml|layername=multipolys
|
||||
type: vector
|
||||
MIN_AREA: 4.0
|
||||
results:
|
||||
OUTPUT:
|
||||
name: expected/remove_multipolygon_parts_by_area.gml
|
||||
type: vector
|
||||
|
@ -236,6 +236,8 @@ set(QGIS_ANALYSIS_SRCS
|
||||
processing/qgsalgorithmremoveduplicatevertices.cpp
|
||||
processing/qgsalgorithmremoveholes.cpp
|
||||
processing/qgsalgorithmremovenullgeometry.cpp
|
||||
processing/qgsalgorithmremovepartsbyarea.cpp
|
||||
processing/qgsalgorithmremovepartsbylength.cpp
|
||||
processing/qgsalgorithmrenamelayer.cpp
|
||||
processing/qgsalgorithmrenametablefield.cpp
|
||||
processing/qgsalgorithmrepairshapefile.cpp
|
||||
|
161
src/analysis/processing/qgsalgorithmremovepartsbyarea.cpp
Normal file
161
src/analysis/processing/qgsalgorithmremovepartsbyarea.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmremovepartsbyarea.cpp
|
||||
---------------------
|
||||
begin : July 2024
|
||||
copyright : (C) 2024 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 "qgsalgorithmremovepartsbyarea.h"
|
||||
#include "qgsgeometrycollection.h"
|
||||
#include "qgssurface.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
QString QgsRemovePartsByAreaAlgorithm::name() const
|
||||
{
|
||||
return QStringLiteral( "removepartsbyarea" );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByAreaAlgorithm::displayName() const
|
||||
{
|
||||
return QObject::tr( "Remove parts by area" );
|
||||
}
|
||||
|
||||
QStringList QgsRemovePartsByAreaAlgorithm::tags() const
|
||||
{
|
||||
return QObject::tr( "remove,delete,drop,filter,polygon,size" ).split( ',' );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByAreaAlgorithm::group() const
|
||||
{
|
||||
return QObject::tr( "Vector geometry" );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByAreaAlgorithm::groupId() const
|
||||
{
|
||||
return QStringLiteral( "vectorgeometry" );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByAreaAlgorithm::outputName() const
|
||||
{
|
||||
return QObject::tr( "Cleaned" );
|
||||
}
|
||||
|
||||
QList<int> QgsRemovePartsByAreaAlgorithm::inputLayerTypes() const
|
||||
{
|
||||
return QList<int>() << static_cast< int >( Qgis::ProcessingSourceType::VectorPolygon );
|
||||
}
|
||||
|
||||
Qgis::ProcessingSourceType QgsRemovePartsByAreaAlgorithm::outputLayerType() const
|
||||
{
|
||||
return Qgis::ProcessingSourceType::VectorPolygon;
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByAreaAlgorithm::shortDescription() const
|
||||
{
|
||||
return QObject::tr( "Removes polygons which are smaller than a specified area." );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByAreaAlgorithm::shortHelpString() const
|
||||
{
|
||||
return QObject::tr( "This algorithm takes a polygon layer and removes polygons which are smaller than a specified area.\n\n"
|
||||
"If the input geometry is a multipart geometry, then the parts will be filtered by their individual areas. If no parts match the "
|
||||
"required minimum area, then the feature will be skipped and omitted from the output layer.\n\n"
|
||||
"If the input geometry is a singlepart geometry, then the feature will be skipped if the geometry's "
|
||||
"area is below the required size and omitted from the output layer.\n\n"
|
||||
"The area will be calculated using Cartesian calculations in the source layer's coordinate reference system.\n\n"
|
||||
"Attributes are not modified." );
|
||||
}
|
||||
|
||||
QgsRemovePartsByAreaAlgorithm *QgsRemovePartsByAreaAlgorithm::createInstance() const
|
||||
{
|
||||
return new QgsRemovePartsByAreaAlgorithm();
|
||||
}
|
||||
|
||||
Qgis::ProcessingFeatureSourceFlags QgsRemovePartsByAreaAlgorithm::sourceFlags() const
|
||||
{
|
||||
// skip geometry checks - this algorithm can be used to repair geometries
|
||||
return Qgis::ProcessingFeatureSourceFlag::SkipGeometryValidityChecks;
|
||||
}
|
||||
|
||||
void QgsRemovePartsByAreaAlgorithm::initParameters( const QVariantMap & )
|
||||
{
|
||||
std::unique_ptr< QgsProcessingParameterArea > minArea = std::make_unique< QgsProcessingParameterArea >( QStringLiteral( "MIN_AREA" ), QObject::tr( "Remove parts with area less than" ), 0.0, QStringLiteral( "INPUT" ), false, 0 );
|
||||
minArea->setIsDynamic( true );
|
||||
minArea->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "MIN_AREA" ), QObject::tr( "Remove parts with area less than" ), QgsPropertyDefinition::DoublePositive ) );
|
||||
minArea->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
|
||||
addParameter( minArea.release() );
|
||||
}
|
||||
|
||||
bool QgsRemovePartsByAreaAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
|
||||
{
|
||||
mMinArea = parameterAsDouble( parameters, QStringLiteral( "MIN_AREA" ), context );
|
||||
mDynamicMinArea = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "MIN_AREA" ) );
|
||||
if ( mDynamicMinArea )
|
||||
mMinAreaProperty = parameters.value( QStringLiteral( "MIN_AREA" ) ).value< QgsProperty >();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsFeatureList QgsRemovePartsByAreaAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
|
||||
{
|
||||
QgsFeature f = feature;
|
||||
if ( f.hasGeometry() )
|
||||
{
|
||||
double minArea = mMinArea;
|
||||
if ( mDynamicMinArea )
|
||||
minArea = mMinAreaProperty.valueAsDouble( context.expressionContext(), minArea );
|
||||
|
||||
const QgsGeometry geometry = f.geometry();
|
||||
QgsGeometry outputGeometry;
|
||||
if ( const QgsGeometryCollection *inputCollection = qgsgeometry_cast< const QgsGeometryCollection * >( geometry.constGet() ) )
|
||||
{
|
||||
std::unique_ptr< QgsAbstractGeometry> filteredGeometry( geometry.constGet()->createEmptyWithSameType() );
|
||||
QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( filteredGeometry.get() );
|
||||
const int size = inputCollection->numGeometries();
|
||||
collection->reserve( size );
|
||||
for ( int i = 0; i < size; ++i )
|
||||
{
|
||||
if ( const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( inputCollection->geometryN( i ) ) )
|
||||
{
|
||||
if ( surface->area() >= minArea )
|
||||
{
|
||||
collection->addGeometry( surface->clone() );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( collection->numGeometries() == 0 )
|
||||
{
|
||||
// skip empty features
|
||||
return {};
|
||||
}
|
||||
outputGeometry = QgsGeometry( std::move( filteredGeometry ) );
|
||||
f.setGeometry( outputGeometry );
|
||||
}
|
||||
else if ( const QgsSurface *surface = qgsgeometry_cast< const QgsSurface * >( geometry.constGet() ) )
|
||||
{
|
||||
if ( surface->area() < minArea )
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return { f };
|
||||
}
|
||||
|
||||
|
||||
///@endcond
|
62
src/analysis/processing/qgsalgorithmremovepartsbyarea.h
Normal file
62
src/analysis/processing/qgsalgorithmremovepartsbyarea.h
Normal file
@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmremovepartsbyarea.h
|
||||
---------------------
|
||||
begin : July 2024
|
||||
copyright : (C) 2024 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 QGSALGORITHMREMOVEPARTSBYAREA_H
|
||||
#define QGSALGORITHMREMOVEPARTSBYAREA_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include "qgis_sip.h"
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Native remove parts by area algorithm.
|
||||
*/
|
||||
class QgsRemovePartsByAreaAlgorithm : public QgsProcessingFeatureBasedAlgorithm
|
||||
{
|
||||
public:
|
||||
QgsRemovePartsByAreaAlgorithm() = default;
|
||||
QString name() const override;
|
||||
QString displayName() const override;
|
||||
QStringList tags() const override;
|
||||
QString group() const override;
|
||||
QString groupId() const override;
|
||||
QString shortDescription() const override;
|
||||
QString shortHelpString() const override;
|
||||
QgsRemovePartsByAreaAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
|
||||
protected:
|
||||
QString outputName() const override;
|
||||
QList<int> inputLayerTypes() const override;
|
||||
Qgis::ProcessingSourceType outputLayerType() const override;
|
||||
Qgis::ProcessingFeatureSourceFlags sourceFlags() const override;
|
||||
bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
private:
|
||||
double mMinArea = 0.0;
|
||||
bool mDynamicMinArea = false;
|
||||
QgsProperty mMinAreaProperty;
|
||||
};
|
||||
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMREMOVEPARTSBYAREA_H
|
161
src/analysis/processing/qgsalgorithmremovepartsbylength.cpp
Normal file
161
src/analysis/processing/qgsalgorithmremovepartsbylength.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmremovepartsbylength.cpp
|
||||
---------------------
|
||||
begin : July 2024
|
||||
copyright : (C) 2024 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 "qgsalgorithmremovepartsbylength.h"
|
||||
#include "qgsgeometrycollection.h"
|
||||
#include "qgscurve.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
QString QgsRemovePartsByLengthAlgorithm::name() const
|
||||
{
|
||||
return QStringLiteral( "removepartsbylength" );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByLengthAlgorithm::displayName() const
|
||||
{
|
||||
return QObject::tr( "Remove parts by length" );
|
||||
}
|
||||
|
||||
QStringList QgsRemovePartsByLengthAlgorithm::tags() const
|
||||
{
|
||||
return QObject::tr( "remove,delete,drop,filter,lines,linestring,polyline,size" ).split( ',' );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByLengthAlgorithm::group() const
|
||||
{
|
||||
return QObject::tr( "Vector geometry" );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByLengthAlgorithm::groupId() const
|
||||
{
|
||||
return QStringLiteral( "vectorgeometry" );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByLengthAlgorithm::outputName() const
|
||||
{
|
||||
return QObject::tr( "Cleaned" );
|
||||
}
|
||||
|
||||
QList<int> QgsRemovePartsByLengthAlgorithm::inputLayerTypes() const
|
||||
{
|
||||
return QList<int>() << static_cast< int >( Qgis::ProcessingSourceType::VectorLine );
|
||||
}
|
||||
|
||||
Qgis::ProcessingSourceType QgsRemovePartsByLengthAlgorithm::outputLayerType() const
|
||||
{
|
||||
return Qgis::ProcessingSourceType::VectorLine;
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByLengthAlgorithm::shortDescription() const
|
||||
{
|
||||
return QObject::tr( "Removes lines which are shorter than a specified length." );
|
||||
}
|
||||
|
||||
QString QgsRemovePartsByLengthAlgorithm::shortHelpString() const
|
||||
{
|
||||
return QObject::tr( "This algorithm takes a line layer and removes lines which are shorter than a specified length.\n\n"
|
||||
"If the input geometry is a multipart geometry, then the parts will be filtered by their individual lengths. If no parts match the "
|
||||
"required minimum length, then the feature will be skipped and omitted from the output layer.\n\n"
|
||||
"If the input geometry is a singlepart geometry, then the feature will be skipped if the geometry's "
|
||||
"length is below the required size and omitted from the output layer.\n\n"
|
||||
"The length will be calculated using Cartesian calculations in the source layer's coordinate reference system.\n\n"
|
||||
"Attributes are not modified." );
|
||||
}
|
||||
|
||||
QgsRemovePartsByLengthAlgorithm *QgsRemovePartsByLengthAlgorithm::createInstance() const
|
||||
{
|
||||
return new QgsRemovePartsByLengthAlgorithm();
|
||||
}
|
||||
|
||||
Qgis::ProcessingFeatureSourceFlags QgsRemovePartsByLengthAlgorithm::sourceFlags() const
|
||||
{
|
||||
// skip geometry checks - this algorithm can be used to repair geometries
|
||||
return Qgis::ProcessingFeatureSourceFlag::SkipGeometryValidityChecks;
|
||||
}
|
||||
|
||||
void QgsRemovePartsByLengthAlgorithm::initParameters( const QVariantMap & )
|
||||
{
|
||||
std::unique_ptr< QgsProcessingParameterDistance > minLength = std::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "MIN_LENGTH" ), QObject::tr( "Remove parts with lengths less than" ), 0.0, QStringLiteral( "INPUT" ), false, 0 );
|
||||
minLength->setIsDynamic( true );
|
||||
minLength->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "MIN_LENGTH" ), QObject::tr( "Remove parts with length less than" ), QgsPropertyDefinition::DoublePositive ) );
|
||||
minLength->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) );
|
||||
addParameter( minLength.release() );
|
||||
}
|
||||
|
||||
bool QgsRemovePartsByLengthAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * )
|
||||
{
|
||||
mMinLength = parameterAsDouble( parameters, QStringLiteral( "MIN_LENGTH" ), context );
|
||||
mDynamicMinLength = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "MIN_LENGTH" ) );
|
||||
if ( mDynamicMinLength )
|
||||
mMinLengthProperty = parameters.value( QStringLiteral( "MIN_LENGTH" ) ).value< QgsProperty >();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsFeatureList QgsRemovePartsByLengthAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * )
|
||||
{
|
||||
QgsFeature f = feature;
|
||||
if ( f.hasGeometry() )
|
||||
{
|
||||
double minLength = mMinLength;
|
||||
if ( mDynamicMinLength )
|
||||
minLength = mMinLengthProperty.valueAsDouble( context.expressionContext(), minLength );
|
||||
|
||||
const QgsGeometry geometry = f.geometry();
|
||||
QgsGeometry outputGeometry;
|
||||
if ( const QgsGeometryCollection *inputCollection = qgsgeometry_cast< const QgsGeometryCollection * >( geometry.constGet() ) )
|
||||
{
|
||||
std::unique_ptr< QgsAbstractGeometry> filteredGeometry( geometry.constGet()->createEmptyWithSameType() );
|
||||
QgsGeometryCollection *collection = qgsgeometry_cast< QgsGeometryCollection * >( filteredGeometry.get() );
|
||||
const int size = inputCollection->numGeometries();
|
||||
collection->reserve( size );
|
||||
for ( int i = 0; i < size; ++i )
|
||||
{
|
||||
if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( inputCollection->geometryN( i ) ) )
|
||||
{
|
||||
if ( curve->length() >= minLength )
|
||||
{
|
||||
collection->addGeometry( curve->clone() );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( collection->numGeometries() == 0 )
|
||||
{
|
||||
// skip empty features
|
||||
return {};
|
||||
}
|
||||
outputGeometry = QgsGeometry( std::move( filteredGeometry ) );
|
||||
f.setGeometry( outputGeometry );
|
||||
}
|
||||
else if ( const QgsCurve *curve = qgsgeometry_cast< const QgsCurve * >( geometry.constGet() ) )
|
||||
{
|
||||
if ( curve->length() < minLength )
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return { f };
|
||||
}
|
||||
|
||||
|
||||
///@endcond
|
62
src/analysis/processing/qgsalgorithmremovepartsbylength.h
Normal file
62
src/analysis/processing/qgsalgorithmremovepartsbylength.h
Normal file
@ -0,0 +1,62 @@
|
||||
/***************************************************************************
|
||||
qgsalgorithmremovepartsbylength.h
|
||||
---------------------
|
||||
begin : July 2024
|
||||
copyright : (C) 2024 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 QGSALGORITHMREMOVEPARTSBYLENGTH_H
|
||||
#define QGSALGORITHMREMOVEPARTSBYLENGTH_H
|
||||
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include "qgis_sip.h"
|
||||
#include "qgsprocessingalgorithm.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* Native remove parts by length algorithm.
|
||||
*/
|
||||
class QgsRemovePartsByLengthAlgorithm : public QgsProcessingFeatureBasedAlgorithm
|
||||
{
|
||||
public:
|
||||
QgsRemovePartsByLengthAlgorithm() = default;
|
||||
QString name() const override;
|
||||
QString displayName() const override;
|
||||
QStringList tags() const override;
|
||||
QString group() const override;
|
||||
QString groupId() const override;
|
||||
QString shortDescription() const override;
|
||||
QString shortHelpString() const override;
|
||||
QgsRemovePartsByLengthAlgorithm *createInstance() const override SIP_FACTORY;
|
||||
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
|
||||
|
||||
protected:
|
||||
QString outputName() const override;
|
||||
QList<int> inputLayerTypes() const override;
|
||||
Qgis::ProcessingSourceType outputLayerType() const override;
|
||||
Qgis::ProcessingFeatureSourceFlags sourceFlags() const override;
|
||||
bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
|
||||
|
||||
private:
|
||||
double mMinLength = 0.0;
|
||||
bool mDynamicMinLength = false;
|
||||
QgsProperty mMinLengthProperty;
|
||||
};
|
||||
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
#endif // QGSALGORITHMREMOVEPARTSBYLENGTH_H
|
@ -219,6 +219,8 @@
|
||||
#include "qgsalgorithmremoveduplicatevertices.h"
|
||||
#include "qgsalgorithmremoveholes.h"
|
||||
#include "qgsalgorithmremovenullgeometry.h"
|
||||
#include "qgsalgorithmremovepartsbyarea.h"
|
||||
#include "qgsalgorithmremovepartsbylength.h"
|
||||
#include "qgsalgorithmrenamelayer.h"
|
||||
#include "qgsalgorithmrenametablefield.h"
|
||||
#include "qgsalgorithmrepairshapefile.h"
|
||||
@ -570,6 +572,8 @@ void QgsNativeAlgorithms::loadAlgorithms()
|
||||
addAlgorithm( new QgsRemoveDuplicatesByAttributeAlgorithm() );
|
||||
addAlgorithm( new QgsRemoveHolesAlgorithm() );
|
||||
addAlgorithm( new QgsRemoveNullGeometryAlgorithm() );
|
||||
addAlgorithm( new QgsRemovePartsByAreaAlgorithm() );
|
||||
addAlgorithm( new QgsRemovePartsByLengthAlgorithm() );
|
||||
addAlgorithm( new QgsRenameLayerAlgorithm() );
|
||||
addAlgorithm( new QgsRenameTableFieldAlgorithm() );
|
||||
addAlgorithm( new QgsRepairShapefileAlgorithm() );
|
||||
|
Loading…
x
Reference in New Issue
Block a user