Merge pull request #57584 from nirvn/cad_construction_guides

[advanced digitizing] Implement visual construction guides
This commit is contained in:
Mathieu Pellerin 2024-06-25 15:35:01 +07:00 committed by GitHub
commit 2fb1de2ce1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 388 additions and 17 deletions

View File

@ -132,7 +132,6 @@ Returns the recent CAD point at the specified ``index`` (in map coordinates).
.. versionadded:: 3.22
%End
%Property( name = cadPointList, get = _cadPointList, set = _setCadPointList )
void _setCadPointList( const QList< QgsPointXY > &list );
QList< QgsPointXY > _cadPointList() const;

View File

@ -277,7 +277,36 @@ Sets whether M is enabled
bool constructionMode() const;
%Docstring
construction mode is used to draw intermediate points. These points won't be given any further (i.e. to the map tools)
Returns whether the construction mode is activated. The construction mode is used to draw intermediate
points that will not be part of a geometry being digitized.
%End
QgsVectorLayer *constructionGuidesLayer() const;
%Docstring
Returns the vector layer within which construction guides are stored.
.. versionadded:: 3.40
%End
bool showConstructionGuides() const;
%Docstring
Returns whether the construction guides are visible.
.. versionadded:: 3.40
%End
bool snapToConstructionGuides() const;
%Docstring
Returns whether points should snap to construction guides.
.. versionadded:: 3.40
%End
bool recordConstructionGuides() const;
%Docstring
Returns whether construction guides are being recorded.
.. versionadded:: 3.40
%End
Qgis::BetweenLineConstraint betweenLineConstraint() const;

View File

@ -132,7 +132,6 @@ Returns the recent CAD point at the specified ``index`` (in map coordinates).
.. versionadded:: 3.22
%End
%Property( name = cadPointList, get = _cadPointList, set = _setCadPointList )
void _setCadPointList( const QList< QgsPointXY > &list );
QList< QgsPointXY > _cadPointList() const;

View File

@ -277,7 +277,36 @@ Sets whether M is enabled
bool constructionMode() const;
%Docstring
construction mode is used to draw intermediate points. These points won't be given any further (i.e. to the map tools)
Returns whether the construction mode is activated. The construction mode is used to draw intermediate
points that will not be part of a geometry being digitized.
%End
QgsVectorLayer *constructionGuidesLayer() const;
%Docstring
Returns the vector layer within which construction guides are stored.
.. versionadded:: 3.40
%End
bool showConstructionGuides() const;
%Docstring
Returns whether the construction guides are visible.
.. versionadded:: 3.40
%End
bool snapToConstructionGuides() const;
%Docstring
Returns whether points should snap to construction guides.
.. versionadded:: 3.40
%End
bool recordConstructionGuides() const;
%Docstring
Returns whether construction guides are being recorded.
.. versionadded:: 3.40
%End
Qgis::BetweenLineConstraint betweenLineConstraint() const;

View File

