Skip to content
Permalink
Browse files

[feature][selfsnap] add snapping to currently digitized feature for c…

…apture tool
  • Loading branch information
olivierdalang committed May 21, 2020
1 parent d48c178 commit 66ebe3400458bf34f4bcafbe87b1ab5caa5cd85d
@@ -700,6 +700,7 @@
<file>themes/default/mIconSnappingMiddle.svg</file>
<file>themes/default/mIconSnappingOnScale.svg</file>
<file>themes/default/mIconSnappingVertex.svg</file>
<file>themes/default/mIconSnappingSelf.svg</file>
<file>themes/default/mIconSnappingSegment.svg</file>
<file>themes/default/mIconTopologicalEditing.svg</file>
<file>themes/default/mIconSnappingIntersection.svg</file>
@@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="mIconSnappingSelf.svg"
id="svg68"
version="1.1"
width="24"
viewBox="0 0 24 24"
height="24">
<metadata
id="metadata74">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs72" />
<sodipodi:namedview
inkscape:current-layer="svg68"
inkscape:window-maximized="0"
inkscape:window-y="120"
inkscape:window-x="351"
inkscape:cy="15.032678"
inkscape:cx="21.715662"
inkscape:zoom="14.849242"
showgrid="false"
id="namedview70"
inkscape:window-height="1163"
inkscape:window-width="1445"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<g
id="g66"
transform="translate(0.04085775,-7.9316355)"
stroke-linecap="round">
<path
sodipodi:nodetypes="cccc"
id="path60"
stroke-width="2"
stroke-linejoin="round"
stroke="#8cbe8c"
fill="none"
d="M 20.566062,23.218131 4.4877133,14.977485 9.0817013,27.060272 2,30" />
<ellipse
id="ellipse62"
stroke-width="2"
stroke="#ffffff"
ry="2.5"
rx="0.75"
fill="#322825"
cy="14"
cx="-14.75" />
<circle
id="circle64"
stroke-width="1.031"
stroke="#8c8c8c"
r="2.034729"
fill="#bebebe"
cy="26.858242"
cx="8.6102972" />
<circle
cx="4.4877133"
cy="15.179515"
fill="#bebebe"
r="2.034729"
stroke="#8c8c8c"
stroke-width="1.031"
id="circle64-5" />
</g>
<g
transform="matrix(1.2651778,0,0,1.2651778,-4.6265242,-0.70591315)"
id="g1921">
<path
sodipodi:nodetypes="cccc"
id="path1853"
stroke-width="0.35534"
stroke-linecap="round"
stroke="#505050"
overflow="visible"
fill="#505050"
d="m 19.461512,9.2175166 -2.259422,1.3635194 2.663548,1.925751 z" />
<path
id="path1855"
stroke-width="0.35534"
stroke-linecap="round"
stroke="#8b7617"
overflow="visible"
fill="#fce94f"
d="M 15.362026,1.9819405 12.900159,3.4032995 16.927342,10.37859 19.38921,8.9572295 15.362026,1.9819405" />
<path
id="path1861"
style="overflow:visible;opacity:0.5;fill:#fce94f;stroke:#8b7617;stroke-width:0.35534;stroke-linecap:round"
d="m 13.957675,3.3398245 3.79029,6.564978" />
<path
id="path1863"
stroke-width="0.236893"
stroke-linecap="square"
stroke="#969696"
overflow="visible"
fill="#969696"
d="M 19.369733,12.033342 17.379211,10.47792 18.198585,10.004853 Z" />
<path
id="path1865"
style="overflow:visible;opacity:0.5;fill:#fce94f;stroke:#8b7617;stroke-width:0.35534;stroke-linecap:round"
d="m 14.983453,2.7475915 3.790289,6.564978" />
<path
id="path1867"
stroke-width="0.236893"
stroke-linecap="round"
stroke="#969696"
overflow="visible"
fill="#e6e6e6"
d="m 15.192412,1.4694895 -2.651241,1.530695 0.516222,0.894122 2.65124,-1.530695 z" />
<path
id="path1869"
stroke-width="0.236893"
stroke-linecap="square"
stroke="#e6e6e6"
overflow="visible"
fill="#e6e6e6"
d="M 19.70856,11.92433 19.319283,9.3578195 18.499909,9.8308845 Z" />
</g>
</svg>
@@ -53,6 +53,8 @@ The QgsCadUtils class provides routines for CAD editing.

QgsPointXY finalMapPoint;

QgsPointLocator::Match snapMatch;

QgsPointLocator::Match edgeMatch;

double softLockCommonAngle;
@@ -343,6 +343,20 @@ Returns if the snapping on intersection is enabled
void setIntersectionSnapping( bool enabled );
%Docstring
Sets if the snapping on intersection is enabled
%End

bool selfSnapping() const;
%Docstring
Returns if self snapping (snapping to the currently digitised feature) is enabled

