diff --git a/python/PyQt6/core/auto_additions/qgsabstractgeometry.py b/python/PyQt6/core/auto_additions/qgsabstractgeometry.py index 960b7e8bc9af..597fec508056 100644 --- a/python/PyQt6/core/auto_additions/qgsabstractgeometry.py +++ b/python/PyQt6/core/auto_additions/qgsabstractgeometry.py @@ -19,7 +19,7 @@ def _force_int(v): return int(v.value) if isinstance(v, Enum) else v QgsAbstractGeometry.WkbFlag.__or__ = lambda flag1, flag2: QgsAbstractGeometry.WkbFlag(_force_int(flag1) | _force_int(flag2)) try: QgsAbstractGeometry.__virtual_methods__ = ['compareTo', 'boundingBox', 'nCoordinates', 'closestSegment', 'length', 'perimeter', 'area', 'area3D', 'centroid', 'isEmpty', 'hasCurvedSegments', 'boundingBoxIntersects', 'segmentize', 'convertTo', 'hasChildGeometries', 'childCount', 'childGeometry', 'childPoint', 'calculateBoundingBox', 'calculateBoundingBox3D', 'clearCache'] - QgsAbstractGeometry.__abstract_methods__ = ['operator==', 'operator!=', 'fuzzyEqual', 'fuzzyDistanceEqual', 'clone', 'clear', 'boundingBox3D', 'dimension', 'geometryType', 'boundary', 'normalize', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'transform', 'draw', 'asQPainterPath', 'vertexNumberFromVertexId', 'nextVertex', 'adjacentVertices', 'coordinateSequence', 'vertexAt', 'closestSegment', 'insertVertex', 'moveVertex', 'deleteVertex', 'segmentLength', 'toCurveType', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'isValid', 'createEmptyWithSameType', 'compareToSameClass'] + QgsAbstractGeometry.__abstract_methods__ = ['operator==', 'operator!=', 'fuzzyEqual', 'fuzzyDistanceEqual', 'clone', 'clear', 'boundingBox3D', 'dimension', 'geometryType', 'boundary', 'normalize', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'transform', 'draw', 'asQPainterPath', 'vertexNumberFromVertexId', 'nextVertex', 'adjacentVertices', 'coordinateSequence', 'vertexAt', 'closestSegment', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'segmentLength', 'toCurveType', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'isValid', 'createEmptyWithSameType', 'compareToSameClass'] QgsAbstractGeometry.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgscircularstring.py b/python/PyQt6/core/auto_additions/qgscircularstring.py index 0dc84d74744f..b2d05f8ed9ca 100644 --- a/python/PyQt6/core/auto_additions/qgscircularstring.py +++ b/python/PyQt6/core/auto_additions/qgscircularstring.py @@ -1,7 +1,7 @@ # The following has been generated automatically from src/core/geometry/qgscircularstring.h try: QgsCircularString.fromTwoPointsAndCenter = staticmethod(QgsCircularString.fromTwoPointsAndCenter) - QgsCircularString.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'isEmpty', 'isValid', 'numPoints', 'indexOf', 'points', 'length', 'startPoint', 'endPoint', 'curveToLine', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'closestSegment', 'pointAt', 'sumUpArea', 'sumUpArea3D', 'hasCurvedSegments', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'xAt', 'yAt', 'zAt', 'mAt', 'scroll', 'createEmptyWithSameType', 'compareToSameClass', 'calculateBoundingBox3D'] + QgsCircularString.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'isEmpty', 'isValid', 'numPoints', 'indexOf', 'points', 'length', 'startPoint', 'endPoint', 'curveToLine', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'closestSegment', 'pointAt', 'sumUpArea', 'sumUpArea3D', 'hasCurvedSegments', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'xAt', 'yAt', 'zAt', 'mAt', 'scroll', 'createEmptyWithSameType', 'compareToSameClass', 'calculateBoundingBox3D'] QgsCircularString.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgscompoundcurve.py b/python/PyQt6/core/auto_additions/qgscompoundcurve.py index f62c79e10382..22d9d372cca4 100644 --- a/python/PyQt6/core/auto_additions/qgscompoundcurve.py +++ b/python/PyQt6/core/auto_additions/qgscompoundcurve.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/geometry/qgscompoundcurve.h try: - QgsCompoundCurve.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'length', 'startPoint', 'endPoint', 'points', 'numPoints', 'isEmpty', 'isValid', 'indexOf', 'curveToLine', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'simplifiedTypeRef', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'closestSegment', 'pointAt', 'sumUpArea', 'sumUpArea3D', 'hasCurvedSegments', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'xAt', 'yAt', 'zAt', 'mAt', 'scroll', 'createEmptyWithSameType', 'compareToSameClass', 'calculateBoundingBox3D'] + QgsCompoundCurve.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'length', 'startPoint', 'endPoint', 'points', 'numPoints', 'isEmpty', 'isValid', 'indexOf', 'curveToLine', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'simplifiedTypeRef', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'closestSegment', 'pointAt', 'sumUpArea', 'sumUpArea3D', 'hasCurvedSegments', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'xAt', 'yAt', 'zAt', 'mAt', 'scroll', 'createEmptyWithSameType', 'compareToSameClass', 'calculateBoundingBox3D'] QgsCompoundCurve.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgscurvepolygon.py b/python/PyQt6/core/auto_additions/qgscurvepolygon.py index 8a2a4541dd97..94fd064501dd 100644 --- a/python/PyQt6/core/auto_additions/qgscurvepolygon.py +++ b/python/PyQt6/core/auto_additions/qgscurvepolygon.py @@ -1,7 +1,7 @@ # The following has been generated automatically from src/core/geometry/qgscurvepolygon.h try: QgsCurvePolygon.__virtual_methods__ = ['surfaceToPolygon', 'toPolygon', 'setExteriorRing', 'addInteriorRing'] - QgsCurvePolygon.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'area', 'area3D', 'perimeter', 'boundary', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'asQPainterPath', 'draw', 'transform', 'insertVertex', 'moveVertex', 'deleteVertex', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'isEmpty', 'closestSegment', 'nextVertex', 'adjacentVertices', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'segmentLength', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D'] + QgsCurvePolygon.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'area', 'area3D', 'perimeter', 'boundary', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'asQPainterPath', 'draw', 'transform', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'isEmpty', 'closestSegment', 'nextVertex', 'adjacentVertices', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'segmentLength', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D'] QgsCurvePolygon.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgsgeometrycollection.py b/python/PyQt6/core/auto_additions/qgsgeometrycollection.py index 5f412dc6ac53..bf6b93af20a9 100644 --- a/python/PyQt6/core/auto_additions/qgsgeometrycollection.py +++ b/python/PyQt6/core/auto_additions/qgsgeometrycollection.py @@ -1,7 +1,7 @@ # The following has been generated automatically from src/core/geometry/qgsgeometrycollection.h try: QgsGeometryCollection.__virtual_methods__ = ['addGeometry', 'addGeometries', 'insertGeometry', 'removeGeometry', 'wktOmitChildType'] - QgsGeometryCollection.__overridden_methods__ = ['operator==', 'operator!=', 'fuzzyEqual', 'fuzzyDistanceEqual', 'clone', 'isEmpty', 'dimension', 'geometryType', 'clear', 'snappedToGrid', 'removeDuplicateNodes', 'boundary', 'adjacentVertices', 'vertexNumberFromVertexId', 'boundingBoxIntersects', 'normalize', 'transform', 'draw', 'asQPainterPath', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'boundingBox3D', 'coordinateSequence', 'nCoordinates', 'closestSegment', 'nextVertex', 'insertVertex', 'moveVertex', 'deleteVertex', 'length', 'area', 'area3D', 'perimeter', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'segmentLength', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'isValid', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'simplifiedTypeRef', 'simplifyByDistance', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D', 'clearCache'] + QgsGeometryCollection.__overridden_methods__ = ['operator==', 'operator!=', 'fuzzyEqual', 'fuzzyDistanceEqual', 'clone', 'isEmpty', 'dimension', 'geometryType', 'clear', 'snappedToGrid', 'removeDuplicateNodes', 'boundary', 'adjacentVertices', 'vertexNumberFromVertexId', 'boundingBoxIntersects', 'normalize', 'transform', 'draw', 'asQPainterPath', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'boundingBox3D', 'coordinateSequence', 'nCoordinates', 'closestSegment', 'nextVertex', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'length', 'area', 'area3D', 'perimeter', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'segmentLength', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'isValid', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'simplifiedTypeRef', 'simplifyByDistance', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D', 'clearCache'] QgsGeometryCollection.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgslinestring.py b/python/PyQt6/core/auto_additions/qgslinestring.py index eec33b9b147e..31e1550b5b4a 100644 --- a/python/PyQt6/core/auto_additions/qgslinestring.py +++ b/python/PyQt6/core/auto_additions/qgslinestring.py @@ -2,7 +2,7 @@ try: QgsLineString.fromBezierCurve = staticmethod(QgsLineString.fromBezierCurve) QgsLineString.fromQPolygonF = staticmethod(QgsLineString.fromQPolygonF) - QgsLineString.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'xAt', 'yAt', 'zAt', 'mAt', 'toCurveType', 'geometryType', 'dimension', 'clone', 'clear', 'isEmpty', 'indexOf', 'isValid', 'snappedToGrid', 'removeDuplicateNodes', 'isClosed', 'isClosed2D', 'boundingBoxIntersects', 'asQPolygonF', 'simplifyByDistance', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'length', 'startPoint', 'endPoint', 'curveToLine', 'numPoints', 'nCoordinates', 'points', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'reversed', 'interpolatePoint', 'curveSubstring', 'closestSegment', 'pointAt', 'centroid', 'sumUpArea', 'sumUpArea3D', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'convertTo', 'scroll', 'createEmptyWithSameType', 'calculateBoundingBox3D', 'compareToSameClass'] + QgsLineString.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'xAt', 'yAt', 'zAt', 'mAt', 'toCurveType', 'geometryType', 'dimension', 'clone', 'clear', 'isEmpty', 'indexOf', 'isValid', 'snappedToGrid', 'removeDuplicateNodes', 'isClosed', 'isClosed2D', 'boundingBoxIntersects', 'asQPolygonF', 'simplifyByDistance', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'length', 'startPoint', 'endPoint', 'curveToLine', 'numPoints', 'nCoordinates', 'points', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'closestSegment', 'pointAt', 'centroid', 'sumUpArea', 'sumUpArea3D', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'convertTo', 'scroll', 'createEmptyWithSameType', 'calculateBoundingBox3D', 'compareToSameClass'] QgsLineString.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgspoint.py b/python/PyQt6/core/auto_additions/qgspoint.py index 977d8db85d72..73226ec88f1f 100644 --- a/python/PyQt6/core/auto_additions/qgspoint.py +++ b/python/PyQt6/core/auto_additions/qgspoint.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/geometry/qgspoint.h try: - QgsPoint.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'normalize', 'isEmpty', 'boundingBox3D', 'geometryType', 'dimension', 'clone', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'draw', 'asQPainterPath', 'transform', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'boundary', 'isValid', 'insertVertex', 'moveVertex', 'deleteVertex', 'closestSegment', 'nextVertex', 'adjacentVertices', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'toCurveType', 'segmentLength', 'boundingBoxIntersects', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'convertTo', 'createEmptyWithSameType', 'compareToSameClass', 'childCount', 'childPoint'] + QgsPoint.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'normalize', 'isEmpty', 'boundingBox3D', 'geometryType', 'dimension', 'clone', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'draw', 'asQPainterPath', 'transform', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'boundary', 'isValid', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'closestSegment', 'nextVertex', 'adjacentVertices', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'toCurveType', 'segmentLength', 'boundingBoxIntersects', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'convertTo', 'createEmptyWithSameType', 'compareToSameClass', 'childCount', 'childPoint'] QgsPoint.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgspolyhedralsurface.py b/python/PyQt6/core/auto_additions/qgspolyhedralsurface.py index 32dec7a27334..940a24ff42f7 100644 --- a/python/PyQt6/core/auto_additions/qgspolyhedralsurface.py +++ b/python/PyQt6/core/auto_additions/qgspolyhedralsurface.py @@ -1,7 +1,7 @@ # The following has been generated automatically from src/core/geometry/qgspolyhedralsurface.h try: QgsPolyhedralSurface.__virtual_methods__ = ['setPatches', 'addPatch'] - QgsPolyhedralSurface.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'isValid', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'area', 'area3D', 'perimeter', 'boundary', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'asQPainterPath', 'draw', 'transform', 'insertVertex', 'moveVertex', 'deleteVertex', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'isEmpty', 'closestSegment', 'nextVertex', 'adjacentVertices', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'segmentLength', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D'] + QgsPolyhedralSurface.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'isValid', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'area', 'area3D', 'perimeter', 'boundary', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'asQPainterPath', 'draw', 'transform', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'isEmpty', 'closestSegment', 'nextVertex', 'adjacentVertices', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'segmentLength', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D'] QgsPolyhedralSurface.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgstriangle.py b/python/PyQt6/core/auto_additions/qgstriangle.py index 7451280fc4cf..9c9c864f2b09 100644 --- a/python/PyQt6/core/auto_additions/qgstriangle.py +++ b/python/PyQt6/core/auto_additions/qgstriangle.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/geometry/qgstriangle.h try: - QgsTriangle.__overridden_methods__ = ['operator==', 'operator!=', 'geometryType', 'clone', 'clear', 'fromWkb', 'fromWkt', 'asGml3', 'surfaceToPolygon', 'toCurveType', 'addInteriorRing', 'deleteVertex', 'insertVertex', 'moveVertex', 'setExteriorRing', 'boundary', 'vertexAt', 'createEmptyWithSameType'] + QgsTriangle.__overridden_methods__ = ['operator==', 'operator!=', 'geometryType', 'clone', 'clear', 'fromWkb', 'fromWkt', 'asGml3', 'surfaceToPolygon', 'toCurveType', 'addInteriorRing', 'deleteVertex', 'deleteVertices', 'insertVertex', 'moveVertex', 'setExteriorRing', 'boundary', 'vertexAt', 'createEmptyWithSameType'] QgsTriangle.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_additions/qgstriangulatedsurface.py b/python/PyQt6/core/auto_additions/qgstriangulatedsurface.py index 72420c0220e4..2b129faf6550 100644 --- a/python/PyQt6/core/auto_additions/qgstriangulatedsurface.py +++ b/python/PyQt6/core/auto_additions/qgstriangulatedsurface.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/geometry/qgstriangulatedsurface.h try: - QgsTriangulatedSurface.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'clone', 'clear', 'fromWkb', 'fromWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'snappedToGrid', 'insertVertex', 'deleteVertex', 'addPatch', 'createEmptyWithSameType', 'compareToSameClass'] + QgsTriangulatedSurface.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'clone', 'clear', 'fromWkb', 'fromWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'snappedToGrid', 'insertVertex', 'deleteVertex', 'deleteVertices', 'addPatch', 'createEmptyWithSameType', 'compareToSameClass'] QgsTriangulatedSurface.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/PyQt6/core/auto_generated/geometry/qgsabstractgeometry.sip.in b/python/PyQt6/core/auto_generated/geometry/qgsabstractgeometry.sip.in index c756a2b42c48..d9b82509e1df 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgsabstractgeometry.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgsabstractgeometry.sip.in @@ -517,6 +517,22 @@ Deletes a vertex within the geometry .. seealso:: :py:func:`insertVertex` .. seealso:: :py:func:`moveVertex` +%End + + virtual bool deleteVertices( const QList &positions ) = 0; +%Docstring +Deletes vertices within the geometry If a vertex cannot be deleted, the +method returns ``False`` and the geometry may be left in a partially +modified and invalid state + +:param positions: list of vertex ids for vertices to delete + +:return: ``True`` if all requested vertices were deleted, ``False`` if a + single vertex could not be deleted + +.. seealso:: :py:func:`deleteVertex` + +.. versionadded:: 4.0 %End virtual double length() const; diff --git a/python/PyQt6/core/auto_generated/geometry/qgscircularstring.sip.in b/python/PyQt6/core/auto_generated/geometry/qgscircularstring.sip.in index 1c821447b207..ea0cf9128a57 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgscircularstring.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgscircularstring.sip.in @@ -175,6 +175,8 @@ circular string. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/, QgsVertexId &vertexAfter /Out/, int *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const; virtual bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const; diff --git a/python/PyQt6/core/auto_generated/geometry/qgscompoundcurve.sip.in b/python/PyQt6/core/auto_generated/geometry/qgscompoundcurve.sip.in index d74f5b8fcf54..0f5173a376c6 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgscompoundcurve.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgscompoundcurve.sip.in @@ -167,6 +167,8 @@ Converts the vertex at the given position from/to circular virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/, QgsVertexId &vertexAfter /Out/, int *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const; virtual bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const; diff --git a/python/PyQt6/core/auto_generated/geometry/qgscurvepolygon.sip.in b/python/PyQt6/core/auto_generated/geometry/qgscurvepolygon.sip.in index 29ffdc078fef..ba9cd97281f2 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgscurvepolygon.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgscurvepolygon.sip.in @@ -267,6 +267,8 @@ This convention matches the OGC Simple Features specification. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual QgsCoordinateSequence coordinateSequence() const; diff --git a/python/PyQt6/core/auto_generated/geometry/qgsgeometry.sip.in b/python/PyQt6/core/auto_generated/geometry/qgsgeometry.sip.in index cfa76dfc0e9a..a419c81841d7 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgsgeometry.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgsgeometry.sip.in @@ -834,6 +834,26 @@ LineString with less than 2 vertices), the geometry is cleared instead. vertex was successfully deleted or the geometry was cleared. %End + bool deleteVertices( const QList &atVertices ); +%Docstring +Deletes vertices at the given positions (first number is index 0) + +For Point geometries, this clears the geometry. For MultiPoint +geometries, this removes point geometries at the specified indices. For +other geometry types, this removes the vertices at the specified +indices. If after removal of the vertices the geometry would become +invalid (e.g. a LineString with less than 2 vertices), the geometry is +cleared instead. + +:return: ``False`` if any of the given atVertices does not correspond to + a valid vertex on this geometry or if any vertices fail to be + deleted + +.. seealso:: :py:func:`deleteVertex` + +.. versionadded:: 4.0 +%End + bool toggleCircularAtVertex( int atVertex ); %Docstring Converts the vertex at the given position from/to circular diff --git a/python/PyQt6/core/auto_generated/geometry/qgsgeometrycollection.sip.in b/python/PyQt6/core/auto_generated/geometry/qgsgeometrycollection.sip.in index 4f96cbf37f75..b2e7b0431c71 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgsgeometrycollection.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgsgeometrycollection.sip.in @@ -223,6 +223,8 @@ ownership to the caller. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual double length() const /HoldGIL/; diff --git a/python/PyQt6/core/auto_generated/geometry/qgslinestring.sip.in b/python/PyQt6/core/auto_generated/geometry/qgslinestring.sip.in index ec5ea3d1aacd..9cf461dcaf13 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgslinestring.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgslinestring.sip.in @@ -728,6 +728,8 @@ approximation of the curve. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual QgsLineString *reversed() const /Factory/; diff --git a/python/PyQt6/core/auto_generated/geometry/qgspoint.sip.in b/python/PyQt6/core/auto_generated/geometry/qgspoint.sip.in index 64f9e6059800..04553fb94861 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgspoint.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgspoint.sip.in @@ -419,6 +419,8 @@ Example virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/, QgsVertexId &vertexAfter /Out/, int *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const; diff --git a/python/PyQt6/core/auto_generated/geometry/qgspolyhedralsurface.sip.in b/python/PyQt6/core/auto_generated/geometry/qgspolyhedralsurface.sip.in index 5f12b2fcc4ea..2f7fd7980eb2 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgspolyhedralsurface.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgspolyhedralsurface.sip.in @@ -170,6 +170,8 @@ deleted. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual QgsCoordinateSequence coordinateSequence() const; diff --git a/python/PyQt6/core/auto_generated/geometry/qgstriangle.sip.in b/python/PyQt6/core/auto_generated/geometry/qgstriangle.sip.in index 84a7805a0960..f114e451c3d7 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgstriangle.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgstriangle.sip.in @@ -92,6 +92,8 @@ triangle. Inherited method not used. You cannot delete or insert a vertex directly. Returns always ``False``. %End + virtual bool deleteVertices( const QList &positions ); + virtual bool insertVertex( QgsVertexId position, const QgsPoint &vertex ); %Docstring diff --git a/python/PyQt6/core/auto_generated/geometry/qgstriangulatedsurface.sip.in b/python/PyQt6/core/auto_generated/geometry/qgstriangulatedsurface.sip.in index 6969c175aeff..a6f0c726d683 100644 --- a/python/PyQt6/core/auto_generated/geometry/qgstriangulatedsurface.sip.in +++ b/python/PyQt6/core/auto_generated/geometry/qgstriangulatedsurface.sip.in @@ -68,6 +68,8 @@ only of triangle patches. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + void setTriangles( const QVector &triangles /Transfer/ ); %Docstring diff --git a/python/core/auto_additions/qgsabstractgeometry.py b/python/core/auto_additions/qgsabstractgeometry.py index fcc9e35d1876..601167a05580 100644 --- a/python/core/auto_additions/qgsabstractgeometry.py +++ b/python/core/auto_additions/qgsabstractgeometry.py @@ -2,7 +2,7 @@ QgsAbstractGeometry.SegmentationToleranceType.baseClass = QgsAbstractGeometry try: QgsAbstractGeometry.__virtual_methods__ = ['compareTo', 'boundingBox', 'nCoordinates', 'closestSegment', 'length', 'perimeter', 'area', 'area3D', 'centroid', 'isEmpty', 'hasCurvedSegments', 'boundingBoxIntersects', 'segmentize', 'convertTo', 'hasChildGeometries', 'childCount', 'childGeometry', 'childPoint', 'calculateBoundingBox', 'calculateBoundingBox3D', 'clearCache'] - QgsAbstractGeometry.__abstract_methods__ = ['operator==', 'operator!=', 'fuzzyEqual', 'fuzzyDistanceEqual', 'clone', 'clear', 'boundingBox3D', 'dimension', 'geometryType', 'boundary', 'normalize', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'transform', 'draw', 'asQPainterPath', 'vertexNumberFromVertexId', 'nextVertex', 'adjacentVertices', 'coordinateSequence', 'vertexAt', 'closestSegment', 'insertVertex', 'moveVertex', 'deleteVertex', 'segmentLength', 'toCurveType', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'isValid', 'createEmptyWithSameType', 'compareToSameClass'] + QgsAbstractGeometry.__abstract_methods__ = ['operator==', 'operator!=', 'fuzzyEqual', 'fuzzyDistanceEqual', 'clone', 'clear', 'boundingBox3D', 'dimension', 'geometryType', 'boundary', 'normalize', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'transform', 'draw', 'asQPainterPath', 'vertexNumberFromVertexId', 'nextVertex', 'adjacentVertices', 'coordinateSequence', 'vertexAt', 'closestSegment', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'segmentLength', 'toCurveType', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'isValid', 'createEmptyWithSameType', 'compareToSameClass'] QgsAbstractGeometry.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgscircularstring.py b/python/core/auto_additions/qgscircularstring.py index 0dc84d74744f..b2d05f8ed9ca 100644 --- a/python/core/auto_additions/qgscircularstring.py +++ b/python/core/auto_additions/qgscircularstring.py @@ -1,7 +1,7 @@ # The following has been generated automatically from src/core/geometry/qgscircularstring.h try: QgsCircularString.fromTwoPointsAndCenter = staticmethod(QgsCircularString.fromTwoPointsAndCenter) - QgsCircularString.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'isEmpty', 'isValid', 'numPoints', 'indexOf', 'points', 'length', 'startPoint', 'endPoint', 'curveToLine', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'closestSegment', 'pointAt', 'sumUpArea', 'sumUpArea3D', 'hasCurvedSegments', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'xAt', 'yAt', 'zAt', 'mAt', 'scroll', 'createEmptyWithSameType', 'compareToSameClass', 'calculateBoundingBox3D'] + QgsCircularString.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'isEmpty', 'isValid', 'numPoints', 'indexOf', 'points', 'length', 'startPoint', 'endPoint', 'curveToLine', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'closestSegment', 'pointAt', 'sumUpArea', 'sumUpArea3D', 'hasCurvedSegments', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'xAt', 'yAt', 'zAt', 'mAt', 'scroll', 'createEmptyWithSameType', 'compareToSameClass', 'calculateBoundingBox3D'] QgsCircularString.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgscompoundcurve.py b/python/core/auto_additions/qgscompoundcurve.py index f62c79e10382..22d9d372cca4 100644 --- a/python/core/auto_additions/qgscompoundcurve.py +++ b/python/core/auto_additions/qgscompoundcurve.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/geometry/qgscompoundcurve.h try: - QgsCompoundCurve.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'length', 'startPoint', 'endPoint', 'points', 'numPoints', 'isEmpty', 'isValid', 'indexOf', 'curveToLine', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'simplifiedTypeRef', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'closestSegment', 'pointAt', 'sumUpArea', 'sumUpArea3D', 'hasCurvedSegments', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'xAt', 'yAt', 'zAt', 'mAt', 'scroll', 'createEmptyWithSameType', 'compareToSameClass', 'calculateBoundingBox3D'] + QgsCompoundCurve.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'length', 'startPoint', 'endPoint', 'points', 'numPoints', 'isEmpty', 'isValid', 'indexOf', 'curveToLine', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'simplifiedTypeRef', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'closestSegment', 'pointAt', 'sumUpArea', 'sumUpArea3D', 'hasCurvedSegments', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'xAt', 'yAt', 'zAt', 'mAt', 'scroll', 'createEmptyWithSameType', 'compareToSameClass', 'calculateBoundingBox3D'] QgsCompoundCurve.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgscurvepolygon.py b/python/core/auto_additions/qgscurvepolygon.py index 8a2a4541dd97..94fd064501dd 100644 --- a/python/core/auto_additions/qgscurvepolygon.py +++ b/python/core/auto_additions/qgscurvepolygon.py @@ -1,7 +1,7 @@ # The following has been generated automatically from src/core/geometry/qgscurvepolygon.h try: QgsCurvePolygon.__virtual_methods__ = ['surfaceToPolygon', 'toPolygon', 'setExteriorRing', 'addInteriorRing'] - QgsCurvePolygon.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'area', 'area3D', 'perimeter', 'boundary', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'asQPainterPath', 'draw', 'transform', 'insertVertex', 'moveVertex', 'deleteVertex', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'isEmpty', 'closestSegment', 'nextVertex', 'adjacentVertices', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'segmentLength', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D'] + QgsCurvePolygon.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'area', 'area3D', 'perimeter', 'boundary', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'asQPainterPath', 'draw', 'transform', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'isEmpty', 'closestSegment', 'nextVertex', 'adjacentVertices', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'segmentLength', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D'] QgsCurvePolygon.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgsgeometrycollection.py b/python/core/auto_additions/qgsgeometrycollection.py index 5f412dc6ac53..bf6b93af20a9 100644 --- a/python/core/auto_additions/qgsgeometrycollection.py +++ b/python/core/auto_additions/qgsgeometrycollection.py @@ -1,7 +1,7 @@ # The following has been generated automatically from src/core/geometry/qgsgeometrycollection.h try: QgsGeometryCollection.__virtual_methods__ = ['addGeometry', 'addGeometries', 'insertGeometry', 'removeGeometry', 'wktOmitChildType'] - QgsGeometryCollection.__overridden_methods__ = ['operator==', 'operator!=', 'fuzzyEqual', 'fuzzyDistanceEqual', 'clone', 'isEmpty', 'dimension', 'geometryType', 'clear', 'snappedToGrid', 'removeDuplicateNodes', 'boundary', 'adjacentVertices', 'vertexNumberFromVertexId', 'boundingBoxIntersects', 'normalize', 'transform', 'draw', 'asQPainterPath', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'boundingBox3D', 'coordinateSequence', 'nCoordinates', 'closestSegment', 'nextVertex', 'insertVertex', 'moveVertex', 'deleteVertex', 'length', 'area', 'area3D', 'perimeter', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'segmentLength', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'isValid', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'simplifiedTypeRef', 'simplifyByDistance', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D', 'clearCache'] + QgsGeometryCollection.__overridden_methods__ = ['operator==', 'operator!=', 'fuzzyEqual', 'fuzzyDistanceEqual', 'clone', 'isEmpty', 'dimension', 'geometryType', 'clear', 'snappedToGrid', 'removeDuplicateNodes', 'boundary', 'adjacentVertices', 'vertexNumberFromVertexId', 'boundingBoxIntersects', 'normalize', 'transform', 'draw', 'asQPainterPath', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'boundingBox3D', 'coordinateSequence', 'nCoordinates', 'closestSegment', 'nextVertex', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'length', 'area', 'area3D', 'perimeter', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'segmentLength', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'isValid', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'simplifiedTypeRef', 'simplifyByDistance', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D', 'clearCache'] QgsGeometryCollection.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgslinestring.py b/python/core/auto_additions/qgslinestring.py index eec33b9b147e..31e1550b5b4a 100644 --- a/python/core/auto_additions/qgslinestring.py +++ b/python/core/auto_additions/qgslinestring.py @@ -2,7 +2,7 @@ try: QgsLineString.fromBezierCurve = staticmethod(QgsLineString.fromBezierCurve) QgsLineString.fromQPolygonF = staticmethod(QgsLineString.fromQPolygonF) - QgsLineString.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'xAt', 'yAt', 'zAt', 'mAt', 'toCurveType', 'geometryType', 'dimension', 'clone', 'clear', 'isEmpty', 'indexOf', 'isValid', 'snappedToGrid', 'removeDuplicateNodes', 'isClosed', 'isClosed2D', 'boundingBoxIntersects', 'asQPolygonF', 'simplifyByDistance', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'length', 'startPoint', 'endPoint', 'curveToLine', 'numPoints', 'nCoordinates', 'points', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'reversed', 'interpolatePoint', 'curveSubstring', 'closestSegment', 'pointAt', 'centroid', 'sumUpArea', 'sumUpArea3D', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'convertTo', 'scroll', 'createEmptyWithSameType', 'calculateBoundingBox3D', 'compareToSameClass'] + QgsLineString.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'equals', 'xAt', 'yAt', 'zAt', 'mAt', 'toCurveType', 'geometryType', 'dimension', 'clone', 'clear', 'isEmpty', 'indexOf', 'isValid', 'snappedToGrid', 'removeDuplicateNodes', 'isClosed', 'isClosed2D', 'boundingBoxIntersects', 'asQPolygonF', 'simplifyByDistance', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'length', 'startPoint', 'endPoint', 'curveToLine', 'numPoints', 'nCoordinates', 'points', 'draw', 'transform', 'addToPainterPath', 'drawAsPolygon', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'reversed', 'interpolatePoint', 'curveSubstring', 'closestSegment', 'pointAt', 'centroid', 'sumUpArea', 'sumUpArea3D', 'vertexAngle', 'segmentLength', 'distanceBetweenVertices', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'convertTo', 'scroll', 'createEmptyWithSameType', 'calculateBoundingBox3D', 'compareToSameClass'] QgsLineString.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgspoint.py b/python/core/auto_additions/qgspoint.py index 977d8db85d72..73226ec88f1f 100644 --- a/python/core/auto_additions/qgspoint.py +++ b/python/core/auto_additions/qgspoint.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/geometry/qgspoint.h try: - QgsPoint.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'normalize', 'isEmpty', 'boundingBox3D', 'geometryType', 'dimension', 'clone', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'draw', 'asQPainterPath', 'transform', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'boundary', 'isValid', 'insertVertex', 'moveVertex', 'deleteVertex', 'closestSegment', 'nextVertex', 'adjacentVertices', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'toCurveType', 'segmentLength', 'boundingBoxIntersects', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'convertTo', 'createEmptyWithSameType', 'compareToSameClass', 'childCount', 'childPoint'] + QgsPoint.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'normalize', 'isEmpty', 'boundingBox3D', 'geometryType', 'dimension', 'clone', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'clear', 'fromWkb', 'fromWkt', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'draw', 'asQPainterPath', 'transform', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'boundary', 'isValid', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'closestSegment', 'nextVertex', 'adjacentVertices', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'toCurveType', 'segmentLength', 'boundingBoxIntersects', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'convertTo', 'createEmptyWithSameType', 'compareToSameClass', 'childCount', 'childPoint'] QgsPoint.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgspolyhedralsurface.py b/python/core/auto_additions/qgspolyhedralsurface.py index 32dec7a27334..940a24ff42f7 100644 --- a/python/core/auto_additions/qgspolyhedralsurface.py +++ b/python/core/auto_additions/qgspolyhedralsurface.py @@ -1,7 +1,7 @@ # The following has been generated automatically from src/core/geometry/qgspolyhedralsurface.h try: QgsPolyhedralSurface.__virtual_methods__ = ['setPatches', 'addPatch'] - QgsPolyhedralSurface.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'isValid', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'area', 'area3D', 'perimeter', 'boundary', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'asQPainterPath', 'draw', 'transform', 'insertVertex', 'moveVertex', 'deleteVertex', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'isEmpty', 'closestSegment', 'nextVertex', 'adjacentVertices', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'segmentLength', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D'] + QgsPolyhedralSurface.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'dimension', 'clone', 'clear', 'fromWkb', 'fromWkt', 'isValid', 'wkbSize', 'asWkb', 'asWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'area', 'area3D', 'perimeter', 'boundary', 'snappedToGrid', 'simplifyByDistance', 'removeDuplicateNodes', 'boundingBoxIntersects', 'asQPainterPath', 'draw', 'transform', 'insertVertex', 'moveVertex', 'deleteVertex', 'deleteVertices', 'coordinateSequence', 'nCoordinates', 'vertexNumberFromVertexId', 'isEmpty', 'closestSegment', 'nextVertex', 'adjacentVertices', 'hasCurvedSegments', 'segmentize', 'vertexAngle', 'vertexCount', 'ringCount', 'partCount', 'vertexAt', 'segmentLength', 'addZValue', 'addMValue', 'dropZValue', 'dropMValue', 'swapXy', 'toCurveType', 'createEmptyWithSameType', 'childCount', 'childGeometry', 'compareToSameClass', 'calculateBoundingBox3D'] QgsPolyhedralSurface.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgstriangle.py b/python/core/auto_additions/qgstriangle.py index 7451280fc4cf..9c9c864f2b09 100644 --- a/python/core/auto_additions/qgstriangle.py +++ b/python/core/auto_additions/qgstriangle.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/geometry/qgstriangle.h try: - QgsTriangle.__overridden_methods__ = ['operator==', 'operator!=', 'geometryType', 'clone', 'clear', 'fromWkb', 'fromWkt', 'asGml3', 'surfaceToPolygon', 'toCurveType', 'addInteriorRing', 'deleteVertex', 'insertVertex', 'moveVertex', 'setExteriorRing', 'boundary', 'vertexAt', 'createEmptyWithSameType'] + QgsTriangle.__overridden_methods__ = ['operator==', 'operator!=', 'geometryType', 'clone', 'clear', 'fromWkb', 'fromWkt', 'asGml3', 'surfaceToPolygon', 'toCurveType', 'addInteriorRing', 'deleteVertex', 'deleteVertices', 'insertVertex', 'moveVertex', 'setExteriorRing', 'boundary', 'vertexAt', 'createEmptyWithSameType'] QgsTriangle.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_additions/qgstriangulatedsurface.py b/python/core/auto_additions/qgstriangulatedsurface.py index 72420c0220e4..2b129faf6550 100644 --- a/python/core/auto_additions/qgstriangulatedsurface.py +++ b/python/core/auto_additions/qgstriangulatedsurface.py @@ -1,6 +1,6 @@ # The following has been generated automatically from src/core/geometry/qgstriangulatedsurface.h try: - QgsTriangulatedSurface.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'clone', 'clear', 'fromWkb', 'fromWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'snappedToGrid', 'insertVertex', 'deleteVertex', 'addPatch', 'createEmptyWithSameType', 'compareToSameClass'] + QgsTriangulatedSurface.__overridden_methods__ = ['fuzzyEqual', 'fuzzyDistanceEqual', 'operator==', 'operator!=', 'geometryType', 'clone', 'clear', 'fromWkb', 'fromWkt', 'asGml2', 'asGml3', 'asKml', 'normalize', 'snappedToGrid', 'insertVertex', 'deleteVertex', 'deleteVertices', 'addPatch', 'createEmptyWithSameType', 'compareToSameClass'] QgsTriangulatedSurface.__group__ = ['geometry'] except (NameError, AttributeError): pass diff --git a/python/core/auto_generated/geometry/qgsabstractgeometry.sip.in b/python/core/auto_generated/geometry/qgsabstractgeometry.sip.in index 542cb131c411..edb1bd9b9b00 100644 --- a/python/core/auto_generated/geometry/qgsabstractgeometry.sip.in +++ b/python/core/auto_generated/geometry/qgsabstractgeometry.sip.in @@ -517,6 +517,22 @@ Deletes a vertex within the geometry .. seealso:: :py:func:`insertVertex` .. seealso:: :py:func:`moveVertex` +%End + + virtual bool deleteVertices( const QList &positions ) = 0; +%Docstring +Deletes vertices within the geometry If a vertex cannot be deleted, the +method returns ``False`` and the geometry may be left in a partially +modified and invalid state + +:param positions: list of vertex ids for vertices to delete + +:return: ``True`` if all requested vertices were deleted, ``False`` if a + single vertex could not be deleted + +.. seealso:: :py:func:`deleteVertex` + +.. versionadded:: 4.0 %End virtual double length() const; diff --git a/python/core/auto_generated/geometry/qgscircularstring.sip.in b/python/core/auto_generated/geometry/qgscircularstring.sip.in index 2aca5bcdff80..a3a454ae500a 100644 --- a/python/core/auto_generated/geometry/qgscircularstring.sip.in +++ b/python/core/auto_generated/geometry/qgscircularstring.sip.in @@ -175,6 +175,8 @@ circular string. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/, QgsVertexId &vertexAfter /Out/, int *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const; virtual bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const; diff --git a/python/core/auto_generated/geometry/qgscompoundcurve.sip.in b/python/core/auto_generated/geometry/qgscompoundcurve.sip.in index da820885f304..15bc27e0d40a 100644 --- a/python/core/auto_generated/geometry/qgscompoundcurve.sip.in +++ b/python/core/auto_generated/geometry/qgscompoundcurve.sip.in @@ -167,6 +167,8 @@ Converts the vertex at the given position from/to circular virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/, QgsVertexId &vertexAfter /Out/, int *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const; virtual bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const; diff --git a/python/core/auto_generated/geometry/qgscurvepolygon.sip.in b/python/core/auto_generated/geometry/qgscurvepolygon.sip.in index 2773fc1f98c5..1e8752ae5e3b 100644 --- a/python/core/auto_generated/geometry/qgscurvepolygon.sip.in +++ b/python/core/auto_generated/geometry/qgscurvepolygon.sip.in @@ -267,6 +267,8 @@ This convention matches the OGC Simple Features specification. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual QgsCoordinateSequence coordinateSequence() const; diff --git a/python/core/auto_generated/geometry/qgsgeometry.sip.in b/python/core/auto_generated/geometry/qgsgeometry.sip.in index f24e1079922a..5b18c8032714 100644 --- a/python/core/auto_generated/geometry/qgsgeometry.sip.in +++ b/python/core/auto_generated/geometry/qgsgeometry.sip.in @@ -834,6 +834,26 @@ LineString with less than 2 vertices), the geometry is cleared instead. vertex was successfully deleted or the geometry was cleared. %End + bool deleteVertices( const QList &atVertices ); +%Docstring +Deletes vertices at the given positions (first number is index 0) + +For Point geometries, this clears the geometry. For MultiPoint +geometries, this removes point geometries at the specified indices. For +other geometry types, this removes the vertices at the specified +indices. If after removal of the vertices the geometry would become +invalid (e.g. a LineString with less than 2 vertices), the geometry is +cleared instead. + +:return: ``False`` if any of the given atVertices does not correspond to + a valid vertex on this geometry or if any vertices fail to be + deleted + +.. seealso:: :py:func:`deleteVertex` + +.. versionadded:: 4.0 +%End + bool toggleCircularAtVertex( int atVertex ); %Docstring Converts the vertex at the given position from/to circular diff --git a/python/core/auto_generated/geometry/qgsgeometrycollection.sip.in b/python/core/auto_generated/geometry/qgsgeometrycollection.sip.in index 06768a3ed954..4dd9848465a2 100644 --- a/python/core/auto_generated/geometry/qgsgeometrycollection.sip.in +++ b/python/core/auto_generated/geometry/qgsgeometrycollection.sip.in @@ -223,6 +223,8 @@ ownership to the caller. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual double length() const /HoldGIL/; diff --git a/python/core/auto_generated/geometry/qgslinestring.sip.in b/python/core/auto_generated/geometry/qgslinestring.sip.in index 1309c420097b..d50cb993d280 100644 --- a/python/core/auto_generated/geometry/qgslinestring.sip.in +++ b/python/core/auto_generated/geometry/qgslinestring.sip.in @@ -728,6 +728,8 @@ approximation of the curve. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual QgsLineString *reversed() const /Factory/; diff --git a/python/core/auto_generated/geometry/qgspoint.sip.in b/python/core/auto_generated/geometry/qgspoint.sip.in index f29e2d25d882..bab1700793c6 100644 --- a/python/core/auto_generated/geometry/qgspoint.sip.in +++ b/python/core/auto_generated/geometry/qgspoint.sip.in @@ -419,6 +419,8 @@ Example virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt /Out/, QgsVertexId &vertexAfter /Out/, int *leftOf /Out/ = 0, double epsilon = 4 * DBL_EPSILON ) const; diff --git a/python/core/auto_generated/geometry/qgspolyhedralsurface.sip.in b/python/core/auto_generated/geometry/qgspolyhedralsurface.sip.in index 3fb0bef092e7..cb5401f3ddf5 100644 --- a/python/core/auto_generated/geometry/qgspolyhedralsurface.sip.in +++ b/python/core/auto_generated/geometry/qgspolyhedralsurface.sip.in @@ -170,6 +170,8 @@ deleted. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + virtual QgsCoordinateSequence coordinateSequence() const; diff --git a/python/core/auto_generated/geometry/qgstriangle.sip.in b/python/core/auto_generated/geometry/qgstriangle.sip.in index 84a7805a0960..f114e451c3d7 100644 --- a/python/core/auto_generated/geometry/qgstriangle.sip.in +++ b/python/core/auto_generated/geometry/qgstriangle.sip.in @@ -92,6 +92,8 @@ triangle. Inherited method not used. You cannot delete or insert a vertex directly. Returns always ``False``. %End + virtual bool deleteVertices( const QList &positions ); + virtual bool insertVertex( QgsVertexId position, const QgsPoint &vertex ); %Docstring diff --git a/python/core/auto_generated/geometry/qgstriangulatedsurface.sip.in b/python/core/auto_generated/geometry/qgstriangulatedsurface.sip.in index 6969c175aeff..a6f0c726d683 100644 --- a/python/core/auto_generated/geometry/qgstriangulatedsurface.sip.in +++ b/python/core/auto_generated/geometry/qgstriangulatedsurface.sip.in @@ -68,6 +68,8 @@ only of triangle patches. virtual bool deleteVertex( QgsVertexId position ); + virtual bool deleteVertices( const QList &positions ); + void setTriangles( const QVector &triangles /Transfer/ ); %Docstring diff --git a/src/core/geometry/qgsabstractgeometry.h b/src/core/geometry/qgsabstractgeometry.h index 3fbc740cacd7..f93b90c669d9 100644 --- a/src/core/geometry/qgsabstractgeometry.h +++ b/src/core/geometry/qgsabstractgeometry.h @@ -528,6 +528,16 @@ class CORE_EXPORT QgsAbstractGeometry */ virtual bool deleteVertex( QgsVertexId position ) = 0; + /** + * Deletes vertices within the geometry + * If a vertex cannot be deleted, the method returns FALSE and the geometry may be left in a partially modified and invalid state + * \param positions list of vertex ids for vertices to delete + * \returns TRUE if all requested vertices were deleted, FALSE if a single vertex could not be deleted + * \see deleteVertex + * \since QGIS 4.0 + */ + virtual bool deleteVertices( const QList &positions ) = 0; + /** * Returns the planar, 2-dimensional length of the geometry. * diff --git a/src/core/geometry/qgscircularstring.cpp b/src/core/geometry/qgscircularstring.cpp index 02f5cbb4dd78..cd2312f4b12d 100644 --- a/src/core/geometry/qgscircularstring.cpp +++ b/src/core/geometry/qgscircularstring.cpp @@ -1315,6 +1315,84 @@ void QgsCircularString::deleteVertex( int i ) clearCache(); } +bool QgsCircularString::deleteVertices( const QList &positions ) +{ + if ( positions.empty() ) + { + return true; + } + + int nVertices = this->numPoints(); + + QList vertices = positions; + + std::sort( vertices.begin(), vertices.end(), []( const QgsVertexId & a, const QgsVertexId & b ) + { + return a.vertex < b.vertex; + } + ); + + // remove adjacent vertices as deleting one will also delete the other + for ( size_t i = vertices.size() - 1; i >= 1; i-- ) + { + int vertexNr = vertices[i].vertex; + int prevVertexNr = vertices[i - 1].vertex; + + if ( vertexNr - 1 == prevVertexNr ) + { + if ( vertexNr < nVertices - 2 ) + { + vertices.removeAt( i ); + } + else + { + vertices.removeAt( i - 1 ); + } + + nVertices -= 2; + i--; // adjacent vertices handled, we can skip the next one as well + + if ( i == 0 ) + break; + } + } + + nVertices = this->numPoints(); + + QListIterator positionsIt( vertices ); + positionsIt.toBack(); + while ( positionsIt.hasPrevious() ) + { + if ( nVertices < 4 ) //circular string must have at least 3 vertices + { + clear(); + return true; + } + + int currentVertexNr = positionsIt.previous().vertex; + + if ( currentVertexNr < 0 || currentVertexNr > ( nVertices - 1 ) ) + { + return false; + } + + if ( currentVertexNr < nVertices - 2 ) + { + deleteVertex( currentVertexNr + 1 ); + deleteVertex( currentVertexNr ); + nVertices = nVertices - 2; + } + else + { + deleteVertex( currentVertexNr ); + deleteVertex( currentVertexNr - 1 ); + nVertices = nVertices - 2; + } + } + + return true; +} + double QgsCircularString::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const { double minDist = std::numeric_limits::max(); diff --git a/src/core/geometry/qgscircularstring.h b/src/core/geometry/qgscircularstring.h index 4650bdc76ffc..70b248661807 100644 --- a/src/core/geometry/qgscircularstring.h +++ b/src/core/geometry/qgscircularstring.h @@ -270,6 +270,7 @@ class CORE_EXPORT QgsCircularString: public QgsCurve bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt SIP_OUT, QgsVertexId &vertexAfter SIP_OUT, int *leftOf SIP_OUT = nullptr, double epsilon = 4 * std::numeric_limits::epsilon() ) const override; bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override; void sumUpArea( double &sum SIP_OUT ) const override; diff --git a/src/core/geometry/qgscompoundcurve.cpp b/src/core/geometry/qgscompoundcurve.cpp index 16e5f67c1aaa..166c937f54ee 100644 --- a/src/core/geometry/qgscompoundcurve.cpp +++ b/src/core/geometry/qgscompoundcurve.cpp @@ -922,6 +922,167 @@ bool QgsCompoundCurve::deleteVertex( QgsVertexId position ) return success; } +bool QgsCompoundCurve::deleteVertices( const QList &positions ) +{ + // we create a list of vertices to delete for each curve + QMap> curveVertices; + for ( QgsVertexId position : positions ) + { + const QVector< QPair > curveIds = curveVertexId( position ); + + if ( curveIds.isEmpty() ) + return false; + + const int firstCurveId = curveIds.at( 0 ).first; + const QgsVertexId firstCurveVertex = curveIds.at( 0 ).second; + curveVertices[firstCurveId].append( firstCurveVertex ); + if ( curveIds.size() == 2 ) // vertex is shared between two curves + { + const int secondCurveId = curveIds.at( 1 ).first; + const QgsVertexId secondCurveVertex = curveIds.at( 1 ).second; + curveVertices[secondCurveId].append( secondCurveVertex ); + } + } + + // loop through the curves in reverse order and delete vertices + QMapIterator> curveVerticesIt( curveVertices ); + curveVerticesIt.toBack(); + while ( curveVerticesIt.hasPrevious() ) + { + curveVerticesIt.previous(); + const int curveId = curveVerticesIt.key(); + QgsCurve *curve = mCurves.at( curveId ); + QList vertices = curveVerticesIt.value(); + + const QgsCircularString *circularString = qgsgeometry_cast( curve ); + // If the vertex to delete is the middle vertex of a circularstring arc, we transform + // this circularstring arc into a linestring without the middle vertex + if ( circularString ) + { + // we loop through the vertices to see if we need to handle special case + // of a middle vertex (see deleteVertex) + std::sort( vertices.begin(), vertices.end(), []( const QgsVertexId & a, const QgsVertexId & b ) { return a.vertex < b.vertex; } ); + QList circularVerticesToDelete; + + QListIterator curveVerticesIt( vertices ); + + // search for odd vertices (middle vertices of an arc) + for ( size_t i = vertices.size(); i -- > 0; ) + { + const QgsVertexId curveVertexId = vertices.at( i ); + + // check if a middle vertex of an arc + if ( curveVertexId.vertex % 2 == 1 ) + { + // check if neighbouring vertices are also to be deleted + // if so, we just add this vertex to the list and continue iterating + if ( !circularVerticesToDelete.isEmpty() ) + { + if ( curveVertexId.vertex == circularVerticesToDelete.last().vertex - 1 ) + { + circularVerticesToDelete.append( curveVertexId ); + continue; + } + } + else if ( i != 0 && curveVertexId.vertex - 1 == vertices.at( i - 1 ).vertex ) + { + circularVerticesToDelete.append( curveVertexId ); + continue; + } + + // we found a middle vertex of an arc and none of its neighbours are to be deleted + // we need to handle special case of middle vertex of an arc deletion + // first we delete all the vertices that come before it in this circularstring + if ( !circularVerticesToDelete.isEmpty() ) + { + if ( !curve->deleteVertices( circularVerticesToDelete ) ) + return false; + } + circularVerticesToDelete.clear(); + + // next, we remove that arc and replace it with a linestring that skips the middle vertex + QgsPointSequence points; + circularString->points( points ); + + removeCurve( curveId ); + + if ( curveVertexId.vertex < points.length() - 2 ) + { + auto curveC = std::make_unique(); + curveC->setPoints( points.mid( curveVertexId.vertex + 1 ) ); + mCurves.insert( curveId, curveC.release() ); + } + + const QgsPointSequence partB = QgsPointSequence() << points[curveVertexId.vertex - 1] << points[curveVertexId.vertex + 1]; + auto curveB = std::make_unique(); + curveB->setPoints( partB ); + mCurves.insert( curveId, curveB.release() ); + curve = mCurves.at( curveId ); + + if ( curveVertexId.vertex > 1 ) + { + auto curveA = std::make_unique(); + curveA->setPoints( points.mid( 0, curveVertexId.vertex ) ); + mCurves.insert( curveId, curveA.release() ); + } + curve = mCurves.at( curveId ); // we need to get the new curve + circularString = qgsgeometry_cast( curve ); + + continue; + } + + // not a middle vertex of an arc + circularVerticesToDelete.append( curveVertexId ); + } + + // remove any remaining circular vertices to delete + if ( !circularVerticesToDelete.isEmpty() ) + { + if ( !curve->deleteVertices( circularVerticesToDelete ) ) + return false; + } + continue; // circularstring handled, continue to next curve + } + + if ( !curve->deleteVertices( vertices ) ) + return false; + } + + // remove any empty curves + for ( int i = mCurves.size() - 1; i >= 0; i-- ) + { + QgsCurve *curve = mCurves.at( i ); + if ( curve->numPoints() == 0 ) + { + removeCurve( i ); + } + } + + if ( mCurves.isEmpty() ) + { + clearCache(); + return true; + } + + // ensure all curves are connected + for ( size_t i = mCurves.size() - 1; i > 0; i-- ) + { + QgsCurve *curve = mCurves.at( i ); + QgsCurve *previousCurve = mCurves.at( i - 1 ); + if ( previousCurve->endPoint() != curve->startPoint() ) + { + QgsLineString *line = new QgsLineString(); + line->insertVertex( QgsVertexId( 0, 0, 0 ), previousCurve->endPoint() ); + line->insertVertex( QgsVertexId( 0, 0, 1 ), curve->startPoint() ); + mCurves.insert( i, line ); + } + } + + condenseCurves(); // merge consecutive LineStrings and CircularStrings + clearCache(); + return true; +} + QVector< QPair > QgsCompoundCurve::curveVertexId( QgsVertexId id ) const { QVector< QPair > curveIds; diff --git a/src/core/geometry/qgscompoundcurve.h b/src/core/geometry/qgscompoundcurve.h index b50d2207f24f..935b10a83880 100644 --- a/src/core/geometry/qgscompoundcurve.h +++ b/src/core/geometry/qgscompoundcurve.h @@ -188,6 +188,7 @@ class CORE_EXPORT QgsCompoundCurve: public QgsCurve bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt SIP_OUT, QgsVertexId &vertexAfter SIP_OUT, int *leftOf SIP_OUT = nullptr, double epsilon = 4 * std::numeric_limits::epsilon() ) const override; bool pointAt( int node, QgsPoint &point, Qgis::VertexType &type ) const override; void sumUpArea( double &sum SIP_OUT ) const override; diff --git a/src/core/geometry/qgscurvepolygon.cpp b/src/core/geometry/qgscurvepolygon.cpp index faaa05f1cc32..e45168362611 100644 --- a/src/core/geometry/qgscurvepolygon.cpp +++ b/src/core/geometry/qgscurvepolygon.cpp @@ -1293,6 +1293,101 @@ bool QgsCurvePolygon::deleteVertex( QgsVertexId vId ) return success; } +bool QgsCurvePolygon::deleteVertices( const QList &positions ) +{ + QMap> ringVertices; + for ( const QgsVertexId &pos : positions ) + { + const int interiorRingId = pos.ring - 1; + if ( !mExteriorRing || pos.ring < 0 || interiorRingId >= mInteriorRings.size() ) + { + return false; + } + ringVertices[pos.ring].append( pos ); + } + + QMapIterator> ringVerticesIt( ringVertices ); + ringVerticesIt.toBack(); + while ( ringVerticesIt.hasPrevious() ) + { + ringVerticesIt.previous(); + QList vertices = ringVerticesIt.value(); + int ringId = ringVerticesIt.key(); + + const int interiorRingId = ringId - 1; + + // cppcheck-suppress containerOutOfBounds + QgsCurve *ring = ringId == 0 ? mExteriorRing.get() : mInteriorRings.at( interiorRingId ); + + int n = ring->numPoints(); + + // sort so we can check for first/last vertex deletion + std::sort( vertices.begin(), vertices.end(), []( const QgsVertexId & a, const QgsVertexId & b ) + { + return a.vertex < b.vertex; + } + ); + + QgsVertexId firstVertexId = vertices.first(); + QgsVertexId lastVertexId = vertices.last(); + + // check if we are deleting the same point twice and remove the first, but not in a compound curve + if ( ( firstVertexId.vertex == 0 ) && ( lastVertexId.vertex == n - 1 ) && !( QgsWkbTypes::flatType( ring->wkbType() ) == Qgis::WkbType::CompoundCurve ) ) + { + vertices.removeFirst(); + } + + if ( vertices.size() > n - 4 ) + { + // no points will be left in ring, so remove whole ring + if ( ringId == 0 ) + { + mExteriorRing.reset(); + if ( !mInteriorRings.isEmpty() ) + { + mExteriorRing.reset( mInteriorRings.takeFirst() ); + } + } + else + { + removeInteriorRing( ringId - 1 ); + } + continue; + } + + if ( !ring->deleteVertices( vertices ) ) + { + return false; + } + + // in case of a compound curve, first/last vertex may have been deleted even if not specified + // in such case, we copy the first vertex and add it at the end + if ( QgsWkbTypes::flatType( ring->wkbType() ) == Qgis::WkbType::CompoundCurve ) + { + // add start point at the end if not the same + if ( !( ring->vertexAt( QgsVertexId( 0, 0, 0 ) ) == ring->vertexAt( QgsVertexId( 0, 0, ring->numPoints() - 1 ) ) ) ) + { + QgsCompoundCurve *compoundRing = qgsgeometry_cast( ring ); + compoundRing->addVertex( ring->vertexAt( QgsVertexId( 0, 0, 0 ) ) ); + } + continue; + } + + // If first or last vertex is removed, re-sync the last/first vertex + if ( vertices.last().vertex == n - 1 ) + { + ring->moveVertex( QgsVertexId( 0, 0, 0 ), ring->vertexAt( QgsVertexId( 0, 0, ring->numPoints() - 1 ) ) ); + } + else if ( vertices.first().vertex == 0 ) + { + ring->moveVertex( QgsVertexId( 0, 0, ring->numPoints() - 1 ), ring->vertexAt( QgsVertexId( 0, 0, 0 ) ) ); + } + } + + clearCache(); + return true; +} + bool QgsCurvePolygon::hasCurvedSegments() const { if ( mExteriorRing && mExteriorRing->hasCurvedSegments() ) diff --git a/src/core/geometry/qgscurvepolygon.h b/src/core/geometry/qgscurvepolygon.h index 33bfef6f3747..661680c93cbb 100644 --- a/src/core/geometry/qgscurvepolygon.h +++ b/src/core/geometry/qgscurvepolygon.h @@ -367,6 +367,7 @@ class CORE_EXPORT QgsCurvePolygon: public QgsSurface bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; QgsCoordinateSequence coordinateSequence() const override; int nCoordinates() const override; diff --git a/src/core/geometry/qgsgeometry.cpp b/src/core/geometry/qgsgeometry.cpp index f24f5074983a..7b95ff03d58b 100644 --- a/src/core/geometry/qgsgeometry.cpp +++ b/src/core/geometry/qgsgeometry.cpp @@ -677,6 +677,47 @@ bool QgsGeometry::deleteVertex( int atVertex ) return d->geometry->deleteVertex( id ); } +bool QgsGeometry::deleteVertices( const QList &atVertices ) +{ + if ( !d->geometry ) + { + return false; + } + + // if it is a point, set the geometry to nullptr + if ( QgsWkbTypes::flatType( d->geometry->wkbType() ) == Qgis::WkbType::Point ) + { + if ( atVertices.size() != 1 && !atVertices.contains( 0 ) ) + return false; + + reset( nullptr ); + return true; + } + + QList vertexIds; + for ( int vertex : atVertices ) + { + QgsVertexId id; + if ( !vertexIdFromVertexNr( vertex, id ) ) + return false; + + vertexIds.append( id ); + } + + // create a copy of the original geometry to restore it in case of failure + std::unique_ptr< QgsAbstractGeometry > originalGeometry( d->geometry->clone() ); + + detach(); + + if ( !d->geometry->deleteVertices( vertexIds ) ) + { + reset( std::move( originalGeometry ) ); + return false; + } + + return true; +} + bool QgsGeometry::toggleCircularAtVertex( int atVertex ) { diff --git a/src/core/geometry/qgsgeometry.h b/src/core/geometry/qgsgeometry.h index a773128add36..c78d57c94d3b 100644 --- a/src/core/geometry/qgsgeometry.h +++ b/src/core/geometry/qgsgeometry.h @@ -878,6 +878,21 @@ class CORE_EXPORT QgsGeometry */ bool deleteVertex( int atVertex ); + /** + * Deletes vertices at the given positions (first number is index 0) + * + * For Point geometries, this clears the geometry. + * For MultiPoint geometries, this removes point geometries at the specified indices. + * For other geometry types, this removes the vertices at the specified indices. + * If after removal of the vertices the geometry would become invalid (e.g. a LineString with less than 2 vertices), + * the geometry is cleared instead. + * \returns FALSE if any of the given atVertices does not correspond to a valid vertex + * on this geometry or if any vertices fail to be deleted + * \see deleteVertex() + * \since QGIS 4.0 + */ + bool deleteVertices( const QList &atVertices ); + /** * Converts the vertex at the given position from/to circular * \returns FALSE if atVertex does not correspond to a valid vertex diff --git a/src/core/geometry/qgsgeometrycollection.cpp b/src/core/geometry/qgsgeometrycollection.cpp index 33e9732681ed..0ae2ac5d0d09 100644 --- a/src/core/geometry/qgsgeometrycollection.cpp +++ b/src/core/geometry/qgsgeometrycollection.cpp @@ -679,6 +679,49 @@ bool QgsGeometryCollection::deleteVertex( QgsVertexId position ) return success; } +bool QgsGeometryCollection::deleteVertices( const QList &positions ) +{ + QMap> partVertices; + for ( QgsVertexId pos : positions ) + { + partVertices[pos.part].append( pos ); + } + + QMapIterator> partVerticesIt( partVertices ); + partVerticesIt.toBack(); + while ( partVerticesIt.hasPrevious() ) + { + partVerticesIt.previous(); + int part = partVerticesIt.key(); + QList partVertices = partVerticesIt.value(); + QgsAbstractGeometry *geom = mGeometries.at( part ); + if ( !geom ) + { + return false; + } + + if ( QgsWkbTypes::flatType( geom->wkbType() ) == Qgis::WkbType::Point ) + { + removeGeometry( part ); + continue; + } + + // quit if any vertex on any part fails to be deleted + if ( !geom->deleteVertices( partVertices ) ) + { + return false; + } + + // remove geometry if no vertices left + if ( geom->isEmpty() ) + { + removeGeometry( part ); + } + } + clearCache(); // set bounding box invalid + return true; +} + double QgsGeometryCollection::length() const { double length = 0.0; diff --git a/src/core/geometry/qgsgeometrycollection.h b/src/core/geometry/qgsgeometrycollection.h index 3dbd75d804f1..2b19dd0ef7cb 100644 --- a/src/core/geometry/qgsgeometrycollection.h +++ b/src/core/geometry/qgsgeometrycollection.h @@ -290,6 +290,7 @@ class CORE_EXPORT QgsGeometryCollection: public QgsAbstractGeometry bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; double length() const override SIP_HOLDGIL; double area() const override SIP_HOLDGIL; diff --git a/src/core/geometry/qgslinestring.cpp b/src/core/geometry/qgslinestring.cpp index dde64e9bfd3a..713600a8b26e 100644 --- a/src/core/geometry/qgslinestring.cpp +++ b/src/core/geometry/qgslinestring.cpp @@ -2099,6 +2099,50 @@ bool QgsLineString::deleteVertex( QgsVertexId position ) return true; } +bool QgsLineString::deleteVertices( const QList &vertices ) +{ + if ( vertices.isEmpty() ) + { + return false; + } + + QList positions = vertices; + + std::sort( positions.begin(), positions.end(), []( const QgsVertexId & a, const QgsVertexId & b ) + { + return a.vertex > b.vertex; + } + ); + + if ( positions.first().vertex >= mX.size() || positions.last().vertex < 0 ) + { + return false; + } + + for ( QgsVertexId position : positions ) + { + mX.remove( position.vertex ); + mY.remove( position.vertex ); + if ( is3D() ) + { + mZ.remove( position.vertex ); + } + if ( isMeasure() ) + { + mM.remove( position.vertex ); + } + } + + if ( numPoints() <= 1 ) + { + clear(); + return true; + } + + clearCache(); //set bounding box invalid + return true; +} + /*************************************************************************** * This class is considered CRITICAL and any change MUST be accompanied with * full unit tests. diff --git a/src/core/geometry/qgslinestring.h b/src/core/geometry/qgslinestring.h index 2380d03b92c4..c0d1223c6644 100644 --- a/src/core/geometry/qgslinestring.h +++ b/src/core/geometry/qgslinestring.h @@ -1034,6 +1034,7 @@ class CORE_EXPORT QgsLineString: public QgsCurve bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; QgsLineString *reversed() const override SIP_FACTORY; QgsPoint *interpolatePoint( double distance ) const override SIP_FACTORY; diff --git a/src/core/geometry/qgspoint.cpp b/src/core/geometry/qgspoint.cpp index 3f4abb67a0d9..a29e30df5229 100644 --- a/src/core/geometry/qgspoint.cpp +++ b/src/core/geometry/qgspoint.cpp @@ -467,6 +467,12 @@ bool QgsPoint::deleteVertex( QgsVertexId position ) return false; } +bool QgsPoint::deleteVertices( const QList &positions ) +{ + Q_UNUSED( positions ) + return false; +} + double QgsPoint::closestSegment( const QgsPoint &pt, QgsPoint &segmentPt, QgsVertexId &vertexAfter, int *leftOf, double epsilon ) const { Q_UNUSED( pt ) diff --git a/src/core/geometry/qgspoint.h b/src/core/geometry/qgspoint.h index 83ced4eec476..cc84ef2bc0fb 100644 --- a/src/core/geometry/qgspoint.h +++ b/src/core/geometry/qgspoint.h @@ -583,6 +583,7 @@ class CORE_EXPORT QgsPoint: public QgsAbstractGeometry bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; double closestSegment( const QgsPoint &pt, QgsPoint &segmentPt SIP_OUT, QgsVertexId &vertexAfter SIP_OUT, int *leftOf SIP_OUT = nullptr, double epsilon = 4 * std::numeric_limits::epsilon() ) const override; bool nextVertex( QgsVertexId &id, QgsPoint &vertex SIP_OUT ) const override; diff --git a/src/core/geometry/qgspolyhedralsurface.cpp b/src/core/geometry/qgspolyhedralsurface.cpp index c82908f9dfd6..d1a5eb4c11c7 100644 --- a/src/core/geometry/qgspolyhedralsurface.cpp +++ b/src/core/geometry/qgspolyhedralsurface.cpp @@ -760,6 +760,41 @@ bool QgsPolyhedralSurface::deleteVertex( QgsVertexId vId ) return success; } +bool QgsPolyhedralSurface::deleteVertices( const QList &positions ) +{ + QMap> partVertices; + for ( QgsVertexId pos : positions ) + { + partVertices[pos.part].append( pos ); + } + + QMapIterator> partVerticesIt( partVertices ); + partVerticesIt.toBack(); + while ( partVerticesIt.hasPrevious() ) + { + partVerticesIt.previous(); + + int part = partVerticesIt.key(); + QList vertexMap = partVerticesIt.value(); + if ( part < 0 || part >= partCount() ) + continue; + + QgsPolygon *patch = mPatches.at( part ); + + if ( patch->deleteVertices( vertexMap ) ) + { + // if the patch has lost its exterior ring, remove it + if ( !patch->exteriorRing() ) + { + delete mPatches.takeAt( part ); + } + clearCache(); + } + } + + return true; +} + bool QgsPolyhedralSurface::hasCurvedSegments() const { return false; diff --git a/src/core/geometry/qgspolyhedralsurface.h b/src/core/geometry/qgspolyhedralsurface.h index 0757c4621485..405150c5e29a 100644 --- a/src/core/geometry/qgspolyhedralsurface.h +++ b/src/core/geometry/qgspolyhedralsurface.h @@ -251,6 +251,7 @@ class CORE_EXPORT QgsPolyhedralSurface: public QgsSurface bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool moveVertex( QgsVertexId position, const QgsPoint &newPos ) override; bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; QgsCoordinateSequence coordinateSequence() const override; int nCoordinates() const override; diff --git a/src/core/geometry/qgstriangle.cpp b/src/core/geometry/qgstriangle.cpp index 7482d3a1fceb..978efdce0629 100644 --- a/src/core/geometry/qgstriangle.cpp +++ b/src/core/geometry/qgstriangle.cpp @@ -262,6 +262,12 @@ bool QgsTriangle::deleteVertex( QgsVertexId position ) return false; } +bool QgsTriangle::deleteVertices( const QList &positions ) +{ + Q_UNUSED( positions ) + return false; +} + bool QgsTriangle::insertVertex( QgsVertexId position, const QgsPoint &vertex ) { Q_UNUSED( position ) diff --git a/src/core/geometry/qgstriangle.h b/src/core/geometry/qgstriangle.h index 4451b866fb7c..d933d654029e 100644 --- a/src/core/geometry/qgstriangle.h +++ b/src/core/geometry/qgstriangle.h @@ -91,6 +91,7 @@ class CORE_EXPORT QgsTriangle : public QgsPolygon void setInteriorRings( const QVector< QgsCurve *> &rings ) = delete; // cppcheck-suppress duplInheritedMember //! Inherited method not used. You cannot delete or insert a vertex directly. Returns always FALSE. bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; //! Inherited method not used. You cannot delete or insert a vertex directly. Returns always FALSE. bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool moveVertex( QgsVertexId vId, const QgsPoint &newPos ) override; diff --git a/src/core/geometry/qgstriangulatedsurface.cpp b/src/core/geometry/qgstriangulatedsurface.cpp index 0073d8cb620e..7514cf2be9db 100644 --- a/src/core/geometry/qgstriangulatedsurface.cpp +++ b/src/core/geometry/qgstriangulatedsurface.cpp @@ -309,6 +309,12 @@ bool QgsTriangulatedSurface::deleteVertex( QgsVertexId vId ) return false; } +bool QgsTriangulatedSurface::deleteVertices( const QList &positions ) +{ + Q_UNUSED( positions ) + return false; +} + int QgsTriangulatedSurface::compareToSameClass( const QgsAbstractGeometry *other ) const { const QgsTriangulatedSurface *otherTriangulatedSurface = qgsgeometry_cast( other ); diff --git a/src/core/geometry/qgstriangulatedsurface.h b/src/core/geometry/qgstriangulatedsurface.h index 5857eeb4f8d0..93bbaac6ead0 100644 --- a/src/core/geometry/qgstriangulatedsurface.h +++ b/src/core/geometry/qgstriangulatedsurface.h @@ -119,6 +119,7 @@ class CORE_EXPORT QgsTriangulatedSurface: public QgsPolyhedralSurface bool insertVertex( QgsVertexId position, const QgsPoint &vertex ) override; bool deleteVertex( QgsVertexId position ) override; + bool deleteVertices( const QList &positions ) override; /** * Sets all triangles, transferring ownership to the polyhedral surface. diff --git a/tests/src/python/test_qgsgeometry.py b/tests/src/python/test_qgsgeometry.py index 0e77d553e04f..65f6855f1ac9 100644 --- a/tests/src/python/test_qgsgeometry.py +++ b/tests/src/python/test_qgsgeometry.py @@ -2827,6 +2827,719 @@ def testDeleteVertex(self): wkt = polygon.asWkt() assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + def testDeleteVertices(self): + # 2-+-+-+-+-3 + # | | + # + 6-+-+-7 + + # | | | | + # + + 9-+-8 + + # | | | + # ! 5-+-+-+-4 + # | + # 1-+-+-+-+-0 + + linestringwkt = "LineString (5 0, 0 0, 0 4, 5 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" + linestring = QgsGeometry.fromWkt(linestringwkt) + + # test invalid range + assert not linestring.deleteVertices( + [-5] + ), "Delete vertices [-5] unexpectedly succeeded" + assert not linestring.deleteVertices( + [100] + ), "Delete vertices 100 unexpectedly succeeded" + # single invalid value should fail + assert not linestring.deleteVertices( + [1, 10] + ), "Delete vertices [1, 10] unexpectedly succeeded" + + # test deletion of single vertex + assert linestring.deleteVertices([3]), "Delete vertices [5 4] failed" + expwkt = "LineString (5 0, 0 0, 0 4, 5 1, 1 1, 1 3, 4 3, 4 2, 2 2)" + wkt = linestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of multiple vertices + linestring = QgsGeometry.fromWkt(linestringwkt) + + assert linestring.deleteVertices( + [0, 1, 8, 9] + ), "Delete vertices 5 0, 0 0, 4 2, 2 2 failed" + expwkt = "LineString (0 4, 5 4, 5 1, 1 1, 1 3, 4 3)" + wkt = linestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of entire geometry (remove all but one in linestring) + linestring = QgsGeometry.fromWkt(linestringwkt) + + assert linestring.deleteVertices( + [1, 2, 3, 4, 5, 6, 7, 8, 9] + ), "Delete vertices [1, 2, 3, 4, 5, 7, 8, 9, 9] failed" + expwkt = "LineString EMPTY" + wkt = linestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of entire geometry (list all vertices) + linestring = QgsGeometry.fromWkt(linestringwkt) + + assert linestring.deleteVertices( + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + ), "Delete vertices [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] failed" + expwkt = "LineString EMPTY" + wkt = linestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # 2-3 6-+-7 + # | | | | + # 0-1 4 5 8-9 + + multilinestringwkt = ( + "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1, 5 1, 5 0, 6 0))" + ) + multilinestring = QgsGeometry.fromWkt(multilinestringwkt) + + # test invalid range + assert not multilinestring.deleteVertices( + [-5] + ), "Delete vertices [-5] unexpectedly succeeded" + assert not multilinestring.deleteVertices( + [100] + ), "Delete vertices 100 unexpectedly succeeded" + # single invalid value should fail + assert not multilinestring.deleteVertices( + [1, 10] + ), "Delete vertices [1, 10] unexpectedly succeeded" + + # test deletion of single vertex + assert multilinestring.deleteVertices([0]), "Delete vertex [0] failed" + expwkt = "MultiLineString ((1 0, 1 1, 2 1, 2 0), (3 0, 3 1, 5 1, 5 0, 6 0))" + wkt = multilinestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of multiple vertices + multilinestring = QgsGeometry.fromWkt(multilinestringwkt) + + assert multilinestring.deleteVertices( + [0, 1, 8, 9] + ), "Delete vertices [0, 1, 8, 9] failed" + expwkt = "MultiLineString ((1 1, 2 1, 2 0), (3 0, 3 1, 5 1))" + wkt = multilinestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of a part of multilinestring (list all but one) + multilinestring = QgsGeometry.fromWkt(multilinestringwkt) + + assert multilinestring.deleteVertices( + [6, 7, 8, 9] + ), "Delete vertices [6, 7, 8, 9] failed" + expwkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0))" + wkt = multilinestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of a part of multilinestring (list all) + multilinestring = QgsGeometry.fromWkt(multilinestringwkt) + + assert multilinestring.deleteVertices( + [5, 6, 7, 8, 9] + ), "Delete vertices [5, 6, 7, 8, 9] failed" + expwkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0))" + wkt = multilinestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of entire geometry (remove all but one in multilinestring) + multilinestring = QgsGeometry.fromWkt(multilinestringwkt) + + assert multilinestring.deleteVertices( + [1, 2, 3, 4, 5, 6, 7, 8, 9] + ), "Delete vertices [1, 2, 3, 4, 5, 6, 7, 8, 9] failed" + expwkt = "MultiLineString EMPTY" + wkt = multilinestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of entire geometry (list all vertices) + multilinestring = QgsGeometry.fromWkt(multilinestringwkt) + + assert multilinestring.deleteVertices( + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + ), "Delete vertices [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] failed" + expwkt = "MultiLineString EMPTY" + wkt = multilinestring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # 5---4 + # | | + # | 2-3 + # | | + # 0-1 + + polygonwkt = "Polygon ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))" + polygon = QgsGeometry.fromWkt(polygonwkt) + + # test invalid range + assert not polygon.deleteVertices( + [-5] + ), "Delete vertices -5 unexpectedly succeeded" + assert not polygon.deleteVertices( + [100] + ), "Delete vertices 100 unexpectedly succeeded" + # single invalid value should fail + assert not polygon.deleteVertices( + [1, 10] + ), "Delete vertices [1, 10] unexpectedly succeeded" + + # test deletion of single vertex + assert polygon.deleteVertices([0]), "Delete vertices [0] failed" + expwkt = "Polygon ((1 0, 1 1, 2 1, 2 2, 0 2, 1 0))" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of start and endpoint (same point) + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices([0, 6]), "Delete vertices [0, 6] failed" + expwkt = "Polygon ((0 2, 1 0, 1 1, 2 1, 2 2, 0 2))" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of multiple vertices + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices([0, 4, 5]), "Delete vertices [0, 4, 5] failed" + expwkt = "Polygon ((1 0, 1 1, 2 1, 1 0))" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of entire geometry (list all but two) + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices( + [2, 3, 4, 5] + ), "Delete vertices [2, 3, 4, 5] failed" + expwkt = "Polygon EMPTY" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of entire geometry (list all but one) + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices( + [1, 2, 3, 4, 5] + ), "Delete vertices [1, 2, 3, 4, 5] failed" + expwkt = "Polygon EMPTY" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of entire geometry (list all) + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices( + [0, 1, 2, 3, 4, 5] + ), "Delete vertices [0, 1, 2, 3, 4, 5] failed" + expwkt = "Polygon EMPTY" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # 3 - + - + - + - + - 2 + # | | + # + 5 - + - + - 6 + + # | | | | + # + 8 - + - + - 7 + + # | | + # + 10- + - + -11 + + # | | | | + # + 13- + - + -12 + + # | | + # + 18- + - + -17 + + # | | | | + # + 15- + - + -16 + + # | | + # 0 - + - + - + - + - 1 + + # polygon with interior rings + polygonwkt = "Polygon ((0 0, 5 0, 5 7, 0 7, 0 0), (1 6, 4 6, 4 5, 1 5, 1 6), (1 4, 4 4, 4 3, 1 3, 1 4), (1 2, 4 2, 4 1, 1 1, 1 2))" + polygon = QgsGeometry.fromWkt(polygonwkt) + + # test deletion of single vertex (we don't care if the polygon becomes invalid) + assert polygon.deleteVertices([0]), "Delete vertex [0] failed" + expwkt = "Polygon ((5 0, 5 7, 0 7, 5 0), (1 6, 4 6, 4 5, 1 5, 1 6), (1 4, 4 4, 4 3, 1 3, 1 4), (1 2, 4 2, 4 1, 1 1, 1 2))" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of single vertex in all rings (start and end point) + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices([0, 4, 5, 9, 10, 14, 15, 19]) + expwkt = "Polygon ((0 7, 5 0, 5 7, 0 7), (1 5, 4 6, 4 5, 1 5), (1 3, 4 4, 4 3, 1 3), (1 1, 4 2, 4 1, 1 1))" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of exterior ring + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices([0, 1]), "Delete vertices [0, 1] failed" + expwkt = "Polygon ((1 6, 4 6, 4 5, 1 5, 1 6), (1 4, 4 4, 4 3, 1 3, 1 4), (1 2, 4 2, 4 1, 1 1, 1 2))" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of interior ring + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices([5, 6, 9]), "Delete vertices [5, 6, 9] failed" + expwkt = "Polygon ((0 0, 5 0, 5 7, 0 7, 0 0), (1 4, 4 4, 4 3, 1 3, 1 4), (1 2, 4 2, 4 1, 1 1, 1 2))" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of multiple interior rings + polygon = QgsGeometry.fromWkt(polygonwkt) + + assert polygon.deleteVertices( + [5, 6, 9, 15, 16] + ), "Delete vertices [5, 6, 9, 15, 16] failed" + expwkt = "Polygon ((0 0, 5 0, 5 7, 0 7, 0 0), (1 4, 4 4, 4 3, 1 3, 1 4))" + wkt = polygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # 5 - + - 4 10- + - 9 + # | | | | + # + 2 - 3 11- 12 + + # | | | | + # 0 - 1 7 - 8 + + multipolygonwkt = "MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)), ((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + multipolygon = QgsGeometry.fromWkt(multipolygonwkt) + + # test single vertex deletion + assert multipolygon.deleteVertices([0]), "Delete vertices [0] failed" + expwkt = "MultiPolygon (((1 0, 1 1, 2 1, 2 2, 0 2, 1 0)), ((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + wkt = multipolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + assert multipolygon.deleteVertices([4]), "Delete vertices [4] failed" + expwkt = "MultiPolygon (((1 0, 1 1, 2 1, 2 2, 1 0)), ((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + wkt = multipolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of start and endpoint + multipolygon = QgsGeometry.fromWkt(multipolygonwkt) + + assert multipolygon.deleteVertices([0, 6]), "Delete vertices [0, 6] failed" + expwkt = "MultiPolygon (((0 2, 1 0, 1 1, 2 1, 2 2, 0 2)), ((4 0, 5 0, 5 2, 3 2, 3 1, 4 1, 4 0)))" + wkt = multipolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test multiple deletion + multipolygon = QgsGeometry.fromWkt(multipolygonwkt) + + assert multipolygon.deleteVertices( + [0, 1, 11, 12] + ), "Delete vertices [0, 1, 10, 11] failed" + expwkt = ( + "MultiPolygon (((1 1, 2 1, 2 2, 0 2, 1 1)), ((4 0, 5 0, 5 2, 3 2, 4 0)))" + ) + wkt = multipolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # 3 - + - + - + - + - 2 23- + - + - + - + -22 + # | | | | + # + 5 - + - + - 6 + + 25- + - + -26 + + # | | | | | | | | + # + 8 - + - + - 7 + + 28- + - + -27 + + # | | | | + # + 10- + - + -11 + + 30- + - + -31 + + # | | | | | | | | + # + 13- + - + -12 + + 33- + - + -32 + + # | | | | + # + 18- + - + -17 + + 38- + - + -37 + + # | | | | | | | | + # + 15- + - + -16 + + 35- + - + -36 + + # | | | | + # 0 - + - + - + - + - 1 20- + - + - + - + -21 + + # multipolygon with interior rings + multipolygonwkt = "MultiPolygon (((0 0, 5 0, 5 7, 0 7, 0 0), (1 6, 4 6, 4 5, 1 5, 1 6), (1 4, 4 4, 4 3, 1 3, 1 4), (1 2, 4 2, 4 1, 1 1, 1 2)), ((6 0, 11 0, 11 7, 6 7, 6 0), (7 6, 10 6, 10 5, 7 5, 7 6), (7 4, 10 4, 10 3, 7 3, 7 4), (7 2, 10 2, 10 1, 7 1, 7 2)))" + multipolygon = QgsGeometry.fromWkt(multipolygonwkt) + + # test deletion of start and endpoint of exterior and interior rings + assert multipolygon.deleteVertices( + [0, 4, 5, 9, 20, 24, 25, 29] + ), "Delete vertices [0, 4, 5, 9, 20, 24, 25, 29] failed" + expwkt = "MultiPolygon (((0 7, 5 0, 5 7, 0 7), (1 5, 4 6, 4 5, 1 5), (1 4, 4 4, 4 3, 1 3, 1 4), (1 2, 4 2, 4 1, 1 1, 1 2)), ((6 7, 11 0, 11 7, 6 7), (7 5, 10 6, 10 5, 7 5), (7 4, 10 4, 10 3, 7 3, 7 4), (7 2, 10 2, 10 1, 7 1, 7 2)))" + wkt = multipolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of multiple interior rings of both polygons + multipolygon = QgsGeometry.fromWkt(multipolygonwkt) + + assert multipolygon.deleteVertices( + [10, 13, 15, 18, 30, 33, 35, 38] + ), "Delete vertices [10, 13, 15, 18, 30, 33, 35, 38] failed" + expwkt = "MultiPolygon (((0 0, 5 0, 5 7, 0 7, 0 0), (1 6, 4 6, 4 5, 1 5, 1 6)), ((6 0, 11 0, 11 7, 6 7, 6 0), (7 6, 10 6, 10 5, 7 5, 7 6)))" + wkt = multipolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of entire part + multipolygon = QgsGeometry.fromWkt(multipolygonwkt) + + assert multipolygon.deleteVertices( + [0, 1, 5, 6, 10, 11, 17, 18] + ), "Delete vertices [0, 1, 5, 6, 10, 11, 17, 18] failed" + expwkt = "MultiPolygon (((6 0, 11 0, 11 7, 6 7, 6 0), (7 6, 10 6, 10 5, 7 5, 7 6), (7 4, 10 4, 10 3, 7 3, 7 4), (7 2, 10 2, 10 1, 7 1, 7 2)))" + wkt = multipolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # 1 + # | + # 0 - + - 2 + # | + # 3 + + # closed circle (first and last point are the same) + circularstringwkt = "CircularString (0 1, 1 2, 2 1, 1 0, 0 1)" + circularstring = QgsGeometry.fromWkt(circularstringwkt) + + # test invalid range + assert not circularstring.deleteVertices( + [-5] + ), "Delete vertices -5 unexpectedly succeeded" + assert not circularstring.deleteVertices( + [100] + ), "Delete vertices 100 unexpectedly succeeded" + # single invalid value should fail + assert not circularstring.deleteVertices( + [1, 10] + ), "Delete vertices [1, 10] unexpectedly succeeded" + + # test single vertex deletion + assert circularstring.deleteVertices([1]), "Delete vertices [1] failed" + expwkt = "CircularString (0 1, 1 0, 0 1)" + wkt = circularstring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test consecutive vertex deletion + circularstring = QgsGeometry.fromWkt(circularstringwkt) + assert circularstring.deleteVertices([3, 4]), "Delete vertices [3, 4] failed" + expwkt = "CircularString (0 1, 1 2, 2 1)" + wkt = circularstring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + circularstring = QgsGeometry.fromWkt(circularstringwkt) + assert circularstring.deleteVertices([2, 3]), "Delete vertices [2, 3] failed" + expwkt = "CircularString (0 1, 1 2, 0 1)" + wkt = circularstring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + circularstring = QgsGeometry.fromWkt(circularstringwkt) + assert circularstring.deleteVertices([1, 2]), "Delete vertices [1, 2] failed" + expwkt = "CircularString (0 1, 1 0, 0 1)" + wkt = circularstring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # delete entire circle + circularstring = QgsGeometry.fromWkt(circularstringwkt) + assert circularstring.deleteVertices( + [0, 1, 2, 3, 4] + ), "Delete vertices [0, 1, 2, 3, 4] failed" + expwkt = "CircularString EMPTY" + wkt = circularstring.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # compoundcurve + compoundcurvewkt = ( + "CompoundCurve ( (0 1, 1 2, 2 1, 1 0, 0 1), (0 1, 0 2, 0 3) )" + ) + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + + # test invalid range + assert not compoundcurve.deleteVertices( + [-5] + ), "Delete vertices -5 unexpectedly succeeded" + assert not compoundcurve.deleteVertices( + [100] + ), "Delete vertices 100 unexpectedly succeeded" + # single invalid value should fail + assert not compoundcurve.deleteVertices( + [1, 10] + ), "Delete vertices [1, 10] unexpectedly succeeded" + + # test single vertex deletion + assert compoundcurve.deleteVertices([6]), "Delete vertices [6] failed" + expwkt = "CompoundCurve ( (0 1, 1 2, 2 1, 1 0, 0 1, 0 2) )" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + assert compoundcurve.deleteVertices([1]), "Delete vertices [1] failed" + expwkt = "CompoundCurve ((0 1, 2 1, 1 0, 0 1, 0 2))" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test single vertex belonging to both strings + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices([4]), "Delete vertices [5, 6] failed" + expwkt = "CompoundCurve ( (0 1, 1 2, 2 1, 1 0, 0 2, 0 3) )" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # remove one linestring from compoundcurve + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices([5, 6]), "Delete vertices [5, 6] failed" + expwkt = "CompoundCurve ( (0 1, 1 2, 2 1, 1 0, 0 1) )" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices( + [0, 1, 2, 3] + ), "Delete vertices [0, 1, 2, 3] failed" + expwkt = "CompoundCurve ( (0 1, 0 2, 0 3) )" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # remove all strings + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices( + [0, 1, 2, 3, 4, 5, 6] + ), "Delete vertices [0, 1, 2, 3, 4, 5, 6] failed" + expwkt = "CompoundCurve EMPTY" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices( + [1, 2, 3, 4, 5] + ), "Delete vertices [1, 2, 3, 4, 5] failed" + expwkt = "CompoundCurve EMPTY" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices( + [0, 2, 3, 4, 6] + ), "Delete vertices [0, 2, 3, 4, 6] failed" + expwkt = "CompoundCurve EMPTY" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices( + [0, 1, 2, 3, 5, 6] + ), "Delete vertices [0, 1, 2, 3, 5, 6] failed" + expwkt = "CompoundCurve EMPTY" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # compoundcurve with circularstring + compoundcurvewkt = "CompoundCurve (CircularString(-1 -1, -1.5 -0.5, -2 0, -1 1, 0 0), CircularString(0 0, 1 1, 2 0, 1.5 -0.5, 1 -1))" + + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices([4]), "Delete vertices [4] failed" + expwkt = "CompoundCurve (CircularString (-1 -1, -1.5 -0.5, -2 0), (-2 0, 2 0), CircularString (2 0, 1.5 -0.5, 1 -1))" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices([0]), "Delete vertices [0] failed" + expwkt = "CompoundCurve ( CircularString( -2 0, -1 1, 0 0, 1 1, 2 0, 1.5 -0.5, 1 -1) )" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices([0, 1]), "Delete vertices [0, 1] failed" + expwkt = "CompoundCurve ( CircularString(-2 0, -1 1, 0 0, 1 1, 2 0, 1.5 -0.5, 1 -1) )" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + compoundcurve = QgsGeometry.fromWkt(compoundcurvewkt) + assert compoundcurve.deleteVertices([7, 8]), "Delete vertices [7, 8] failed" + expwkt = "CompoundCurve (CircularString(-1 -1, -1.5 -0.5, -2 0, -1 1, 0 0, 1 1, 2 0) )" + wkt = compoundcurve.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # curvepolygon1 + curvepolygonwkt = ( + "CurvePolygon( CompoundCurve( CircularString(0 0, 1 1, 2 0), (2 0, 0 0) ) )" + ) + + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices([0]), "Delete vertices [0] failed" + expwkt = "CurvePolygon EMPTY" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices( + [0, 1, 2, 3] + ), "Delete vertices [0, 1, 2, 3] failed" + expwkt = "CurvePolygon EMPTY" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # curvepolygon2 + curvepolygonwkt = "CurvePolygon( CompoundCurve( CircularString (0 0, 1 1, 2 0, 1.5 -0.5, 1 -1), (1 -1, 0 0)))" + + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices([0]), "Delete vertices [0] failed" + expwkt = "CurvePolygon( CompoundCurve( CircularString(2 0, 1.5 -0.5, 1 -1), (1 -1, 0 0, 2 0) ) )" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices([1]), "Delete vertices [1] failed" + expwkt = "CurvePolygon( CompoundCurve( (0 0, 2 0), CircularString(2 0, 1.5 -0.5, 1 -1), (1 -1, 0 0) ) )" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices([0, 1]), "Delete vertices [0, 1] failed" + expwkt = "CurvePolygon( CompoundCurve( CircularString (2 0, 1.5 -0.5, 1 -1), (1 -1, 0 0, 2 0)))" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices( + [0, 1, 2, 3] + ), "Delete vertices [0, 1, 2, 3] failed" + expwkt = "CurvePolygon EMPTY" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # curvepolygon3 + curvepolygonwkt = "CurvePolygon (CompoundCurve (CircularString (3 19, 0 22, 3 25, 6 28, 9 25),( 9 25, 14 20, 19 25 ),CircularString (19 25, 22 28, 25 25, 28 22, 25 19),(25 19, 20 14, 25 9),CircularString (25 9, 28 6, 25 3, 22 0, 19 3),(19 3, 14 8, 9 3),CircularString (9 3, 6 0, 3 3, 0 6, 3 9),(3 9, 8 14, 3 19) ))))" + + # passing all the vertices should not crash and the entire geometry should be cleared + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices( + [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + ] + ), "Delete vertices [0, 1, 2, 3, 4] failed" + expwkt = "CurvePolygon EMPTY" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deleting single circularstring + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices( + [0, 1, 2, 3, 4] + ), "Delete vertices [0, 1, 2, 3, 4] failed" + expwkt = "CurvePolygon (CompoundCurve ((14 20, 19 25),CircularString (19 25, 22 28, 25 25, 28 22, 25 19),(25 19, 20 14, 25 9),CircularString (25 9, 28 6, 25 3, 22 0, 19 3),(19 3, 14 8, 9 3),CircularString (9 3, 6 0, 3 3, 0 6, 3 9),(3 9, 8 14, 3 19, 14 20)))" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deleting circularstrings on opposing sides + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices( + [0, 1, 2, 3, 4, 12, 13, 14, 15, 16] + ), "Delete vertices [0, 1, 2, 3, 4, 12, 13, 14, 15, 16] failed" + expwkt = "CurvePolygon (CompoundCurve ((14 20, 19 25),CircularString (19 25, 22 28, 25 25, 28 22, 25 19),(25 19, 20 14, 14 8, 9 3),CircularString (9 3, 6 0, 3 3, 0 6, 3 9),(3 9, 8 14, 3 19, 14 20)))" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # delete all but first circularstring + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices( + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + ), "Delete vertices [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] failed" + expwkt = "CurvePolygon (CompoundCurve ((14 8, 9 3),CircularString (9 3, 6 0, 3 3, 0 6, 3 9),(3 9, 8 14, 3 19, 14 8)))" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deleting all but last arm + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices( + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] + ), "Delete vertices [0, 1, 2, 3, 4, 12, 13, 14, 15, 16] failed" + expwkt = "CurvePolygon (CompoundCurve ((14 8, 9 3),CircularString (9 3, 6 0, 3 3, 0 6, 3 9),(3 9, 8 14, 3 19, 14 8)))" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deleting first and last circularstring along with their connecting lines + # we are checking if the ring is properly closed after vertices are deleted + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices( + [0, 1, 2, 3, 4, 18, 19, 20, 21, 22, 23, 24] + ), "Delete vertices [0, 1, 2, 3, 4, 18, 19, 20, 21, 22, 23, 24] failed" + expwkt = "CurvePolygon (CompoundCurve ((14 20, 19 25),CircularString (19 25, 22 28, 25 25, 28 22, 25 19),(25 19, 20 14, 25 9),CircularString (25 9, 28 6, 25 3, 22 0, 19 3),(19 3, 14 8, 14 20)))" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # deletion of first/last point works differently if compound curve, the ring should be properly closed + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices([0, 24]), "Delete vertices [0, 24] failed" + expwkt = "CurvePolygon (CompoundCurve (CircularString (3 25, 6 28, 9 25),( 9 25, 14 20, 19 25 ),CircularString (19 25, 22 28, 25 25, 28 22, 25 19),(25 19, 20 14, 25 9),CircularString (25 9, 28 6, 25 3, 22 0, 19 3),(19 3, 14 8, 9 3),CircularString (9 3, 6 0, 3 3, 0 6, 3 9),(3 9, 8 14, 3 25)))" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of line connection between first and last circularstrings + # connecting line is made out of 3 points, after removing 2 of them + # circularstrings should not merge, but be joined with a line connecting the start/end points + curvepolygon = QgsGeometry.fromWkt(curvepolygonwkt) + assert curvepolygon.deleteVertices([24, 23]), "Delete vertices [24, 23] failed" + expwkt = "CurvePolygon (CompoundCurve (CircularString (3 19, 0 22, 3 25, 6 28, 9 25),(9 25, 14 20, 19 25),CircularString (19 25, 22 28, 25 25, 28 22, 25 19),(25 19, 20 14, 25 9),CircularString (25 9, 28 6, 25 3, 22 0, 19 3),(19 3, 14 8, 9 3),CircularString (9 3, 6 0, 3 3, 0 6, 3 9),(3 9, 3 19)))" + wkt = curvepolygon.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # geometry collection + collectionwkt = "GeometryCollection( Point(0 1), Point(0 2), Point(0 3), LineString(0 0, 1 1, 2 2), Polygon((0 0, 1 1, 1 2, 2 2, 0 0)) )" + collection = QgsGeometry.fromWkt(collectionwkt) + + assert not collection.deleteVertices( + [-1] + ), "Delete vertices -1 unexpectedly succeeded" + assert not collection.deleteVertices( + [100] + ), "Delete vertices 100 unexpectedly succeeded" + + # test deletion of point in collection + assert collection.deleteVertices([1]), "Delete vertices [1] failed" + expwkt = "GeometryCollection( Point (0 1), Point (0 3), LineString (0 0, 1 1, 2 2), Polygon ((0 0, 1 1, 1 2, 2 2, 0 0)) )" + wkt = collection.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of vertex in linestring in collection + collection = QgsGeometry.fromWkt(collectionwkt) + assert collection.deleteVertices([5]), "Delete vertices [5] failed" + expwkt = "GeometryCollection( Point (0 1), Point (0 2), Point (0 3), LineString (0 0, 1 1), Polygon ((0 0, 1 1, 1 2, 2 2, 0 0)) )" + wkt = collection.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of vertex in polygon in collection + collection = QgsGeometry.fromWkt(collectionwkt) + assert collection.deleteVertices([8]), "Delete vertices [8] failed" + expwkt = "GeometryCollection( Point (0 1), Point (0 2), Point (0 3), LineString (0 0, 1 1, 2 2), Polygon ((0 0, 1 1, 2 2, 0 0)) )" + wkt = collection.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + + # test deletion of multiple vertices in different geometries in collection + collection = QgsGeometry.fromWkt(collectionwkt) + assert collection.deleteVertices([0, 4, 7]), "Delete vertices [0, 4, 7] failed" + expwkt = "GeometryCollection( Point (0 2), Point (0 3), LineString (0 0, 2 2), Polygon((0 0, 1 2, 2 2, 0 0)) )" + wkt = collection.asWkt() + assert compareWkt(expwkt, wkt), f"Expected:\n{expwkt}\nGot:\n{wkt}\n" + def testInsertVertex(self): linestring = QgsGeometry.fromWkt("LineString(1 0, 2 0)")