@ -48,8 +48,8 @@ QgsCadUtils::AlignMapPointOutput QgsCadUtils::alignMapPoint( const QgsPointXY &o
res.softLockX = std::numeric_limits<double>::quiet_NaN();
res.softLockY = std::numeric_limits<double>::quiet_NaN();
// try to snap to anything
const QgsPointLocator::Match snapMatch = ctx.snappingUtils->snapToMap( originalMapPoint, nullptr, true );
// try to snap to project layer(s) as well as visible construction guides
QgsPointLocator::Match snapMatch = ctx.snappingUtils->snapToMap( originalMapPoint, nullptr, true );
res.snapMatch = snapMatch;
QgsPointXY point = snapMatch.isValid() ? snapMatch.point() : originalMapPoint;
QgsPointXY edgePt0, edgePt1;

View File

@ -195,7 +195,6 @@ class CORE_EXPORT QgsCadUtils
*/
QQueue< QgsPointLocator::Match > lockedSnapVertices() const { return mLockedSnapVertices; } SIP_SKIP;
#ifdef SIP_RUN
SIP_PROPERTY( name = cadPointList, get = _cadPointList, set = _setCadPointList )
#endif

View File

@ -28,6 +28,7 @@ QgsAdvancedDigitizingCanvasItem::QgsAdvancedDigitizingCanvasItem( QgsMapCanvas *
, mSnapPen( QPen( QColor( 127, 0, 0, 150 ), 1 ) )
, mSnapLinePen( QPen( QColor( 127, 0, 0, 150 ), 1, Qt::DashLine ) )
, mCursorPen( QPen( QColor( 127, 127, 127, 255 ), 1 ) )
, mConstructionGuidesPen( QPen( QColor( 20, 210, 150 ), 1, Qt::DashLine ) )
, mAdvancedDigitizingDockWidget( cadDockWidget )
{
}
@ -37,6 +38,27 @@ void QgsAdvancedDigitizingCanvasItem::paint( QPainter *painter )
if ( !mAdvancedDigitizingDockWidget->cadEnabled() )
return;
painter->setRenderHint( QPainter::Antialiasing );
painter->setCompositionMode( QPainter::CompositionMode_Difference );
// Draw construction guides
if ( mAdvancedDigitizingDockWidget->showConstructionGuides() )
{
if ( QgsVectorLayer *constructionGuidesLayer = mAdvancedDigitizingDockWidget->constructionGuidesLayer() )
{
QgsFeatureIterator it = constructionGuidesLayer->getFeatures( QgsFeatureRequest().setNoAttributes().setFilterRect( mMapCanvas->mapSettings().visibleExtent() ) );
QgsFeature feature;
painter->setPen( mConstructionGuidesPen );
while ( it.nextFeature( feature ) )
{
QgsGeometry geom = feature.geometry();
geom.mapToPixel( *mMapCanvas->getCoordinateTransform() );
const QPolygonF polygon = geom.asQPolygonF();
painter->drawPolyline( polygon );
}
}
}
// Use visible polygon rather than extent to properly handle rotated maps
QPolygonF mapPoly = mMapCanvas->mapSettings().visiblePolygon();
const double canvasWidth = QLineF( mapPoly[0], mapPoly[1] ).length();
@ -83,9 +105,6 @@ void QgsAdvancedDigitizingCanvasItem::paint( QPainter *painter )
snapSegmentPix2 = toCanvasCoordinates( snappedSegment[1] );
}
painter->setRenderHint( QPainter::Antialiasing );
painter->setCompositionMode( QPainter::CompositionMode_Difference );
// Draw point snap
if ( curPointExist && snappedToVertex )
{
@ -226,7 +245,7 @@ void QgsAdvancedDigitizingCanvasItem::paint( QPainter *painter )
}
}
// Draw constr
// Draw constraints
if ( mAdvancedDigitizingDockWidget->betweenLineConstraint() == Qgis::BetweenLineConstraint::NoConstraint )
{
if ( curPointExist && previousPointExist )

View File

@ -60,6 +60,7 @@ class GUI_EXPORT QgsAdvancedDigitizingCanvasItem : public QgsMapCanvasItem
QPen mSnapPen;
QPen mSnapLinePen;
QPen mCursorPen;
QPen mConstructionGuidesPen;
QgsAdvancedDigitizingDockWidget *mAdvancedDigitizingDockWidget = nullptr;
};

View File

