|
@@ -25,6 +25,7 @@ |
|
|
#include "qgsadvanceddigitizingdockwidget.h" |
|
|
#include "qgsvectorlayerlabeling.h" |
|
|
#include "qgscallout.h" |
|
|
#include "qgsstatusbar.h" |
|
|
|
|
|
QgsMapToolMoveLabel::QgsMapToolMoveLabel( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDock ) |
|
|
: QgsMapToolLabel( canvas, cadDock ) |
|
@@ -67,7 +68,15 @@ void QgsMapToolMoveLabel::cadCanvasMoveEvent( QgsMapMouseEvent *e ) |
|
|
else if ( mCalloutMoveRubberBand ) |
|
|
{ |
|
|
const int index = mCurrentCalloutMoveOrigin ? 0 : 1; |
|
|
mCalloutMoveRubberBand->movePoint( index, e->mapPoint() ); |
|
|
|
|
|
QgsPointXY mapPoint = e->mapPoint(); |
|
|
if ( e->modifiers() & Qt::ShiftModifier ) |
|
|
{ |
|
|
// shift modifier = snap to common angles |
|
|
mapPoint = snapCalloutPointToCommonAngle( mapPoint, true ); |
|
|
} |
|
|
|
|
|
mCalloutMoveRubberBand->movePoint( index, mapPoint ); |
|
|
mCalloutMoveRubberBand->update(); |
|
|
} |
|
|
else |
|
@@ -231,17 +240,23 @@ void QgsMapToolMoveLabel::cadCanvasPressEvent( QgsMapMouseEvent *e ) |
|
|
case Qt::LeftButton: |
|
|
{ |
|
|
// second click drops label/callout |
|
|
const bool isCalloutMove = !mCurrentCallout.layerID.isEmpty(); |
|
|
QgsPointXY releaseCoords = e->mapPoint(); |
|
|
if ( isCalloutMove && e->modifiers() & Qt::ShiftModifier ) |
|
|
{ |
|
|
// shift modifier = snap to common angles |
|
|
releaseCoords = snapCalloutPointToCommonAngle( releaseCoords, false ); |
|
|
} |
|
|
|
|
|
deleteRubberBands(); |
|
|
|
|
|
const bool isCalloutMove = !mCurrentCallout.layerID.isEmpty(); |
|
|
QgsVectorLayer *vlayer = !isCalloutMove ? mCurrentLabel.layer : QgsProject::instance()->mapLayer<QgsVectorLayer *>( mCurrentCallout.layerID ); |
|
|
if ( !vlayer ) |
|
|
{ |
|
|
return; |
|
|
} |
|
|
const QgsFeatureId featureId = !isCalloutMove ? mCurrentLabel.pos.featureId : mCurrentCallout.featureId; |
|
|
|
|
|
QgsPointXY releaseCoords = e->mapPoint(); |
|
|
double xdiff = releaseCoords.x() - mStartPointMapCoords.x(); |
|
|
double ydiff = releaseCoords.y() - mStartPointMapCoords.y(); |
|
|
|
|
@@ -549,5 +564,41 @@ bool QgsMapToolMoveLabel::currentCalloutDataDefinedPosition( double &x, bool &xS |
|
|
return true; |
|
|
} |
|
|
|
|
|
QgsPointXY QgsMapToolMoveLabel::snapCalloutPointToCommonAngle( const QgsPointXY &mapPoint, bool showStatusMessage ) const |
|
|
{ |
|
|
const int index = mCurrentCalloutMoveOrigin ? 0 : 1; |
|
|
|
|
|
QgsPointXY start = *mCalloutMoveRubberBand->getPoint( 0, index == 0 ? 1 : 0 ); |
|
|
const double cursorDistance = start.distance( mapPoint ); |
|
|
|
|
|
// snap to common angles (15 degree increments) |
|
|
double closestDist = std::numeric_limits< double >::max(); |
|
|
double closestX = 0; |
|
|
double closestY = 0; |
|
|
int bestAngle = 0; |
|
|
|
|
|
const double angleOffset = -canvas()->rotation(); |
|
|
|
|
|
for ( int angle = 0; angle < 360; angle += 15 ) |
|
|
{ |
|
|
const QgsPointXY end = start.project( cursorDistance * 2, angle + angleOffset ); |
|
|
double minDistX = 0; |
|
|
double minDistY = 0; |
|
|
const double angleDist = QgsGeometryUtils::sqrDistToLine( mapPoint.x(), mapPoint.y(), start.x(), start.y(), end.x(), end.y(), minDistX, minDistY, 4 * std::numeric_limits<double>::epsilon() ); |
|
|
if ( angleDist < closestDist ) |
|
|
{ |
|
|
closestDist = angleDist; |
|
|
closestX = minDistX; |
|
|
closestY = minDistY; |
|
|
bestAngle = angle; |
|
|
} |
|
|
} |
|
|
|
|
|
if ( showStatusMessage ) |
|
|
QgisApp::instance()->statusBarIface()->showMessage( tr( "Callout angle: %1°" ).arg( bestAngle ), 2000 ); |
|
|
|
|
|
return QgsPointXY( closestX, closestY ); |
|
|
} |
|
|
|
|
|
|
|
|
|