39using namespace Qt::StringLiterals;
47 if ( !mLayer->isSpatial() )
58 mLayer->changeGeometry( atFeatureId, geometry );
64 if ( !mLayer->isSpatial() )
75 mLayer->changeGeometry( atFeatureId, geometry );
87 if ( !mLayer->isSpatial() )
113 return mLayer->changeGeometry( atFeatureId, geometry );
123 if ( !mLayer->isSpatial() )
138 geometry.
set(
nullptr );
141 mLayer->changeGeometry( featureId, geometry );
157 if ( !ring->isClosed() )
171 if ( !targetFeatureIds.isEmpty() )
184 bool success =
false;
195 addRingReturnCode = g.
addRing(
static_cast< QgsCurve *
>( ring->clone() ) );
199 addRingReturnCode = g.
addRing(
static_cast< QgsCurve *
>( ring->reversed() ) );
205 if ( modifiedFeatureIds )
207 modifiedFeatureIds->insert( f.
id() );
220double QgsVectorLayerEditUtils::getTopologicalSearchRadius(
const QgsVectorLayer *layer )
240void QgsVectorLayerEditUtils::addTopologicalPointsToLayers(
const QgsGeometry &geom,
QgsVectorLayer *vlayer,
const QList<QgsMapLayer *> &layers,
const QString &toolName )
245 for ( QgsMapLayer *layer : layers )
247 QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layer );
252 QgsCoordinateTransform ct;
253 if ( vectorLayer->
crs() != vlayer->
crs() )
260 catch ( QgsCsException & )
262 QgsDebugError( u
"Bounding box transformation failed, skipping topological points for layer %1"_s.arg( vlayer->
id() ) );
266 bbox.
grow( getTopologicalSearchRadius( vectorLayer ) );
273 vectorLayer->
beginEditCommand( QObject::tr(
"Topological points added by '%1'" ).arg( toolName ) );
276 if ( vectorLayer->
crs() != vlayer->
crs() )
281 QgsGeometry transformedGeom( geom );
282 transformedGeom.transform( ct );
285 catch ( QgsCsException & )
287 QgsDebugError( u
"transformation to vectorLayer coordinate failed"_s );
295 if ( returnValue == 0 )
312 for ( QVector<QgsPointXY>::const_iterator it = ring.constBegin(); it != ring.constEnd(); ++it )
316 return addRing( l, targetFeatureIds, modifiedFeatureId );
322 return addRing( ringLine, targetFeatureIds, modifiedFeatureId );
327 std::unique_ptr<QgsCurve> uniquePtrRing( ring );
328 if ( modifiedFeatureId )
332 if ( modifiedFeatureId && !modifiedFeatureIds.empty() )
333 *modifiedFeatureId = *modifiedFeatureIds.begin();
336 return staticAddRing( mLayer, uniquePtrRing, targetFeatureIds,
nullptr,
true );
341 std::unique_ptr<QgsCurve> uniquePtrRing( ring );
342 return staticAddRing( mLayer, uniquePtrRing, targetFeatureIds, modifiedFeatureIds,
false );
349 for ( QVector<QgsPointXY>::const_iterator it = points.constBegin(); it != points.constEnd(); ++it )
353 return addPart( l, featureId );
358 if ( !mLayer->isSpatial() )
362 bool firstPart =
false;
364 if ( !mLayer->getFeatures(
QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
380 if ( firstPart &&
QgsWkbTypes::isSingleType( mLayer->wkbType() ) && mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
385 mLayer->changeGeometry( featureId, geometry );
392 std::unique_ptr<QgsCurve> uniquePtrRing( ring );
394 if ( !mLayer->isSpatial() )
398 bool firstPart =
false;
400 if ( !mLayer->getFeatures(
QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
413 uniquePtrRing.reset( uniquePtrRing->reversed() );
420 if ( firstPart &&
QgsWkbTypes::isSingleType( mLayer->wkbType() ) && mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
425 mLayer->changeGeometry( featureId, geometry );
432 std::unique_ptr<QgsCurvePolygon> uniquePtrPoly( polygon );
434 if ( !mLayer->isSpatial() )
441 bool firstPart =
false;
443 if ( !mLayer->getFeatures(
QgsFeatureRequest().setFilterFid( featureId ).setNoAttributes() ).nextFeature( f ) )
470 if ( firstPart &&
QgsWkbTypes::isSingleType( mLayer->wkbType() ) && mLayer->dataProvider()->doesStrictFeatureTypeCheck() )
475 mLayer->changeGeometry( featureId, geometry );
483 if ( !mLayer->isSpatial() )
495 mLayer->changeGeometry( featureId, geometry );
503 for ( QVector<QgsPointXY>::const_iterator it = splitLine.constBegin(); it != splitLine.constEnd(); ++it )
514 bool preserveCircular =
false;
515 return splitFeatures( &lineString, topologyTestPoints, preserveCircular, topologicalEditing );
520 if ( !mLayer->isSpatial() )
526 int numberOfSplitFeatures = 0;
529 const QgsFeatureIds selectedIds = mLayer->selectedFeatureIds();
531 if ( !selectedIds.isEmpty() )
533 features = mLayer->getSelectedFeatures();
547 else if ( bBox.
height() == 0.0 && bBox.
width() > 0 )
555 double bufferDistance = 0.000001;
556 if ( mLayer->crs().isGeographic() )
557 bufferDistance = 0.00000001;
570 const int fieldCount = mLayer->fields().count();
571#if !( GEOS_VERSION_MAJOR > 3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 15 ) )
582 QVector<QgsGeometry> newGeometries;
587#if GEOS_VERSION_MAJOR > 3 || ( GEOS_VERSION_MAJOR == 3 && GEOS_VERSION_MINOR >= 15 )
588 splitFunctionReturn = featureGeom.
splitGeometry( curve, newGeometries, preserveCircular, topologicalEditing, featureTopologyTestPoints );
592 bool preserveCircularForGeom = preserveCircular;
593 preserveCircularForGeom &= ( splitCurveContainsCurves || featureGeom.
constGet()->hasCurvedSegments() );
594 splitFunctionReturn = featureGeom.
splitGeometry( curve, newGeometries, preserveCircularForGeom, topologicalEditing, featureTopologyTestPoints );
597 topologyTestPoints.append( featureTopologyTestPoints );
602 double featureGeomSize = size( featureGeom );
604 QVector<QgsGeometry>::iterator largestNewFeature = std::max_element( newGeometries.begin(), newGeometries.end(), [&size](
const QgsGeometry &a,
const QgsGeometry &b ) ->
bool {
605 return size( a ) < size( b );
608 if ( size( *largestNewFeature ) > featureGeomSize )
611 *largestNewFeature = featureGeom;
616 mLayer->changeGeometry( feat.
id(), featureGeom );
620 for (
int fieldIdx = 0; fieldIdx < fieldCount; ++fieldIdx )
622 const QgsField field = mLayer->fields().at( fieldIdx );
634 const double originalValue = feat.
attribute( fieldIdx ).toDouble();
636 double originalSize = 0;
638 switch ( originalGeom.
type() )
646 originalSize = originalGeom.
length();
649 originalSize = originalGeom.
area();
654 switch ( featureGeom.
type() )
662 newSize = featureGeom.
length();
665 newSize = featureGeom.
area();
669 attributeMap.insert( fieldIdx, originalSize > 0 ? ( originalValue * newSize / originalSize ) : originalValue );
676 if ( !attributeMap.isEmpty() )
678 mLayer->changeAttributeValues( feat.
id(), attributeMap );
682 for (
const QgsGeometry &geom : std::as_const( newGeometries ) )
685 for (
int fieldIdx = 0; fieldIdx < fieldCount; ++fieldIdx )
687 const QgsField field = mLayer->fields().at( fieldIdx );
696 attributeMap.insert( fieldIdx, feat.
attribute( fieldIdx ) );
703 attributeMap.insert( fieldIdx, feat.
attribute( fieldIdx ) );
707 const double originalValue = feat.
attribute( fieldIdx ).toDouble();
709 double originalSize = 0;
711 switch ( originalGeom.
type() )
719 originalSize = originalGeom.
length();
722 originalSize = originalGeom.
area();
727 switch ( geom.
type() )
738 newSize = geom.
area();
742 attributeMap.insert( fieldIdx, originalSize > 0 ? ( originalValue * newSize / originalSize ) : originalValue );
756 if ( topologicalEditing )
758 QgsPointSequence::const_iterator topol_it = featureTopologyTestPoints.constBegin();
759 for ( ; topol_it != featureTopologyTestPoints.constEnd(); ++topol_it )
764 ++numberOfSplitFeatures;
768 returnCode = splitFunctionReturn;
772 if ( !featuresDataToAdd.isEmpty() )
777 mLayer->addFeatures( featuresListToAdd );
780 if ( numberOfSplitFeatures == 0 )
791 for ( QVector<QgsPointXY>::const_iterator it = splitLine.constBegin(); it != splitLine.constEnd(); ++it )
800 if ( !mLayer->isSpatial() )
803 double xMin, yMin, xMax, yMax;
805 int numberOfSplitParts = 0;
809 if ( mLayer->selectedFeatureCount() > 0 )
811 fit = mLayer->getSelectedFeatures();
815 if ( boundingBoxFromPointList( splitLine, xMin, yMin, xMax, yMax ) )
835 else if ( bBox.
height() == 0.0 && bBox.
width() > 0 )
843 double bufferDistance = 0.000001;
844 if ( mLayer->crs().isGeographic() )
845 bufferDistance = 0.00000001;
862 QVector<QgsGeometry> resultCollection;
866 QVector<QgsGeometry> newGeometries;
869 const Qgis::GeometryOperationResult splitFunctionReturn = part.splitGeometry( splitLine, newGeometries, topologicalEditing, partTopologyTestPoints,
false );
873 for (
int i = 0; i < newGeometries.size(); ++i )
875 resultCollection.append( newGeometries.at( i ).asGeometryCollection() );
878 topologyTestPoints.append( partTopologyTestPoints );
880 ++numberOfSplitParts;
887 resultCollection.append( part );
891 return splitFunctionReturn;
896 mLayer->changeGeometry( feat.
id(), newGeom );
898 if ( topologicalEditing )
900 QgsPointSequence::const_iterator topol_it = topologyTestPoints.constBegin();
901 for ( ; topol_it != topologyTestPoints.constEnd(); ++topol_it )
907 if ( numberOfSplitParts == 0 && mLayer->selectedFeatureCount() > 0 )
920 if ( !mLayer->isSpatial() )
928 bool pointsAdded =
false;
940 return pointsAdded ? 0 : 2;
945 if ( !mLayer->isSpatial() )
948 double segmentSearchEpsilon = mLayer->crs().isGeographic() ? 1e-12 : 1e-8;
951 double threshold = getTopologicalSearchRadius( mLayer );
954 searchRect.
grow( threshold );
959 bool pointsAdded =
false;
966 mLayer->changeGeometry( f.
id(), geom );
970 return pointsAdded ? 0 : 2;
975 if ( !mLayer->isSpatial() )
983 bool pointsAdded =
false;
985 QgsPointSequence::const_iterator it = ps.constBegin();
986 while ( it != ps.constEnd() )
995 return pointsAdded ? 0 : 2;
1007 errorMessage.clear();
1009 if ( mergeFeatureIds.isEmpty() )
1011 errorMessage = QObject::tr(
"List of features to merge is empty" );
1016 for (
int i = 0; i < mergeAttributes.count(); ++i )
1018 QVariant val = mergeAttributes.at( i );
1021 && mLayer->dataProvider()
1022 && mLayer->dataProvider()->defaultValueClause( mLayer->fields().fieldOriginIndex( i ) ) == val;
1025 QString errorMessageConvertCompatible;
1026 if ( !isDefaultValue && !mLayer->fields().at( i ).convertCompatible( val, &errorMessageConvertCompatible ) )
1028 if ( errorMessage.isEmpty() )
1029 errorMessage = QObject::tr(
"Could not store value '%1' in field of type %2: %3" ).arg( mergeAttributes.at( i ).toString(), mLayer->fields().at( i ).typeName(), errorMessageConvertCompatible );
1031 newAttributes[i] = val;
1034 mLayer->beginEditCommand( QObject::tr(
"Merged features" ) );
1037 QgsFeatureIds::const_iterator feature_it = mergeFeatureIds.constBegin();
1038 for ( ; feature_it != mergeFeatureIds.constEnd(); ++feature_it )
1040 if ( *feature_it != targetFeatureId )
1041 mLayer->deleteFeature( *feature_it );
1049 mLayer->addFeature( mergeFeature );
1053 mLayer->changeGeometry( targetFeatureId, mergeGeometry );
1054 mLayer->changeAttributeValues( targetFeatureId, newAttributes );
1057 mLayer->endEditCommand();
1059 mLayer->triggerRepaint();
1064bool QgsVectorLayerEditUtils::boundingBoxFromPointList(
const QgsPointSequence &list,
double &xmin,
double &ymin,
double &xmax,
double &ymax )
const
1071 xmin = std::numeric_limits<double>::max();
1072 xmax = -std::numeric_limits<double>::max();
1073 ymin = std::numeric_limits<double>::max();
1074 ymax = -std::numeric_limits<double>::max();
1076 for ( QgsPointSequence::const_iterator it = list.constBegin(); it != list.constEnd(); ++it )
1078 if ( it->x() < xmin )
1082 if ( it->x() > xmax )
1086 if ( it->y() < ymin )
1090 if ( it->y() > ymax )
@ NoOrientation
Unknown orientation or sentinel value.
@ CounterClockwise
Counter-clockwise direction.
@ Clockwise
Clockwise direction.
GeometryOperationResult
Success or failure of a geometry operation.
@ AddPartSelectedGeometryNotFound
The selected geometry cannot be found.
@ InvalidInputGeometryType
The input geometry (ring, part, split line, etc.) has not the correct geometry type.
@ Success
Operation succeeded.
@ AddRingNotInExistingFeature
The input ring doesn't have any existing ring to fit into.
@ AddRingNotClosed
The input ring is not closed.
@ NothingHappened
Nothing happened, without any error.
@ InvalidBaseGeometry
The base geometry on which the operation is done is invalid or empty.
@ LayerNotEditable
Cannot edit layer.
@ ExactIntersect
Use exact geometry intersection (slower) instead of bounding boxes.
@ NoGeometry
Geometry is not required. It may still be returned if e.g. required for a filter condition.
@ GeometryRatio
New values are computed by the ratio of their area/length compared to the area/length of the original...
@ UnsetField
Clears the field value so that the data provider backend will populate using any backend triggers or ...
@ DefaultValue
Use default field value.
@ Duplicate
Duplicate original value.
@ Provider
Field originates from the underlying data provider of the vector layer.
VectorEditResult
Specifies the result of a vector layer edit operation.
@ EmptyGeometry
Edit operation resulted in an empty geometry.
@ Success
Edit operation was successful.
@ FetchFeatureFailed
Unable to fetch requested feature.
@ EditFailed
Edit operation failed.
@ InvalidLayer
Edit failed due to invalid layer.
The vertex_iterator class provides an STL-style iterator for vertices.
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
bool isMeasure() const
Returns true if the geometry contains m values.
virtual QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual int nCoordinates() const
Returns the number of nodes contained in the geometry.
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
virtual bool hasCurvedSegments() const
Returns true if the geometry contains curved segments.
Qgis::DistanceUnit mapUnits
Curve polygon geometry type.
void forceCounterClockwise()
Forces the polygon to respect the exterior ring is counter-clockwise, interior rings are clockwise co...
void forceClockwise()
Forces the polygon to respect the exterior ring is clockwise, interior rings are counter-clockwise co...
Abstract base class for curved geometry type.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
Wraps a request for features to a vector layer (or directly its vector data provider).
QgsFeatureRequest & setFilterRect(const QgsRectangle &rectangle)
Sets the rectangle from which features will be taken.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Q_INVOKABLE QVariant attribute(const QString &name) const
Lookup attribute value by attribute name.
Encapsulate a field in an attribute table or data source.
Qgis::FieldDomainSplitPolicy splitPolicy() const
Returns the field's split policy, which indicates how field values should be handled during a split o...
double geometryPrecision() const
The precision in which geometries on this layer should be saved.
A geometry is the spatial representation of a feature.
double length() const
Returns the planar, 2-dimensional length of geometry.
bool addTopologicalPoint(const QgsPoint &point, double snappingTolerance=1e-8, double segmentSearchEpsilon=1e-12)
Adds a vertex to the segment which intersect point but don't already have a vertex there.
static QgsGeometry collectGeometry(const QVector< QgsGeometry > &geometries)
Creates a new multipart geometry from a list of QgsGeometry objects.
QVector< QgsGeometry > asGeometryCollection() const
Returns contents of the geometry as a list of geometries.
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
bool insertVertex(double x, double y, int beforeVertex)
Insert a new vertex before the given vertex index, ring and item (first number is index 0) If the req...
bool convertToSingleType()
Converts multi type geometry into single type geometry e.g.
Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring)
Adds a new ring to this geometry.
double area() const
Returns the planar, 2-dimensional area of the geometry.
Qgis::AngularDirection polygonOrientation() const
Returns the orientation of the polygon.
bool deleteVertices(const QSet< int > &atVertices)
Deletes vertices at the given positions (first number is index 0).
void set(QgsAbstractGeometry *geometry)
Sets the underlying geometry store.
QgsAbstractGeometry::vertex_iterator vertices_begin() const
Returns STL-style iterator pointing to the first vertex of the geometry.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
Qgis::GeometryOperationResult addPartV2(const QVector< QgsPointXY > &points, Qgis::WkbType wkbType=Qgis::WkbType::Unknown)
Adds a new part to a the geometry.
Qgis::GeometryOperationResult translate(double dx, double dy, double dz=0.0, double dm=0.0)
Translates this geometry by dx, dy, dz and dm.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitGeometry(const QVector< QgsPointXY > &splitLine, QVector< QgsGeometry > &newGeometries, bool topological, QVector< QgsPointXY > &topologyTestPoints, bool splitFeature=true)
Splits this geometry according to a given line.
bool moveVertex(double x, double y, int atVertex)
Moves the vertex at the given position number and item (first number is index 0) to the given coordin...
QgsAbstractGeometry::vertex_iterator vertices_end() const
Returns STL-style iterator pointing to the imaginary vertex after the last vertex of the geometry.
Line string geometry type, with support for z-dimension and m-values.
QgsCoordinateReferenceSystem crs
QgsCoordinateTransformContext transformContext() const
Returns the layer data provider coordinate transform context or a default transform context if the la...
Point geometry type, with support for z-dimension and m-values.
A rectangle specified with double values.
void setYMinimum(double y)
Set the minimum y value.
void setXMinimum(double x)
Set the minimum x value.
void setYMaximum(double y)
Set the maximum y value.
void setXMaximum(double x)
Set the maximum x value.
void grow(double delta)
Grows the rectangle in place by the specified amount.
static const QgsSettingsEntryDouble * settingsDigitizingDefaultMValue
Settings entry digitizing default m value.
static const QgsSettingsEntryDouble * settingsDigitizingDefaultZValue
Settings entry digitizing default z value.
Represents a default, "not-specified" value for a feature attribute.
int translateFeature(QgsFeatureId featureId, double dx, double dy)
Translates feature by dx, dy.
Qgis::VectorEditResult deleteVertices(QgsFeatureId featureId, const QSet< int > &vertices)
Deletes a set of vertices from a feature.
bool mergeFeatures(const QgsFeatureId &targetFeatureId, const QgsFeatureIds &mergeFeatureIds, const QgsAttributes &mergeAttributes, const QgsGeometry &unionGeometry, QString &errorMessage)
Merge features into a single one.
QgsVectorLayerEditUtils(QgsVectorLayer *layer)
bool insertVertex(double x, double y, QgsFeatureId atFeatureId, int beforeVertex)
Insert a new vertex before the given vertex number, in the given ring, item (first number is index 0)...
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addPart(const QVector< QgsPointXY > &ring, QgsFeatureId featureId)
Adds a new part polygon to a multipart feature.
Qgis::VectorEditResult deleteVertex(QgsFeatureId featureId, int vertex)
Deletes a vertex from a feature.
Qgis::GeometryOperationResult addRingV2(QgsCurve *ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureIds *modifiedFeatureIds=nullptr)
Adds a ring to polygon/multipolygon features.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitParts(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits parts cut by the given line.
Q_DECL_DEPRECATED Qgis::GeometryOperationResult splitFeatures(const QVector< QgsPointXY > &splitLine, bool topologicalEditing=false)
Splits features cut by the given line.
bool moveVertex(double x, double y, QgsFeatureId atFeatureId, int atVertex)
Moves the vertex at the given position number, ring and item (first number is index 0),...
Q_DECL_DEPRECATED Qgis::GeometryOperationResult addRing(const QVector< QgsPointXY > &ring, const QgsFeatureIds &targetFeatureIds=QgsFeatureIds(), QgsFeatureId *modifiedFeatureId=nullptr)
Adds a ring to polygon/multipolygon features.
Encapsulate geometry and attributes for new features, to be passed to createFeatures.
QList< QgsVectorLayerUtils::QgsFeatureData > QgsFeaturesDataList
Alias for list of QgsFeatureData.
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
static QgsFeatureList createFeatures(const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context=nullptr)
Creates a set of new features ready for insertion into a layer.
Represents a vector layer which manages a vector based dataset.
bool isEditable() const final
Returns true if the provider is in editing mode.
bool isSpatial() const final
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
void endEditCommand()
Finish edit command and add it to undo/redo stack.
void destroyEditCommand()
Destroy active command and reverts all changes in it.
QgsGeometryOptions * geometryOptions() const
Configuration and logic to apply automatically on any edit happening on this layer.
Q_INVOKABLE QgsVectorLayerEditBuffer * editBuffer()
Buffer with uncommitted editing operations. Only valid after editing has been turned on.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const final
Queries the layer for features specified in request.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
void beginEditCommand(const QString &text)
Create edit command for undo/redo operations.
int addTopologicalPoints(const QgsGeometry &geom)
Adds topological points for every vertex of the geometry.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
bool changeGeometry(QgsFeatureId fid, QgsGeometry &geometry, bool skipDefaultValue=false)
Changes a feature's geometry within the layer's edit buffer (but does not immediately commit the chan...
static Q_INVOKABLE bool isSingleType(Qgis::WkbType type)
Returns true if the WKB type is a single type.
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
QVector< QgsPoint > QgsPointSequence
QMap< int, QVariant > QgsAttributeMap
QList< QgsFeature > QgsFeatureList
QSet< QgsFeatureId > QgsFeatureIds
qint64 QgsFeatureId
64 bit feature ids negative numbers are used for uncommitted/newly added features
#define QgsDebugError(str)