Skip to content

Commit

Permalink
make avoidIntersections return an enum
Browse files Browse the repository at this point in the history
  • Loading branch information
troopa81 committed Sep 21, 2023
1 parent 1956783 commit a541a1a
Show file tree
Hide file tree
Showing 11 changed files with 84 additions and 19 deletions.
5 changes: 4 additions & 1 deletion python/core/auto_additions/qgis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1464,7 +1464,10 @@
QgsGeometry.SplitCannotSplitPoint = Qgis.GeometryOperationResult.SplitCannotSplitPoint
QgsGeometry.SplitCannotSplitPoint.is_monkey_patched = True
QgsGeometry.SplitCannotSplitPoint.__doc__ = "Cannot split points"
Qgis.GeometryOperationResult.__doc__ = "Success or failure of a geometry operation.\n\nThis enum gives details about cause of failure.\n\n.. versionadded:: 3.22\n\n" + '* ``Success``: ' + Qgis.GeometryOperationResult.Success.__doc__ + '\n' + '* ``NothingHappened``: ' + Qgis.GeometryOperationResult.NothingHappened.__doc__ + '\n' + '* ``InvalidBaseGeometry``: ' + Qgis.GeometryOperationResult.InvalidBaseGeometry.__doc__ + '\n' + '* ``InvalidInputGeometryType``: ' + Qgis.GeometryOperationResult.InvalidInputGeometryType.__doc__ + '\n' + '* ``SelectionIsEmpty``: ' + Qgis.GeometryOperationResult.SelectionIsEmpty.__doc__ + '\n' + '* ``SelectionIsGreaterThanOne``: ' + Qgis.GeometryOperationResult.SelectionIsGreaterThanOne.__doc__ + '\n' + '* ``GeometryEngineError``: ' + Qgis.GeometryOperationResult.GeometryEngineError.__doc__ + '\n' + '* ``LayerNotEditable``: ' + Qgis.GeometryOperationResult.LayerNotEditable.__doc__ + '\n' + '* ``AddPartSelectedGeometryNotFound``: ' + Qgis.GeometryOperationResult.AddPartSelectedGeometryNotFound.__doc__ + '\n' + '* ``AddPartNotMultiGeometry``: ' + Qgis.GeometryOperationResult.AddPartNotMultiGeometry.__doc__ + '\n' + '* ``AddRingNotClosed``: ' + Qgis.GeometryOperationResult.AddRingNotClosed.__doc__ + '\n' + '* ``AddRingNotValid``: ' + Qgis.GeometryOperationResult.AddRingNotValid.__doc__ + '\n' + '* ``AddRingCrossesExistingRings``: ' + Qgis.GeometryOperationResult.AddRingCrossesExistingRings.__doc__ + '\n' + '* ``AddRingNotInExistingFeature``: ' + Qgis.GeometryOperationResult.AddRingNotInExistingFeature.__doc__ + '\n' + '* ``SplitCannotSplitPoint``: ' + Qgis.GeometryOperationResult.SplitCannotSplitPoint.__doc__
QgsGeometry.OperationChangedGeometryType = Qgis.GeometryOperationResult.OperationChangedGeometryType
QgsGeometry.OperationChangedGeometryType.is_monkey_patched = True
QgsGeometry.OperationChangedGeometryType.__doc__ = "Operation has changed geometry type"
Qgis.GeometryOperationResult.__doc__ = "Success or failure of a geometry operation.\n\nThis enum gives details about cause of failure.\n\n.. versionadded:: 3.22\n\n" + '* ``Success``: ' + Qgis.GeometryOperationResult.Success.__doc__ + '\n' + '* ``NothingHappened``: ' + Qgis.GeometryOperationResult.NothingHappened.__doc__ + '\n' + '* ``InvalidBaseGeometry``: ' + Qgis.GeometryOperationResult.InvalidBaseGeometry.__doc__ + '\n' + '* ``InvalidInputGeometryType``: ' + Qgis.GeometryOperationResult.InvalidInputGeometryType.__doc__ + '\n' + '* ``SelectionIsEmpty``: ' + Qgis.GeometryOperationResult.SelectionIsEmpty.__doc__ + '\n' + '* ``SelectionIsGreaterThanOne``: ' + Qgis.GeometryOperationResult.SelectionIsGreaterThanOne.__doc__ + '\n' + '* ``GeometryEngineError``: ' + Qgis.GeometryOperationResult.GeometryEngineError.__doc__ + '\n' + '* ``LayerNotEditable``: ' + Qgis.GeometryOperationResult.LayerNotEditable.__doc__ + '\n' + '* ``AddPartSelectedGeometryNotFound``: ' + Qgis.GeometryOperationResult.AddPartSelectedGeometryNotFound.__doc__ + '\n' + '* ``AddPartNotMultiGeometry``: ' + Qgis.GeometryOperationResult.AddPartNotMultiGeometry.__doc__ + '\n' + '* ``AddRingNotClosed``: ' + Qgis.GeometryOperationResult.AddRingNotClosed.__doc__ + '\n' + '* ``AddRingNotValid``: ' + Qgis.GeometryOperationResult.AddRingNotValid.__doc__ + '\n' + '* ``AddRingCrossesExistingRings``: ' + Qgis.GeometryOperationResult.AddRingCrossesExistingRings.__doc__ + '\n' + '* ``AddRingNotInExistingFeature``: ' + Qgis.GeometryOperationResult.AddRingNotInExistingFeature.__doc__ + '\n' + '* ``SplitCannotSplitPoint``: ' + Qgis.GeometryOperationResult.SplitCannotSplitPoint.__doc__ + '\n' + '* ``OperationChangedGeometryType``: ' + Qgis.GeometryOperationResult.OperationChangedGeometryType.__doc__
# --
Qgis.GeometryOperationResult.baseClass = Qgis
QgsGeometry.ValidityFlag = Qgis.GeometryValidityFlag
Expand Down
18 changes: 17 additions & 1 deletion python/core/auto_generated/geometry/qgsgeometry.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -2430,7 +2430,7 @@ empty if none of the child geometries match the desired type.
.. versionadded:: 3.2
%End

int avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers );
int avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers );

%Docstring
Modifies geometry to avoid intersections with the layers specified in project properties
Expand All @@ -2444,6 +2444,22 @@ Modifies geometry to avoid intersections with the layers specified in project pr
4 if the geometry is not intersected by one of the geometries present in the provided layers.

.. versionadded:: 1.5
%End

Qgis::GeometryOperationResult avoidIntersectionsV2( const QList<QgsVectorLayer *> &avoidIntersectionsLayers );

%Docstring
Modifies geometry to avoid intersections with the layers specified in project properties

:param avoidIntersectionsLayers: list of layers to check for intersections

:return: Success in case of success
InvalidInputGeometryType if geometry is not of polygon type
OperationChangedGeometryType if avoid intersection has changed the geometry type,
InvalidBaseGeometry at least one geometry intersected is invalid. The algorithm may not work and return the same geometry as the input. You must fix your intersecting geometries.
NothingHappened if the geometry is not intersected by one of the geometries present in the provided layers.

.. versionadded:: 3.34
%End

QgsGeometry makeValid( Qgis::MakeValidMethod method = Qgis::MakeValidMethod::Linework, bool keepCollapsed = false ) const throw( QgsNotSupportedException );
Expand Down
1 change: 1 addition & 0 deletions python/core/auto_generated/qgis.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,7 @@ The development version
AddRingNotInExistingFeature,
// Split features
SplitCannotSplitPoint,
OperationChangedGeometryType,
};

enum class GeometryValidityFlag
Expand Down
9 changes: 4 additions & 5 deletions src/app/gps/qgsappgpsdigitizing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,18 +277,18 @@ void QgsAppGpsDigitizing::createFeature()