.. versionadded:: 3.14
%End

void setSelfSnapping( bool enabled );
%Docstring
Sets if self snapping (snapping to the currently digitised feature) is enabled

.. versionadded:: 3.14
%End

SIP_PYDICT individualLayerSettings() const;
@@ -166,6 +166,42 @@ Set if invisible features must be snapped or not.
.. versionadded:: 3.2
%End

void addExtraSnapLayer( QgsVectorLayer *vl );
%Docstring
Supply an extra snapping layer (typically a memory layer).
This is can be used by map tools to provide additionnal
snappings points.

.. seealso:: :py:func:`removeExtraSnapLayer`

.. seealso:: :py:func:`getExtraSnapLayers`

.. versionadded:: 3.14
%End

void removeExtraSnapLayer( QgsVectorLayer *vl );
%Docstring
Removes an extra snapping layer

.. seealso:: :py:func:`addExtraSnapLayer`

.. seealso:: :py:func:`getExtraSnapLayers`

.. versionadded:: 3.14
%End

QSet<QgsVectorLayer *> getExtraSnapLayers();
%Docstring
Returns the list of extra snapping layers

.. seealso:: :py:func:`addExtraSnapLayer`

.. seealso:: :py:func:`removeExtraSnapLayer`

.. versionadded:: 3.14
%End


public slots:

void setConfig( const QgsSnappingConfig &snappingConfig );
@@ -287,6 +287,14 @@ QgsSnappingWidget::QgsSnappingWidget( QgsProject *project, QgsMapCanvas *canvas,
tracingMenu->addAction( widgetAction );
mEnableTracingAction->setMenu( tracingMenu );

// self-snapping button
mSelfSnappingAction = new QAction( tr( "Self-snapping" ), this );
mSelfSnappingAction->setCheckable( true );
mSelfSnappingAction->setIcon( QIcon( QgsApplication::getThemeIcon( "/mIconSnappingSelf.svg" ) ) );
mSelfSnappingAction->setToolTip( tr( "Enable Self-snapping" ) );
mSelfSnappingAction->setObjectName( QStringLiteral( "SelfSnappingAction" ) );
connect( mSelfSnappingAction, &QAction::toggled, this, &QgsSnappingWidget::enableSelfSnapping );

// layout
if ( mDisplayMode == ToolBar )
{
@@ -316,6 +324,7 @@ QgsSnappingWidget::QgsSnappingWidget( QgsProject *project, QgsMapCanvas *canvas,
mAvoidIntersectionsModeAction = tb->addWidget( mAvoidIntersectionsModeButton );
tb->addAction( mIntersectionSnappingAction );
tb->addAction( mEnableTracingAction );
tb->addAction( mSelfSnappingAction );
}
else
{
@@ -350,6 +359,12 @@ QgsSnappingWidget::QgsSnappingWidget( QgsProject *project, QgsMapCanvas *canvas,
interButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
layout->addWidget( interButton );

QToolButton *selfsnapButton = new QToolButton();
selfsnapButton->addAction( mSelfSnappingAction );
selfsnapButton->setDefaultAction( mSelfSnappingAction );
selfsnapButton->setToolButtonStyle( Qt::ToolButtonTextBesideIcon );
layout->addWidget( selfsnapButton );

layout->setContentsMargins( 0, 0, 0, 0 );
layout->setAlignment( Qt::AlignRight );
layout->setSpacing( mDisplayMode == Widget ? 3 : 0 );
@@ -488,6 +503,11 @@ void QgsSnappingWidget::projectSnapSettingsChanged()
mIntersectionSnappingAction->setChecked( config.intersectionSnapping() );
}

if ( config.selfSnapping() != mSelfSnappingAction->isChecked() )
{
mSelfSnappingAction->setChecked( config.selfSnapping() );
}

toggleSnappingWidgets( config.enabled() );

}
@@ -552,6 +572,7 @@ void QgsSnappingWidget::toggleSnappingWidgets( bool enabled )
mAdvancedConfigWidget->setEnabled( enabled );
}
mIntersectionSnappingAction->setEnabled( enabled );
mSelfSnappingAction->setEnabled( enabled );
mEnableTracingAction->setEnabled( enabled );
}

@@ -593,6 +614,12 @@ void QgsSnappingWidget::enableIntersectionSnapping( bool enabled )
mProject->setSnappingConfig( mConfig );
}

void QgsSnappingWidget::enableSelfSnapping( bool enabled )
{
mConfig.setSelfSnapping( enabled );
mProject->setSnappingConfig( mConfig );
}

