Merge pull request #7959 from m-kuhn/geometryOptions

Add a new QML category "Geometry Options"
This commit is contained in:
Matthias Kuhn 2018-09-19 15:52:38 +02:00 committed by GitHub
commit 3cb82a58c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 124 additions and 71 deletions

View File

@ -1,7 +1,7 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsgeometryfixes.h *
* src/core/qgsgeometryoptions.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
@ -9,24 +9,24 @@
class QgsGeometryFixes
class QgsGeometryOptions
{
%Docstring
The QgsGeometryFixes class contains options to automatically adjust geometries to
The QgsGeometryOptions class contains options to automatically adjust geometries to
constraints on a layer.
.. versionadded:: 3.4
%End
%TypeHeaderCode
#include "qgsgeometryfixes.h"
#include "qgsgeometryoptions.h"
%End
public:
QgsGeometryFixes();
QgsGeometryOptions();
%Docstring
Create a new QgsGeometryFixes object.
Create a new QgsGeometryOptions object.
%End
bool removeDuplicateNodes() const;
@ -72,6 +72,20 @@ Determines if at least one fix is enabled.
%Docstring
Apply any fixes configured on this class to ``geometry``.
.. versionadded:: 3.4
%End
void writeXml( QDomNode &node ) const;
%Docstring
Write the geometry options to the ``node``.
.. versionadded:: 3.4
%End
void readXml( const QDomNode &node );
%Docstring
Read the geometry options from ``node``.
.. versionadded:: 3.4
%End
@ -80,7 +94,7 @@ Apply any fixes configured on this class to ``geometry``.
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsgeometryfixes.h *
* src/core/qgsgeometryoptions.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -89,6 +89,7 @@ This is the base class for all map layer types (vector, raster).
AttributeTable,
Rendering,
CustomProperties,
GeometryOptions,
AllStyleCategories
};
typedef QFlags<QgsMapLayer::StyleCategory> StyleCategories;

View File

@ -2230,7 +2230,7 @@ Test if an edit command is active
.. versionadded:: 3.0
%End
QgsGeometryFixes *geometryFixes() const;
QgsGeometryOptions *geometryOptions() const;
%Docstring
Configuration and logic to apply automatically on any edit happening on this layer.

View File

@ -54,7 +54,7 @@
%Include auto_generated/qgsfields.sip
%Include auto_generated/qgsfileutils.sip
%Include auto_generated/qgsfontutils.sip
%Include auto_generated/qgsgeometryfixes.sip
%Include auto_generated/qgsgeometryoptions.sip
%Include auto_generated/qgsgeometrysimplifier.sip
%Include auto_generated/qgshistogram.sip
%Include auto_generated/qgshstoreutils.sip

View File

@ -208,6 +208,17 @@ QVariant QgsMapLayerStyleCategoriesModel::data( const QModelIndex &index, int ro
return QgsApplication::getThemeIcon( QStringLiteral( "/mActionOptions.svg" ) );
}
break;
case QgsMapLayer::GeometryOptions:
switch ( role )
{
case Qt::DisplayRole:
return tr( "Geometry Options" );
case Qt::ToolTipRole:
return tr( "Geometry constraints and validity checks" );
case Qt::DecorationRole:
return QgsApplication::getThemeIcon( QStringLiteral( "/propertyicons/digitizing.svg" ) );
}
break;
case QgsMapLayer::AllStyleCategories:
switch ( role )
{

View File

@ -60,7 +60,7 @@
#include "qgsnewauxiliaryfielddialog.h"
#include "qgslabelinggui.h"
#include "qgssymbollayer.h"
#include "qgsgeometryfixes.h"
#include "qgsgeometryoptions.h"
#include "qgsvectorlayersavestyledialog.h"
#include "qgsvectorlayerloadstyledialog.h"
@ -401,8 +401,8 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
mRemoveDuplicateNodesCheckbox->setEnabled( true );
mGeometryPrecisionSpinBox->setEnabled( true );
mRemoveDuplicateNodesCheckbox->setChecked( mLayer->geometryFixes()->removeDuplicateNodes() );
mGeometryPrecisionSpinBox->setValue( mLayer->geometryFixes()->geometryPrecision() );
mRemoveDuplicateNodesCheckbox->setChecked( mLayer->geometryOptions()->removeDuplicateNodes() );
mGeometryPrecisionSpinBox->setValue( mLayer->geometryOptions()->geometryPrecision() );
mGeometryPrecisionSpinBox->setSuffix( QStringLiteral( " [%1]" ).arg( QgsUnitTypes::toAbbreviatedString( mLayer->crs().mapUnits() ) ) );
}
@ -751,8 +751,8 @@ void QgsVectorLayerProperties::apply()
mVector3DWidget->apply();
#endif
mLayer->geometryFixes()->setRemoveDuplicateNodes( mRemoveDuplicateNodesCheckbox->isChecked() );
mLayer->geometryFixes()->setGeometryPrecision( mGeometryPrecisionSpinBox->value() );
mLayer->geometryOptions()->setRemoveDuplicateNodes( mRemoveDuplicateNodesCheckbox->isChecked() );
mLayer->geometryOptions()->setGeometryPrecision( mGeometryPrecisionSpinBox->value() );
// update symbology
emit refreshLegend( mLayer->id() );

