17
17
QgsFeature , QgsGeometry , QgsSettings , QgsApplication , QgsMemoryProviderUtils , QgsWkbTypes , QgsField , QgsFields , QgsProcessingFeatureSourceDefinition , QgsProcessingContext , QgsProcessingFeedback , QgsCoordinateReferenceSystem , QgsProject , QgsProcessingException
18
18
)
19
19
from processing .core .Processing import Processing
20
+ from processing .core .ProcessingConfig import ProcessingConfig
21
+ from processing .tools import dataobjects
20
22
from processing .gui .AlgorithmExecutor import execute_in_place_run
21
23
from qgis .testing import start_app , unittest
22
24
from qgis .PyQt .QtTest import QSignalSpy
@@ -132,7 +134,8 @@ def test_support_in_place_edit(self):
132
134
Z_ONLY = {t : t .find ('Z' ) > 0 for t in _all_true ().keys ()}
133
135
M_ONLY = {t : t .rfind ('M' ) > 0 for t in _all_true ().keys ()}
134
136
NOT_M = {t : t .rfind ('M' ) < 1 and t != 'NoGeometry' for t in _all_true ().keys ()}
135
- POLYGON_ONLY = {t : t in ('Polygon' , 'MultiPolygon' ) for t in _all_true ().keys ()}
137
+ POLYGON_ONLY = {t : t .find ('Polygon' ) for t in _all_true ().keys ()}
138
+ POLYGON_ONLY_NOT_M_NOT_Z = {t : t in ('Polygon' , 'MultiPolygon' ) for t in _all_true ().keys ()}
136
139
MULTI_ONLY = {t : t .find ('Multi' ) == 0 for t in _all_true ().keys ()}
137
140
SINGLE_ONLY = {t : t .find ('Multi' ) == - 1 for t in _all_true ().keys ()}
138
141
LINESTRING_AND_POLYGON_ONLY = {t : (t .find ('LineString' ) >= 0 or t .find ('Polygon' ) >= 0 ) for t in _all_true ().keys ()}
@@ -149,9 +152,9 @@ def test_support_in_place_edit(self):
149
152
self ._support_inplace_edit_tester ('native:explodelines' , LINESTRING_ONLY )
150
153
self ._support_inplace_edit_tester ('native:extendlines' , LINESTRING_ONLY )
151
154
self ._support_inplace_edit_tester ('native:fixgeometries' , NOT_M )
152
- self ._support_inplace_edit_tester ('native:minimumenclosingcircle' , POLYGON_ONLY )
153
- self ._support_inplace_edit_tester ('native:multiringconstantbuffer' , POLYGON_ONLY )
154
- self ._support_inplace_edit_tester ('native:orientedminimumboundingbox' , POLYGON_ONLY )
155
+ self ._support_inplace_edit_tester ('native:minimumenclosingcircle' , POLYGON_ONLY_NOT_M_NOT_Z )
156
+ self ._support_inplace_edit_tester ('native:multiringconstantbuffer' , POLYGON_ONLY_NOT_M_NOT_Z )
157
+ self ._support_inplace_edit_tester ('native:orientedminimumboundingbox' , POLYGON_ONLY_NOT_M_NOT_Z )
155
158
self ._support_inplace_edit_tester ('qgis:orthogonalize' , LINESTRING_AND_POLYGON_ONLY )
156
159
self ._support_inplace_edit_tester ('native:removeduplicatevertices' , GEOMETRY_ONLY )
157
160
self ._support_inplace_edit_tester ('native:rotatefeatures' , GEOMETRY_ONLY )
@@ -172,6 +175,7 @@ def test_support_in_place_edit(self):
172
175
self ._support_inplace_edit_tester ('native:difference' , GEOMETRY_ONLY )
173
176
self ._support_inplace_edit_tester ('native:dropgeometries' , ALL )
174
177
self ._support_inplace_edit_tester ('native:splitwithlines' , LINESTRING_AND_POLYGON_ONLY )
178
+ self ._support_inplace_edit_tester ('native:buffer' , POLYGON_ONLY_NOT_M_NOT_Z )
175
179
176
180
def _make_compatible_tester (self , feature_wkt , layer_wkb_name , attrs = [1 ]):
177
181
layer = self ._make_layer (layer_wkb_name )
@@ -659,6 +663,71 @@ def test_fix_geometries(self):
659
663
self .assertEqual (wkt1 , 'PolygonZ ((0 0 1, 1 1 2.25, 2 0 4, 0 0 1))' )
660
664
self .assertEqual (wkt2 , 'PolygonZ ((1 1 2.25, 0 2 3, 2 2 1, 1 1 2.25))' )
661
665
666
+ def _test_difference_on_invalid_geometries (self , geom_option ):
667
+ polygon_layer = self ._make_layer ('Polygon' )
668
+ self .assertTrue (polygon_layer .startEditing ())
669
+ f = QgsFeature (polygon_layer .fields ())
670
+ f .setAttributes ([1 ])
671
+ # Flake!
672
+ f .setGeometry (QgsGeometry .fromWkt ('Polygon ((0 0, 2 2, 0 2, 2 0, 0 0))' ))
673
+ self .assertTrue (f .isValid ())
674
+ self .assertTrue (polygon_layer .addFeatures ([f ]))
675
+ polygon_layer .commitChanges ()
676
+ polygon_layer .rollBack ()
677
+ self .assertEqual (polygon_layer .featureCount (), 1 )
678
+
679
+ overlay_layer = self ._make_layer ('Polygon' )
680
+ self .assertTrue (overlay_layer .startEditing ())
681
+ f = QgsFeature (overlay_layer .fields ())
682
+ f .setAttributes ([1 ])
683
+ f .setGeometry (QgsGeometry .fromWkt ('Polygon ((0 0, 2 0, 2 2, 0 2, 0 0))' ))
684
+ self .assertTrue (f .isValid ())
685
+ self .assertTrue (overlay_layer .addFeatures ([f ]))
686
+ overlay_layer .commitChanges ()
687
+ overlay_layer .rollBack ()
688
+ self .assertEqual (overlay_layer .featureCount (), 1 )
689
+
690
+ QgsProject .instance ().addMapLayers ([polygon_layer , overlay_layer ])
691
+
692
+ old_features = [f for f in polygon_layer .getFeatures ()]
693
+
694
+ # 'Ignore features with invalid geometries' = 1
695
+ ProcessingConfig .setSettingValue (ProcessingConfig .FILTER_INVALID_GEOMETRIES , geom_option )
696
+
697
+ feedback = ConsoleFeedBack ()
698
+ context = dataobjects .createContext (feedback )
699
+ context .setProject (QgsProject .instance ())
700
+
701
+ alg = self .registry .createAlgorithmById ('native:difference' )
702
+ self .assertIsNotNone (alg )
703
+
704
+ parameters = {
705
+ 'OVERLAY' : overlay_layer ,
706
+ 'INPUT' : polygon_layer ,
707
+ 'OUTPUT' : ':memory' ,
708
+ }
709
+
710
+ old_features = [f for f in polygon_layer .getFeatures ()]
711
+
712
+ self .assertTrue (polygon_layer .startEditing ())
713
+ polygon_layer .selectAll ()
714
+ ok , _ = execute_in_place_run (
715
+ alg , parameters , context = context , feedback = feedback , raise_exceptions = True )
716
+
717
+ new_features = [f for f in polygon_layer .getFeatures ()]
718
+
719
+ return old_features , new_features
720
+
721
+ def test_difference_on_invalid_geometries (self ):
722
+ """Test #20147 difference deletes invalid geometries"""
723
+
724
+ old_features , new_features = self ._test_difference_on_invalid_geometries (1 )
725
+ self .assertEqual (len (new_features ), 1 )
726
+ old_features , new_features = self ._test_difference_on_invalid_geometries (0 )
727
+ self .assertEqual (len (new_features ), 1 )
728
+ old_features , new_features = self ._test_difference_on_invalid_geometries (2 )
729
+ self .assertEqual (len (new_features ), 1 )
730
+
662
731
663
732
if __name__ == '__main__' :
664
733
unittest .main ()
0 commit comments