void QgsSnappingWidget::onSnappingTreeLayersChanged()
{
mLayerTreeView->expandAll();
@@ -114,6 +114,8 @@ class APP_EXPORT QgsSnappingWidget : public QWidget

void enableIntersectionSnapping( bool enabled );

void enableSelfSnapping( bool enabled );

void modeButtonTriggered( QAction *action );
void avoidIntersectionsModeButtonTriggered( QAction *action );
void typeButtonTriggered( QAction *action );
@@ -172,6 +174,7 @@ class APP_EXPORT QgsSnappingWidget : public QWidget
QAction *mIntersectionSnappingAction = nullptr;
QAction *mEnableTracingAction = nullptr;
QgsDoubleSpinBox *mTracingOffsetSpinBox = nullptr;
QAction *mSelfSnappingAction = nullptr;
QTreeView *mLayerTreeView = nullptr;
QWidget *mAdvancedConfigWidget = nullptr;
QgsFloatingWidget *mAdvancedConfigContainer = nullptr;
@@ -179,6 +179,7 @@ bool QgsSnappingConfig::operator==( const QgsSnappingConfig &other ) const
&& mTolerance == other.mTolerance
&& mUnits == other.mUnits
&& mIntersectionSnapping == other.mIntersectionSnapping
&& mSelfSnapping == other.mSelfSnapping
&& mIndividualLayerSettings == other.mIndividualLayerSettings
&& mScaleDependencyMode == other.mScaleDependencyMode
&& mMinimumScale == other.mMinimumScale
@@ -218,6 +219,7 @@ void QgsSnappingConfig::reset()
mUnits = units;
}
mIntersectionSnapping = false;
mSelfSnapping = false;

// set advanced config
if ( mProject )
@@ -343,6 +345,16 @@ void QgsSnappingConfig::setIntersectionSnapping( bool enabled )
mIntersectionSnapping = enabled;
}

bool QgsSnappingConfig::selfSnapping() const
{
return mSelfSnapping;
}

void QgsSnappingConfig::setSelfSnapping( bool enabled )
{
mSelfSnapping = enabled;
}

QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings> QgsSnappingConfig::individualLayerSettings() const
{
return mIndividualLayerSettings;
@@ -459,6 +471,9 @@ void QgsSnappingConfig::readProject( const QDomDocument &doc )
if ( snapSettingsElem.hasAttribute( QStringLiteral( "intersection-snapping" ) ) )
mIntersectionSnapping = snapSettingsElem.attribute( QStringLiteral( "intersection-snapping" ) ) == QLatin1String( "1" );

if ( snapSettingsElem.hasAttribute( QStringLiteral( "self-snapping" ) ) )
mSelfSnapping = snapSettingsElem.attribute( QStringLiteral( "self-snapping" ) ) == QLatin1String( "1" );

// do not clear the settings as they must be automatically synchronized with current layers
QDomNodeList nodes = snapSettingsElem.elementsByTagName( QStringLiteral( "individual-layer-settings" ) );
if ( nodes.count() )
@@ -504,6 +519,7 @@ void QgsSnappingConfig::writeProject( QDomDocument &doc )
snapSettingsElem.setAttribute( QStringLiteral( "tolerance" ), mTolerance );
snapSettingsElem.setAttribute( QStringLiteral( "unit" ), static_cast<int>( mUnits ) );
snapSettingsElem.setAttribute( QStringLiteral( "intersection-snapping" ), QString::number( mIntersectionSnapping ) );
snapSettingsElem.setAttribute( QStringLiteral( "self-snapping" ), QString::number( mSelfSnapping ) );
snapSettingsElem.setAttribute( QStringLiteral( "scaleDependencyMode" ), QString::number( mScaleDependencyMode ) );
snapSettingsElem.setAttribute( QStringLiteral( "minScale" ), mMinimumScale );
snapSettingsElem.setAttribute( QStringLiteral( "maxScale" ), mMaximumScale );
@@ -335,6 +335,20 @@ class CORE_EXPORT QgsSnappingConfig
//! Sets if the snapping on intersection is enabled
void setIntersectionSnapping( bool enabled );

/**
* Returns if self snapping (snapping to the currently digitised feature) is enabled
*
* \since QGIS 3.14
*/
bool selfSnapping() const;

/**
* Sets if self snapping (snapping to the currently digitised feature) is enabled
*
* \since QGIS 3.14
*/
void setSelfSnapping( bool enabled );

//! Returns individual snapping settings for all layers
#ifndef SIP_RUN
QHash<QgsVectorLayer *, QgsSnappingConfig::IndividualLayerSettings> individualLayerSettings() const;
@@ -458,6 +472,7 @@ class CORE_EXPORT QgsSnappingConfig
double mMaximumScale = 0.0;
QgsTolerance::UnitType mUnits = QgsTolerance::ProjectUnits;
bool mIntersectionSnapping = false;
bool mSelfSnapping = false;

QHash<QgsVectorLayer *, IndividualLayerSettings> mIndividualLayerSettings;

0 comments on commit 66ebe34

Please sign in to comment.
You can’t perform that action at this time.