Skip to content
Permalink
Browse files

[needs-docs][processing] Add option to check validity alg to ignore s…

…elf-intersection

causing rings errors

By default the algorithm now uses the strict OGC definition of polygon validity, where
a polygon is marked as invalid if a self-intersecting ring causes an interior hole.
If the "Ignore ring self intersections" option is checked, then this rule will be
ignored and a more lenient validity check will be performed.

Refs #16418, refs #21336
  • Loading branch information
nyalldawson committed Feb 26, 2019
1 parent 4e04d02 commit 49742c302afb97e6272ce8b6b3a806014cdbdb5b
@@ -51,6 +51,8 @@ qgis:checkvalidity: >

The geometries are classified in three groups (valid, invalid and error), and a vector layer is generated with the features in each of these categories.

By default the algorithm uses the strict OGC definition of polygon validity, where a polygon is marked as invalid if a self-intersecting ring causes an interior hole. If the "Ignore ring self intersections" option is checked, then this rule will be ignored and a more lenient validity check will be performed.

qgis:clip: >
This algorithm clips a vector layer using the polygons of an additional polygons layer. Only the parts of the features in the input layer that falls within the polygons of the clipping layer will be added to the resulting layer.

@@ -45,7 +45,8 @@
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
QgsProcessingParameterFeatureSink,
QgsProcessingOutputNumber)
QgsProcessingOutputNumber,
QgsProcessingParameterBoolean)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm

settings_method_key = "/qgis/digitizing/validate_geometries"
@@ -62,6 +63,7 @@ class CheckValidity(QgisAlgorithm):
INVALID_COUNT = 'INVALID_COUNT'
ERROR_OUTPUT = 'ERROR_OUTPUT'
ERROR_COUNT = 'ERROR_COUNT'
IGNORE_RING_SELF_INTERSECTION = 'IGNORE_RING_SELF_INTERSECTION'

def icon(self):
return QgsApplication.getThemeIcon("/algorithms/mAlgorithmCheckGeometry.svg")
@@ -96,6 +98,9 @@ def initAlgorithm(self, config=None):
'useCheckBoxes': True,
'columns': 3}})

self.addParameter(QgsProcessingParameterBoolean(self.IGNORE_RING_SELF_INTERSECTION,
self.tr('Ignore ring self intersections'), defaultValue=False))

self.addParameter(QgsProcessingParameterFeatureSink(self.VALID_OUTPUT, self.tr('Valid output'), QgsProcessing.TypeVectorAnyGeometry, '', True))
self.addOutput(QgsProcessingOutputNumber(self.VALID_COUNT, self.tr('Count of valid features')))

@@ -112,6 +117,7 @@ def displayName(self):
return self.tr('Check validity')

def processAlgorithm(self, parameters, context, feedback):
ignore_ring_self_intersection = self.parameterAsBool(parameters, self.IGNORE_RING_SELF_INTERSECTION, context)
method_param = self.parameterAsEnum(parameters, self.METHOD, context)
if method_param == 0:
settings = QgsSettings()
@@ -121,10 +127,11 @@ def processAlgorithm(self, parameters, context, feedback):
else:
method = method_param - 1

results = self.doCheck(method, parameters, context, feedback)
results = self.doCheck(method, parameters, context, feedback, ignore_ring_self_intersection)
return results

def doCheck(self, method, parameters, context, feedback):
def doCheck(self, method, parameters, context, feedback, ignore_ring_self_intersection):
flags = QgsGeometry.FlagAllowSelfTouchingHoles if ignore_ring_self_intersection else QgsGeometry.ValidityFlags()
source = self.parameterAsSource(parameters, self.INPUT_LAYER, context)
if source is None:
raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT_LAYER))
@@ -155,7 +162,7 @@ def doCheck(self, method, parameters, context, feedback):

valid = True
if not geom.isNull() and not geom.isEmpty():
errors = list(geom.validateGeometry(method))
errors = list(geom.validateGeometry(method, flags))
if errors:
valid = False
reasons = []
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ poly_ring_self_intersection_error_ignore_self.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

</ogr:FeatureCollection>
@@ -0,0 +1,30 @@
<?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" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="poly_ring_self_intersection_error_ignore_self" type="ogr:poly_ring_self_intersection_error_ignore_self_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="poly_ring_self_intersection_error_ignore_self_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="message" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="255"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ poly_ring_self_intersection_invalid_ignore_self.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

</ogr:FeatureCollection>
@@ -0,0 +1,30 @@
<?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" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="poly_ring_self_intersection_invalid_ignore_self" type="ogr:poly_ring_self_intersection_invalid_ignore_self_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="poly_ring_self_intersection_invalid_ignore_self_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="_errors" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="255"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ poly_ring_self_intersection_valid_ignore_self.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>200</gml:X><gml:Y>200</gml:Y></gml:coord>
<gml:coord><gml:X>400</gml:X><gml:Y>400</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:poly_ring_self_intersection_valid_ignore_self fid="poly_ring_self_intersection.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:28356"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>200,400 400,400 400,200 300,200 350,250 250,250 300,200 200,200 200,400</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
</ogr:poly_ring_self_intersection_valid_ignore_self>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,23 @@
<?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" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="poly_ring_self_intersection_valid_ignore_self" type="ogr:poly_ring_self_intersection_valid_ignore_self_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="poly_ring_self_intersection_valid_ignore_self_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
@@ -3764,6 +3764,25 @@ tests:
name: expected/poly_ring_self_intersection_valid.gml
type: vector

- algorithm: qgis:checkvalidity
name: Check validity polygon ring self intersection, ignoring self intersections
params:
IGNORE_RING_SELF_INTERSECTION: true
INPUT_LAYER:
name: custom/poly_ring_self_intersection.gml|layername=poly_ring_self_intersection
type: vector
METHOD: 2
results:
ERROR_OUTPUT:
name: expected/poly_ring_self_intersection_error_ignore_self.gml
type: vector
INVALID_OUTPUT:
name: expected/poly_ring_self_intersection_invalid_ignore_self.gml
type: vector
VALID_OUTPUT:
name: expected/poly_ring_self_intersection_valid_ignore_self.gml
type: vector

- algorithm: qgis:polygonize
name: Polygonize
params:

0 comments on commit 49742c3

Please sign in to comment.
You can’t perform that action at this time.