Skip to content

Commit

Permalink
Fix broken manual rotation anchor point setting via ctrl+click in rot…
Browse files Browse the repository at this point in the history
…ate features tool

Ctrl+clicking to set the manual rotation point had no effect, and the selected
rotation point was always reset as soon as the rotation action started.

Apparently this has been broken for some time (confirmed broken since 3.4 at least!).

Also add tests.
  • Loading branch information
nyalldawson committed Jan 8, 2021
1 parent 0d785c8 commit 378841e
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 9 deletions.
22 changes: 13 additions & 9 deletions src/app/qgsmaptoolrotatefeature.cpp
Expand Up @@ -202,7 +202,8 @@ void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
{
if ( !mAnchorPoint )
{
return;
mAnchorPoint = qgis::make_unique<QgsVertexMarker>( mCanvas );
mAnchorPoint->setIconType( QgsVertexMarker::ICON_CROSS );
}
mAnchorPoint->setCenter( toMapCoordinates( e->pos() ) );
mStartPointMapCoords = toMapCoordinates( e->pos() );
Expand Down Expand Up @@ -233,10 +234,12 @@ void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );

bool autoCalculateAnchorPoint = false;
if ( !mAnchorPoint )
{
mAnchorPoint = qgis::make_unique<QgsVertexMarker>( mCanvas );
mAnchorPoint->setIconType( QgsVertexMarker::ICON_CROSS );
autoCalculateAnchorPoint = true;
}

if ( vlayer->selectedFeatureCount() == 0 )
Expand Down Expand Up @@ -274,8 +277,15 @@ void QgsMapToolRotateFeature::canvasReleaseEvent( QgsMapMouseEvent *e )
}

QgsRectangle bound = cf.geometry().boundingBox();
mStartPointMapCoords = toMapCoordinates( vlayer, bound.center() );
mAnchorPoint->setCenter( mStartPointMapCoords );
if ( autoCalculateAnchorPoint )
{
mStartPointMapCoords = toMapCoordinates( vlayer, bound.center() );
mAnchorPoint->setCenter( mStartPointMapCoords );
}
else
{
mStartPointMapCoords = mAnchorPoint->center();
}

mStPoint = toCanvasCoordinates( mStartPointMapCoords );

Expand Down Expand Up @@ -407,14 +417,8 @@ void QgsMapToolRotateFeature::applyRotation( double rotation )
i = i + 1;
vertex = geom.vertexAt( i );
}

}

double anchorX = a * anchorPoint.x() + b * anchorPoint.y() + c;
double anchorY = d * anchorPoint.x() + ee * anchorPoint.y() + f;

mAnchorPoint->setCenter( QgsPointXY( anchorX, anchorY ) );

deleteRotationWidget();
deleteRubberband();

Expand Down
65 changes: 65 additions & 0 deletions tests/src/app/testqgsmaptoolrotatefeature.cpp
Expand Up @@ -44,6 +44,9 @@ class TestQgsMapToolRotateFeature: public QObject
void cleanupTestCase();// will be called after the last testfunction was executed.

void testRotateFeature();
void testRotateFeatureManualAnchor();
void testCancelManualAnchor();
void testRotateFeatureManualAnchorAfterStartRotate();

private:
QgisApp *mQgisApp = nullptr;
Expand Down Expand Up @@ -140,6 +143,68 @@ void TestQgsMapToolRotateFeature::testRotateFeature()
mLayerBase->undoStack()->undo();
}

void TestQgsMapToolRotateFeature::testRotateFeatureManualAnchor()
{
// test rotating around a fixed anchor point
TestQgsMapToolUtils utils( mRotateTool );

// set anchor point
utils.mouseClick( 0, 5, Qt::LeftButton, Qt::ControlModifier, true );

utils.mouseClick( 1, 1, Qt::LeftButton, Qt::KeyboardModifiers(), true );
utils.mouseMove( 2, 1 );
utils.mouseClick( 2, 1, Qt::LeftButton, Qt::KeyboardModifiers(), true );

QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((2.06 0.34, 0.87 1.1, 1.84 1.31, 2.06 0.34))" ) );
QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0, 1.1 5, 2.1 5, 2.1 0))" ) );

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

void TestQgsMapToolRotateFeature::testCancelManualAnchor()
{
// test canceling rotation around a fixed anchor point
TestQgsMapToolUtils utils( mRotateTool );

// set anchor point
utils.mouseClick( 0, 5, Qt::LeftButton, Qt::ControlModifier, true );

// right click = remove anchor point
utils.mouseClick( 10, 15, Qt::RightButton, Qt::KeyboardModifiers(), true );

// now rotate -- should be around feature center, not anchor point
utils.mouseClick( 1, 1, Qt::LeftButton, Qt::KeyboardModifiers(), true );
utils.mouseMove( 2, 1 );
utils.mouseClick( 2, 1, Qt::LeftButton, Qt::KeyboardModifiers(), true );

QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((0.72 -0.17, 0.28 1.17, 1.17 0.72, 0.72 -0.17))" ) );
QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0, 1.1 5, 2.1 5, 2.1 0))" ) );

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

void TestQgsMapToolRotateFeature::testRotateFeatureManualAnchorAfterStartRotate()
{
// test rotating around a fixed anchor point, where the fixed anchor point is placed after rotation begins
TestQgsMapToolUtils utils( mRotateTool );

// start rotation
utils.mouseClick( 1, 1, Qt::LeftButton, Qt::KeyboardModifiers(), true );

// set anchor point
utils.mouseMove( 0, 5 );
utils.mouseClick( 0, 5, Qt::LeftButton, Qt::ControlModifier, true );

// complete rotation
utils.mouseMove( 2, 1 );
utils.mouseClick( 2, 1, Qt::LeftButton, Qt::KeyboardModifiers(), true );

QCOMPARE( mLayerBase->getFeature( 1 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((-5.06 5.63, -3.79 6.26, -4.11 5.32, -5.06 5.63))" ) );
QCOMPARE( mLayerBase->getFeature( 2 ).geometry().asWkt( 2 ), QStringLiteral( "Polygon ((1.1 0, 1.1 5, 2.1 5, 2.1 0))" ) );

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


QGSTEST_MAIN( TestQgsMapToolRotateFeature )
#include "testqgsmaptoolrotatefeature.moc"

0 comments on commit 378841e

Please sign in to comment.