Skip to content
Permalink
Browse files
Manual backport of #42383
  • Loading branch information
uclaros authored and nyalldawson committed May 20, 2021
1 parent 602df12 commit 1ada1becab33a5ce7b0a98ca7aeba3d778326866
Showing with 101 additions and 72 deletions.
  1. +44 −54 src/app/qgsmaptoolrotatefeature.cpp
  2. +12 −8 src/app/qgsmaptoolrotatefeature.h
  3. +45 −10 tests/src/app/testqgsmaptoolrotatefeature.cpp
@@ -22,6 +22,7 @@
#include <limits>
#include <cmath>

#include "qgsadvanceddigitizingdockwidget.h"
#include "qgsmaptoolrotatefeature.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"


@@ -57,7 +59,7 @@ QgsAngleMagnetWidget::QgsAngleMagnetWidget( const QString &label, QWidget *paren
mAngleSpinBox->setSuffix( tr( "°" ) );
mAngleSpinBox->setSingleStep( 1 );
mAngleSpinBox->setValue( 0 );
mAngleSpinBox->setShowClearButton( false );
mAngleSpinBox->setClearValue( 0 );
mAngleSpinBox->setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred );
mLayout->addWidget( mAngleSpinBox );

@@ -136,27 +138,33 @@ void QgsAngleMagnetWidget::angleSpinBoxValueChanged( double angle )
}

QgsMapToolRotateFeature::QgsMapToolRotateFeature( QgsMapCanvas *canvas )
: QgsMapToolEdit( canvas )
: QgsMapToolAdvancedDigitizing( canvas, QgisApp::instance()->cadDockWidget() )
, mSnapIndicator( qgis::make_unique< QgsSnapIndicator>( canvas ) )
, mRotation( 0 )
, mRotationOffset( 0 )
, mRotationActive( false )
{
mToolName = tr( "Rotate feature" );
}

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

void QgsMapToolRotateFeature::canvasMoveEvent( QgsMapMouseEvent *e )
void QgsMapToolRotateFeature::cadCanvasMoveEvent( QgsMapMouseEvent *e )
{
mSnapIndicator->setMatch( e->mapPointMatch() );

if ( mRotationActive )
{
const double XDistance = e->pos().x() - mStPoint.x();
const double YDistance = e->pos().y() - mStPoint.y();
double rotation = std::atan2( YDistance, XDistance ) * ( 180 / M_PI ) - mRotationOffset;
const QgsPointXY pt = e->mapPoint();
const double XDistance = pt.x() - mStartPointMapCoords.x();
const double YDistance = pt.y() - mStartPointMapCoords.y();
double rotation = std::atan2( XDistance, YDistance ) * ( 180 / M_PI ) - mRotationOffset;

if ( mRotationWidget )
{
@@ -174,8 +182,7 @@ void QgsMapToolRotateFeature::canvasMoveEvent( QgsMapMouseEvent *e )
}
}


void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
void QgsMapToolRotateFeature::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
{
if ( !mCanvas )
{
@@ -188,6 +195,8 @@ void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
deleteRotationWidget();
deleteRubberband();
notifyNotVectorLayer();
mSnapIndicator->setMatch( QgsPointLocator::Match() );
mCadDockWidget->clear();
return;
}

@@ -205,9 +214,10 @@ void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
mAnchorPoint = qgis::make_unique<QgsVertexMarker>( mCanvas );
mAnchorPoint->setIconType( QgsVertexMarker::ICON_CROSS );
}
mAnchorPoint->setCenter( toMapCoordinates( e->pos() ) );
mStartPointMapCoords = toMapCoordinates( e->pos() );
mAnchorPoint->setCenter( e->mapPoint() );
mStartPointMapCoords = e->mapPoint();
mStPoint = e->pos();
cadDockWidget()->clear();
return;
}

@@ -221,15 +231,15 @@ void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )

deleteRubberband();

mInitialPos = e->pos();
mInitialPos = e->mapPoint();

if ( !vlayer->isEditable() )
{
notifyNotEditableLayer();
return;
}

QgsPointXY layerCoords = toLayerCoordinates( vlayer, e->pos() );
QgsPointXY layerCoords = toLayerCoordinates( vlayer, e->mapPoint() );
double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() );
QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );
@@ -311,9 +321,9 @@ void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )

mRubberBand->show();

double XDistance = mInitialPos.x() - mAnchorPoint->x();
double YDistance = mInitialPos.y() - mAnchorPoint->y();
mRotationOffset = std::atan2( YDistance, XDistance ) * ( 180 / M_PI );
double XDistance = mInitialPos.x() - mAnchorPoint->center().x();
double YDistance = mInitialPos.y() - mAnchorPoint->center().y();
mRotationOffset = std::atan2( XDistance, YDistance ) * ( 180 / M_PI );