@ -43,6 +43,9 @@
const QgsSettingsEntryBool *QgsAdvancedDigitizingDockWidget::settingsCadSnappingPriorityPrioritizeFeature = new QgsSettingsEntryBool( QStringLiteral( "cad-snapping-prioritize-feature" ), QgsSettingsTree::sTreeDigitizing, false, tr( "Determines if snapping to features has priority over snapping to common angles." ) ) ;
const QgsSettingsEntryBool *QgsAdvancedDigitizingDockWidget::settingsCadRecordConstructionGuides = new QgsSettingsEntryBool( QStringLiteral( "cad-record-construction-guides" ), QgsSettingsTree::sTreeDigitizing, false, tr( "Determines if construction guides are being recorded." ) ) ;
const QgsSettingsEntryBool *QgsAdvancedDigitizingDockWidget::settingsCadShowConstructionGuides = new QgsSettingsEntryBool( QStringLiteral( "cad-show-construction-guides" ), QgsSettingsTree::sTreeDigitizing, true, tr( "Determines whether construction guides are shown." ) ) ;
const QgsSettingsEntryBool *QgsAdvancedDigitizingDockWidget::settingsCadSnapToConstructionGuides = new QgsSettingsEntryBool( QStringLiteral( "cad-snap-to-construction-guides" ), QgsSettingsTree::sTreeDigitizing, false, tr( "Determines if points will snap to construction guides." ) ) ;
QgsAdvancedDigitizingDockWidget::QgsAdvancedDigitizingDockWidget( QgsMapCanvas *canvas, QWidget *parent )
@ -194,6 +197,46 @@ QgsAdvancedDigitizingDockWidget::QgsAdvancedDigitizingDockWidget( QgsMapCanvas *
mCommonAngleActions.insert( it->first, action );
}
// Construction modes
QMenu *constructionSettingsMenu = new QMenu( this );
mRecordConstructionGuides = new QAction( tr( "Record Construction Guides" ), constructionSettingsMenu );
mRecordConstructionGuides->setCheckable( true );
mRecordConstructionGuides->setChecked( settingsCadRecordConstructionGuides->value() );
constructionSettingsMenu->addAction( mRecordConstructionGuides );
connect( mRecordConstructionGuides, &QAction::triggered, this, [ = ]() { settingsCadRecordConstructionGuides->setValue( mRecordConstructionGuides->isChecked() ); } );
mShowConstructionGuides = new QAction( tr( "Show Construction Guides" ), constructionSettingsMenu );
mShowConstructionGuides->setCheckable( true );
mShowConstructionGuides->setChecked( settingsCadShowConstructionGuides->value() );
constructionSettingsMenu->addAction( mShowConstructionGuides );
connect( mShowConstructionGuides, &QAction::triggered, this, [ = ]()
{
settingsCadShowConstructionGuides->setValue( mShowConstructionGuides->isChecked() );
updateCadPaintItem();
} );
mSnapToConstructionGuides = new QAction( tr( "Snap to Visible Construction Guides" ), constructionSettingsMenu );
mSnapToConstructionGuides->setCheckable( true );
mSnapToConstructionGuides->setChecked( settingsCadSnapToConstructionGuides->value() );
constructionSettingsMenu->addAction( mSnapToConstructionGuides );
connect( mSnapToConstructionGuides, &QAction::triggered, this, [ = ]() { settingsCadSnapToConstructionGuides->setValue( mSnapToConstructionGuides->isChecked() ); } );
constructionSettingsMenu->addSeparator();
mClearConstructionGuides = new QAction( tr( "Clear Construction Guides" ), constructionSettingsMenu );
constructionSettingsMenu->addAction( mClearConstructionGuides );
connect( mClearConstructionGuides, &QAction::triggered, this, [ = ]()
{
resetConstructionGuides();
updateCadPaintItem();
} );
QToolButton *constructionModeToolButton = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionModeAction ) );
constructionModeToolButton->setPopupMode( QToolButton::MenuButtonPopup );
constructionModeToolButton->setMenu( constructionSettingsMenu );
constructionModeToolButton->setObjectName( QStringLiteral( "ConstructionModeButton" ) );
qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
mSettingsAction->setMenu( mCommonAngleActionsMenu );
mSettingsAction->setCheckable( true );
@ -368,6 +411,12 @@ QgsAdvancedDigitizingDockWidget::QgsAdvancedDigitizingDockWidget( QgsMapCanvas *
updateCapacity( true );
connect( QgsProject::instance(), &QgsProject::snappingConfigChanged, this, [ = ] { updateCapacity( true ); } );
connect( QgsProject::instance(), &QgsProject::cleared, this, [ = ]()
{
mConstructionGuidesLayer.reset();
} );
connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, [ = ] { updateConstructionGuidesCrs(); } );
disable();
}
@ -672,6 +721,14 @@ void QgsAdvancedDigitizingDockWidget::setConstructionMode( bool enabled )
{
mConstructionMode = enabled;
mConstructionModeAction->setChecked( enabled );
if ( recordConstructionGuides() )
{
if ( enabled && mCadPointList.size() > 1 )
{
mConstructionGuideLine.addVertex( mCadPointList.at( 1 ) );
}
}
}
void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
@ -1195,6 +1252,11 @@ bool QgsAdvancedDigitizingDockWidget::applyConstraints( QgsMapMouseEvent *e )
context.setCadPoints( mCadPointList );
context.setLockedSnapVertices( mLockedSnapVertices );
if ( snapToConstructionGuides() )
{
context.snappingUtils->addExtraSnapLayer( mConstructionGuidesLayer.get() );
}
context.commonAngleConstraint.locked = !mMapCanvas->mapSettings().destinationCrs().isGeographic();
context.commonAngleConstraint.relative = context.angleConstraint.relative;
context.commonAngleConstraint.value = mCommonAngleConstraint;
@ -1254,6 +1316,7 @@ bool QgsAdvancedDigitizingDockWidget::applyConstraints( QgsMapMouseEvent *e )
* the point is not linked to a layer.
*/
e->setMapPoint( point );
mSnapMatch = context.snappingUtils->snapToMap( point, nullptr, true );
if ( mSnapMatch.layer() )
{
@ -1265,6 +1328,8 @@ bool QgsAdvancedDigitizingDockWidget::applyConstraints( QgsMapMouseEvent *e )
}
}
context.snappingUtils->removeExtraSnapLayer( mConstructionGuidesLayer.get() );
if ( mSnapMatch.hasVertex() || mSnapMatch.hasLineEndpoint() )
{
toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
@ -1501,6 +1566,11 @@ bool QgsAdvancedDigitizingDockWidget::canvasKeyPressEventFilter( QKeyEvent *e )
void QgsAdvancedDigitizingDockWidget::clear()
{
if ( !mConstructionGuideLine.isEmpty() )
{
mConstructionGuideLine.clear();
}
clearPoints();
releaseLocks();
}
@ -1524,6 +1594,13 @@ void QgsAdvancedDigitizingDockWidget::keyPressEvent( QKeyEvent *e )
case Qt::Key_Escape:
{
releaseLocks();
if ( mConstructionGuideLine.numPoints() >= 2 )
{
mConstructionGuidesLayer->dataProvider()->deleteFeatures( QgsFeatureIds() << mConstructionGuideId );
mConstructionGuideLine.clear();
}
break;
}
default:
@ -1575,6 +1652,22 @@ bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
const QEvent::Type type = e->type();
switch ( e->key() )
{
case Qt::Key_Escape:
{
if ( mConstructionMode && mConstructionGuideLine.numPoints() >= 2 )
{
mConstructionGuidesLayer->dataProvider()->deleteFeatures( QgsFeatureIds() << mConstructionGuideId );
mConstructionGuideLine.clear();
if ( mCadPointList.size() > 1 )
{
mConstructionGuideLine.addVertex( mCadPointList.at( 1 ) );
}
updateCadPaintItem();
}
break;
}
case Qt::Key_X:
{
// modifier+x ONLY caught for ShortcutOverride events...
@ -1856,7 +1949,20 @@ void QgsAdvancedDigitizingDockWidget::enable()
{
show();
}
setCadEnabled( mSessionActive );
if ( !mConstructionGuidesLayer )
{
resetConstructionGuides();
}
if ( mDeferredUpdateConstructionGuidesCrs )
{
updateConstructionGuidesCrs();
}
updateCadPaintItem();
}
void QgsAdvancedDigitizingDockWidget::disable()
@ -1903,6 +2009,39 @@ void QgsAdvancedDigitizingDockWidget::addPoint( const QgsPointXY &point )
mCadPointList.insert( 0, pt );
}
if ( recordConstructionGuides() )
{
if ( constructionMode() )
{
mConstructionGuideLine.addVertex( pt );
if ( mConstructionGuideLine.numPoints() == 2 )
{
QgsFeature feature;
QgsGeometry geom( mConstructionGuideLine.clone() );
feature.setGeometry( geom );
mConstructionGuidesLayer->dataProvider()->addFeature( feature );
mConstructionGuideId = feature.id();
}
else if ( mConstructionGuideLine.numPoints() > 2 )
{
QgsGeometry geom( mConstructionGuideLine.clone() );
mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
}
}
else
{
if ( !mConstructionGuideLine.isEmpty() )
{
mConstructionGuideLine.addVertex( pt );
QgsGeometry geom( mConstructionGuideLine.clone() );
mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
mConstructionGuideLine.clear();
}
}
}
updateCapacity();
updateCadPaintItem();
}
@ -2146,3 +2285,58 @@ double QgsAdvancedDigitizingDockWidget::getLineM( ) const
{
return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
}
bool QgsAdvancedDigitizingDockWidget::showConstructionGuides() const
{
return mShowConstructionGuides ? mShowConstructionGuides->isChecked() : false;
}
bool QgsAdvancedDigitizingDockWidget::snapToConstructionGuides() const
{
return mSnapToConstructionGuides ? mShowConstructionGuides->isChecked() && mSnapToConstructionGuides->isChecked() : false;
}
bool QgsAdvancedDigitizingDockWidget::recordConstructionGuides() const
{
return mRecordConstructionGuides ? mRecordConstructionGuides->isChecked() : false;
}
void QgsAdvancedDigitizingDockWidget::updateConstructionGuidesCrs()
{
if ( !mConstructionGuidesLayer )
{
return;
}
if ( !cadEnabled() )
{
mDeferredUpdateConstructionGuidesCrs = true;
}
QgsCoordinateTransform transform = QgsCoordinateTransform( mConstructionGuidesLayer->crs(), mMapCanvas->mapSettings().destinationCrs(), QgsProject::instance()->transformContext() );
mConstructionGuidesLayer->setCrs( mMapCanvas->mapSettings().destinationCrs() );
QgsFeatureIterator it = mConstructionGuidesLayer->getFeatures( QgsFeatureRequest().setNoAttributes() );
QgsFeature feature;
while ( it.nextFeature( feature ) )
{
QgsGeometry geom = feature.geometry();
geom.transform( transform );
mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { feature.id(), geom } } );
}
mDeferredUpdateConstructionGuidesCrs = false;
}
void QgsAdvancedDigitizingDockWidget::resetConstructionGuides()
{
if ( mConstructionGuidesLayer )
{
mConstructionGuidesLayer.reset();
}
const QgsVectorLayer::LayerOptions options( QgsProject::instance()->transformContext(), false, false );
mConstructionGuidesLayer = std::make_unique<QgsVectorLayer>( QStringLiteral( "LineString?crs=%1" ).arg( mMapCanvas->mapSettings().destinationCrs().authid() ),
QStringLiteral( "constructionGuides" ),
QStringLiteral( "memory" ),
options );
}