View File

@ -204,7 +204,7 @@ SET(QGIS_CORE_SRCS
qgsfontutils.cpp
qgsgeometrysimplifier.cpp
qgsgeometryvalidator.cpp
qgsgeometryfixes.cpp
qgsgeometryoptions.cpp
qgsgml.cpp
qgsgmlschema.cpp
qgshistogram.cpp
@ -867,7 +867,7 @@ SET(QGIS_CORE_HDRS
qgsfields.h
qgsfileutils.h
qgsfontutils.h
qgsgeometryfixes.h
qgsgeometryoptions.h
qgsgeometrysimplifier.h
qgshistogram.h
qgshstoreutils.h

View File

@ -1,5 +1,5 @@
/***************************************************************************
qgsgeometryfixes.cpp
qgsgeometryoptions.cpp
-------------------
begin : Aug 23, 2018
copyright : (C) 2018 by Matthias Kuhn
@ -15,34 +15,36 @@
* *
***************************************************************************/
#include "qgsgeometryfixes.h"
#include "qgsgeometryoptions.h"
bool QgsGeometryFixes::removeDuplicateNodes() const
#include "qgsxmlutils.h"
bool QgsGeometryOptions::removeDuplicateNodes() const
{
return mRemoveDuplicateNodes;
}
void QgsGeometryFixes::setRemoveDuplicateNodes( bool value )
void QgsGeometryOptions::setRemoveDuplicateNodes( bool value )
{
mRemoveDuplicateNodes = value;
}
double QgsGeometryFixes::geometryPrecision() const
double QgsGeometryOptions::geometryPrecision() const
{
return mGeometryPrecision;
}
void QgsGeometryFixes::setGeometryPrecision( double value )
void QgsGeometryOptions::setGeometryPrecision( double value )
{
mGeometryPrecision = value;
}
bool QgsGeometryFixes::isActive() const
bool QgsGeometryOptions::isActive() const
{
return mGeometryPrecision != 0.0 || mRemoveDuplicateNodes;
}
void QgsGeometryFixes::apply( QgsGeometry &geometry ) const
void QgsGeometryOptions::apply( QgsGeometry &geometry ) const
{
if ( mGeometryPrecision != 0.0 )
geometry = geometry.snappedToGrid( mGeometryPrecision, mGeometryPrecision );
@ -50,3 +52,19 @@ void QgsGeometryFixes::apply( QgsGeometry &geometry ) const
if ( mRemoveDuplicateNodes )
geometry.removeDuplicateNodes();
}
void QgsGeometryOptions::writeXml( QDomNode &node ) const
{
QDomElement geometryOptionsElement = node.ownerDocument().createElement( QStringLiteral( "geometryOptions" ) );
node.appendChild( geometryOptionsElement );
geometryOptionsElement.setAttribute( QStringLiteral( "removeDuplicateNodes" ), mRemoveDuplicateNodes ? 1 : 0 );
geometryOptionsElement.setAttribute( QStringLiteral( "geometryPrecision" ), mGeometryPrecision );
}
void QgsGeometryOptions::readXml( const QDomNode &node )
{
QDomElement geometryOptionsElement = node.toElement();
setGeometryPrecision( geometryOptionsElement.attribute( QStringLiteral( "geometryPrecision" ), QStringLiteral( "0.0" ) ).toDouble() );
setRemoveDuplicateNodes( geometryOptionsElement.attribute( QStringLiteral( "removeDuplicateNodes" ), QStringLiteral( "0" ) ).toInt() == 1 );
}

View File

@ -1,5 +1,5 @@
/***************************************************************************
qgsgeometryfixes.h
qgsgeometryoptions.h
-------------------
begin : Aug 23, 2018
copyright : (C) 2018 by Matthias Kuhn
@ -15,27 +15,29 @@
* *
***************************************************************************/
#ifndef QGSGEOMETRYFIXES_H
#define QGSGEOMETRYFIXES_H
#ifndef QGSGEOMETRYOPTIONS_H
#define QGSGEOMETRYOPTIONS_H
#include "qgis_core.h"
#include "qgis_sip.h"
#include "qgsgeometry.h"
/**
* \ingroup core
*
* The QgsGeometryFixes class contains options to automatically adjust geometries to
* The QgsGeometryOptions class contains options to automatically adjust geometries to
* constraints on a layer.
*
* \since QGIS 3.4
*/
class CORE_EXPORT QgsGeometryFixes
class CORE_EXPORT QgsGeometryOptions
{
public:
/**
* Create a new QgsGeometryFixes object.
* Create a new QgsGeometryOptions object.
*/
QgsGeometryFixes() = default;
QgsGeometryOptions() = default;
/**
* Automatically remove duplicate nodes on all geometries which are edited on this layer.
@ -83,6 +85,20 @@ class CORE_EXPORT QgsGeometryFixes
*/
void apply( QgsGeometry &geometry ) const;
/**
* Write the geometry options to the \a node.
*
* \since QGIS 3.4
*/
void writeXml( QDomNode &node ) const;
/**
* Read the geometry options from \a node.
*
* \since QGIS 3.4
*/
void readXml( const QDomNode &node );
private:
/**
@ -102,4 +118,4 @@ class CORE_EXPORT QgsGeometryFixes
double mGeometryPrecision = 0.0;
};
#endif // QGSGEOMETRYFIXES_H
#endif // QGSGEOMETRYOPTIONS_H

View File

@ -153,8 +153,9 @@ class CORE_EXPORT QgsMapLayer : public QObject
AttributeTable = 1 << 9, //!< Attribute table settings: choice and order of columns, conditional styling
Rendering = 1 << 10, //!< Rendering: scale visibility, simplify method, opacity
CustomProperties = 1 << 11, //!< Custom properties (by plugins for instance)
GeometryOptions = 1 << 12, //!< Geometry validation configuration
AllStyleCategories = LayerConfiguration | Symbology | Symbology3D | Labeling | Fields | Forms | Actions |
MapTips | Diagrams | AttributeTable | Rendering | CustomProperties,
MapTips | Diagrams | AttributeTable | Rendering | CustomProperties | GeometryOptions,
};
Q_ENUM( StyleCategory )
Q_DECLARE_FLAGS( StyleCategories, StyleCategory )

View File

@ -95,7 +95,7 @@
#include "qgstaskmanager.h"
#include "qgstransaction.h"
#include "qgsauxiliarystorage.h"
#include "qgsgeometryfixes.h"
#include "qgsgeometryoptions.h"
#include "diagram/qgsdiagram.h"
@ -150,7 +150,7 @@ QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
, mAuxiliaryLayerKey( QString() )
, mReadExtentFromXml( options.readExtentFromXml )
{
mGeometryFixes = qgis::make_unique<QgsGeometryFixes>();
mGeometryOptions = qgis::make_unique<QgsGeometryOptions>();
mActions = new QgsActionManager( this );
mConditionalStyles = new QgsConditionalLayerStyles();
@ -947,10 +947,10 @@ bool QgsVectorLayer::addFeature( QgsFeature &feature, Flags )
return false;
if ( mGeometryFixes->isActive() )
if ( mGeometryOptions->isActive() )
{
QgsGeometry geom = feature.geometry();
mGeometryFixes->apply( geom );
mGeometryOptions->apply( geom );
feature.setGeometry( geom );
}
@ -2064,12 +2064,9 @@ bool QgsVectorLayer::readSymbology( const QDomNode &layerNode, QString &errorMes
}
}
if ( categories.testFlag( LayerConfiguration ) )
{
QDomElement geometryOptionsElement = layerNode.namedItem( QStringLiteral( "geometryOptions" ) ).toElement();
mGeometryFixes->setGeometryPrecision( geometryOptionsElement.attribute( QStringLiteral( "geometryPrecision" ), QStringLiteral( "0.0" ) ).toDouble() );
mGeometryFixes->setRemoveDuplicateNodes( geometryOptionsElement.attribute( QStringLiteral( "removeDuplicateNodes" ), QStringLiteral( "0" ) ).toInt() == 1 );
}
if ( categories.testFlag( GeometryOptions ) )
mGeometryOptions->readXml( layerNode.namedItem( QStringLiteral( "geometryOptions" ) ) );
if ( categories.testFlag( Forms ) )
mEditFormConfig.readXml( layerNode, context );
@ -2286,13 +2283,8 @@ bool QgsVectorLayer::writeSymbology( QDomNode &node, QDomDocument &doc, QString
( void )writeStyle( node, doc, errorMessage, context, categories );
if ( categories.testFlag( LayerConfiguration ) )
{
QDomElement geometryOptionsElement = doc.createElement( QStringLiteral( "geometryOptions" ) );
node.appendChild( geometryOptionsElement );
geometryOptionsElement.setAttribute( QStringLiteral( "removeDuplicateNodes" ), mGeometryFixes->removeDuplicateNodes() ? 1 : 0 );
geometryOptionsElement.setAttribute( QStringLiteral( "geometryPrecision" ), mGeometryFixes->geometryPrecision() );
}
if ( categories.testFlag( GeometryOptions ) )
mGeometryOptions->writeXml( node );
if ( categories.testFlag( Fields ) )
{
@ -2593,8 +2585,8 @@ bool QgsVectorLayer::changeGeometry( QgsFeatureId fid, QgsGeometry &geom, bool s
return false;
}
if ( mGeometryFixes->isActive() )
mGeometryFixes->apply( geom );
if ( mGeometryOptions->isActive() )
mGeometryOptions->apply( geom );
updateExtents();
@ -3058,12 +3050,12 @@ bool QgsVectorLayer::addFeatures( QgsFeatureList &features, Flags )
if ( !mEditBuffer || !mDataProvider )
return false;
if ( mGeometryFixes->isActive() )
if ( mGeometryOptions->isActive() )
{
for ( auto feature = features.begin(); feature != features.end(); ++feature )
{
QgsGeometry geom = feature->geometry();
mGeometryFixes->apply( geom );
mGeometryOptions->apply( geom );
feature->setGeometry( geom );
}
}
@ -4849,9 +4841,9 @@ QgsAbstractVectorLayerLabeling *QgsVectorLayer::readLabelingFromCustomProperties
return labeling;
}
QgsGeometryFixes *QgsVectorLayer::geometryFixes() const
QgsGeometryOptions *QgsVectorLayer::geometryOptions() const
{
return mGeometryFixes.get();
return mGeometryOptions.get();
}
void QgsVectorLayer::setReadExtentFromXml( bool readExtentFromXml )

View File

@ -71,7 +71,7 @@ class QgsPoint;
class QgsFeedback;
class QgsAuxiliaryStorage;
class QgsAuxiliaryLayer;
class QgsGeometryFixes;
class QgsGeometryOptions;
typedef QList<int> QgsAttributeList;
typedef QSet<int> QgsAttributeIds;
@ -2007,7 +2007,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*
* \since QGIS 3.4
*/
QgsGeometryFixes *geometryFixes() const;
QgsGeometryOptions *geometryOptions() const;
public slots:
@ -2499,7 +2499,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
QgsVectorLayerFeatureCounter *mFeatureCounter = nullptr;
std::unique_ptr<QgsGeometryFixes> mGeometryFixes;
std::unique_ptr<QgsGeometryOptions> mGeometryOptions;
friend class QgsVectorLayerFeatureSource;
};

View File

@ -18,7 +18,7 @@
#include "qgsmapcanvas.h"
#include "qgsadvanceddigitizingdockwidget.h"
#include "qgsvectorlayer.h"
#include "qgsgeometryfixes.h"
#include "qgsgeometryoptions.h"
#include "qgssnaptogridcanvasitem.h"
QgsMapToolAdvancedDigitizing::QgsMapToolAdvancedDigitizing( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
@ -45,7 +45,7 @@ void QgsMapToolAdvancedDigitizing::canvasPressEvent( QgsMapMouseEvent *e )
QgsVectorLayer *layer = currentVectorLayer();
if ( mSnapToLayerGridEnabled && layer )
{
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
e->snapToGrid( layer->geometryOptions()->geometryPrecision(), layer->crs() );
}
cadCanvasPressEvent( e );
@ -85,7 +85,7 @@ void QgsMapToolAdvancedDigitizing::canvasReleaseEvent( QgsMapMouseEvent *e )
QgsVectorLayer *layer = currentVectorLayer();
if ( mSnapToGridCanvasItem && mSnapToLayerGridEnabled && layer )
{
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
e->snapToGrid( layer->geometryOptions()->geometryPrecision(), layer->crs() );
}
cadCanvasReleaseEvent( e );
@ -110,7 +110,7 @@ void QgsMapToolAdvancedDigitizing::canvasMoveEvent( QgsMapMouseEvent *e )
QgsVectorLayer *layer = currentVectorLayer();
if ( mSnapToGridCanvasItem && mSnapToLayerGridEnabled && layer )
{
e->snapToGrid( layer->geometryFixes()->geometryPrecision(), layer->crs() );
e->snapToGrid( layer->geometryOptions()->geometryPrecision(), layer->crs() );
mSnapToGridCanvasItem->setPoint( e->mapPoint() );
}
@ -127,7 +127,7 @@ void QgsMapToolAdvancedDigitizing::activate()
if ( layer )
{
mSnapToGridCanvasItem->setCrs( currentVectorLayer()->crs() );
mSnapToGridCanvasItem->setPrecision( currentVectorLayer()->geometryFixes()->geometryPrecision() );
mSnapToGridCanvasItem->setPrecision( currentVectorLayer()->geometryOptions()->geometryPrecision() );
}
mSnapToGridCanvasItem->setEnabled( mSnapToLayerGridEnabled );
}
@ -155,7 +155,7 @@ void QgsMapToolAdvancedDigitizing::onCurrentLayerChanged()
QgsVectorLayer *layer = currentVectorLayer();
if ( layer && mSnapToLayerGridEnabled )
{
mSnapToGridCanvasItem->setPrecision( layer->geometryFixes()->geometryPrecision() );
mSnapToGridCanvasItem->setPrecision( layer->geometryOptions()->geometryPrecision() );
mSnapToGridCanvasItem->setCrs( layer->crs() );
}

View File

@ -2776,36 +2776,36 @@ class TestQgsVectorLayer(unittest.TestCase, FeatureSourceTestCase):
def testPrecision(self):
layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int", "vl", "memory")
layer.geometryFixes().setGeometryPrecision(10)
layer.geometryOptions().setGeometryPrecision(10)
geom = QgsGeometry.fromWkt('Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))')
feature = QgsFeature(layer.fields())
feature.setGeometry(geom)
layer.startEditing()
layer.addFeature(feature)
self.assertGeometriesEqual(QgsGeometry.fromWkt('Polygon ((2596410 1224650, 2596400 1224650, 2596410 1224640, 2596410 1224650))'), feature.geometry(), 'geometry with unsnapped nodes', 'fixed geometry')
layer.geometryFixes().setGeometryPrecision(0.0)
layer.geometryOptions().setGeometryPrecision(0.0)
feature.setGeometry(QgsGeometry.fromWkt('Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))'))
layer.addFeature(feature)
self.assertGeometriesEqual(QgsGeometry.fromWkt('Polygon ((2596411 1224654, 2596400 1224652, 2596405 1224640, 2596410 1224641, 2596411 1224654))'), feature.geometry(), 'geometry with duplicates', 'unchanged geometry')
def testRemoveDuplicateNodes(self):
layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int", "vl", "memory")
layer.geometryFixes().setRemoveDuplicateNodes(True)
layer.geometryOptions().setRemoveDuplicateNodes(True)
geom = QgsGeometry.fromWkt('Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))')
feature = QgsFeature(layer.fields())
feature.setGeometry(geom)
layer.startEditing()
layer.addFeature(feature)
self.assertGeometriesEqual(feature.geometry(), QgsGeometry.fromWkt('Polygon ((70 80, 80 90, 60 50, 70 80))'), 'fixed geometry', 'geometry with duplicates')
layer.geometryFixes().setRemoveDuplicateNodes(False)
layer.geometryOptions().setRemoveDuplicateNodes(False)
feature.setGeometry(QgsGeometry.fromWkt('Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))'))
layer.addFeature(feature)
self.assertGeometriesEqual(feature.geometry(), QgsGeometry.fromWkt('Polygon ((70 80, 80 90, 80 90, 60 50, 70 80))'), 'unchanged geometry', 'geometry with duplicates')
def testPrecisionAndDuplicateNodes(self):
layer = QgsVectorLayer("Polygon?crs=epsg:2056&field=pk:int", "vl", "memory")
layer.geometryFixes().setGeometryPrecision(10)
layer.geometryFixes().setRemoveDuplicateNodes(True)
layer.geometryOptions().setGeometryPrecision(10)
layer.geometryOptions().setRemoveDuplicateNodes(True)
geom = QgsGeometry.fromWkt('Polygon ((2596411 1224654, 2596400 1224652, 2596402 1224653, 2596405 1224640, 2596410 1224641, 2596411 1224654))')
feature = QgsFeature(layer.fields())
feature.setGeometry(geom)