diff --git a/python/core/auto_generated/qgsgeometryfixes.sip.in b/python/core/auto_generated/qgsgeometryfixes.sip.in new file mode 100644 index 000000000000..fef87e8ff0e7 --- /dev/null +++ b/python/core/auto_generated/qgsgeometryfixes.sip.in @@ -0,0 +1,78 @@ +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/qgsgeometryfixes.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ + + + + +class QgsGeometryFixes +{ +%Docstring +The QgsGeometryFixes class contains options to +%End + +%TypeHeaderCode +#include "qgsgeometryfixes.h" +%End + public: + QgsGeometryFixes(); + + bool removeDuplicateNodes() const; +%Docstring +Automatically remove duplicate nodes on all geometries which are edited on this layer. + +.. versionadded:: 3.4 +%End + + void setRemoveDuplicateNodes( bool value ); +%Docstring +Automatically remove duplicate nodes on all geometries which are edited on this layer. + +.. versionadded:: 3.4 +%End + + double geometryPrecision() const; +%Docstring +The precision in which geometries on this layer should be saved. +Geometries which are edited on this layer will be rounded to multiples of this value (snap to grid). +Set to 0.0 to disable. + +.. versionadded:: 3.4 +%End + + void setGeometryPrecision( double value ); +%Docstring +The precision in which geometries on this layer should be saved. +Geometries which are edited on this layer will be rounded to multiples of this value (snap to grid). +Set to 0.0 to disable. + +.. versionadded:: 3.4 +%End + + bool isActive() const; +%Docstring +Determines if at least one fix is enabled. + +.. versionadded:: 3.4 +%End + + void apply( QgsGeometry &geometry ) const; +%Docstring +Apply any fixes configured on this class to ``geometry``. + +.. versionadded:: 3.4 +%End + +}; + +/************************************************************************ + * This file has been generated automatically from * + * * + * src/core/qgsgeometryfixes.h * + * * + * Do not edit manually ! Edit header and run scripts/sipify.pl again * + ************************************************************************/ diff --git a/python/core/auto_generated/qgsvectorlayer.sip.in b/python/core/auto_generated/qgsvectorlayer.sip.in index ea2d4347b179..a74661b886d2 100644 --- a/python/core/auto_generated/qgsvectorlayer.sip.in +++ b/python/core/auto_generated/qgsvectorlayer.sip.in @@ -329,16 +329,6 @@ Constructor for LayerOptions. }; - struct GeometryOptions - { - explicit GeometryOptions( bool removeDuplicateNodes = false, double geometryPrecision = 0.0 ); - - - bool removeDuplicateNodes; - - double geometryPrecision; - }; - explicit QgsVectorLayer( const QString &path = QString(), const QString &baseName = QString(), const QString &providerLib = "ogr", const QgsVectorLayer::LayerOptions &options = QgsVectorLayer::LayerOptions() ); %Docstring @@ -2235,39 +2225,9 @@ Test if an edit command is active .. versionadded:: 3.0 %End - bool removeDuplicateNodes() const; -%Docstring -If the `removeDuplicateNodes` property is set on a layer, whenever a new feature enters -the edit buffer or the geometry of an existing feature is changed, duplicate nodes will -automatically be removed without any user intervention. - -.. versionadded:: 3.4 -%End - - void setRemoveDuplicateNodes( bool removeDuplicateNodes ); -%Docstring -If the `removeDuplicateNodes` property is set on a layer, whenever a new feature enters -the edit buffer or the geometry of an existing feature is changed, duplicate nodes will -automatically be removed without any user intervention. - -.. versionadded:: 3.4 -%End - - - double geometryPrecision() const; -%Docstring -The `geometryPrecision` property of a layer will enable an automatic snap to grid operation -on a layer whenever a new feature is added or the geometry of an existing feature is changed. -If it is set to 0.0, this feature is disabled. - -.. versionadded:: 3.4 -%End - - void setGeometryPrecision( double geometryPrecision ); + QgsGeometryFixes *geometryFixes() const; %Docstring -The `geometryPrecision` property of a layer will enable an automatic snap to grid -on a layer whenever a new feature is added or the geometry of an existing feature is changed. -If it is set to 0.0, this feature is disabled. +Configuration and logic to apply automatically on any edit happening on this layer. .. versionadded:: 3.4 %End @@ -2637,7 +2597,7 @@ Emitted when the feature count for symbols on this layer has been recalculated. Sets the extent %End - private: // Private methods + private: QgsVectorLayer( const QgsVectorLayer &rhs ); }; diff --git a/python/core/core_auto.sip b/python/core/core_auto.sip index 6de63d2963ab..e41dd356f8fe 100644 --- a/python/core/core_auto.sip +++ b/python/core/core_auto.sip @@ -53,6 +53,7 @@ %Include auto_generated/qgsfields.sip %Include auto_generated/qgsfileutils.sip %Include auto_generated/qgsfontutils.sip +%Include auto_generated/qgsgeometryfixes.sip %Include auto_generated/qgsgeometrysimplifier.sip %Include auto_generated/qgshistogram.sip %Include auto_generated/qgshtmlutils.sip diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5b7b14651b0e..326456435c9f 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -203,6 +203,7 @@ SET(QGIS_CORE_SRCS qgsfontutils.cpp qgsgeometrysimplifier.cpp qgsgeometryvalidator.cpp + qgsgeometryfixes.cpp qgsgml.cpp qgsgmlschema.cpp qgshistogram.cpp @@ -860,6 +861,7 @@ SET(QGIS_CORE_HDRS qgsfields.h qgsfileutils.h qgsfontutils.h + qgsgeometryfixes.h qgsgeometrysimplifier.h qgshistogram.h qgshtmlutils.h diff --git a/src/core/qgsgeometryfixes.cpp b/src/core/qgsgeometryfixes.cpp new file mode 100644 index 000000000000..21469a8ff396 --- /dev/null +++ b/src/core/qgsgeometryfixes.cpp @@ -0,0 +1,52 @@ +/*************************************************************************** + qgsgeometryfixes.cpp + ------------------- + begin : Aug 23, 2018 + copyright : (C) 2018 by Matthias Kuhn + email : matthias@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgsgeometryfixes.h" + +bool QgsGeometryFixes::removeDuplicateNodes() const +{ + return mRemoveDuplicateNodes; +} + +void QgsGeometryFixes::setRemoveDuplicateNodes( bool value ) +{ + mRemoveDuplicateNodes = value; +} + +double QgsGeometryFixes::geometryPrecision() const +{ + return mGeometryPrecision; +} + +void QgsGeometryFixes::setGeometryPrecision( double value ) +{ + mGeometryPrecision = value; +} + +bool QgsGeometryFixes::isActive() const +{ + return mGeometryPrecision != 0.0 || mRemoveDuplicateNodes; +} + +void QgsGeometryFixes::apply( QgsGeometry &geometry ) const +{ + if ( mGeometryPrecision != 0.0 ) + geometry = geometry.snappedToGrid( mGeometryPrecision, mGeometryPrecision ); + + if ( mRemoveDuplicateNodes ) + geometry.removeDuplicateNodes(); +} diff --git a/src/core/qgsgeometryfixes.h b/src/core/qgsgeometryfixes.h new file mode 100644 index 000000000000..0fd1806a1e59 --- /dev/null +++ b/src/core/qgsgeometryfixes.h @@ -0,0 +1,96 @@ +/*************************************************************************** + qgsgeometryfixes.h + ------------------- + begin : Aug 23, 2018 + copyright : (C) 2018 by Matthias Kuhn + email : matthias@opengis.ch + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSGEOMETRYFIXES_H +#define QGSGEOMETRYFIXES_H + +#include "qgsgeometry.h" + +/** + * The QgsGeometryFixes class contains options to + */ +class CORE_EXPORT QgsGeometryFixes +{ + public: + QgsGeometryFixes() = default; + + /** + * Automatically remove duplicate nodes on all geometries which are edited on this layer. + * + * \since QGIS 3.4 + */ + bool removeDuplicateNodes() const; + + /** + * Automatically remove duplicate nodes on all geometries which are edited on this layer. + * + * \since QGIS 3.4 + */ + void setRemoveDuplicateNodes( bool value ); + + /** + * The precision in which geometries on this layer should be saved. + * Geometries which are edited on this layer will be rounded to multiples of this value (snap to grid). + * Set to 0.0 to disable. + * + * \since QGIS 3.4 + */ + double geometryPrecision() const; + + /** + * The precision in which geometries on this layer should be saved. + * Geometries which are edited on this layer will be rounded to multiples of this value (snap to grid). + * Set to 0.0 to disable. + * + * \since QGIS 3.4 + */ + void setGeometryPrecision( double value ); + + /** + * Determines if at least one fix is enabled. + * + * \since QGIS 3.4 + */ + bool isActive() const; + + /** + * Apply any fixes configured on this class to \a geometry. + * + * \since QGIS 3.4 + */ + void apply( QgsGeometry &geometry ) const; + + private: + + /** + * Automatically remove duplicate nodes on all geometries which are edited on this layer. + * + * \since QGIS 3.4 + */ + bool mRemoveDuplicateNodes = false; + + /** + * The precision in which geometries on this layer should be saved. + * Geometries which are edited on this layer will be rounded to multiples of this value (snap to grid). + * Set to 0.0 to disable. + * + * \since QGIS 3.4 + */ + double mGeometryPrecision = 0.0; +}; + +#endif // QGSGEOMETRYFIXES_H diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 9e30c0ebce09..ed4104e9df8a 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -95,6 +95,7 @@ #include "qgstaskmanager.h" #include "qgstransaction.h" #include "qgsauxiliarystorage.h" +#include "qgsgeometryfixes.h" #include "diagram/qgsdiagram.h" @@ -149,6 +150,7 @@ QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath, , mAuxiliaryLayerKey( QString() ) , mReadExtentFromXml( options.readExtentFromXml ) { + mGeometryFixes = qgis::make_unique(); mActions = new QgsActionManager( this ); mConditionalStyles = new QgsConditionalLayerStyles(); @@ -757,20 +759,6 @@ void QgsVectorLayer::setExtent( const QgsRectangle &r ) mValidExtent = true; } -void QgsVectorLayer::applyGeometryFixes( QgsGeometry &geom ) const -{ - if ( mGeometryOptions.geometryPrecision != 0.0 ) - geom = geom.snappedToGrid( mGeometryOptions.geometryPrecision, mGeometryOptions.geometryPrecision ); - - if ( mGeometryOptions.removeDuplicateNodes ) - geom.removeDuplicateNodes(); -} - -bool QgsVectorLayer::geometryFixesEnabled() const -{ - return mGeometryOptions.geometryPrecision != 0.0 || mGeometryOptions.removeDuplicateNodes; -} - void QgsVectorLayer::updateDefaultValues( QgsFeatureId fid, QgsFeature feature ) { if ( !mDefaultValueOnUpdateFields.isEmpty() ) @@ -959,10 +947,10 @@ bool QgsVectorLayer::addFeature( QgsFeature &feature, Flags ) return false; - if ( geometryFixesEnabled() ) + if ( mGeometryFixes->isActive() ) { QgsGeometry geom = feature.geometry(); - applyGeometryFixes( geom ); + mGeometryFixes->apply( geom ); feature.setGeometry( geom ); } @@ -2064,8 +2052,8 @@ bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMes } QDomElement geometryOptionsElement = layerNode.namedItem( QStringLiteral( "geometryOptions" ) ).toElement(); - mGeometryOptions.geometryPrecision = geometryOptionsElement.attribute( QStringLiteral( "geometryPrecision" ), QStringLiteral( "0.0" ) ).toDouble(); - mGeometryOptions.removeDuplicateNodes = geometryOptionsElement.attribute( QStringLiteral( "removeDuplicateNodes" ), QStringLiteral( "0" ) ).toInt() == 1; + mGeometryFixes->setGeometryPrecision( geometryOptionsElement.attribute( QStringLiteral( "geometryPrecision" ), QStringLiteral( "0.0" ) ).toDouble() ); + mGeometryFixes->setRemoveDuplicateNodes( geometryOptionsElement.attribute( QStringLiteral( "removeDuplicateNodes" ), QStringLiteral( "0" ) ).toInt() == 1 ); mEditFormConfig.readXml( layerNode, context ); @@ -2264,8 +2252,8 @@ bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString QDomElement geometryOptionsElement = doc.createElement( QStringLiteral( "geometryOptions" ) ); node.appendChild( geometryOptionsElement ); - geometryOptionsElement.setAttribute( QStringLiteral( "removeDuplicateNodes" ), mGeometryOptions.removeDuplicateNodes ? 1 : 0 ); - geometryOptionsElement.setAttribute( QStringLiteral( "geometryPrecision" ), mGeometryOptions.geometryPrecision ); + geometryOptionsElement.setAttribute( QStringLiteral( "removeDuplicateNodes" ), mGeometryFixes->removeDuplicateNodes() ? 1 : 0 ); + geometryOptionsElement.setAttribute( QStringLiteral( "geometryPrecision" ), mGeometryFixes->geometryPrecision() ); int index = 0; Q_FOREACH ( const QgsField &field, mFields ) @@ -2526,8 +2514,8 @@ bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool s return false; } - if ( geometryFixesEnabled() ) - applyGeometryFixes( geom ); + if ( mGeometryFixes->isActive() ) + mGeometryFixes->apply( geom ); updateExtents(); @@ -2997,12 +2985,12 @@ bool QgsVectorLayer::addFeatures( QgsFeatureList &features, Flags ) if ( !mEditBuffer || !mDataProvider ) return false; - if ( geometryFixesEnabled() ) + if ( mGeometryFixes->isActive() ) { for ( auto feature = features.begin(); feature != features.end(); ++feature ) { QgsGeometry geom = feature->geometry(); - applyGeometryFixes( geom ); + mGeometryFixes->apply( geom ); feature->setGeometry( geom ); } } @@ -4791,24 +4779,9 @@ QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties return labeling; } -double QgsVectorLayer::geometryPrecision() const -{ - return mGeometryOptions.geometryPrecision; -} - -void QgsVectorLayer::setGeometryPrecision( double geometryPrecision ) -{ - mGeometryOptions.geometryPrecision = geometryPrecision; -} - -bool QgsVectorLayer::removeDuplicateNodes() const -{ - return mGeometryOptions.removeDuplicateNodes; -} - -void QgsVectorLayer::setRemoveDuplicateNodes( bool removeDuplicateNodes ) +QgsGeometryFixes *QgsVectorLayer::geometryFixes() const { - mGeometryOptions.removeDuplicateNodes = removeDuplicateNodes; + return mGeometryFixes.get(); } void QgsVectorLayer::setReadExtentFromXml( bool readExtentFromXml ) diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index a211f0b1830d..d246bb7e00bf 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -72,6 +72,7 @@ class QgsPoint; class QgsFeedback; class QgsAuxiliaryStorage; class QgsAuxiliaryLayer; +class QgsGeometryFixes; typedef QList QgsAttributeList; typedef QSet QgsAttributeIds; @@ -408,32 +409,6 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte }; - struct GeometryOptions - { - explicit GeometryOptions( bool removeDuplicateNodes = false, double geometryPrecision = 0.0 ) - : removeDuplicateNodes( removeDuplicateNodes ) - , geometryPrecision( geometryPrecision ) - { - } - - - /** - * Automatically remove duplicate nodes on all geometries which are edited on this layer. - * - * \since QGIS 3.4 - */ - bool removeDuplicateNodes = false; - - /** - * The precision in which geometries on this layer should be saved. - * Geometries which are edited on this layer will be rounded to multiples of this value (snap to grid). - * Set to 0.0 to disable. - * - * \since QGIS 3.4 - */ - double geometryPrecision = 0.0; - }; - /** * Constructor - creates a vector layer * @@ -2019,41 +1994,11 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte bool isEditCommandActive() const { return mEditCommandActive; } /** - * If the `removeDuplicateNodes` property is set on a layer, whenever a new feature enters - * the edit buffer or the geometry of an existing feature is changed, duplicate nodes will - * automatically be removed without any user intervention. - * - * \since QGIS 3.4 - */ - bool removeDuplicateNodes() const; - - /** - * If the `removeDuplicateNodes` property is set on a layer, whenever a new feature enters - * the edit buffer or the geometry of an existing feature is changed, duplicate nodes will - * automatically be removed without any user intervention. + * Configuration and logic to apply automatically on any edit happening on this layer. * * \since QGIS 3.4 */ - void setRemoveDuplicateNodes( bool removeDuplicateNodes ); - - - /** - * The `geometryPrecision` property of a layer will enable an automatic snap to grid operation - * on a layer whenever a new feature is added or the geometry of an existing feature is changed. - * If it is set to 0.0, this feature is disabled. - * - * \since QGIS 3.4 - */ - double geometryPrecision() const; - - /** - * The `geometryPrecision` property of a layer will enable an automatic snap to grid - * on a layer whenever a new feature is added or the geometry of an existing feature is changed. - * If it is set to 0.0, this feature is disabled. - * - * \since QGIS 3.4 - */ - void setGeometryPrecision( double geometryPrecision ); + QgsGeometryFixes *geometryFixes() const; public slots: @@ -2386,18 +2331,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte //! Sets the extent void setExtent( const QgsRectangle &rect ) override; - private: // Private methods - - /** - * Applies automatic fixes to geometries added to or edited on this layer. - */ - void applyGeometryFixes( QgsGeometry &geom ) const; - - /** - * Check if geometry fixes are enabled and `applyGeometryFixes` needs to be called. - */ - bool geometryFixesEnabled() const; - + private: void updateDefaultValues( QgsFeatureId fid, QgsFeature feature = QgsFeature() ); /** @@ -2556,7 +2490,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte QgsVectorLayerFeatureCounter *mFeatureCounter = nullptr; - GeometryOptions mGeometryOptions; + std::unique_ptr mGeometryFixes; friend class QgsVectorLayerFeatureSource; };