mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Return enum instead of int from QgsGeometry operations
This commit is contained in:
parent
8d615543b7
commit
86e8da74cb
@ -44,6 +44,23 @@ class QgsGeometry
|
||||
#include "qgsgeometry.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum OperationResult
|
||||
{
|
||||
Success,
|
||||
NothingHappened,
|
||||
InvalidBaseGeometry,
|
||||
InvalidInput,
|
||||
GeometryEngineError,
|
||||
AddPartSelectedGeometryNotFound,
|
||||
AddPartNotMultiGeometry,
|
||||
AddRingNotClosed,
|
||||
AddRingNotValid,
|
||||
AddRingCrossesExistingRings,
|
||||
AddRingNotInExistingFeature,
|
||||
SplitCannotSplitPoint,
|
||||
};
|
||||
|
||||
QgsGeometry();
|
||||
%Docstring
|
||||
Constructor
|
||||
@ -380,63 +397,58 @@ Returns true if WKB of the geometry is of WKBMulti* type
|
||||
:rtype: float
|
||||
%End
|
||||
|
||||
int addRing( const QList<QgsPointXY> &ring );
|
||||
OperationResult addRing( const QList<QgsPointXY> &ring );
|
||||
%Docstring
|
||||
Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
|
||||
:return: 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
|
||||
3 ring is not valid geometry, 4 ring not disjoint with existing rings, 5 no polygon found which contained the ring*
|
||||
:rtype: int
|
||||
\param ring The ring to be added
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int addRing( QgsCurve *ring /Transfer/ );
|
||||
OperationResult addRing( QgsCurve *ring /Transfer/ );
|
||||
%Docstring
|
||||
Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
|
||||
:return: 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
|
||||
3 ring is not valid geometry, 4 ring not disjoint with existing rings, 5 no polygon found which contained the ring*
|
||||
:rtype: int
|
||||
\param ring The ring to be added
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int addPart( const QList<QgsPointXY> &points, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry ) /PyName=addPoints/;
|
||||
OperationResult addPart( const QList<QgsPointXY> &points, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry ) /PyName=addPoints/;
|
||||
%Docstring
|
||||
Adds a new part to a the geometry.
|
||||
\param points points describing part to add
|
||||
\param geomType default geometry type to create if no existing geometry
|
||||
:return: 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
not disjoint with existing polygons of the feature
|
||||
:rtype: int
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int addPart( const QgsPointSequence &points, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry ) /PyName=addPointsV2/;
|
||||
OperationResult addPart( const QgsPointSequence &points, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry ) /PyName=addPointsV2/;
|
||||
%Docstring
|
||||
Adds a new part to a the geometry.
|
||||
\param points points describing part to add
|
||||
\param geomType default geometry type to create if no existing geometry
|
||||
:return: 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
not disjoint with existing polygons of the feature
|
||||
:rtype: int
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int addPart( QgsAbstractGeometry *part /Transfer/, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry );
|
||||
OperationResult addPart( QgsAbstractGeometry *part /Transfer/, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry );
|
||||
%Docstring
|
||||
Adds a new part to this geometry.
|
||||
\param part part to add (ownership is transferred)
|
||||
\param geomType default geometry type to create if no existing geometry
|
||||
:return: 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
not disjoint with existing polygons of the feature
|
||||
:rtype: int
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
|
||||
int addPart( const QgsGeometry &newPart ) /PyName=addPartGeometry/;
|
||||
OperationResult addPart( const QgsGeometry &newPart ) /PyName=addPartGeometry/;
|
||||
%Docstring
|
||||
Adds a new island polygon to a multipolygon feature
|
||||
:return: 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
not disjoint with existing polygons of the feature
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
.. note::
|
||||
|
||||
available in Python bindings as addPartGeometry
|
||||
.. versionadded:: 2.2
|
||||
:rtype: int
|
||||
available in python bindings as addPartGeometry
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
QgsGeometry removeInteriorRings( double minimumAllowedArea = -1 ) const;
|
||||
@ -448,52 +460,52 @@ not disjoint with existing polygons of the feature
|
||||
:rtype: QgsGeometry
|
||||
%End
|
||||
|
||||
int translate( double dx, double dy );
|
||||
OperationResult translate( double dx, double dy );
|
||||
%Docstring
|
||||
Translate this geometry by dx, dy
|
||||
:return: 0 in case of success*
|
||||
:rtype: int
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int transform( const QgsCoordinateTransform &ct );
|
||||
OperationResult transform( const QgsCoordinateTransform &ct );
|
||||
%Docstring
|
||||
Transform this geometry as described by CoordinateTransform ct
|
||||
:return: 0 in case of success*
|
||||
:rtype: int
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int transform( const QTransform &ct );
|
||||
OperationResult transform( const QTransform &ct );
|
||||
%Docstring
|
||||
Transform this geometry as described by QTransform ct
|
||||
.. versionadded:: 2.8
|
||||
:return: 0 in case of success*
|
||||
:rtype: int
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int rotate( double rotation, const QgsPointXY ¢er );
|
||||
OperationResult rotate( double rotation, const QgsPointXY ¢er );
|
||||
%Docstring
|
||||
Rotate this geometry around the Z axis
|
||||
.. versionadded:: 2.8
|
||||
\param rotation clockwise rotation in degrees
|
||||
\param center rotation center
|
||||
:return: 0 in case of success*
|
||||
:rtype: int
|
||||
\param rotation clockwise rotation in degrees
|
||||
\param center rotation center
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int splitGeometry( const QList<QgsPointXY> &splitLine,
|
||||
QList<QgsGeometry> &newGeometries /Out/,
|
||||
bool topological,
|
||||
QList<QgsPointXY> &topologyTestPoints /Out/ );
|
||||
OperationResult splitGeometry( const QList<QgsPointXY> &splitLine, QList<QgsGeometry> &newGeometries, bool topological, QList<QgsPointXY> &topologyTestPoints );
|
||||
%Docstring
|
||||
:rtype: int
|
||||
Splits this geometry according to a given line.
|
||||
\param splitLine the line that splits the geometry
|
||||
\param[out] newGeometries list of new geometries that have been created with the split
|
||||
\param topological true if topological editing is enabled
|
||||
\param[out] topologyTestPoints points that need to be tested for topological completeness in the dataset
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
int reshapeGeometry( const QgsLineString &reshapeLineString );
|
||||
OperationResult reshapeGeometry( const QgsLineString &reshapeLineString );
|
||||
%Docstring
|
||||
Replaces a part of this geometry with another line
|
||||
:return: 0 in case of success
|
||||
.. versionadded:: 1.3
|
||||
:rtype: int
|
||||
:return: OperationResult a result code: success or reason of failure
|
||||
:rtype: OperationResult
|
||||
%End
|
||||
|
||||
|
||||
|
@ -21,6 +21,19 @@ class QgsGeometryEngine
|
||||
#include "qgsgeometryengine.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum EngineOperationResult
|
||||
{
|
||||
Success,
|
||||
NothingHappened,
|
||||
MethodNotImplemented,
|
||||
EngineError,
|
||||
NodedGeometryError,
|
||||
InvalidBaseGeometry,
|
||||
InvalidInput,
|
||||
SplitCannotSplitPoint,
|
||||
};
|
||||
|
||||
virtual ~QgsGeometryEngine();
|
||||
|
||||
virtual void geometryChanged() = 0;
|
||||
@ -230,12 +243,12 @@ class QgsGeometryEngine
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
virtual int splitGeometry( const QgsLineString &splitLine,
|
||||
QList<QgsAbstractGeometry *> &newGeometries,
|
||||
bool topological,
|
||||
QgsPointSequence &topologyTestPoints, QString *errorMsg = 0 ) const;
|
||||
virtual QgsGeometryEngine::EngineOperationResult splitGeometry( const QgsLineString &splitLine,
|
||||
QList<QgsAbstractGeometry *> &newGeometries,
|
||||
bool topological,
|
||||
QgsPointSequence &topologyTestPoints, QString *errorMsg = 0 ) const;
|
||||
%Docstring
|
||||
:rtype: int
|
||||
:rtype: QgsGeometryEngine.EngineOperationResult
|
||||
%End
|
||||
|
||||
virtual QgsAbstractGeometry *offsetCurve( double distance, int segments, int joinStyle, double miterLimit, QString *errorMsg = 0 ) const = 0 /Factory/;
|
||||
|
@ -63,29 +63,51 @@ class QgsVectorLayerEditUtils
|
||||
:rtype: QgsVectorLayer.EditResult
|
||||
%End
|
||||
|
||||
int addRing( const QList<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds = QgsFeatureIds(), QgsFeatureId *modifiedFeatureId = 0 );
|
||||
QgsGeometry::OperationResult addRing( const QList<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds = QgsFeatureIds(), QgsFeatureId *modifiedFeatureId = 0 );
|
||||
%Docstring
|
||||
:rtype: int
|
||||
Adds a ring to polygon/multipolygon features
|
||||
@param ring ring to add
|
||||
@param targetFeatureIds if specified, only these features will be the candidates for adding a ring. Otherwise
|
||||
all intersecting features are tested and the ring is added to the first valid feature.
|
||||
@param modifiedFeatureId if specified, feature ID for feature that ring was added to will be stored in this parameter
|
||||
@return OperationResult result code: success or reason of failure
|
||||
:rtype: QgsGeometry.OperationResult
|
||||
%End
|
||||
|
||||
int addRing( QgsCurve *ring, const QgsFeatureIds &targetFeatureIds = QgsFeatureIds(), QgsFeatureId *modifiedFeatureId = 0 ) /PyName=addCurvedRing/;
|
||||
QgsGeometry::OperationResult addRing( QgsCurve *ring, const QgsFeatureIds &targetFeatureIds = QgsFeatureIds(), QgsFeatureId *modifiedFeatureId = 0 ) /PyName=addCurvedRing/;
|
||||
%Docstring
|
||||
:rtype: int
|
||||
Adds a ring to polygon/multipolygon features
|
||||
@param ring ring to add
|
||||
@param targetFeatureIds if specified, only these features will be the candidates for adding a ring. Otherwise
|
||||
all intersecting features are tested and the ring is added to the first valid feature.
|
||||
@param modifiedFeatureId if specified, feature ID for feature that ring was added to will be stored in this parameter
|
||||
@return OperationResult result code: success or reason of failure
|
||||
.. note::
|
||||
|
||||
available in python bindings as addCurvedRing
|
||||
:rtype: QgsGeometry.OperationResult
|
||||
%End
|
||||
|
||||
int addPart( const QList<QgsPointXY> &ring, QgsFeatureId featureId );
|
||||
QgsGeometry::OperationResult addPart( const QList<QgsPointXY> &ring, QgsFeatureId featureId );
|
||||
%Docstring
|
||||
:rtype: int
|
||||
Adds a new part polygon to a multipart feature
|
||||
@returns QgsGeometry.OperationResult a result code: success or reason of failure
|
||||
:rtype: QgsGeometry.OperationResult
|
||||
%End
|
||||
|
||||
int addPart( const QgsPointSequence &ring, QgsFeatureId featureId );
|
||||
QgsGeometry::OperationResult addPart( const QgsPointSequence &ring, QgsFeatureId featureId );
|
||||
%Docstring
|
||||
:rtype: int
|
||||
Adds a new part polygon to a multipart feature
|
||||
@returns QgsGeometry.OperationResult a result code: success or reason of failure
|
||||
.. note::
|
||||
|
||||
available in python bindings as addPartV2
|
||||
:rtype: QgsGeometry.OperationResult
|
||||
%End
|
||||
|
||||
int addPart( QgsCurve *ring, QgsFeatureId featureId ) /PyName=addCurvedPart/;
|
||||
QgsGeometry::OperationResult addPart( QgsCurve *ring, QgsFeatureId featureId ) /PyName=addCurvedPart/;
|
||||
%Docstring
|
||||
:rtype: int
|
||||
:rtype: QgsGeometry.OperationResult
|
||||
%End
|
||||
|
||||
int translateFeature( QgsFeatureId featureId, double dx, double dy );
|
||||
@ -98,14 +120,14 @@ class QgsVectorLayerEditUtils
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
int splitParts( const QList<QgsPointXY> &splitLine, bool topologicalEditing = false );
|
||||
QgsGeometry::OperationResult splitParts( const QList<QgsPointXY> &splitLine, bool topologicalEditing = false );
|
||||
%Docstring
|
||||
:rtype: int
|
||||
:rtype: QgsGeometry.OperationResult
|
||||
%End
|
||||
|
||||
int splitFeatures( const QList<QgsPointXY> &splitLine, bool topologicalEditing = false );
|
||||
QgsGeometry::OperationResult splitFeatures( const QList<QgsPointXY> &splitLine, bool topologicalEditing = false );
|
||||
%Docstring
|
||||
:rtype: int
|
||||
:rtype: QgsGeometry.OperationResult
|
||||
%End
|
||||
|
||||
int addTopologicalPoints( const QgsGeometry &geom );
|
||||
@ -130,15 +152,6 @@ class QgsVectorLayerEditUtils
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
int boundingBoxFromPointList( const QList<QgsPointXY> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const;
|
||||
%Docstring
|
||||
Little helper function that gives bounding box from a list of points.
|
||||
:return: 0 in case of success *
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
|
@ -626,7 +626,7 @@ double QgsGeometry::closestSegmentWithContext(
|
||||
return sqrDist;
|
||||
}
|
||||
|
||||
int QgsGeometry::addRing( const QList<QgsPointXY> &ring )
|
||||
QgsGeometry::OperationResult QgsGeometry::addRing( const QList<QgsPointXY> &ring )
|
||||
{
|
||||
detach( true );
|
||||
|
||||
@ -634,12 +634,12 @@ int QgsGeometry::addRing( const QList<QgsPointXY> &ring )
|
||||
return addRing( ringLine );
|
||||
}
|
||||
|
||||
int QgsGeometry::addRing( QgsCurve *ring )
|
||||
QgsGeometry::OperationResult QgsGeometry::addRing( QgsCurve *ring )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
delete ring;
|
||||
return 1;
|
||||
return InvalidInput;
|
||||
}
|
||||
|
||||
detach( true );
|
||||
@ -647,14 +647,14 @@ int QgsGeometry::addRing( QgsCurve *ring )
|
||||
return QgsGeometryEditUtils::addRing( d->geometry, ring );
|
||||
}
|
||||
|
||||
int QgsGeometry::addPart( const QList<QgsPointXY> &points, QgsWkbTypes::GeometryType geomType )
|
||||
QgsGeometry::OperationResult QgsGeometry::addPart( const QList<QgsPointXY> &points, QgsWkbTypes::GeometryType geomType )
|
||||
{
|
||||
QgsPointSequence l;
|
||||
convertPointList( points, l );
|
||||
return addPart( l, geomType );
|
||||
}
|
||||
|
||||
int QgsGeometry::addPart( const QgsPointSequence &points, QgsWkbTypes::GeometryType geomType )
|
||||
QgsGeometry::OperationResult QgsGeometry::addPart( const QgsPointSequence &points, QgsWkbTypes::GeometryType geomType )
|
||||
{
|
||||
QgsAbstractGeometry *partGeom = nullptr;
|
||||
if ( points.size() == 1 )
|
||||
@ -670,7 +670,7 @@ int QgsGeometry::addPart( const QgsPointSequence &points, QgsWkbTypes::GeometryT
|
||||
return addPart( partGeom, geomType );
|
||||
}
|
||||
|
||||
int QgsGeometry::addPart( QgsAbstractGeometry *part, QgsWkbTypes::GeometryType geomType )
|
||||
QgsGeometry::OperationResult QgsGeometry::addPart( QgsAbstractGeometry *part, QgsWkbTypes::GeometryType geomType )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
@ -687,7 +687,7 @@ int QgsGeometry::addPart( QgsAbstractGeometry *part, QgsWkbTypes::GeometryType g
|
||||
d->geometry = new QgsMultiPolygonV2();
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return QgsGeometry::AddPartNotMultiGeometry;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -699,11 +699,15 @@ int QgsGeometry::addPart( QgsAbstractGeometry *part, QgsWkbTypes::GeometryType g
|
||||
return QgsGeometryEditUtils::addPart( d->geometry, part );
|
||||
}
|
||||
|
||||
int QgsGeometry::addPart( const QgsGeometry &newPart )
|
||||
QgsGeometry::OperationResult QgsGeometry::addPart( const QgsGeometry &newPart )
|
||||
{
|
||||
if ( !d->geometry || !newPart.d || !newPart.d->geometry )
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
}
|
||||
if ( !newPart.d || !newPart.d->geometry )
|
||||
{
|
||||
return QgsGeometry::AddPartNotMultiGeometry;
|
||||
}
|
||||
|
||||
return addPart( newPart.d->geometry->clone() );
|
||||
@ -744,11 +748,15 @@ QgsGeometry QgsGeometry::removeInteriorRings( double minimumRingArea ) const
|
||||
}
|
||||
}
|
||||
|
||||
int QgsGeometry::addPart( GEOSGeometry *newPart )
|
||||
QgsGeometry::OperationResult QgsGeometry::addPart( GEOSGeometry *newPart )
|
||||
{
|
||||
if ( !d->geometry || !newPart )
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
}
|
||||
if ( !newPart )
|
||||
{
|
||||
return QgsGeometry::AddPartNotMultiGeometry;
|
||||
}
|
||||
|
||||
detach( true );
|
||||
@ -757,24 +765,24 @@ int QgsGeometry::addPart( GEOSGeometry *newPart )
|
||||
return QgsGeometryEditUtils::addPart( d->geometry, geom );
|
||||
}
|
||||
|
||||
int QgsGeometry::translate( double dx, double dy )
|
||||
QgsGeometry::OperationResult QgsGeometry::translate( double dx, double dy )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
detach( true );
|
||||
|
||||
d->geometry->transform( QTransform::fromTranslate( dx, dy ) );
|
||||
return 0;
|
||||
return QgsGeometry::Success;
|
||||
}
|
||||
|
||||
int QgsGeometry::rotate( double rotation, const QgsPointXY ¢er )
|
||||
QgsGeometry::OperationResult QgsGeometry::rotate( double rotation, const QgsPointXY ¢er )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
detach( true );
|
||||
@ -783,14 +791,14 @@ int QgsGeometry::rotate( double rotation, const QgsPointXY ¢er )
|
||||
t.rotate( -rotation );
|
||||
t.translate( -center.x(), -center.y() );
|
||||
d->geometry->transform( t );
|
||||
return 0;
|
||||
return QgsGeometry::Success;
|
||||
}
|
||||
|
||||
int QgsGeometry::splitGeometry( const QList<QgsPointXY> &splitLine, QList<QgsGeometry> &newGeometries, bool topological, QList<QgsPointXY> &topologyTestPoints )
|
||||
QgsGeometry::OperationResult QgsGeometry::splitGeometry( const QList<QgsPointXY> &splitLine, QList<QgsGeometry> &newGeometries, bool topological, QList<QgsPointXY> &topologyTestPoints )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 0;
|
||||
return InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
QList<QgsAbstractGeometry *> newGeoms;
|
||||
@ -798,9 +806,9 @@ int QgsGeometry::splitGeometry( const QList<QgsPointXY> &splitLine, QList<QgsGeo
|
||||
QgsPointSequence tp;
|
||||
|
||||
QgsGeos geos( d->geometry );
|
||||
int result = geos.splitGeometry( splitLineString, newGeoms, topological, tp );
|
||||
QgsGeometryEngine::EngineOperationResult result = geos.splitGeometry( splitLineString, newGeoms, topological, tp );
|
||||
|
||||
if ( result == 0 )
|
||||
if ( result == QgsGeometryEngine::Success )
|
||||
{
|
||||
detach( false );
|
||||
d->geometry = newGeoms.at( 0 );
|
||||
@ -813,27 +821,69 @@ int QgsGeometry::splitGeometry( const QList<QgsPointXY> &splitLine, QList<QgsGeo
|
||||
}
|
||||
|
||||
convertPointList( tp, topologyTestPoints );
|
||||
return result;
|
||||
|
||||
switch ( result )
|
||||
{
|
||||
case QgsGeometryEngine::Success:
|
||||
return QgsGeometry::Success;
|
||||
case QgsGeometryEngine::MethodNotImplemented:
|
||||
case QgsGeometryEngine::EngineError:
|
||||
case QgsGeometryEngine::NodedGeometryError:
|
||||
return QgsGeometry::GeometryEngineError;
|
||||
case QgsGeometryEngine::InvalidBaseGeometry:
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
case QgsGeometryEngine::InvalidInput:
|
||||
return QgsGeometry::InvalidInput;
|
||||
case QgsGeometryEngine::SplitCannotSplitPoint:
|
||||
return QgsGeometry::SplitCannotSplitPoint;
|
||||
case QgsGeometryEngine::NothingHappened:
|
||||
return QgsGeometry::NothingHappened;
|
||||
//default: do not implement default to handle properly all cases
|
||||
}
|
||||
|
||||
// this should never be reached
|
||||
Q_ASSERT( false );
|
||||
return QgsGeometry::NothingHappened;
|
||||
}
|
||||
|
||||
int QgsGeometry::reshapeGeometry( const QgsLineString &reshapeLineString )
|
||||
QgsGeometry::OperationResult QgsGeometry::reshapeGeometry( const QgsLineString &reshapeLineString )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 0;
|
||||
return InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
QgsGeos geos( d->geometry );
|
||||
int errorCode = 0;
|
||||
QgsGeometryEngine::EngineOperationResult errorCode = QgsGeometryEngine::Success;
|
||||
QgsAbstractGeometry *geom = geos.reshapeGeometry( reshapeLineString, &errorCode );
|
||||
if ( errorCode == 0 && geom )
|
||||
if ( errorCode == QgsGeometryEngine::Success && geom )
|
||||
{
|
||||
detach( false );
|
||||
delete d->geometry;
|
||||
d->geometry = geom;
|
||||
return 0;
|
||||
return Success;
|
||||
}
|
||||
return errorCode;
|
||||
|
||||
switch ( errorCode )
|
||||
{
|
||||
case QgsGeometryEngine::Success:
|
||||
return Success;
|
||||
case QgsGeometryEngine::MethodNotImplemented:
|
||||
case QgsGeometryEngine::EngineError:
|
||||
case QgsGeometryEngine::NodedGeometryError:
|
||||
return GeometryEngineError;
|
||||
case QgsGeometryEngine::InvalidBaseGeometry:
|
||||
return InvalidBaseGeometry;
|
||||
case QgsGeometryEngine::InvalidInput:
|
||||
return InvalidInput;
|
||||
case QgsGeometryEngine::SplitCannotSplitPoint: // should not happen
|
||||
return GeometryEngineError;
|
||||
case QgsGeometryEngine::NothingHappened:
|
||||
return NothingHappened;
|
||||
}
|
||||
|
||||
// should not be reached
|
||||
return GeometryEngineError;
|
||||
}
|
||||
|
||||
int QgsGeometry::makeDifferenceInPlace( const QgsGeometry &other )
|
||||
@ -2091,28 +2141,28 @@ bool QgsGeometry::requiresConversionToStraightSegments() const
|
||||
return d->geometry->hasCurvedSegments();
|
||||
}
|
||||
|
||||
int QgsGeometry::transform( const QgsCoordinateTransform &ct )
|
||||
QgsGeometry::OperationResult QgsGeometry::transform( const QgsCoordinateTransform &ct )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
detach();
|
||||
d->geometry->transform( ct );
|
||||
return 0;
|
||||
return QgsGeometry::Success;
|
||||
}
|
||||
|
||||
int QgsGeometry::transform( const QTransform &ct )
|
||||
QgsGeometry::OperationResult QgsGeometry::transform( const QTransform &ct )
|
||||
{
|
||||
if ( !d->geometry )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
detach();
|
||||
d->geometry->transform( ct );
|
||||
return 0;
|
||||
return QgsGeometry::Success;
|
||||
}
|
||||
|
||||
void QgsGeometry::mapToPixel( const QgsMapToPixel &mtp )
|
||||
|
@ -96,6 +96,30 @@ struct QgsGeometryPrivate;
|
||||
class CORE_EXPORT QgsGeometry
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Success or failure of a geometry operation.
|
||||
* This gived details about cause of failure.
|
||||
*/
|
||||
enum OperationResult
|
||||
{
|
||||
Success = 0, //!< Operation succeeded
|
||||
NothingHappened, //!< Nothing happened, without any error
|
||||
InvalidBaseGeometry, //!< The base geometry on which the operation is done is invalid or empty
|
||||
InvalidInput, //!< The input geometry (ring, part, split line, etc.) has not the correct geometry type
|
||||
GeometryEngineError, //!< Geometry engine misses a method implemented or an error occured in the geometry engine
|
||||
/* Add part issues */
|
||||
AddPartSelectedGeometryNotFound, //!< The selected geometry cannot be found
|
||||
AddPartNotMultiGeometry, //!< The source geometry is not multi
|
||||
/* Add ring issues*/
|
||||
AddRingNotClosed, //!< The imput ring is not closed
|
||||
AddRingNotValid, //!< The input ring is not valid
|
||||
AddRingCrossesExistingRings, //!< The input ring crosses existing rings (it is not disjoint)
|
||||
AddRingNotInExistingFeature, //!< The input ring doesn't have any existing ring to fit into
|
||||
/* Split features */
|
||||
SplitCannotSplitPoint, //!< Cannot split points
|
||||
};
|
||||
|
||||
//! Constructor
|
||||
QgsGeometry();
|
||||
|
||||
@ -390,62 +414,58 @@ class CORE_EXPORT QgsGeometry
|
||||
double closestSegmentWithContext( const QgsPointXY &point, QgsPointXY &minDistPoint SIP_OUT, int &afterVertex SIP_OUT ) const;
|
||||
#endif
|
||||
|
||||
/** Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
|
||||
\returns 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
|
||||
3 ring is not valid geometry, 4 ring not disjoint with existing rings, 5 no polygon found which contained the ring*/
|
||||
int addRing( const QList<QgsPointXY> &ring );
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
/**
|
||||
* Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
|
||||
* \param ring The ring to be added
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
OperationResult addRing( const QList<QgsPointXY> &ring );
|
||||
|
||||
/** Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
|
||||
\returns 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
|
||||
3 ring is not valid geometry, 4 ring not disjoint with existing rings, 5 no polygon found which contained the ring*/
|
||||
int addRing( QgsCurve *ring SIP_TRANSFER );
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
/**
|
||||
* Adds a new ring to this geometry. This makes only sense for polygon and multipolygons.
|
||||
* \param ring The ring to be added
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
OperationResult addRing( QgsCurve *ring SIP_TRANSFER );
|
||||
|
||||
/** Adds a new part to a the geometry.
|
||||
/**
|
||||
* Adds a new part to a the geometry.
|
||||
* \param points points describing part to add
|
||||
* \param geomType default geometry type to create if no existing geometry
|
||||
* \returns 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
* not disjoint with existing polygons of the feature
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
int addPart( const QList<QgsPointXY> &points, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry ) SIP_PYNAME( addPoints );
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
OperationResult addPart( const QList<QgsPointXY> &points, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry ) SIP_PYNAME( addPoints );
|
||||
|
||||
/** Adds a new part to a the geometry.
|
||||
/**
|
||||
* Adds a new part to a the geometry.
|
||||
* \param points points describing part to add
|
||||
* \param geomType default geometry type to create if no existing geometry
|
||||
* \returns 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
* not disjoint with existing polygons of the feature
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
int addPart( const QgsPointSequence &points, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry ) SIP_PYNAME( addPointsV2 );
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
OperationResult addPart( const QgsPointSequence &points, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry ) SIP_PYNAME( addPointsV2 );
|
||||
|
||||
/** Adds a new part to this geometry.
|
||||
/**
|
||||
* Adds a new part to this geometry.
|
||||
* \param part part to add (ownership is transferred)
|
||||
* \param geomType default geometry type to create if no existing geometry
|
||||
* \returns 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
* not disjoint with existing polygons of the feature
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
int addPart( QgsAbstractGeometry *part SIP_TRANSFER, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry );
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
OperationResult addPart( QgsAbstractGeometry *part SIP_TRANSFER, QgsWkbTypes::GeometryType geomType = QgsWkbTypes::UnknownGeometry );
|
||||
|
||||
/** Adds a new island polygon to a multipolygon feature
|
||||
/**
|
||||
* Adds a new island polygon to a multipolygon feature
|
||||
* \param newPart part to add. Ownership is NOT transferred.
|
||||
* \returns 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
* not disjoint with existing polygons of the feature
|
||||
* \note not available in Python bindings
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
* \note not available in python bindings
|
||||
*/
|
||||
int addPart( GEOSGeometry *newPart ) SIP_SKIP;
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
OperationResult addPart( GEOSGeometry *newPart ) SIP_SKIP;
|
||||
|
||||
/** Adds a new island polygon to a multipolygon feature
|
||||
\returns 0 in case of success, 1 if not a multipolygon, 2 if ring is not a valid geometry, 3 if new polygon ring
|
||||
not disjoint with existing polygons of the feature
|
||||
\note available in Python bindings as addPartGeometry
|
||||
\since QGIS 2.2
|
||||
/**
|
||||
* Adds a new island polygon to a multipolygon feature
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
* \note available in python bindings as addPartGeometry
|
||||
*/
|
||||
int addPart( const QgsGeometry &newPart ) SIP_PYNAME( addPartGeometry );
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
OperationResult addPart( const QgsGeometry &newPart ) SIP_PYNAME( addPartGeometry );
|
||||
|
||||
/**
|
||||
* Removes the interior rings from a (multi)polygon geometry. If the minimumAllowedArea
|
||||
@ -455,52 +475,57 @@ class CORE_EXPORT QgsGeometry
|
||||
*/
|
||||
QgsGeometry removeInteriorRings( double minimumAllowedArea = -1 ) const;
|
||||
|
||||
/** Translate this geometry by dx, dy
|
||||
\returns 0 in case of success*/
|
||||
int translate( double dx, double dy );
|
||||
|
||||
/** Transform this geometry as described by CoordinateTransform ct
|
||||
\returns 0 in case of success*/
|
||||
int transform( const QgsCoordinateTransform &ct );
|
||||
|
||||
/** Transform this geometry as described by QTransform ct
|
||||
\since QGIS 2.8
|
||||
\returns 0 in case of success*/
|
||||
int transform( const QTransform &ct );
|
||||
|
||||
/** Rotate this geometry around the Z axis
|
||||
\since QGIS 2.8
|
||||
\param rotation clockwise rotation in degrees
|
||||
\param center rotation center
|
||||
\returns 0 in case of success*/
|
||||
int rotate( double rotation, const QgsPointXY ¢er );
|
||||
|
||||
/** Splits this geometry according to a given line.
|
||||
\param splitLine the line that splits the geometry
|
||||
\param[out] newGeometries list of new geometries that have been created with the split
|
||||
\param topological true if topological editing is enabled
|
||||
\param[out] topologyTestPoints points that need to be tested for topological completeness in the dataset
|
||||
\returns 0 in case of success, 1 if geometry has not been split, error else*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
int splitGeometry( const QList<QgsPointXY> &splitLine,
|
||||
QList<QgsGeometry> &newGeometries SIP_OUT,
|
||||
bool topological,
|
||||
QList<QgsPointXY> &topologyTestPoints SIP_OUT );
|
||||
|
||||
/** Replaces a part of this geometry with another line
|
||||
* \returns 0 in case of success
|
||||
* \since QGIS 1.3
|
||||
/**
|
||||
* Translate this geometry by dx, dy
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
int reshapeGeometry( const QgsLineString &reshapeLineString );
|
||||
OperationResult translate( double dx, double dy );
|
||||
|
||||
/** Changes this geometry such that it does not intersect the other geometry
|
||||
/**
|
||||
* Transform this geometry as described by CoordinateTransform ct
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
OperationResult transform( const QgsCoordinateTransform &ct );
|
||||
|
||||
/**
|
||||
* Transform this geometry as described by QTransform ct
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
OperationResult transform( const QTransform &ct );
|
||||
|
||||
/**
|
||||
* Rotate this geometry around the Z axis
|
||||
* \param rotation clockwise rotation in degrees
|
||||
* \param center rotation center
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
OperationResult rotate( double rotation, const QgsPointXY ¢er );
|
||||
|
||||
/**
|
||||
* Splits this geometry according to a given line.
|
||||
* \param splitLine the line that splits the geometry
|
||||
* \param[out] newGeometries list of new geometries that have been created with the split
|
||||
* \param topological true if topological editing is enabled
|
||||
* \param[out] topologyTestPoints points that need to be tested for topological completeness in the dataset
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
OperationResult splitGeometry( const QList<QgsPointXY> &splitLine, QList<QgsGeometry> &newGeometries, bool topological, QList<QgsPointXY> &topologyTestPoints );
|
||||
|
||||
/**
|
||||
* Replaces a part of this geometry with another line
|
||||
* \returns OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
OperationResult reshapeGeometry( const QgsLineString &reshapeLineString );
|
||||
|
||||
/**
|
||||
* Changes this geometry such that it does not intersect the other geometry
|
||||
* \param other geometry that should not be intersect
|
||||
* \returns 0 in case of success
|
||||
* \note Not available in Python
|
||||
*/
|
||||
int makeDifferenceInPlace( const QgsGeometry &other ) SIP_SKIP;
|
||||
|
||||
/** Returns the geometry formed by modifying this geometry such that it does not
|
||||
/**
|
||||
* Returns the geometry formed by modifying this geometry such that it does not
|
||||
* intersect the other geometry.
|
||||
* \param other geometry that should not be intersect
|
||||
* \returns difference geometry, or empty geometry if difference could not be calculated
|
||||
|
@ -26,11 +26,12 @@ email : marco.hugentobler at sourcepole dot com
|
||||
#include "qgsvectorlayer.h"
|
||||
#include <limits>
|
||||
|
||||
int QgsGeometryEditUtils::addRing( QgsAbstractGeometry *geom, QgsCurve *ring )
|
||||
QgsGeometry::OperationResult QgsGeometryEditUtils::addRing( QgsAbstractGeometry *geom, QgsCurve *r )
|
||||
{
|
||||
std::unique_ptr<QgsCurve> ring( r );
|
||||
if ( !ring )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidInput;
|
||||
}
|
||||
|
||||
QList< QgsCurvePolygon * > polygonList;
|
||||
@ -50,23 +51,20 @@ int QgsGeometryEditUtils::addRing( QgsAbstractGeometry *geom, QgsCurve *ring )
|
||||
}
|
||||
else
|
||||
{
|
||||
delete ring;
|
||||
return 1; //not polygon / multipolygon;
|
||||
return QgsGeometry::InvalidInput; //not polygon / multipolygon;
|
||||
}
|
||||
|
||||
//ring must be closed
|
||||
if ( !ring->isClosed() )
|
||||
{
|
||||
delete ring;
|
||||
return 2;
|
||||
return QgsGeometry::AddRingNotClosed;
|
||||
}
|
||||
else if ( !ring->isRing() )
|
||||
{
|
||||
delete ring;
|
||||
return 3;
|
||||
return QgsGeometry::AddRingNotValid;
|
||||
}
|
||||
|
||||
std::unique_ptr<QgsGeometryEngine> ringGeom( QgsGeometry::createGeometryEngine( ring ) );
|
||||
std::unique_ptr<QgsGeometryEngine> ringGeom( QgsGeometry::createGeometryEngine( ring.get() ) );
|
||||
ringGeom->prepareGeometry();
|
||||
|
||||
//for each polygon, test if inside outer ring and no intersection with other interior ring
|
||||
@ -81,8 +79,7 @@ int QgsGeometryEditUtils::addRing( QgsAbstractGeometry *geom, QgsCurve *ring )
|
||||
{
|
||||
if ( !ringGeom->disjoint( ( *polyIter )->interiorRing( i ) ) )
|
||||
{
|
||||
delete ring;
|
||||
return 4;
|
||||
return QgsGeometry::AddRingCrossesExistingRings;
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,59 +89,62 @@ int QgsGeometryEditUtils::addRing( QgsAbstractGeometry *geom, QgsCurve *ring )
|
||||
if ( QgsWkbTypes::hasM( geom->wkbType() ) )
|
||||
ring->addMValue( 0 );
|
||||
|
||||
( *polyIter )->addInteriorRing( ring );
|
||||
return 0; //success
|
||||
( *polyIter )->addInteriorRing( ring.release() );
|
||||
return QgsGeometry::Success; //success
|
||||
}
|
||||
}
|
||||
delete ring;
|
||||
return 5; //not contained in any outer ring
|
||||
return QgsGeometry::AddRingNotInExistingFeature; //not contained in any outer ring
|
||||
}
|
||||
|
||||
int QgsGeometryEditUtils::addPart( QgsAbstractGeometry *geom, QgsAbstractGeometry *part )
|
||||
QgsGeometry::OperationResult QgsGeometryEditUtils::addPart( QgsAbstractGeometry *geom, QgsAbstractGeometry *p )
|
||||
{
|
||||
std::unique_ptr<QgsAbstractGeometry> part( p );
|
||||
if ( !geom )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
if ( !part )
|
||||
{
|
||||
return 2;
|
||||
return QgsGeometry::InvalidInput;
|
||||
}
|
||||
|
||||
//multitype?
|
||||
QgsGeometryCollection *geomCollection = qgsgeometry_cast<QgsGeometryCollection *>( geom );
|
||||
if ( !geomCollection )
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::AddPartNotMultiGeometry;
|
||||
}
|
||||
|
||||
bool added = false;
|
||||
if ( QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::MultiSurface
|
||||
|| QgsWkbTypes::flatType( geom->wkbType() ) == QgsWkbTypes::MultiPolygon )
|
||||
{
|
||||
QgsCurve *curve = qgsgeometry_cast<QgsCurve *>( part );
|
||||
std::unique_ptr<QgsCurve> curve( qgsgeometry_cast<QgsCurve *>( part.get() ) );
|
||||
if ( curve )
|
||||
part.release();
|
||||
|
||||
if ( curve && curve->isClosed() && curve->numPoints() >= 4 )
|
||||
{
|
||||
QgsCurvePolygon *poly = nullptr;
|
||||
std::unique_ptr<QgsCurvePolygon> poly;
|
||||
if ( QgsWkbTypes::flatType( curve->wkbType() ) == QgsWkbTypes::LineString )
|
||||
{
|
||||
poly = new QgsPolygonV2();
|
||||
poly.reset( new QgsPolygonV2() );
|
||||
}
|
||||
else
|
||||
{
|
||||
poly = new QgsCurvePolygon();
|
||||
poly.reset( new QgsCurvePolygon() );
|
||||
}
|
||||
poly->setExteriorRing( curve );
|
||||
added = geomCollection->addGeometry( poly );
|
||||
poly->setExteriorRing( curve.release() );
|
||||
added = geomCollection->addGeometry( poly.release() );
|
||||
}
|
||||
else if ( QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::Polygon )
|
||||
{
|
||||
added = geomCollection->addGeometry( part );
|
||||
added = geomCollection->addGeometry( part.release() );
|
||||
}
|
||||
else if ( QgsWkbTypes::flatType( part->wkbType() ) == QgsWkbTypes::MultiPolygon )
|
||||
{
|
||||
QgsGeometryCollection *parts = static_cast<QgsGeometryCollection *>( part );
|
||||
std::unique_ptr<QgsGeometryCollection> parts( static_cast<QgsGeometryCollection *>( part.release() ) );
|
||||
|
||||
int i;
|
||||
int n = geomCollection->numGeometries();
|
||||
@ -156,23 +156,19 @@ int QgsGeometryEditUtils::addPart( QgsAbstractGeometry *geom, QgsAbstractGeometr
|
||||
{
|
||||
while ( geomCollection->numGeometries() > n )
|
||||
geomCollection->removeGeometry( n );
|
||||
delete part;
|
||||
return 2;
|
||||
return QgsGeometry::InvalidInput;
|
||||
}
|
||||
|
||||
delete part;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete part;
|
||||
return 2;
|
||||
return QgsGeometry::InvalidInput;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
added = geomCollection->addGeometry( part );
|
||||
added = geomCollection->addGeometry( part.release() );
|
||||
}
|
||||
return added ? 0 : 2;
|
||||
return added ? QgsGeometry::Success : QgsGeometry::InvalidInput;
|
||||
}
|
||||
|
||||
bool QgsGeometryEditUtils::deleteRing( QgsAbstractGeometry *geom, int ringNum, int partNum )
|
||||
|
@ -24,6 +24,7 @@ class QgsVectorLayer;
|
||||
#define SIP_NO_FILE
|
||||
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include <QMap>
|
||||
|
||||
/** \ingroup core
|
||||
@ -36,19 +37,24 @@ class QgsGeometryEditUtils
|
||||
{
|
||||
public:
|
||||
|
||||
/** Adds interior ring (taking ownership).
|
||||
\returns 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
|
||||
3 ring is not valid geometry, 4 ring not disjoint with existing rings, 5 no polygon found which contained the ring*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
static int addRing( QgsAbstractGeometry *geom, QgsCurve *ring );
|
||||
/**
|
||||
* Add an interior \a ring to a \a geometry.
|
||||
* Ownership of the \a ring is transferred.
|
||||
* \returns 0 in case of success (ring added), 1 problem with geometry type, 2 ring not closed,
|
||||
* 3 ring is not valid geometry, 4 ring not disjoint with existing rings, 5 no polygon found which contained the ring
|
||||
*/
|
||||
static QgsGeometry::OperationResult addRing( QgsAbstractGeometry *geometry, QgsCurve *ring SIP_TRANSFER );
|
||||
|
||||
/** Adds part to multi type geometry (taking ownership)
|
||||
\returns 0 in case of success, 1 if not a multigeometry, 2 if part is not a valid geometry, 3 if new polygon ring
|
||||
not disjoint with existing polygons of the feature*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
static int addPart( QgsAbstractGeometry *geom, QgsAbstractGeometry *part );
|
||||
/**
|
||||
* Add a \a part to multi type \a geometry.
|
||||
* Ownership of the \a part is transferred.
|
||||
* \returns 0 in case of success, 1 if not a multigeometry, 2 if part is not a valid geometry, 3 if new polygon ring
|
||||
* not disjoint with existing polygons of the feature
|
||||
*/
|
||||
static QgsGeometry::OperationResult addPart( QgsAbstractGeometry *geometry, QgsAbstractGeometry *part SIP_TRANSFER );
|
||||
|
||||
/** Deletes a ring from a geometry.
|
||||
/**
|
||||
* Deletes a ring from a geometry.
|
||||
* \returns true if delete was successful
|
||||
*/
|
||||
static bool deleteRing( QgsAbstractGeometry *geom, int ringNum, int partNum = 0 );
|
||||
|
@ -18,6 +18,7 @@ email : marco.hugentobler at sourcepole dot com
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgslinestring.h"
|
||||
#include "qgsgeometry.h"
|
||||
|
||||
#include <QList>
|
||||
|
||||
@ -31,6 +32,24 @@ class QgsAbstractGeometry;
|
||||
class CORE_EXPORT QgsGeometryEngine
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Success or failure of a geometry operation.
|
||||
* This gived details about cause of failure.
|
||||
*/
|
||||
enum EngineOperationResult
|
||||
{
|
||||
Success = 0, //!< Operation succeeded
|
||||
NothingHappened, //!< Nothing happened, without any error
|
||||
MethodNotImplemented, //!< Method not implemented in geometry engine
|
||||
EngineError, //!< Error occured in the geometry engine
|
||||
NodedGeometryError, //!< Error occured while creating a noded geometry
|
||||
InvalidBaseGeometry, //!< The geometry on which the operation occurs is not valid
|
||||
InvalidInput, //!< The input is not valid
|
||||
/* split */
|
||||
SplitCannotSplitPoint, //!< Points cannot be split
|
||||
};
|
||||
|
||||
virtual ~QgsGeometryEngine() = default;
|
||||
|
||||
virtual void geometryChanged() = 0;
|
||||
@ -190,17 +209,17 @@ class CORE_EXPORT QgsGeometryEngine
|
||||
*/
|
||||
virtual bool isSimple( QString *errorMsg = nullptr ) const = 0;
|
||||
|
||||
virtual int splitGeometry( const QgsLineString &splitLine,
|
||||
QList<QgsAbstractGeometry *> &newGeometries,
|
||||
bool topological,
|
||||
QgsPointSequence &topologyTestPoints, QString *errorMsg = nullptr ) const
|
||||
virtual QgsGeometryEngine::EngineOperationResult splitGeometry( const QgsLineString &splitLine,
|
||||
QList<QgsAbstractGeometry *> &newGeometries,
|
||||
bool topological,
|
||||
QgsPointSequence &topologyTestPoints, QString *errorMsg = nullptr ) const
|
||||
{
|
||||
Q_UNUSED( splitLine );
|
||||
Q_UNUSED( newGeometries );
|
||||
Q_UNUSED( topological );
|
||||
Q_UNUSED( topologyTestPoints );
|
||||
Q_UNUSED( errorMsg );
|
||||
return 2;
|
||||
return MethodNotImplemented;
|
||||
}
|
||||
|
||||
virtual QgsAbstractGeometry *offsetCurve( double distance, int segments, int joinStyle, double miterLimit, QString *errorMsg = nullptr ) const = 0 SIP_FACTORY;
|
||||
|
@ -25,7 +25,6 @@ email : marco.hugentobler at sourcepole dot com
|
||||
#include "qgsmultipolygon.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgspolygon.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include <limits>
|
||||
#include <cstdio>
|
||||
#include <QtCore/qmath.h>
|
||||
@ -519,32 +518,32 @@ double QgsGeos::length( QString *errorMsg ) const
|
||||
return length;
|
||||
}
|
||||
|
||||
int QgsGeos::splitGeometry( const QgsLineString &splitLine,
|
||||
QList<QgsAbstractGeometry *> &newGeometries,
|
||||
bool topological,
|
||||
QgsPointSequence &topologyTestPoints,
|
||||
QString *errorMsg ) const
|
||||
QgsGeometryEngine::EngineOperationResult QgsGeos::splitGeometry( const QgsLineString &splitLine,
|
||||
QList<QgsAbstractGeometry *> &newGeometries,
|
||||
bool topological,
|
||||
QgsPointSequence &topologyTestPoints,
|
||||
QString *errorMsg ) const
|
||||
{
|
||||
|
||||
int returnCode = 0;
|
||||
if ( !mGeometry || !mGeos )
|
||||
EngineOperationResult returnCode = Success;
|
||||
if ( !mGeos || !mGeometry )
|
||||
{
|
||||
return 1;
|
||||
return InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
//return if this type is point/multipoint
|
||||
if ( mGeometry->dimension() == 0 )
|
||||
{
|
||||
return 1; //cannot split points
|
||||
return SplitCannotSplitPoint; //cannot split points
|
||||
}
|
||||
|
||||
if ( !GEOSisValid_r( geosinit.ctxt, mGeos ) )
|
||||
return 7;
|
||||
return InvalidBaseGeometry;
|
||||
|
||||
//make sure splitLine is valid
|
||||
if ( ( mGeometry->dimension() == 1 && splitLine.numPoints() < 1 ) ||
|
||||
( mGeometry->dimension() == 2 && splitLine.numPoints() < 2 ) )
|
||||
return 1;
|
||||
return InvalidInput;
|
||||
|
||||
newGeometries.clear();
|
||||
GEOSGeometry *splitLineGeos = nullptr;
|
||||
@ -561,20 +560,22 @@ int QgsGeos::splitGeometry( const QgsLineString &splitLine,
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
return InvalidInput;
|
||||
}
|
||||
|
||||
if ( !GEOSisValid_r( geosinit.ctxt, splitLineGeos ) || !GEOSisSimple_r( geosinit.ctxt, splitLineGeos ) )
|
||||
{
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, splitLineGeos );
|
||||
return 1;
|
||||
return InvalidInput;
|
||||
}
|
||||
|
||||
if ( topological )
|
||||
{
|
||||
//find out candidate points for topological corrections
|
||||
if ( topologicalTestPointsSplit( splitLineGeos, topologyTestPoints ) != 0 )
|
||||
return 1;
|
||||
if ( !topologicalTestPointsSplit( splitLineGeos, topologyTestPoints ) )
|
||||
{
|
||||
return InvalidInput; // TODO: is it really an invalid input?
|
||||
}
|
||||
}
|
||||
|
||||
//call split function depending on geometry type
|
||||
@ -590,17 +591,17 @@ int QgsGeos::splitGeometry( const QgsLineString &splitLine,
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
return InvalidInput;
|
||||
}
|
||||
}
|
||||
CATCH_GEOS_WITH_ERRMSG( 2 )
|
||||
CATCH_GEOS_WITH_ERRMSG( EngineError )
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int QgsGeos::topologicalTestPointsSplit( const GEOSGeometry *splitLine, QgsPointSequence &testPoints, QString *errorMsg ) const
|
||||
bool QgsGeos::topologicalTestPointsSplit( const GEOSGeometry *splitLine, QgsPointSequence &testPoints, QString *errorMsg ) const
|
||||
{
|
||||
//Find out the intersection points between splitLineGeos and this geometry.
|
||||
//These points need to be tested for topological correctness by the calling function
|
||||
@ -608,7 +609,7 @@ int QgsGeos::topologicalTestPointsSplit( const GEOSGeometry *splitLine, QgsPoint
|
||||
|
||||
if ( !mGeos )
|
||||
{
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
@ -616,7 +617,7 @@ int QgsGeos::topologicalTestPointsSplit( const GEOSGeometry *splitLine, QgsPoint
|
||||
testPoints.clear();
|
||||
GEOSGeometry *intersectionGeom = GEOSIntersection_r( geosinit.ctxt, mGeos, splitLine );
|
||||
if ( !intersectionGeom )
|
||||
return 1;
|
||||
return false;
|
||||
|
||||
bool simple = false;
|
||||
int nIntersectGeoms = 1;
|
||||
@ -656,7 +657,7 @@ int QgsGeos::topologicalTestPointsSplit( const GEOSGeometry *splitLine, QgsPoint
|
||||
}
|
||||
CATCH_GEOS_WITH_ERRMSG( 1 )
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
GEOSGeometry *QgsGeos::linePointDifference( GEOSGeometry *GEOSsplitPoint ) const
|
||||
@ -725,22 +726,22 @@ GEOSGeometry *QgsGeos::linePointDifference( GEOSGeometry *GEOSsplitPoint ) const
|
||||
return asGeos( &lines, mPrecision );
|
||||
}
|
||||
|
||||
int QgsGeos::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeometry *> &newGeometries ) const
|
||||
QgsGeometryEngine::EngineOperationResult QgsGeos::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeometry *> &newGeometries ) const
|
||||
{
|
||||
if ( !splitLine )
|
||||
return 2;
|
||||
return InvalidInput;
|
||||
|
||||
if ( !mGeos )
|
||||
return 5;
|
||||
return InvalidBaseGeometry;
|
||||
|
||||
//first test if linestring intersects geometry. If not, return straight away
|
||||
if ( !GEOSIntersects_r( geosinit.ctxt, splitLine, mGeos ) )
|
||||
return 1;
|
||||
return NothingHappened;
|
||||
|
||||
//check that split line has no linear intersection
|
||||
int linearIntersect = GEOSRelatePattern_r( geosinit.ctxt, mGeos, splitLine, "1********" );
|
||||
if ( linearIntersect > 0 )
|
||||
return 3;
|
||||
return InvalidInput;
|
||||
|
||||
int splitGeomType = GEOSGeomTypeId_r( geosinit.ctxt, splitLine );
|
||||
|
||||
@ -778,25 +779,25 @@ int QgsGeos::splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeom
|
||||
}
|
||||
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, splitGeom );
|
||||
return 0;
|
||||
return Success;
|
||||
}
|
||||
|
||||
int QgsGeos::splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeometry *> &newGeometries ) const
|
||||
QgsGeometryEngine::EngineOperationResult QgsGeos::splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeometry *> &newGeometries ) const
|
||||
{
|
||||
if ( !splitLine )
|
||||
return 2;
|
||||
return InvalidInput;
|
||||
|
||||
if ( !mGeos )
|
||||
return 5;
|
||||
return InvalidBaseGeometry;
|
||||
|
||||
//first test if linestring intersects geometry. If not, return straight away
|
||||
if ( !GEOSIntersects_r( geosinit.ctxt, splitLine, mGeos ) )
|
||||
return 1;
|
||||
return NothingHappened;
|
||||
|
||||
//first union all the polygon rings together (to get them noded, see JTS developer guide)
|
||||
GEOSGeometry *nodedGeometry = nodeGeometries( splitLine, mGeos );
|
||||
if ( !nodedGeometry )
|
||||
return 2; //an error occurred during noding
|
||||
return NodedGeometryError; //an error occurred during noding
|
||||
|
||||
GEOSGeometry *polygons = GEOSPolygonize_r( geosinit.ctxt, &nodedGeometry, 1 );
|
||||
if ( !polygons || numberOfGeometries( polygons ) == 0 )
|
||||
@ -806,7 +807,7 @@ int QgsGeos::splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeo
|
||||
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, nodedGeometry );
|
||||
|
||||
return 4;
|
||||
return InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, nodedGeometry );
|
||||
@ -859,7 +860,7 @@ int QgsGeos::splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeo
|
||||
{
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, testedGeometries[i] );
|
||||
}
|
||||
return 1;
|
||||
return NothingHappened;
|
||||
}
|
||||
|
||||
int i;
|
||||
@ -871,13 +872,13 @@ int QgsGeos::splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeo
|
||||
for ( i = 0; i < testedGeometries.size(); ++i )
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, testedGeometries[i] );
|
||||
|
||||
return 3;
|
||||
return InvalidBaseGeometry;
|
||||
}
|
||||
|
||||
for ( i = 0; i < testedGeometries.size(); ++i )
|
||||
newGeometries << fromGeos( testedGeometries[i] );
|
||||
|
||||
return 0;
|
||||
return Success;
|
||||
}
|
||||
|
||||
GEOSGeometry *QgsGeos::nodeGeometries( const GEOSGeometry *splitLine, const GEOSGeometry *geom )
|
||||
@ -1892,11 +1893,17 @@ QgsAbstractGeometry *QgsGeos::singleSidedBuffer( double distance, int segments,
|
||||
return fromGeos( geos.get() );
|
||||
}
|
||||
|
||||
QgsAbstractGeometry *QgsGeos::reshapeGeometry( const QgsLineString &reshapeWithLine, int *errorCode, QString *errorMsg ) const
|
||||
QgsAbstractGeometry *QgsGeos::reshapeGeometry( const QgsLineString &reshapeWithLine, EngineOperationResult *errorCode, QString *errorMsg ) const
|
||||
{
|
||||
if ( !mGeos || reshapeWithLine.numPoints() < 2 || mGeometry->dimension() == 0 )
|
||||
if ( !mGeos || mGeometry->dimension() == 0 )
|
||||
{
|
||||
if ( errorCode ) { *errorCode = 1; }
|
||||
if ( errorCode ) { *errorCode = InvalidBaseGeometry; }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( reshapeWithLine.numPoints() < 2 )
|
||||
{
|
||||
if ( errorCode ) { *errorCode = InvalidInput; }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1906,7 +1913,7 @@ QgsAbstractGeometry *QgsGeos::reshapeGeometry( const QgsLineString &reshapeWithL
|
||||
int numGeoms = GEOSGetNumGeometries_r( geosinit.ctxt, mGeos );
|
||||
if ( numGeoms == -1 )
|
||||
{
|
||||
if ( errorCode ) { *errorCode = 1; }
|
||||
if ( errorCode ) { *errorCode = InvalidBaseGeometry; }
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, reshapeLineGeos );
|
||||
return nullptr;
|
||||
}
|
||||
@ -1930,7 +1937,8 @@ QgsAbstractGeometry *QgsGeos::reshapeGeometry( const QgsLineString &reshapeWithL
|
||||
reshapedGeometry = reshapePolygon( mGeos, reshapeLineGeos, mPrecision );
|
||||
}
|
||||
|
||||
if ( errorCode ) { *errorCode = 0; }
|
||||
if ( errorCode )
|
||||
*errorCode = Success;
|
||||
QgsAbstractGeometry *reshapeResult = fromGeos( reshapedGeometry );
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, reshapedGeometry );
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, reshapeLineGeos );
|
||||
@ -1978,13 +1986,14 @@ QgsAbstractGeometry *QgsGeos::reshapeGeometry( const QgsLineString &reshapeWithL
|
||||
delete[] newGeoms;
|
||||
if ( !newMultiGeom )
|
||||
{
|
||||
if ( errorCode ) { *errorCode = 3; }
|
||||
if ( errorCode ) { *errorCode = EngineError; }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if ( reshapeTookPlace )
|
||||
{
|
||||
if ( errorCode ) { *errorCode = 0; }
|
||||
if ( errorCode )
|
||||
*errorCode = Success;
|
||||
QgsAbstractGeometry *reshapedMultiGeom = fromGeos( newMultiGeom );
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, newMultiGeom );
|
||||
return reshapedMultiGeom;
|
||||
@ -1992,7 +2001,7 @@ QgsAbstractGeometry *QgsGeos::reshapeGeometry( const QgsLineString &reshapeWithL
|
||||
else
|
||||
{
|
||||
GEOSGeom_destroy_r( geosinit.ctxt, newMultiGeom );
|
||||
if ( errorCode ) { *errorCode = 1; }
|
||||
if ( errorCode ) { *errorCode = NothingHappened; }
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ email : marco.hugentobler at sourcepole dot com
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgsgeometryengine.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include <geos_c.h>
|
||||
|
||||
class QgsLineString;
|
||||
@ -106,11 +107,11 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
|
||||
\param[out] topologyTestPoints points that need to be tested for topological completeness in the dataset
|
||||
\param[out] errorMsg error messages emitted, if any
|
||||
\returns 0 in case of success, 1 if geometry has not been split, error else*/
|
||||
int splitGeometry( const QgsLineString &splitLine,
|
||||
QList<QgsAbstractGeometry *> &newGeometries,
|
||||
bool topological,
|
||||
QgsPointSequence &topologyTestPoints,
|
||||
QString *errorMsg = nullptr ) const override;
|
||||
EngineOperationResult splitGeometry( const QgsLineString &splitLine,
|
||||
QList<QgsAbstractGeometry *> &newGeometries,
|
||||
bool topological,
|
||||
QgsPointSequence &topologyTestPoints,
|
||||
QString *errorMsg = nullptr ) const override;
|
||||
|
||||
QgsAbstractGeometry *offsetCurve( double distance, int segments, int joinStyle, double miterLimit, QString *errorMsg = nullptr ) const override;
|
||||
|
||||
@ -131,8 +132,14 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
|
||||
int joinStyle, double miterLimit,
|
||||
QString *errorMsg = nullptr ) const;
|
||||
|
||||
|
||||
QgsAbstractGeometry *reshapeGeometry( const QgsLineString &reshapeWithLine, int *errorCode, QString *errorMsg = nullptr ) const;
|
||||
/**
|
||||
* Reshapes the geometry using a line
|
||||
* @param reshapeWithLine the line used to reshape lines or polygons
|
||||
* @param errorCode if specified, provides result of operation (success or reason of failure)
|
||||
* @param errorMsg if specified, provides more details about failure
|
||||
* @return the reshaped geometry
|
||||
*/
|
||||
QgsAbstractGeometry *reshapeGeometry( const QgsLineString &reshapeWithLine, EngineOperationResult *errorCode, QString *errorMsg = nullptr ) const;
|
||||
|
||||
/** Merges any connected lines in a LineString/MultiLineString geometry and
|
||||
* converts them to single line strings.
|
||||
@ -261,10 +268,10 @@ class CORE_EXPORT QgsGeos: public QgsGeometryEngine
|
||||
static GEOSGeometry *createGeosPolygon( const QgsAbstractGeometry *poly, double precision );
|
||||
|
||||
//utils for geometry split
|
||||
int topologicalTestPointsSplit( const GEOSGeometry *splitLine, QgsPointSequence &testPoints, QString *errorMsg = nullptr ) const;
|
||||
bool topologicalTestPointsSplit( const GEOSGeometry *splitLine, QgsPointSequence &testPoints, QString *errorMsg = nullptr ) const;
|
||||
GEOSGeometry *linePointDifference( GEOSGeometry *GEOSsplitPoint ) const;
|
||||
int splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeometry *> &newGeometries ) const;
|
||||
int splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeometry *> &newGeometries ) const;
|
||||
EngineOperationResult splitLinearGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeometry *> &newGeometries ) const;
|
||||
EngineOperationResult splitPolygonGeometry( GEOSGeometry *splitLine, QList<QgsAbstractGeometry *> &newGeometries ) const;
|
||||
|
||||
//utils for reshape
|
||||
static GEOSGeometry *reshapeLine( const GEOSGeometry *line, const GEOSGeometry *reshapeLineGeos, double precision );
|
||||
|
@ -29,41 +29,41 @@
|
||||
|
||||
|
||||
QgsVectorLayerEditUtils::QgsVectorLayerEditUtils( QgsVectorLayer *layer )
|
||||
: L( layer )
|
||||
: mLayer( layer )
|
||||
{
|
||||
}
|
||||
|
||||
bool QgsVectorLayerEditUtils::insertVertex( double x, double y, QgsFeatureId atFeatureId, int beforeVertex )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
if ( !mLayer->isSpatial() )
|
||||
return false;
|
||||
|
||||
QgsFeature f;
|
||||
if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
return false; // geometry not found
|
||||
|
||||
QgsGeometry geometry = f.geometry();
|
||||
|
||||
geometry.insertVertex( x, y, beforeVertex );
|
||||
|
||||
L->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
mLayer->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsVectorLayerEditUtils::insertVertex( const QgsPoint &point, QgsFeatureId atFeatureId, int beforeVertex )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
if ( !mLayer->isSpatial() )
|
||||
return false;
|
||||
|
||||
QgsFeature f;
|
||||
if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
return false; // geometry not found
|
||||
|
||||
QgsGeometry geometry = f.geometry();
|
||||
|
||||
geometry.insertVertex( point, beforeVertex );
|
||||
|
||||
L->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
mLayer->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -75,29 +75,29 @@ bool QgsVectorLayerEditUtils::moveVertex( double x, double y, QgsFeatureId atFea
|
||||
|
||||
bool QgsVectorLayerEditUtils::moveVertex( const QgsPoint &p, QgsFeatureId atFeatureId, int atVertex )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
if ( !mLayer->isSpatial() )
|
||||
return false;
|
||||
|
||||
QgsFeature f;
|
||||
if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( atFeatureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
return false; // geometry not found
|
||||
|
||||
QgsGeometry geometry = f.geometry();
|
||||
|
||||
geometry.moveVertex( p, atVertex );
|
||||
|
||||
L->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
mLayer->editBuffer()->changeGeometry( atFeatureId, geometry );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
QgsVectorLayer::EditResult QgsVectorLayerEditUtils::deleteVertex( QgsFeatureId featureId, int vertex )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
if ( !mLayer->isSpatial() )
|
||||
return QgsVectorLayer::InvalidLayer;
|
||||
|
||||
QgsFeature f;
|
||||
if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
return QgsVectorLayer::FetchFeatureFailed; // geometry not found
|
||||
|
||||
QgsGeometry geometry = f.geometry();
|
||||
@ -111,38 +111,38 @@ QgsVectorLayer::EditResult QgsVectorLayerEditUtils::deleteVertex( QgsFeatureId f
|
||||
geometry.setGeometry( nullptr );
|
||||
}
|
||||
|
||||
L->editBuffer()->changeGeometry( featureId, geometry );
|
||||
mLayer->editBuffer()->changeGeometry( featureId, geometry );
|
||||
return !geometry.isNull() ? QgsVectorLayer::Success : QgsVectorLayer::EmptyGeometry;
|
||||
}
|
||||
|
||||
int QgsVectorLayerEditUtils::addRing( const QList<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
|
||||
QgsGeometry::OperationResult QgsVectorLayerEditUtils::addRing( const QList<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
|
||||
{
|
||||
QgsLineString *ringLine = new QgsLineString( ring );
|
||||
return addRing( ringLine, targetFeatureIds, modifiedFeatureId );
|
||||
}
|
||||
|
||||
int QgsVectorLayerEditUtils::addRing( QgsCurve *ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
|
||||
QgsGeometry::OperationResult QgsVectorLayerEditUtils::addRing( QgsCurve *ring, const QgsFeatureIds &targetFeatureIds, QgsFeatureId *modifiedFeatureId )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
if ( !mLayer->isSpatial() )
|
||||
{
|
||||
delete ring;
|
||||
return 5;
|
||||
return QgsGeometry::AddRingNotInExistingFeature;
|
||||
}
|
||||
|
||||
int addRingReturnCode = 5; //default: return code for 'ring not inserted'
|
||||
QgsGeometry::OperationResult addRingReturnCode = QgsGeometry::AddRingNotInExistingFeature; //default: return code for 'ring not inserted'
|
||||
QgsFeature f;
|
||||
|
||||
QgsFeatureIterator fit;
|
||||
if ( !targetFeatureIds.isEmpty() )
|
||||
{
|
||||
//check only specified features
|
||||
fit = L->getFeatures( QgsFeatureRequest().setFilterFids( targetFeatureIds ) );
|
||||
fit = mLayer->getFeatures( QgsFeatureRequest().setFilterFids( targetFeatureIds ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
//check all intersecting features
|
||||
QgsRectangle bBox = ring->boundingBox();
|
||||
fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
|
||||
fit = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
|
||||
}
|
||||
|
||||
//find first valid feature we can add the ring to
|
||||
@ -156,21 +156,22 @@ int QgsVectorLayerEditUtils::addRing( QgsCurve *ring, const QgsFeatureIds &targe
|
||||
|
||||
addRingReturnCode = g.addRing( static_cast< QgsCurve * >( ring->clone() ) );
|
||||
if ( addRingReturnCode == 0 )
|
||||
{
|
||||
L->editBuffer()->changeGeometry( f.id(), g );
|
||||
if ( modifiedFeatureId )
|
||||
*modifiedFeatureId = f.id();
|
||||
if ( addRingReturnCode == QgsGeometry::Success )
|
||||
{
|
||||
mLayer->editBuffer()->changeGeometry( f.id(), g );
|
||||
if ( modifiedFeatureId )
|
||||
*modifiedFeatureId = f.id();
|
||||
|
||||
//setModified( true, true );
|
||||
break;
|
||||
}
|
||||
//setModified( true, true );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
delete ring;
|
||||
return addRingReturnCode;
|
||||
}
|
||||
|
||||
int QgsVectorLayerEditUtils::addPart( const QList<QgsPointXY> &points, QgsFeatureId featureId )
|
||||
QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( const QList<QgsPointXY> &points, QgsFeatureId featureId )
|
||||
{
|
||||
QgsPointSequence l;
|
||||
for ( QList<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd(); ++it )
|
||||
@ -180,16 +181,16 @@ int QgsVectorLayerEditUtils::addPart( const QList<QgsPointXY> &points, QgsFeatur
|
||||
return addPart( l, featureId );
|
||||
}
|
||||
|
||||
int QgsVectorLayerEditUtils::addPart( const QgsPointSequence &points, QgsFeatureId featureId )
|
||||
QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( const QgsPointSequence &points, QgsFeatureId featureId )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
return 6;
|
||||
if ( !mLayer->isSpatial() )
|
||||
return QgsGeometry::AddPartSelectedGeometryNotFound;
|
||||
|
||||
QgsGeometry geometry;
|
||||
bool firstPart = false;
|
||||
QgsFeature f;
|
||||
if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) )
|
||||
return 6; //not found
|
||||
if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) )
|
||||
return QgsGeometry::AddPartSelectedGeometryNotFound; //not found
|
||||
|
||||
if ( !f.hasGeometry() )
|
||||
{
|
||||
@ -201,30 +202,30 @@ int QgsVectorLayerEditUtils::addPart( const QgsPointSequence &points, QgsFeature
|
||||
geometry = f.geometry();
|
||||
}
|
||||
|
||||
int errorCode = geometry.addPart( points, L->geometryType() ) ;
|
||||
if ( errorCode == 0 )
|
||||
QgsGeometry::OperationResult errorCode = geometry.addPart( points, mLayer->geometryType() ) ;
|
||||
if ( errorCode == QgsGeometry::Success )
|
||||
{
|
||||
if ( firstPart && QgsWkbTypes::isSingleType( L->wkbType() )
|
||||
&& L->dataProvider()->doesStrictFeatureTypeCheck() )
|
||||
if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() )
|
||||
&& mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
|
||||
{
|
||||
//convert back to single part if required by layer
|
||||
geometry.convertToSingleType();
|
||||
}
|
||||
L->editBuffer()->changeGeometry( featureId, geometry );
|
||||
mLayer->editBuffer()->changeGeometry( featureId, geometry );
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
int QgsVectorLayerEditUtils::addPart( QgsCurve *ring, QgsFeatureId featureId )
|
||||
QgsGeometry::OperationResult QgsVectorLayerEditUtils::addPart( QgsCurve *ring, QgsFeatureId featureId )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
return 6;
|
||||
if ( !mLayer->isSpatial() )
|
||||
return QgsGeometry::AddPartSelectedGeometryNotFound;
|
||||
|
||||
QgsGeometry geometry;
|
||||
bool firstPart = false;
|
||||
QgsFeature f;
|
||||
if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) )
|
||||
return 6; //not found
|
||||
if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) )
|
||||
return QgsGeometry::AddPartSelectedGeometryNotFound;
|
||||
|
||||
if ( !f.hasGeometry() )
|
||||
{
|
||||
@ -236,16 +237,16 @@ int QgsVectorLayerEditUtils::addPart( QgsCurve *ring, QgsFeatureId featureId )
|
||||
geometry = f.geometry();
|
||||
}
|
||||
|
||||
int errorCode = geometry.addPart( ring, L->geometryType() ) ;
|
||||
if ( errorCode == 0 )
|
||||
QgsGeometry::OperationResult errorCode = geometry.addPart( ring, mLayer->geometryType() ) ;
|
||||
if ( errorCode == QgsGeometry::Success )
|
||||
{
|
||||
if ( firstPart && QgsWkbTypes::isSingleType( L->wkbType() )
|
||||
&& L->dataProvider()->doesStrictFeatureTypeCheck() )
|
||||
if ( firstPart && QgsWkbTypes::isSingleType( mLayer->wkbType() )
|
||||
&& mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
|
||||
{
|
||||
//convert back to single part if required by layer
|
||||
geometry.convertToSingleType();
|
||||
}
|
||||
L->editBuffer()->changeGeometry( featureId, geometry );
|
||||
mLayer->editBuffer()->changeGeometry( featureId, geometry );
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
@ -253,11 +254,11 @@ int QgsVectorLayerEditUtils::addPart( QgsCurve *ring, QgsFeatureId featureId )
|
||||
|
||||
int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx, double dy )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
if ( !mLayer->isSpatial() )
|
||||
return 1;
|
||||
|
||||
QgsFeature f;
|
||||
if ( !L->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
if ( !mLayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setSubsetOfAttributes( QgsAttributeList() ) ).nextFeature( f ) || !f.hasGeometry() )
|
||||
return 1; //geometry not found
|
||||
|
||||
QgsGeometry geometry = f.geometry();
|
||||
@ -265,30 +266,30 @@ int QgsVectorLayerEditUtils::translateFeature( QgsFeatureId featureId, double dx
|
||||
int errorCode = geometry.translate( dx, dy );
|
||||
if ( errorCode == 0 )
|
||||
{
|
||||
L->editBuffer()->changeGeometry( featureId, geometry );
|
||||
mLayer->editBuffer()->changeGeometry( featureId, geometry );
|
||||
}
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
|
||||
int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPointXY> &splitLine, bool topologicalEditing )
|
||||
QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPointXY> &splitLine, bool topologicalEditing )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
return 4;
|
||||
if ( !mLayer->isSpatial() )
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
|
||||
QgsFeatureList newFeatures; //store all the newly created features
|
||||
double xMin, yMin, xMax, yMax;
|
||||
QgsRectangle bBox; //bounding box of the split line
|
||||
int returnCode = 0;
|
||||
int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
|
||||
QgsGeometry::OperationResult returnCode = QgsGeometry::Success;
|
||||
QgsGeometry::OperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
|
||||
int numberOfSplitFeatures = 0;
|
||||
|
||||
QgsFeatureIterator features;
|
||||
const QgsFeatureIds selectedIds = L->selectedFeatureIds();
|
||||
const QgsFeatureIds selectedIds = mLayer->selectedFeatureIds();
|
||||
|
||||
if ( !selectedIds.isEmpty() ) //consider only the selected features if there is a selection
|
||||
{
|
||||
features = L->getSelectedFeatures();
|
||||
features = mLayer->getSelectedFeatures();
|
||||
}
|
||||
else //else consider all the feature that intersect the bounding box of the split line
|
||||
{
|
||||
@ -301,7 +302,7 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPointXY> &splitLine,
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidInput;
|
||||
}
|
||||
|
||||
if ( bBox.isEmpty() )
|
||||
@ -321,7 +322,7 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPointXY> &splitLine,
|
||||
{
|
||||
//If we have a single point, we still create a non-null box
|
||||
double bufferDistance = 0.000001;
|
||||
if ( L->crs().isGeographic() )
|
||||
if ( mLayer->crs().isGeographic() )
|
||||
bufferDistance = 0.00000001;
|
||||
bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
|
||||
bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
|
||||
@ -330,7 +331,7 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPointXY> &splitLine,
|
||||
}
|
||||
}
|
||||
|
||||
features = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
|
||||
features = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
|
||||
}
|
||||
|
||||
QgsFeature feat;
|
||||
@ -344,16 +345,16 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPointXY> &splitLine,
|
||||
QList<QgsPointXY> topologyTestPoints;
|
||||
QgsGeometry featureGeom = feat.geometry();
|
||||
splitFunctionReturn = featureGeom.splitGeometry( splitLine, newGeometries, topologicalEditing, topologyTestPoints );
|
||||
if ( splitFunctionReturn == 0 )
|
||||
if ( splitFunctionReturn == QgsGeometry::Success )
|
||||
{
|
||||
//change this geometry
|
||||
L->editBuffer()->changeGeometry( feat.id(), featureGeom );
|
||||
mLayer->editBuffer()->changeGeometry( feat.id(), featureGeom );
|
||||
|
||||
//insert new features
|
||||
for ( int i = 0; i < newGeometries.size(); ++i )
|
||||
{
|
||||
QgsFeature f = QgsVectorLayerUtils::createFeature( L, newGeometries.at( i ), feat.attributes().toMap() );
|
||||
L->editBuffer()->addFeature( f );
|
||||
QgsFeature f = QgsVectorLayerUtils::createFeature( mLayer, newGeometries.at( i ), feat.attributes().toMap() );
|
||||
mLayer->editBuffer()->addFeature( f );
|
||||
}
|
||||
|
||||
if ( topologicalEditing )
|
||||
@ -366,7 +367,7 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPointXY> &splitLine,
|
||||
}
|
||||
++numberOfSplitFeatures;
|
||||
}
|
||||
else if ( splitFunctionReturn > 1 ) //1 means no split but also no error
|
||||
else if ( splitFunctionReturn != QgsGeometry::Success && splitFunctionReturn != QgsGeometry::NothingHappened ) // i.e. no split but no error occurred
|
||||
{
|
||||
returnCode = splitFunctionReturn;
|
||||
}
|
||||
@ -376,28 +377,28 @@ int QgsVectorLayerEditUtils::splitFeatures( const QList<QgsPointXY> &splitLine,
|
||||
{
|
||||
//There is a selection but no feature has been split.
|
||||
//Maybe user forgot that only the selected features are split
|
||||
returnCode = 4;
|
||||
returnCode = QgsGeometry::NothingHappened;
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
int QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, bool topologicalEditing )
|
||||
QgsGeometry::OperationResult QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, bool topologicalEditing )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
return 4;
|
||||
if ( !mLayer->isSpatial() )
|
||||
return QgsGeometry::InvalidBaseGeometry;
|
||||
|
||||
double xMin, yMin, xMax, yMax;
|
||||
QgsRectangle bBox; //bounding box of the split line
|
||||
int returnCode = 0;
|
||||
int splitFunctionReturn; //return code of QgsGeometry::splitGeometry
|
||||
QgsGeometry::OperationResult returnCode = QgsGeometry::Success;
|
||||
QgsGeometry::OperationResult splitFunctionReturn; //return code of QgsGeometry::splitGeometry
|
||||
int numberOfSplitParts = 0;
|
||||
|
||||
QgsFeatureIterator fit;
|
||||
|
||||
if ( L->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
|
||||
if ( mLayer->selectedFeatureCount() > 0 ) //consider only the selected features if there is a selection
|
||||
{
|
||||
fit = L->getSelectedFeatures();
|
||||
fit = mLayer->getSelectedFeatures();
|
||||
}
|
||||
else //else consider all the feature that intersect the bounding box of the split line
|
||||
{
|
||||
@ -410,7 +411,7 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, boo
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
return QgsGeometry::InvalidInput;
|
||||
}
|
||||
|
||||
if ( bBox.isEmpty() )
|
||||
@ -430,7 +431,7 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, boo
|
||||
{
|
||||
//If we have a single point, we still create a non-null box
|
||||
double bufferDistance = 0.000001;
|
||||
if ( L->crs().isGeographic() )
|
||||
if ( mLayer->crs().isGeographic() )
|
||||
bufferDistance = 0.00000001;
|
||||
bBox.setXMinimum( bBox.xMinimum() - bufferDistance );
|
||||
bBox.setXMaximum( bBox.xMaximum() + bufferDistance );
|
||||
@ -439,7 +440,7 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, boo
|
||||
}
|
||||
}
|
||||
|
||||
fit = L->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
|
||||
fit = mLayer->getFeatures( QgsFeatureRequest().setFilterRect( bBox ).setFlags( QgsFeatureRequest::ExactIntersect ) );
|
||||
}
|
||||
|
||||
int addPartRet = 0;
|
||||
@ -469,7 +470,7 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, boo
|
||||
|
||||
if ( !addPartRet )
|
||||
{
|
||||
L->editBuffer()->changeGeometry( feat.id(), featureGeom );
|
||||
mLayer->editBuffer()->changeGeometry( feat.id(), featureGeom );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -489,7 +490,7 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, boo
|
||||
break;
|
||||
}
|
||||
}
|
||||
L->editBuffer()->changeGeometry( feat.id(), featureGeom );
|
||||
mLayer->editBuffer()->changeGeometry( feat.id(), featureGeom );
|
||||
|
||||
if ( topologicalEditing )
|
||||
{
|
||||
@ -507,11 +508,11 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, boo
|
||||
}
|
||||
}
|
||||
|
||||
if ( numberOfSplitParts == 0 && L->selectedFeatureCount() > 0 && returnCode == 0 )
|
||||
if ( numberOfSplitParts == 0 && mLayer->selectedFeatureCount() > 0 && returnCode == 0 )
|
||||
{
|
||||
//There is a selection but no feature has been split.
|
||||
//Maybe user forgot that only the selected features are split
|
||||
returnCode = 4;
|
||||
returnCode = QgsGeometry::NothingHappened;
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
@ -520,7 +521,7 @@ int QgsVectorLayerEditUtils::splitParts( const QList<QgsPointXY> &splitLine, boo
|
||||
|
||||
int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsGeometry &geom )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
if ( !mLayer->isSpatial() )
|
||||
return 1;
|
||||
|
||||
if ( geom.isNull() )
|
||||
@ -628,18 +629,18 @@ int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsGeometry &geom )
|
||||
|
||||
int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPointXY &p )
|
||||
{
|
||||
if ( !L->isSpatial() )
|
||||
if ( !mLayer->isSpatial() )
|
||||
return 1;
|
||||
|
||||
double segmentSearchEpsilon = L->crs().isGeographic() ? 1e-12 : 1e-8;
|
||||
double segmentSearchEpsilon = mLayer->crs().isGeographic() ? 1e-12 : 1e-8;
|
||||
|
||||
//work with a tolerance because coordinate projection may introduce some rounding
|
||||
double threshold = 0.0000001;
|
||||
if ( L->crs().mapUnits() == QgsUnitTypes::DistanceMeters )
|
||||
if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceMeters )
|
||||
{
|
||||
threshold = 0.001;
|
||||
}
|
||||
else if ( L->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
|
||||
else if ( mLayer->crs().mapUnits() == QgsUnitTypes::DistanceFeet )
|
||||
{
|
||||
threshold = 0.0001;
|
||||
}
|
||||
@ -649,7 +650,7 @@ int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPointXY &p )
|
||||
double sqrSnappingTolerance = threshold * threshold;
|
||||
|
||||
QgsFeature f;
|
||||
QgsFeatureIterator fit = L->getFeatures( QgsFeatureRequest()
|
||||
QgsFeatureIterator fit = mLayer->getFeatures( QgsFeatureRequest()
|
||||
.setFilterRect( searchRect )
|
||||
.setFlags( QgsFeatureRequest::ExactIntersect )
|
||||
.setSubsetOfAttributes( QgsAttributeList() ) );
|
||||
@ -685,7 +686,7 @@ int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPointXY &p )
|
||||
if ( sqrDistVertexSnap < sqrSnappingTolerance )
|
||||
continue; // the vertex already exists - do not insert it
|
||||
|
||||
if ( !L->insertVertex( p.x(), p.y(), fid, segmentAfterVertex ) )
|
||||
if ( !mLayer->insertVertex( p.x(), p.y(), fid, segmentAfterVertex ) )
|
||||
{
|
||||
QgsDebugMsg( "failed to insert topo point" );
|
||||
}
|
||||
@ -695,11 +696,11 @@ int QgsVectorLayerEditUtils::addTopologicalPoints( const QgsPointXY &p )
|
||||
}
|
||||
|
||||
|
||||
int QgsVectorLayerEditUtils::boundingBoxFromPointList( const QList<QgsPointXY> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
|
||||
bool QgsVectorLayerEditUtils::boundingBoxFromPointList( const QList<QgsPointXY> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const
|
||||
{
|
||||
if ( list.size() < 1 )
|
||||
{
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
xmin = std::numeric_limits<double>::max();
|
||||
@ -727,5 +728,5 @@ int QgsVectorLayerEditUtils::boundingBoxFromPointList( const QList<QgsPointXY> &
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
@ -19,9 +19,8 @@
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsfeature.h"
|
||||
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
class QgsCurve;
|
||||
|
||||
@ -66,68 +65,40 @@ class CORE_EXPORT QgsVectorLayerEditUtils
|
||||
QgsVectorLayer::EditResult deleteVertex( QgsFeatureId featureId, int vertex );
|
||||
|
||||
/** Adds a ring to polygon/multipolygon features
|
||||
* \param ring ring to add
|
||||
* \param targetFeatureIds if specified, only these features will be the candidates for adding a ring. Otherwise
|
||||
* @param ring ring to add
|
||||
* @param targetFeatureIds if specified, only these features will be the candidates for adding a ring. Otherwise
|
||||
* all intersecting features are tested and the ring is added to the first valid feature.
|
||||
* \param modifiedFeatureId if specified, feature ID for feature that ring was added to will be stored in this parameter
|
||||
* \returns
|
||||
* 0 in case of success,
|
||||
* 1 problem with feature type,
|
||||
* 2 ring not closed,
|
||||
* 3 ring not valid,
|
||||
* 4 ring crosses existing rings,
|
||||
* 5 no feature found where ring can be inserted
|
||||
* @param modifiedFeatureId if specified, feature ID for feature that ring was added to will be stored in this parameter
|
||||
* @return OperationResult result code: success or reason of failure
|
||||
*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
int addRing( const QList<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds = QgsFeatureIds(), QgsFeatureId *modifiedFeatureId = nullptr );
|
||||
QgsGeometry::OperationResult addRing( const QList<QgsPointXY> &ring, const QgsFeatureIds &targetFeatureIds = QgsFeatureIds(), QgsFeatureId *modifiedFeatureId = nullptr );
|
||||
|
||||
/** Adds a ring to polygon/multipolygon features
|
||||
* \param ring ring to add
|
||||
* \param targetFeatureIds if specified, only these features will be the candidates for adding a ring. Otherwise
|
||||
/**
|
||||
* Adds a ring to polygon/multipolygon features
|
||||
* @param ring ring to add
|
||||
* @param targetFeatureIds if specified, only these features will be the candidates for adding a ring. Otherwise
|
||||
* all intersecting features are tested and the ring is added to the first valid feature.
|
||||
* \param modifiedFeatureId if specified, feature ID for feature that ring was added to will be stored in this parameter
|
||||
* \returns
|
||||
* 0 in case of success,
|
||||
* 1 problem with feature type,
|
||||
* 2 ring not closed,
|
||||
* 3 ring not valid,
|
||||
* 4 ring crosses existing rings,
|
||||
* 5 no feature found where ring can be inserted
|
||||
* \note available in Python bindings as addCurvedRing
|
||||
* @param modifiedFeatureId if specified, feature ID for feature that ring was added to will be stored in this parameter
|
||||
* @return OperationResult result code: success or reason of failure
|
||||
* @note available in python bindings as addCurvedRing
|
||||
*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
int addRing( QgsCurve *ring, const QgsFeatureIds &targetFeatureIds = QgsFeatureIds(), QgsFeatureId *modifiedFeatureId = nullptr ) SIP_PYNAME( addCurvedRing );
|
||||
QgsGeometry::OperationResult addRing( QgsCurve *ring, const QgsFeatureIds &targetFeatureIds = QgsFeatureIds(), QgsFeatureId *modifiedFeatureId = nullptr ) SIP_PYNAME( addCurvedRing );
|
||||
|
||||
/** Adds a new part polygon to a multipart feature
|
||||
* \returns
|
||||
* 0 in case of success,
|
||||
* 1 if selected feature is not multipart,
|
||||
* 2 if ring is not a valid geometry,
|
||||
* 3 if new polygon ring not disjoint with existing rings,
|
||||
* 4 if no feature was selected,
|
||||
* 5 if several features are selected,
|
||||
* 6 if selected geometry not found
|
||||
/**
|
||||
* Adds a new part polygon to a multipart feature
|
||||
* @returns QgsGeometry::OperationResult a result code: success or reason of failure
|
||||
*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
int addPart( const QList<QgsPointXY> &ring, QgsFeatureId featureId );
|
||||
QgsGeometry::OperationResult addPart( const QList<QgsPointXY> &ring, QgsFeatureId featureId );
|
||||
|
||||
/** Adds a new part polygon to a multipart feature
|
||||
* \returns
|
||||
* 0 in case of success,
|
||||
* 1 if selected feature is not multipart,
|
||||
* 2 if ring is not a valid geometry,
|
||||
* 3 if new polygon ring not disjoint with existing rings,
|
||||
* 4 if no feature was selected,
|
||||
* 5 if several features are selected,
|
||||
* 6 if selected geometry not found
|
||||
* \note available in Python bindings as addPartV2
|
||||
/**
|
||||
* Adds a new part polygon to a multipart feature
|
||||
* @returns QgsGeometry::OperationResult a result code: success or reason of failure
|
||||
* @note available in python bindings as addPartV2
|
||||
*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
int addPart( const QgsPointSequence &ring, QgsFeatureId featureId );
|
||||
QgsGeometry::OperationResult addPart( const QgsPointSequence &ring, QgsFeatureId featureId );
|
||||
|
||||
//! \note available in Python bindings as addCurvedPart
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
int addPart( QgsCurve *ring, QgsFeatureId featureId ) SIP_PYNAME( addCurvedPart );
|
||||
// @note available in python bindings as addCurvedPart
|
||||
QgsGeometry::OperationResult addPart( QgsCurve *ring, QgsFeatureId featureId ) SIP_PYNAME( addCurvedPart );
|
||||
|
||||
/** Translates feature by dx, dy
|
||||
* \param featureId id of the feature to translate
|
||||
@ -145,7 +116,7 @@ class CORE_EXPORT QgsVectorLayerEditUtils
|
||||
* 4 if there is a selection but no feature split
|
||||
*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
int splitParts( const QList<QgsPointXY> &splitLine, bool topologicalEditing = false );
|
||||
QgsGeometry::OperationResult splitParts( const QList<QgsPointXY> &splitLine, bool topologicalEditing = false );
|
||||
|
||||
/** Splits features cut by the given line
|
||||
* \param splitLine line that splits the layer features
|
||||
@ -155,7 +126,7 @@ class CORE_EXPORT QgsVectorLayerEditUtils
|
||||
* 4 if there is a selection but no feature split
|
||||
*/
|
||||
// TODO QGIS 3.0 returns an enum instead of a magic constant
|
||||
int splitFeatures( const QList<QgsPointXY> &splitLine, bool topologicalEditing = false );
|
||||
QgsGeometry::OperationResult splitFeatures( const QList<QgsPointXY> &splitLine, bool topologicalEditing = false );
|
||||
|
||||
/** Adds topological points for every vertex of the geometry.
|
||||
* \param geom the geometry where each vertex is added to segments of other features
|
||||
@ -173,15 +144,15 @@ class CORE_EXPORT QgsVectorLayerEditUtils
|
||||
*/
|
||||
int addTopologicalPoints( const QgsPointXY &p );
|
||||
|
||||
protected:
|
||||
|
||||
/** Little helper function that gives bounding box from a list of points.
|
||||
\returns 0 in case of success */
|
||||
int boundingBoxFromPointList( const QList<QgsPointXY> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const;
|
||||
|
||||
private:
|
||||
|
||||
QgsVectorLayer *L = nullptr;
|
||||
/**
|
||||
* Little helper function that gives bounding box from a list of points.
|
||||
* \returns True in case of success
|
||||
*/
|
||||
bool boundingBoxFromPointList( const QList<QgsPointXY> &list, double &xmin, double &ymin, double &xmax, double &ymax ) const;
|
||||
|
||||
QgsVectorLayer *mLayer = nullptr;
|
||||
};
|
||||
|
||||
#endif // QGSVECTORLAYEREDITUTILS_H
|
||||
|
@ -1423,14 +1423,14 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
]
|
||||
|
||||
polyline = QgsGeometry.fromPolyline(points[0])
|
||||
self.assertEqual(polyline.addPoints(points[1][0:1]), 2, "addPoints with one point line unexpectedly succeeded.")
|
||||
self.assertEqual(polyline.addPoints(points[1][0:2]), 0, "addPoints with two point line failed.")
|
||||
self.assertEqual(polyline.addPoints(points[1][0:1]), QgsGeometry.InvalidInput, "addPoints with one point line unexpectedly succeeded.")
|
||||
self.assertEqual(polyline.addPoints(points[1][0:2]), QgsGeometry.Success, "addPoints with two point line failed.")
|
||||
expwkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1))"
|
||||
wkt = polyline.exportToWkt()
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
|
||||
polyline = QgsGeometry.fromPolyline(points[0])
|
||||
self.assertEqual(polyline.addPoints(points[1]), 0, "addPoints with %d point line failed." % len(points[1]))
|
||||
self.assertEqual(polyline.addPoints(points[1]), QgsGeometry.Success, "addPoints with %d point line failed." % len(points[1]))
|
||||
expwkt = "MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 0), (3 0, 3 1, 5 1, 5 0, 6 0))"
|
||||
wkt = polyline.exportToWkt()
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
@ -1439,7 +1439,7 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
polyline = QgsGeometry.fromPolyline(points[0])
|
||||
polyline.geometry().addZValue(4.0)
|
||||
points2 = [QgsPoint(p[0], p[1], 3.0, wkbType=QgsWkbTypes.PointZ) for p in points[1]]
|
||||
self.assertEqual(polyline.addPointsV2(points2), 0)
|
||||
self.assertEqual(polyline.addPointsV2(points2), QgsGeometry.Success)
|
||||
expwkt = "MultiLineStringZ ((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 0 4),(3 0 3, 3 1 3, 5 1 3, 5 0 3, 6 0 3))"
|
||||
wkt = polyline.exportToWkt()
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
@ -1456,12 +1456,12 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
|
||||
polygon = QgsGeometry.fromPolygon(points[0])
|
||||
|
||||
self.assertEqual(polygon.addPoints(points[1][0][0:1]), 2, "addPoints with one point ring unexpectedly succeeded.")
|
||||
self.assertEqual(polygon.addPoints(points[1][0][0:2]), 2, "addPoints with two point ring unexpectedly succeeded.")
|
||||
self.assertEqual(polygon.addPoints(points[1][0][0:3]), 2, "addPoints with unclosed three point ring unexpectedly succeeded.")
|
||||
self.assertEqual(polygon.addPoints([QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(4, 0)]), 2, "addPoints with 'closed' three point ring unexpectedly succeeded.")
|
||||
self.assertEqual(polygon.addPoints(points[1][0][0:1]), QgsGeometry.InvalidInput, "addPoints with one point ring unexpectedly succeeded.")
|
||||
self.assertEqual(polygon.addPoints(points[1][0][0:2]), QgsGeometry.InvalidInput, "addPoints with two point ring unexpectedly succeeded.")
|
||||
self.assertEqual(polygon.addPoints(points[1][0][0:3]), QgsGeometry.InvalidInput, "addPoints with unclosed three point ring unexpectedly succeeded.")
|
||||
self.assertEqual(polygon.addPoints([QgsPointXY(4, 0), QgsPointXY(5, 0), QgsPointXY(4, 0)]), QgsGeometry.InvalidInput, "addPoints with 'closed' three point ring unexpectedly succeeded.")
|
||||
|
||||
self.assertEqual(polygon.addPoints(points[1][0]), 0, "addPoints failed")
|
||||
self.assertEqual(polygon.addPoints(points[1][0]), QgsGeometry.Success, "addPoints failed")
|
||||
expwkt = "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)))"
|
||||
wkt = polygon.exportToWkt()
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
@ -1469,13 +1469,13 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
mp = QgsGeometry.fromMultiPolygon(points[:1])
|
||||
p = QgsGeometry.fromPolygon(points[1])
|
||||
|
||||
self.assertEqual(mp.addPartGeometry(p), 0)
|
||||
self.assertEqual(mp.addPartGeometry(p), QgsGeometry.Success)
|
||||
wkt = mp.exportToWkt()
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
|
||||
mp = QgsGeometry.fromMultiPolygon(points[:1])
|
||||
mp2 = QgsGeometry.fromMultiPolygon(points[1:])
|
||||
self.assertEqual(mp.addPartGeometry(mp2), 0)
|
||||
self.assertEqual(mp.addPartGeometry(mp2), QgsGeometry.Success)
|
||||
wkt = mp.exportToWkt()
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
|
||||
@ -1483,7 +1483,7 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
polygon = QgsGeometry.fromPolygon(points[0])
|
||||
polygon.geometry().addZValue(4.0)
|
||||
points2 = [QgsPoint(pi[0], pi[1], 3.0, wkbType=QgsWkbTypes.PointZ) for pi in points[1][0]]
|
||||
self.assertEqual(polygon.addPointsV2(points2), 0)
|
||||
self.assertEqual(polygon.addPointsV2(points2), QgsGeometry.Success)
|
||||
expwkt = "MultiPolygonZ (((0 0 4, 1 0 4, 1 1 4, 2 1 4, 2 2 4, 0 2 4, 0 0 4)),((4 0 3, 5 0 3, 5 2 3, 3 2 3, 3 1 3, 4 1 3, 4 0 3)))"
|
||||
wkt = polygon.exportToWkt()
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
@ -1492,38 +1492,38 @@ class TestQgsGeometry(unittest.TestCase):
|
||||
empty = QgsGeometry()
|
||||
# if not default type specified, addPart should fail
|
||||
result = empty.addPoints([QgsPointXY(4, 0)])
|
||||
assert result != 0, 'Got return code {}'.format(result)
|
||||
assert result != QgsGeometry.Success, 'Got return code {}'.format(result)
|
||||
result = empty.addPoints([QgsPointXY(4, 0)], QgsWkbTypes.PointGeometry)
|
||||
self.assertEqual(result, 0, 'Got return code {}'.format(result))
|
||||
self.assertEqual(result, QgsGeometry.Success, 'Got return code {}'.format(result))
|
||||
wkt = empty.exportToWkt()
|
||||
expwkt = 'MultiPoint ((4 0))'
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
result = empty.addPoints([QgsPointXY(5, 1)])
|
||||
self.assertEqual(result, 0, 'Got return code {}'.format(result))
|
||||
self.assertEqual(result, QgsGeometry.Success, 'Got return code {}'.format(result))
|
||||
wkt = empty.exportToWkt()
|
||||
expwkt = 'MultiPoint ((4 0),(5 1))'
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
# next try with lines
|
||||
empty = QgsGeometry()
|
||||
result = empty.addPoints(points[0][0], QgsWkbTypes.LineGeometry)
|
||||
self.assertEqual(result, 0, 'Got return code {}'.format(result))
|
||||
self.assertEqual(result, QgsGeometry.Success, 'Got return code {}'.format(result))
|
||||
wkt = empty.exportToWkt()
|
||||
expwkt = 'MultiLineString ((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0))'
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
result = empty.addPoints(points[1][0])
|
||||
self.assertEqual(result, 0, 'Got return code {}'.format(result))
|
||||
self.assertEqual(result, QgsGeometry.Success, 'Got return code {}'.format(result))
|
||||
wkt = empty.exportToWkt()
|
||||
expwkt = 'MultiLineString ((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))'
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
# finally try with polygons
|
||||
empty = QgsGeometry()
|
||||
result = empty.addPoints(points[0][0], QgsWkbTypes.PolygonGeometry)
|
||||
self.assertEqual(result, 0, 'Got return code {}'.format(result))
|
||||
self.assertEqual(result, QgsGeometry.Success, 'Got return code {}'.format(result))
|
||||
wkt = empty.exportToWkt()
|
||||
expwkt = 'MultiPolygon (((0 0, 1 0, 1 1, 2 1, 2 2, 0 2, 0 0)))'
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
result = empty.addPoints(points[1][0])
|
||||
self.assertEqual(result, 0, 'Got return code {}'.format(result))
|
||||
self.assertEqual(result, QgsGeometry.Success, 'Got return code {}'.format(result))
|
||||
wkt = empty.exportToWkt()
|
||||
expwkt = '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)))'
|
||||
assert compareWkt(expwkt, wkt), "Expected:\n%s\nGot:\n%s\n" % (expwkt, wkt)
|
||||
|
Loading…
x
Reference in New Issue
Block a user