if ( geometryLayerCrs.type() == Qgis::GeometryType::Polygon )
{
const int avoidIntersectionsReturn = geometryLayerCrs.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
if ( avoidIntersectionsReturn == 1 )
const Qgis::GeometryOperationResult avoidIntersectionsReturn = geometryLayerCrs.avoidIntersectionsV2( QgsProject::instance()->avoidIntersectionsLayers() );
if ( avoidIntersectionsReturn == Qgis::GeometryOperationResult::InvalidInputGeometryType )
{
//not a polygon type. Impossible to get there
}
else if ( avoidIntersectionsReturn == 2 )
else if ( avoidIntersectionsReturn == Qgis::GeometryOperationResult::OperationChangedGeometryType )
{
//bail out...
QgisApp::instance()->messageBar()->pushWarning( tr( "Add Feature" ), tr( "The feature could not be added because removing the polygon intersections would change the geometry type." ) );
return;
}
else if ( avoidIntersectionsReturn == 3 )
else if ( avoidIntersectionsReturn == Qgis::GeometryOperationResult::InvalidBaseGeometry )
{
QgisApp::instance()->messageBar()->pushCritical( tr( "Add Feature" ), tr( "The feature has been added, but at least one geometry intersected is invalid. These geometries must be manually repaired." ) );
return;
Expand Down Expand Up @@ -488,4 +488,3 @@ QVariant QgsAppGpsDigitizing::timestamp( QgsVectorLayer *vlayer, int idx ) const
}
return value;
}

2 changes: 1 addition & 1 deletion src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10221,7 +10221,7 @@ void QgisApp::pasteFromClipboard( QgsMapLayer *destinationLayer )
}
if ( avoidIntersectionsLayers.size() > 0 )
{
geom.avoidIntersections( avoidIntersectionsLayers );
geom.avoidIntersectionsV2( avoidIntersectionsLayers );
}

// count collapsed geometries
Expand Down
2 changes: 1 addition & 1 deletion src/app/qgsmaptooladdpart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ void QgsMapToolAddPart::finalizeEditCommand( QgsVectorLayer *layer, Qgis::Geomet
case Qgis::GeometryOperationResult::LayerNotEditable:
case Qgis::GeometryOperationResult::NothingHappened:
case Qgis::GeometryOperationResult::SplitCannotSplitPoint:
case Qgis::GeometryOperationResult::OperationChangedGeometryType:
// Should not reach here
// Other OperationResults should not be returned by addPart
errorMessage = tr( "Unexpected OperationResult: %1" ).arg( qgsEnumValueToKey( errorCode ) );
Expand Down Expand Up @@ -228,4 +229,3 @@ QgsVectorLayer *QgsMapToolAddPart::getLayerAndCheckSelection()
else
return nullptr;
}

1 change: 1 addition & 0 deletions src/app/qgsmaptooladdring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ void QgsMapToolAddRing::polygonCaptured( const QgsCurvePolygon *polygon )
case Qgis::GeometryOperationResult::LayerNotEditable:
case Qgis::GeometryOperationResult::AddPartSelectedGeometryNotFound:
case Qgis::GeometryOperationResult::AddPartNotMultiGeometry:
case Qgis::GeometryOperationResult::OperationChangedGeometryType:
errorMessage = tr( "an unknown error occurred (%1)" ).arg( qgsEnumValueToKey( addRingReturnCode ) );
break;
}
Expand Down
42 changes: 36 additions & 6 deletions src/core/geometry/qgsgeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3039,11 +3039,11 @@ bool QgsGeometry::deletePart( int partNum )
return ok;
}

int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
Qgis::GeometryOperationResult QgsGeometry::avoidIntersectionsV2( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
{
if ( !d->geometry )
{
return 1;
return Qgis::GeometryOperationResult::InvalidInputGeometryType;
}

Qgis::WkbType geomTypeBeforeModification = wkbType();
Expand All @@ -3059,15 +3059,45 @@ int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidInterse
}

if ( geomTypeBeforeModification != wkbType() )
return 2;
return Qgis::GeometryOperationResult::OperationChangedGeometryType;
if ( haveInvalidGeometry )
return 3;
return Qgis::GeometryOperationResult::InvalidBaseGeometry;
if ( !geomModified )
return 4;
return Qgis::GeometryOperationResult::NothingHappened;

return 0;
return Qgis::GeometryOperationResult::Success;
}

