I write myself plugin for QGIS with Python3 API. For my plugin logic I need write my self geometry checker because of difficult logic and different actions when I find some of geometry errors. In documentation I find some classes, wicth can help me, but I don't understend how use it.
For example I want individual geometry check with class QgsSingleGeometryCheck.
I do somethong like this:
import qgis.analysis as qgs_ana
import qgis.core as qgs_core
layer_in = qgs_core.QgsProject().instance().mapLayer(layer_id)
for feat in layer_in.getFeatures():
check = qgs_ana.QgsSingleGeometryCheck()
geom = feat.geometry()
print(check.processGeometry(geom))
After run this code I get TypeError like this:
I understend that this error is because QgsSingleGeometryCheck is a abstract class. I don't understend how and what I need override, because no documentation and no example cases. In opensource code of QGIS it looks like in should work like this, but I write only on python and don't understand c++ and what I should do.
Maybe there is another way to do individual Checks for geometry. I learn in documentation another classes whitch can help me, for example QgsGeometryValidator, QgsGeometryEngine in methods of this classes I find some helpful functional for me, but i beleve QGIS have more best way to check geometrys. I want find correct way to doing different geometry checks.
If you do something like this please tell me how can I check geometry for example on duplicate nodes.
PS: QGIS self algorithms like "processing algorithms" is not for me because it work with layer but not with geometry as such.
UPD:
I try using example from Taras link's of overriding abstract classes. Problem with TypeError is decied! BUT...
import qgis.analysis as qgs_ana
import qgis.core as qgs_core
from typing import List
class QgsSingleGeometryCheck(qgs_ana.QgsSingleGeometryCheck):
def processGeometry(self, geometry: qgs_core.QgsGeometry) -> List[qgs_ana.QgsSingleGeometryCheckError]:
pass
layer_in = qgs_core.QgsProject().instance().mapLayer(layer_id)
for feat in layer_in.getFeatures():
check = qgs_ana.QgsSingleGeometryCheck()
geom = feat.geometry()
print(check.processGeometry(geom))
# output: None
Metod processGeometry should return empty list if geometry is valid and list of errors if not valid. In my "new" code it return None in all case. I think method didn't working correctly in my code and I don't know why. Because in example link from Taras, method was override without logic, just pass code inside method.
Actually, I need repeat geometry check logic from standart plugin "Geometry Checker" with my additions. And when I learn documentation QGIS, I found QgsGeometryValidator and experimentally use it, but result is not like in "Geometry Checker" plugin. It is looks like: Result is:
Code with differents validator engine give me:
import qgis.analysis as qgs_ana
import qgis.core as qgs_core
validator_meth = qgs_core.Qgis.GeometryValidationEngine(0)
#ValidatorQgisInternal(0)
#validator_meth = qgs_core.Qgis.GeometryValidationEngine(1)
#ValidatorGeos(1)
layer_in = self.qgis_project.mapLayer(layer_id)
for feat in layer_in.getFeatures():
poly_geom = feat.geometry()
poly_eng = qgs_core.QgsGeometry().createGeometryEngine(poly_geom.constGet())
poly_eng.prepareGeometry()
poly_eng.setLogErrors(enabled=True)
validator = qgs_core.QgsGeometryValidator(geometry=poly_geom)
if not poly_eng.isValid():
errors = [[error.what(), error.where()] for error in validator.validateGeometry(geometry=poly_geom, method=validator_meth)]
for e in errors:
print(f"Feature id {feat.id()} Error {e}")
#Output with ValidatorQgisInternal is:
#Feature id 490 Error ['segments 3 and 142 of line 0 intersect at 1.2131e+06, 418062', <QgsPointXY: POINT(1213096.22999999998137355 418062.03000000002793968)>]
#Feature id 490 Error ['segments 4 and 142 of line 0 intersect at 1.2131e+06, 418062', <QgsPointXY: POINT(1213096.22999999998137355 418062.03000000002793968)>]
# If I change validation engine on ValidatorGeos:
# Output with ValidatorGeos is:
#Feature id 1035 Error ['Self-intersection', <QgsPointXY: POINT(1215741.44999999995343387 416008.21000000002095476)>]
#Feature id 1043 Error ['Self-intersection', <QgsPointXY: POINT(1215590.76000000000931323 415891.94000000000232831)>]
#Feature id 1154 Error ['Self-intersection', <QgsPointXY: POINT(1217266.03000000002793968 415655.30999999999767169)>]
#Feature id 1250 Error ['Self-intersection', <QgsPointXY: POINT(1219298.23999999999068677 420871.39000000001396984)>]
Why It is so different result? In first case is ok, 1 error was found but others is not. In second case 0 errors like in "Geometry Checker" plugin was found.
UPD_2:
Ok, I find "mistake" with @CodeBard help. If I code like him I find new one mistake with duplicate node like in "Geometry Checker" plugin.
import qgis.analysis as qgs_ana
import qgis.core as qgs_core
layer_in = self.qgis_project.mapLayer(layer_id)
for feat in layer_in.getFeatures():
poly_geom = feat.geometry()
validator = qgs_core.QgsGeometryValidator(geometry=poly_geom)
errors = [[error.what(), error.where()] for error in validator.validateGeometry(geometry=poly_geom)]
for e in errors:
print(f"Feature id {feat.id()} Error {e}")
#Output with this code:
#Feature id 461 Error ['line 1 contains 2 duplicate nodes starting at vertex 19', <QgsPointXY: POINT(1212358.13999999989755452 418338.15000000002328306)>]
#Feature id 490 Error ['segments 3 and 142 of line 0 intersect at 1.2131e+06, 418062', <QgsPointXY: POINT(1213096.22999999998137355 418062.03000000002793968)>]
#Feature id 490 Error ['segments 4 and 142 of line 0 intersect at 1.2131e+06, 418062', <QgsPointXY: POINT(1213096.22999999998137355 418062.03000000002793968)>]
I still don't understand where is feature with 699 id like in plugin. ¯_(ツ)_/¯
I really want understand how it work and how I can do it correctly! I will be glad for any help.