createRotationWidget();
if ( e->modifiers() & Qt::ShiftModifier )
@@ -342,6 +352,8 @@ void QgsMapToolRotateFeature::cancel()
mAnchorPoint.reset();
}
mRotationActive = false;
mSnapIndicator->setMatch( QgsPointLocator::Match() );
mCadDockWidget->clear();
}

void QgsMapToolRotateFeature::updateRubberband( double rotation )
@@ -373,54 +385,31 @@ void QgsMapToolRotateFeature::applyRotation( double rotation )
{
deleteRubberband();
notifyNotVectorLayer();
mSnapIndicator->setMatch( QgsPointLocator::Match() );
mCadDockWidget->clear();
return;
}

//calculations for affine transformation
double angle = -1 * mRotation * ( M_PI / 180 );
QgsPointXY anchorPoint = toLayerCoordinates( vlayer, mStartPointMapCoords );
double a = std::cos( angle );
double b = -1 * std::sin( angle );
double c = anchorPoint.x() - std::cos( angle ) * anchorPoint.x() + std::sin( angle ) * anchorPoint.y();
double d = std::sin( angle );
double ee = std::cos( angle );
double f = anchorPoint.y() - std::sin( angle ) * anchorPoint.x() - std::cos( angle ) * anchorPoint.y();

vlayer->beginEditCommand( tr( "Features Rotated" ) );

int start;
if ( vlayer->geometryType() == 2 )
{
start = 1;
}
else
{
start = 0;
}

int i = 0;
const auto constMRotatedFeatures = mRotatedFeatures;
for ( QgsFeatureId id : constMRotatedFeatures )
QgsFeatureRequest request;
request.setFilterFids( mRotatedFeatures ).setNoAttributes();
QgsFeatureIterator fi = vlayer->getFeatures( request );
QgsFeature f;
while ( fi.nextFeature( f ) )
{
QgsFeature feat;
vlayer->getFeatures( QgsFeatureRequest().setFilterFid( id ) ).nextFeature( feat );
QgsGeometry geom = feat.geometry();
i = start;

QgsPointXY vertex = geom.vertexAt( i );
while ( !vertex.isEmpty() )
{
double newX = a * vertex.x() + b * vertex.y() + c;
double newY = d * vertex.x() + ee * vertex.y() + f;

vlayer->moveVertex( newX, newY, id, i );
i = i + 1;
vertex = geom.vertexAt( i );
}
QgsFeatureId id = f.id();
QgsGeometry geom = f.geometry();
geom.rotate( mRotation, anchorPoint );
vlayer->changeGeometry( id, geom );
}

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

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

void QgsMapToolRotateFeature::activate()
@@ -463,7 +452,7 @@ void QgsMapToolRotateFeature::activate()

mStPoint = toCanvasCoordinates( mStartPointMapCoords );
}
QgsMapTool::activate();
QgsMapToolAdvancedDigitizing::activate();
}

void QgsMapToolRotateFeature::deleteRubberband()
@@ -479,7 +468,8 @@ void QgsMapToolRotateFeature::deactivate()
mRotationOffset = 0;
mAnchorPoint.reset();
deleteRubberband();
QgsMapTool::deactivate();
mSnapIndicator->setMatch( QgsPointLocator::Match() );
QgsMapToolAdvancedDigitizing::deactivate();
}

void QgsMapToolRotateFeature::createRotationWidget()
@@ -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 QgsAngleMagnetWidget : public QWidget
{
@@ -65,16 +66,16 @@ class APP_EXPORT QgsAngleMagnetWidget : public QWidget


//! Map tool to rotate features
class APP_EXPORT QgsMapToolRotateFeature: public QgsMapToolEdit
class APP_EXPORT QgsMapToolRotateFeature: public QgsMapToolAdvancedDigitizing
{
Q_OBJECT
public:
QgsMapToolRotateFeature( QgsMapCanvas *canvas );
~QgsMapToolRotateFeature() 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;
@@ -98,14 +99,17 @@ class APP_EXPORT QgsMapToolRotateFeature: public QgsMapToolEdit
void createRotationWidget();
void deleteRotationWidget();

//! Start point of the move in map coordinates
//! Start point of the rotation in map coordinates
QgsPointXY mStartPointMapCoords;
QPointF mInitialPos;
QgsPointXY mInitialPos;

//! Rubberband that shows the feature being moved
//! Rubberband that shows the feature being rotated
QgsRubberBand *mRubberBand = nullptr;

//! Id of moved feature
//! Snapping indicators
std::unique_ptr<QgsSnapIndicator> mSnapIndicator;

//! Id of rotated feature
QgsFeatureIds mRotatedFeatures;
double mRotation;
double mRotationOffset;

0 comments on commit 1ada1be

Please sign in to comment.