int QgsGeometry::avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures )
{
const Qgis::GeometryOperationResult result = avoidIntersectionsV2( avoidIntersectionsLayers, ignoreFeatures );
switch ( result )
{
case Qgis::GeometryOperationResult::Success:
return 0;
case Qgis::GeometryOperationResult::InvalidInputGeometryType:
return 1;
case Qgis::GeometryOperationResult::OperationChangedGeometryType:
return 2;
case Qgis::GeometryOperationResult::InvalidBaseGeometry:
return 3;
case Qgis::GeometryOperationResult::NothingHappened:
return 4;
case Qgis::GeometryOperationResult::SelectionIsEmpty:
case Qgis::GeometryOperationResult::SelectionIsGreaterThanOne:
case Qgis::GeometryOperationResult::GeometryEngineError:
case Qgis::GeometryOperationResult::LayerNotEditable:
case Qgis::GeometryOperationResult::AddPartSelectedGeometryNotFound:
case Qgis::GeometryOperationResult::AddPartNotMultiGeometry:
case Qgis::GeometryOperationResult::AddRingNotClosed:
case Qgis::GeometryOperationResult::AddRingNotValid:
case Qgis::GeometryOperationResult::AddRingCrossesExistingRings:
case Qgis::GeometryOperationResult::AddRingNotInExistingFeature:
case Qgis::GeometryOperationResult::SplitCannotSplitPoint:
// should never happen
return 4;
}
}

QgsGeometry QgsGeometry::makeValid( Qgis::MakeValidMethod method, bool keepCollapsed ) const
{
Expand Down
18 changes: 16 additions & 2 deletions src/core/geometry/qgsgeometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -2551,8 +2551,22 @@ class CORE_EXPORT QgsGeometry
* 4 if the geometry is not intersected by one of the geometries present in the provided layers.
* \since QGIS 1.5
*/
int avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers,
const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures SIP_PYARGREMOVE = ( QHash<QgsVectorLayer *, QSet<QgsFeatureId> >() ) );
Q_DECL_DEPRECATED int avoidIntersections( const QList<QgsVectorLayer *> &avoidIntersectionsLayers,
const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures SIP_PYARGREMOVE = ( QHash<QgsVectorLayer *, QSet<QgsFeatureId> >() ) );

/**
* Modifies geometry to avoid intersections with the layers specified in project properties
* \param avoidIntersectionsLayers list of layers to check for intersections
* \param ignoreFeatures possibility to give a list of features where intersections should be ignored (not available in Python bindings)
* \returns Success in case of success
* InvalidInputGeometryType if geometry is not of polygon type
* OperationChangedGeometryType if avoid intersection has changed the geometry type,
* InvalidBaseGeometry at least one geometry intersected is invalid. The algorithm may not work and return the same geometry as the input. You must fix your intersecting geometries.
* NothingHappened if the geometry is not intersected by one of the geometries present in the provided layers.
* \since QGIS 3.34
*/
Qgis::GeometryOperationResult avoidIntersectionsV2( const QList<QgsVectorLayer *> &avoidIntersectionsLayers,
const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures SIP_PYARGREMOVE = ( QHash<QgsVectorLayer *, QSet<QgsFeatureId> >() ) );

/**
* Attempts to make an invalid geometry valid without losing vertices.
Expand Down
1 change: 1 addition & 0 deletions src/core/qgis.h
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,7 @@ class CORE_EXPORT Qgis
AddRingNotInExistingFeature, //!< The input ring doesn't have any existing ring to fit into
// Split features
SplitCannotSplitPoint, //!< Cannot split points
OperationChangedGeometryType, //!< Operation has changed geometry type
};
Q_ENUM( GeometryOperationResult )

Expand Down
4 changes: 2 additions & 2 deletions src/gui/maptools/qgsmaptoolcapturelayergeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ void QgsMapToolCaptureLayerGeometry::geometryCaptured( const QgsGeometry &geomet
}
if ( avoidIntersectionsLayers.size() > 0 )
{
const int avoidIntersectionsReturn = g.avoidIntersections( avoidIntersectionsLayers );
if ( avoidIntersectionsReturn == 3 )
const Qgis::GeometryOperationResult avoidIntersectionsReturn = g.avoidIntersectionsV2( avoidIntersectionsLayers );
if ( avoidIntersectionsReturn == Qgis::GeometryOperationResult::InvalidBaseGeometry )
{
emit messageEmitted( tr( "The feature has been added, but at least one geometry intersected is invalid. These geometries must be manually repaired." ), Qgis::MessageLevel::Warning );
}
Expand Down

0 comments on commit a541a1a

Please sign in to comment.