2015-05-22 13:18:00 +02:00
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
"""
|
|
|
|
***************************************************************************
|
|
|
|
CheckValidity.py
|
|
|
|
---------------------
|
|
|
|
Date : May 2015
|
|
|
|
Copyright : (C) 2015 by Arnaud Morvan
|
|
|
|
Email : arnaud dot morvan at camptocamp 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. *
|
|
|
|
* *
|
|
|
|
***************************************************************************
|
|
|
|
"""
|
|
|
|
|
|
|
|
__author__ = 'Arnaud Morvan'
|
|
|
|
__date__ = 'May 2015'
|
|
|
|
__copyright__ = '(C) 2015, Arnaud Morvan'
|
|
|
|
|
|
|
|
# This will get replaced with a git SHA1 when you do a git archive323
|
|
|
|
|
|
|
|
__revision__ = '$Format:%H$'
|
|
|
|
|
2016-01-25 15:42:11 +02:00
|
|
|
import os
|
|
|
|
|
2016-04-22 10:38:48 +02:00
|
|
|
from qgis.PyQt.QtGui import QIcon
|
2017-03-03 20:39:17 +01:00
|
|
|
from qgis.PyQt.QtCore import QVariant
|
2016-01-25 15:42:11 +02:00
|
|
|
|
2017-03-03 20:39:17 +01:00
|
|
|
from qgis.core import QgsSettings, QgsGeometry, QgsFeature, QgsField, QgsWkbTypes
|
2015-05-22 13:18:00 +02:00
|
|
|
from processing.core.GeoAlgorithm import GeoAlgorithm
|
|
|
|
from processing.core.parameters import ParameterVector
|
|
|
|
from processing.core.parameters import ParameterSelection
|
|
|
|
from processing.core.outputs import OutputVector
|
|
|
|
from processing.tools import dataobjects, vector
|
|
|
|
|
|
|
|
settings_method_key = "/qgis/digitizing/validate_geometries"
|
2016-01-25 15:42:11 +02:00
|
|
|
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
|
2015-05-22 13:18:00 +02:00
|
|
|
|
|
|
|
|
|
|
|
class CheckValidity(GeoAlgorithm):
|
|
|
|
|
|
|
|
INPUT_LAYER = 'INPUT_LAYER'
|
|
|
|
METHOD = 'METHOD'
|
|
|
|
VALID_OUTPUT = 'VALID_OUTPUT'
|
|
|
|
INVALID_OUTPUT = 'INVALID_OUTPUT'
|
|
|
|
ERROR_OUTPUT = 'ERROR_OUTPUT'
|
|
|
|
|
2017-03-29 10:42:42 +10:00
|
|
|
def icon(self):
|
2016-01-25 15:42:11 +02:00
|
|
|
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'check_geometry.png'))
|
|
|
|
|
2017-03-29 12:04:09 +10:00
|
|
|
def group(self):
|
|
|
|
return self.tr('Vector geometry tools')
|
|
|
|
|
2017-03-29 12:51:59 +10:00
|
|
|
def name(self):
|
2017-03-29 17:09:39 +10:00
|
|
|
return 'checkvalidity'
|
2017-03-29 12:51:59 +10:00
|
|
|
|
|
|
|
def displayName(self):
|
|
|
|
return self.tr('Check validity')
|
2015-05-22 13:18:00 +02:00
|
|
|
|
2017-03-29 12:51:59 +10:00
|
|
|
def defineCharacteristics(self):
|
2015-08-31 16:59:11 +02:00
|
|
|
self.methods = [self.tr('The one selected in digitizing settings'),
|
|
|
|
'QGIS',
|
|
|
|
'GEOS']
|
|
|
|
|
2015-05-22 13:18:00 +02:00
|
|
|
self.addParameter(ParameterVector(
|
|
|
|
self.INPUT_LAYER,
|
2016-08-23 19:33:42 +03:00
|
|
|
self.tr('Input layer')))
|
2015-05-22 13:18:00 +02:00
|
|
|
|
|
|
|
self.addParameter(ParameterSelection(
|
|
|
|
self.METHOD,
|
|
|
|
self.tr('Method'),
|
2015-08-31 16:59:11 +02:00
|
|
|
self.methods))
|
2015-05-22 13:18:00 +02:00
|
|
|
|
|
|
|
self.addOutput(OutputVector(
|
|
|
|
self.VALID_OUTPUT,
|
|
|
|
self.tr('Valid output')))
|
|
|
|
|
|
|
|
self.addOutput(OutputVector(
|
|
|
|
self.INVALID_OUTPUT,
|
|
|
|
self.tr('Invalid output')))
|
|
|
|
|
|
|
|
self.addOutput(OutputVector(
|
|
|
|
self.ERROR_OUTPUT,
|
|
|
|
self.tr('Error output')))
|
|
|
|
|
2017-01-06 20:04:00 +10:00
|
|
|
def processAlgorithm(self, feedback):
|
2017-03-03 20:39:17 +01:00
|
|
|
settings = QgsSettings()
|
2015-05-22 13:18:00 +02:00
|
|
|
initial_method_setting = settings.value(settings_method_key, 1)
|
|
|
|
|
|
|
|
method = self.getParameterValue(self.METHOD)
|
|
|
|
if method != 0:
|
|
|
|
settings.setValue(settings_method_key, method)
|
|
|
|
try:
|
2017-01-06 20:04:00 +10:00
|
|
|
self.doCheck(feedback)
|
2015-05-22 13:18:00 +02:00
|
|
|
finally:
|
|
|
|
settings.setValue(settings_method_key, initial_method_setting)
|
|
|
|
|
2017-01-06 20:04:00 +10:00
|
|
|
def doCheck(self, feedback):
|
2017-04-05 18:35:55 +10:00
|
|
|
layer = dataobjects.getLayerFromString(
|
2015-05-22 13:18:00 +02:00
|
|
|
self.getParameterValue(self.INPUT_LAYER))
|
|
|
|
|
2017-03-03 20:39:17 +01:00
|
|
|
settings = QgsSettings()
|
2015-05-22 13:18:00 +02:00
|
|
|
method = int(settings.value(settings_method_key, 1))
|
|
|
|
|
2017-01-20 08:03:06 +01:00
|
|
|
valid_output = self.getOutputFromName(self.VALID_OUTPUT)
|
2016-08-04 07:33:49 +10:00
|
|
|
valid_fields = layer.fields()
|
2017-01-20 08:03:06 +01:00
|
|
|
valid_writer = valid_output.getVectorWriter(
|
2015-05-22 13:18:00 +02:00
|
|
|
valid_fields,
|
2016-08-04 07:33:49 +10:00
|
|
|
layer.wkbType(),
|
2015-05-22 13:18:00 +02:00
|
|
|
layer.crs())
|
|
|
|
valid_count = 0
|
|
|
|
|
2017-01-20 08:03:06 +01:00
|
|
|
invalid_output = self.getOutputFromName(self.INVALID_OUTPUT)
|
2016-08-04 07:33:49 +10:00
|
|
|
invalid_fields = layer.fields().toList() + [
|
2015-05-22 13:18:00 +02:00
|
|
|
QgsField(name='_errors',
|
2016-01-25 15:42:11 +02:00
|
|
|
type=QVariant.String,
|
2015-05-22 13:18:00 +02:00
|
|
|
len=255)]
|
2017-01-20 08:03:06 +01:00
|
|
|
invalid_writer = invalid_output.getVectorWriter(
|
2015-05-22 13:18:00 +02:00
|
|
|
invalid_fields,
|
2016-08-04 07:33:49 +10:00
|
|
|
layer.wkbType(),
|
2015-05-22 13:18:00 +02:00
|
|
|
layer.crs())
|
|
|
|
invalid_count = 0
|
|
|
|
|
2017-01-20 08:03:06 +01:00
|
|
|
error_output = self.getOutputFromName(self.ERROR_OUTPUT)
|
2015-05-22 13:18:00 +02:00
|
|
|
error_fields = [
|
|
|
|
QgsField(name='message',
|
2016-01-25 15:42:11 +02:00
|
|
|
type=QVariant.String,
|
2015-05-22 13:18:00 +02:00
|
|
|
len=255)]
|
2017-01-20 08:03:06 +01:00
|
|
|
error_writer = error_output.getVectorWriter(
|
2015-05-22 13:18:00 +02:00
|
|
|
error_fields,
|
2016-08-04 09:10:08 +02:00
|
|
|
QgsWkbTypes.Point,
|
2015-05-22 13:18:00 +02:00
|
|
|
layer.crs())
|
|
|
|
error_count = 0
|
|
|
|
|
|
|
|
features = vector.features(layer)
|
2016-02-17 09:36:59 +02:00
|
|
|
total = 100.0 / len(features)
|
2015-05-22 13:18:00 +02:00
|
|
|
for current, inFeat in enumerate(features):
|
2016-08-01 16:25:46 +10:00
|
|
|
geom = inFeat.geometry()
|
2015-05-22 13:18:00 +02:00
|
|
|
attrs = inFeat.attributes()
|
|
|
|
|
|
|
|
valid = True
|
2017-01-30 22:22:09 +10:00
|
|
|
if not geom.isNull() and not geom.isEmpty():
|
2015-05-22 13:18:00 +02:00
|
|
|
errors = list(geom.validateGeometry())
|
|
|
|
if errors:
|
|
|
|
# QGIS method return a summary at the end
|
|
|
|
if method == 1:
|
|
|
|
errors.pop()
|
|
|
|
valid = False
|
|
|
|
reasons = []
|
|
|
|
for error in errors:
|
|
|
|
errFeat = QgsFeature()
|
|
|
|
error_geom = QgsGeometry.fromPoint(error.where())
|
|
|
|
errFeat.setGeometry(error_geom)
|
|
|
|
errFeat.setAttributes([error.what()])
|
|
|
|
error_writer.addFeature(errFeat)
|
|
|
|
error_count += 1
|
|
|
|
|
|
|
|
reasons.append(error.what())
|
|
|
|
|
|
|
|
reason = "\n".join(reasons)
|
|
|
|
if len(reason) > 255:
|
|
|
|
reason = reason[:252] + '...'
|
|
|
|
attrs.append(reason)
|
|
|
|
|
|
|
|
outFeat = QgsFeature()
|
|
|
|
outFeat.setGeometry(geom)
|
|
|
|
outFeat.setAttributes(attrs)
|
|
|
|
|
|
|
|
if valid:
|
|
|
|
valid_writer.addFeature(outFeat)
|
|
|
|
valid_count += 1
|
|
|
|
|
|
|
|
else:
|
|
|
|
invalid_writer.addFeature(outFeat)
|
|
|
|
invalid_count += 1
|
|
|
|
|
2017-01-06 20:04:00 +10:00
|
|
|
feedback.setProgress(int(current * total))
|
2015-05-22 13:18:00 +02:00
|
|
|
|
|
|
|
del valid_writer
|
|
|
|
del invalid_writer
|
|
|
|
del error_writer
|
|
|
|
|
|
|
|
if valid_count == 0:
|
2017-01-20 08:03:06 +01:00
|
|
|
valid_output.open = False
|
2015-05-22 13:18:00 +02:00
|
|
|
if invalid_count == 0:
|
2017-01-20 08:03:06 +01:00
|
|
|
invalid_output.open = False
|
2015-05-22 13:18:00 +02:00
|
|
|
if error_count == 0:
|
2017-01-20 08:03:06 +01:00
|
|
|
error_output.open = False
|