View File

@ -305,9 +305,36 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
*/
void setEnabledM( bool enable );
//! construction mode is used to draw intermediate points. These points won't be given any further (i.e. to the map tools)
/**
* Returns whether the construction mode is activated. The construction mode is used to draw intermediate
* points that will not be part of a geometry being digitized.
*/
bool constructionMode() const { return mConstructionMode; }
/**
* Returns the vector layer within which construction guides are stored.
* \since QGIS 3.40
*/
QgsVectorLayer *constructionGuidesLayer() const { return mConstructionGuidesLayer.get(); }
/**
* Returns whether the construction guides are visible.
* \since QGIS 3.40
*/
bool showConstructionGuides() const;
/**
* Returns whether points should snap to construction guides.
* \since QGIS 3.40
*/
bool snapToConstructionGuides() const;
/**
* Returns whether construction guides are being recorded.
* \since QGIS 3.40
*/
bool recordConstructionGuides() const;
/**
* Returns the between line constraints which are used to place
* perpendicular/parallel segments to snapped segments on the canvas
@ -1013,7 +1040,6 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
//! Updates values of constraints that are not locked based on the current point
void updateUnlockedConstraintValues( const QgsPoint &point );
/**
* Adds or removes the snap match if it is already in the locked snap queue or not.
* \param snapMatch the snap match to add or remove.
@ -1021,6 +1047,17 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
*/
void toggleLockedSnapVertex( const QgsPointLocator::Match &snapMatch, QgsPointLocator::Match previouslySnap );
/**
* Resets the vector layer and point locator objects handling construction guides.
*/
void resetConstructionGuides();
/**
* Updates the construction guides layer CRS to match the map canvas' destination CRS
* and reproject pre-existing construction guides.
*/
void updateConstructionGuidesCrs();
QgsMapCanvas *mMapCanvas = nullptr;
QgsAdvancedDigitizingCanvasItem *mCadPaintItem = nullptr;
//! Snapping indicator
@ -1053,19 +1090,29 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
//! Flag that controls whether snapping to features has priority over common angle
bool mSnappingPrioritizeFeatures = false;
// point list and current snap point / segment
// Point list and current snap point / segment
QList<QgsPoint> mCadPointList;
QList<QgsPointXY> mSnappedSegment;
bool mSessionActive = false;
// error message
// Construction path history
std::unique_ptr<QgsVectorLayer> mConstructionGuidesLayer;
QgsFeatureId mConstructionGuideId;
QgsLineString mConstructionGuideLine;
bool mDeferredUpdateConstructionGuidesCrs = false;
// Error message
std::unique_ptr<QgsMessageBarItem> mErrorMessage;
// UI
QMap< double, QAction *> mCommonAngleActions; // map the common angle actions with their angle values
QAction *mLineExtensionAction;
QAction *mXyVertexAction;
QAction *mLineExtensionAction = nullptr;
QAction *mXyVertexAction = nullptr;
QAction *mRecordConstructionGuides = nullptr;
QAction *mShowConstructionGuides = nullptr;
QAction *mSnapToConstructionGuides = nullptr;
QAction *mClearConstructionGuides = nullptr;
// Snap indicator
QgsPointLocator::Match mSnapMatch;
@ -1088,6 +1135,9 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
QMenu *mFloaterActionsMenu = nullptr;
static const QgsSettingsEntryBool *settingsCadSnappingPriorityPrioritizeFeature;
static const QgsSettingsEntryBool *settingsCadRecordConstructionGuides;
static const QgsSettingsEntryBool *settingsCadShowConstructionGuides;
static const QgsSettingsEntryBool *settingsCadSnapToConstructionGuides;
friend class TestQgsAdvancedDigitizing;
friend class TestQgsAdvancedDigitizingDockWidget;

