Skip to content
Permalink
Browse files

Add snapping support to scale feature tool

  • Loading branch information
uclaros authored and github-actions committed Apr 27, 2021
1 parent eed3818 commit 889d7ece805b75c10b5b4d6a6fa11b30b26e1911
Showing with 66 additions and 13 deletions.
  1. +22 −6 src/app/qgsmaptoolscalefeature.cpp
  2. +11 −7 src/app/qgsmaptoolscalefeature.h
  3. +33 −0 tests/src/app/testqgsmaptoolscalefeature.cpp
@@ -22,6 +22,7 @@
#include <limits>
#include <cmath>

#include "qgsadvanceddigitizingdockwidget.h"
#include "qgsmaptoolscalefeature.h"
#include "qgsfeatureiterator.h"
#include "qgsgeometry.h"
@@ -33,6 +34,7 @@
#include "qgisapp.h"
#include "qgsspinbox.h"
#include "qgsdoublespinbox.h"
#include "qgssnapindicator.h"
#include "qgsmapmouseevent.h"


@@ -107,19 +109,23 @@ void QgsScaleMagnetWidget::scaleSpinBoxValueChanged( double scale )
//

QgsMapToolScaleFeature::QgsMapToolScaleFeature( QgsMapCanvas *canvas )
: QgsMapToolEdit( canvas )
: QgsMapToolAdvancedDigitizing( canvas, QgisApp::instance()->cadDockWidget() )
, mSnapIndicator( std::make_unique< QgsSnapIndicator>( canvas ) )
{
mToolName = tr( "Scale feature" );
}

QgsMapToolScaleFeature::~QgsMapToolScaleFeature()
{
deleteScalingWidget();
mAnchorPoint.reset();
deleteRubberband();
mSnapIndicator->setMatch( QgsPointLocator::Match() );
}

void QgsMapToolScaleFeature::canvasMoveEvent( QgsMapMouseEvent *e )
void QgsMapToolScaleFeature::cadCanvasMoveEvent( QgsMapMouseEvent *e )
{
mSnapIndicator->setMatch( e->mapPointMatch() );
if ( mBaseDistance == 0 )
{
return;
@@ -141,7 +147,7 @@ void QgsMapToolScaleFeature::canvasMoveEvent( QgsMapMouseEvent *e )
}
}

void QgsMapToolScaleFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
void QgsMapToolScaleFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
{
if ( !mCanvas )
{
@@ -154,6 +160,8 @@ void QgsMapToolScaleFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
deleteScalingWidget();
deleteRubberband();
notifyNotVectorLayer();
mSnapIndicator->setMatch( QgsPointLocator::Match() );
mCadDockWidget->clear();
return;
}

@@ -173,6 +181,7 @@ void QgsMapToolScaleFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
}
mAnchorPoint->setCenter( e->mapPoint() );
mFeatureCenterMapCoords = e->mapPoint();
cadDockWidget()->clear();
return;
}

@@ -298,6 +307,8 @@ void QgsMapToolScaleFeature::cancel()
mAnchorPoint.reset();
}
mScalingActive = false;
mSnapIndicator->setMatch( QgsPointLocator::Match() );
mCadDockWidget->clear();
}

void QgsMapToolScaleFeature::updateRubberband( double scale )
@@ -335,6 +346,8 @@ void QgsMapToolScaleFeature::applyScaling( double scale )
{
deleteRubberband();
notifyNotVectorLayer();
mSnapIndicator->setMatch( QgsPointLocator::Match() );
mCadDockWidget->clear();
return;
}

@@ -358,6 +371,8 @@ void QgsMapToolScaleFeature::applyScaling( double scale )

deleteScalingWidget();
deleteRubberband();
mSnapIndicator->setMatch( QgsPointLocator::Match() );
mCadDockWidget->clear();

if ( mAutoSetAnchorPoint )
mAnchorPoint.reset();
@@ -373,7 +388,7 @@ void QgsMapToolScaleFeature::keyReleaseEvent( QKeyEvent *e )
cancel();
return;
}
QgsMapTool::keyReleaseEvent( e );
QgsMapToolAdvancedDigitizing::keyReleaseEvent( e );
}

void QgsMapToolScaleFeature::activate()
@@ -398,7 +413,7 @@ void QgsMapToolScaleFeature::activate()
mAnchorPoint->setIconType( QgsVertexMarker::ICON_CROSS );
mAnchorPoint->setCenter( mFeatureCenterMapCoords );
}
QgsMapTool::activate();
QgsMapToolAdvancedDigitizing::activate();
}

void QgsMapToolScaleFeature::deleteRubberband()
@@ -415,7 +430,8 @@ void QgsMapToolScaleFeature::deactivate()
mScalingActive = false;
mAnchorPoint.reset();
deleteRubberband();
QgsMapTool::deactivate();
mSnapIndicator->setMatch( QgsPointLocator::Match() );
QgsMapToolAdvancedDigitizing::deactivate();
}