View File

@ -60,6 +60,8 @@ class TestQgsAdvancedDigitizing: public QObject
void releaseLockAfterDisable();
void constructionGuides();
private:
TestQgsMapToolAdvancedDigitizingUtils getMapToolDigitizingUtils( QgsVectorLayer *layer );
QString getWktFromLastAddedFeature( TestQgsMapToolAdvancedDigitizingUtils utils, QSet<QgsFeatureId> oldFeatures );
@ -1163,5 +1165,55 @@ void TestQgsAdvancedDigitizing::releaseLockAfterDisable()
mAdvancedDigitizingDockWidget->enableAction()->trigger();
}
void TestQgsAdvancedDigitizing::constructionGuides()
{
auto utils = getMapToolDigitizingUtils( mLayer3950 );
QVERIFY( mAdvancedDigitizingDockWidget->cadEnabled() );
QCOMPARE( mAdvancedDigitizingDockWidget->constructionGuidesLayer()->featureCount(), 0 );
mAdvancedDigitizingDockWidget->mRecordConstructionGuides->setChecked( true );
mAdvancedDigitizingDockWidget->setConstructionMode( true );
// enter a few construction steps while guide recording is on
utils.mouseClick( 10, 10, Qt::LeftButton );
utils.mouseClick( 10, 11, Qt::LeftButton );
utils.mouseClick( 10, 12, Qt::LeftButton );
utils.mouseClick( 10, 13, Qt::LeftButton );
utils.mouseClick( 10, 14, Qt::LeftButton );
utils.mouseClick( 20, 01, Qt::RightButton );
QCOMPARE( mAdvancedDigitizingDockWidget->constructionGuidesLayer()->featureCount(), 1 );
mAdvancedDigitizingDockWidget->mRecordConstructionGuides->setChecked( false );
// enter a few construction steps while guide recording is off
utils.mouseClick( 10, 10, Qt::LeftButton );
utils.mouseClick( 10, 11, Qt::LeftButton );
utils.mouseClick( 10, 12, Qt::LeftButton );
utils.mouseClick( 10, 13, Qt::LeftButton );
utils.mouseClick( 10, 14, Qt::LeftButton );
utils.mouseClick( 20, 01, Qt::RightButton );
QCOMPARE( mAdvancedDigitizingDockWidget->constructionGuidesLayer()->featureCount(), 1 );
QgsSnappingConfig snapConfig = mCanvas->snappingUtils()->config();
snapConfig.setEnabled( true );
mCanvas->snappingUtils()->setConfig( snapConfig );
mAdvancedDigitizingDockWidget->mSnapToConstructionGuides->setChecked( true );
// snap on an existing constructio guide vertex
utils.mouseMove( 10.1, 10 );
QCOMPARE( mAdvancedDigitizingDockWidget->currentPointV2(), QgsPoint( 10, 10 ) );
mAdvancedDigitizingDockWidget->mSnapToConstructionGuides->setChecked( false );
// do not snap on an existing construction guide vertex
utils.mouseMove( 10.5, 14.5 );
QGSCOMPARENEARPOINT( mAdvancedDigitizingDockWidget->currentPointV2(), QgsPoint( 10.5, 14.5 ), 0.1 );
}
QGSTEST_MAIN( TestQgsAdvancedDigitizing )
#include "testqgsadvanceddigitizing.moc"