void QgsMapToolScaleFeature::createScalingWidget()
@@ -18,7 +18,7 @@

#include <QWidget>

#include "qgsmaptooledit.h"
#include "qgsmaptooladvanceddigitizing.h"
#include "qgsvertexmarker.h"
#include "qgis_app.h"
#include "qgsgeometry.h"
@@ -27,6 +27,7 @@
class QgsDoubleSpinBox;
class QHBoxLayout;
class QgsSpinBox;
class QgsSnapIndicator;

class APP_EXPORT QgsScaleMagnetWidget : public QWidget
{
@@ -62,16 +63,16 @@ class APP_EXPORT QgsScaleMagnetWidget : public QWidget


//! Map tool to scale features
class APP_EXPORT QgsMapToolScaleFeature: public QgsMapToolEdit
class APP_EXPORT QgsMapToolScaleFeature: public QgsMapToolAdvancedDigitizing
{
Q_OBJECT
public:
QgsMapToolScaleFeature( QgsMapCanvas *canvas );
~QgsMapToolScaleFeature() override;

void canvasMoveEvent( QgsMapMouseEvent *e ) override;
void cadCanvasMoveEvent( QgsMapMouseEvent *e ) override;

void canvasReleaseEvent( QgsMapMouseEvent *e ) override;
void cadCanvasReleaseEvent( QgsMapMouseEvent *e ) override;

//! called when map tool is being deactivated
void deactivate() override;
@@ -95,15 +96,18 @@ class APP_EXPORT QgsMapToolScaleFeature: public QgsMapToolEdit
void createScalingWidget();
void deleteScalingWidget();

//! Start point of the move in map coordinates
//! Start point of the scaling in map coordinates
QgsPointXY mFeatureCenterMapCoords;
//! Rubberband that shows the feature being moved
//! Rubberband that shows the feature being scaled
QgsRubberBand *mRubberBand = nullptr;

//! Id of moved feature
//! Id of scaled feature
QgsFeatureIds mScaledFeatures;
QVector< QgsGeometry > mOriginalGeometries;

//! Snapping indicators
std::unique_ptr<QgsSnapIndicator> mSnapIndicator;

double mScaling = 0;
double mBaseDistance = 1;
QgsRectangle mExtent;
@@ -48,6 +48,7 @@ class TestQgsMapToolScaleFeature: public QObject
void testCancelManualAnchor();
void testScaleFeatureWithAnchorSetAfterStart();
void testScaleSelectedFeatures();
void testScaleFeatureManualAnchorSnapping();

private:
QgisApp *mQgisApp = nullptr;
@@ -113,6 +114,7 @@ void TestQgsMapToolScaleFeature::initTestCase()

mCanvas->setLayers( QList<QgsMapLayer *>() << mLayerBase );
mCanvas->setCurrentLayer( mLayerBase );
mCanvas->snappingUtils()->locatorForLayer( mLayerBase )->init();

// create the tool
mScaleTool = new QgsMapToolScaleFeature( mCanvas );
@@ -229,6 +231,37 @@ void TestQgsMapToolScaleFeature::testScaleSelectedFeatures()
mLayerBase->undoStack()->undo();
}

void TestQgsMapToolScaleFeature::testScaleFeatureManualAnchorSnapping()
{
TestQgsMapToolUtils utils( mScaleTool );

QgsSnappingConfig cfg = mCanvas->snappingUtils()->config();
const double tolerance = cfg.tolerance();
const QgsTolerance::UnitType units = cfg.units();
cfg.setTolerance( 0.5 );
cfg.setUnits( QgsTolerance::LayerUnits );
mCanvas->snappingUtils()->setConfig( cfg );

//set manual anchor point, should snap to (-2, -2)
utils.mouseClick( -1.9, -1.9, Qt::LeftButton, Qt::ControlModifier, true );

// resize, source point should snap to (-1, -1)
utils.mouseMove( -0.9, -0.9 );
utils.mouseClick( -0.9, -0.9, Qt::LeftButton, Qt::KeyboardModifiers(), true );
// target point should snap to (1.1, 0.8)
utils.mouseMove( 1.2, 0.9 );
utils.mouseClick( 1.2, 0.9, Qt::LeftButton, Qt::KeyboardModifiers(), true );

QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-2 -2, -2 0.95, 0.95 0.95, 0.95 -2, -2 -2))" ) );
QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0.8, 1.1 5, 2.1 5, 2.1 0.8, 1.1 0.8))" ) );

mLayerBase->undoStack()->undo();

// restore tolerance setting
cfg.setTolerance( tolerance );
cfg.setUnits( units );
mCanvas->snappingUtils()->setConfig( cfg );
}

QGSTEST_MAIN( TestQgsMapToolScaleFeature )
#include "testqgsmaptoolscalefeature.moc"

0 comments on commit 889d7ec

Please sign in to comment.