Skip to content
Permalink
Browse files

Move feature now benefits from Advanced Digitizing

QgsMapToolMoveFeature now inherits QgsMapToolAdvancedDigitizing
this allows to specify distance, angles, complex and multiple moves at once
it is now a click and click operation (similarly to the rotate feature map tool): so it can be cancelled once enabled with the right click
  • Loading branch information
3nids committed Aug 11, 2016
1 parent 7ee55a7 commit af1fee525a0a5acdcd3919a87118dcdcf52f80f1
@@ -261,6 +261,12 @@ variant instead.</li>
<li>expandAction() has been removed. Use QgsExpression::replaceExpressionText() instead.</li>
</ul>

\subsection qgis_api_break_3_0_QgsAdvancedDigitizingDockWidget QgsAdvancedDigitizingDockWidget

<ul>
<li>canvasReleaseEvent takes now QgsAdvancedDigitizingDockWidget::CaptureMode as second argument.</li>
</ul>

\subsection qgis_api_break_3_0_QgsAtlasComposition QgsAtlasComposition

<ul>
@@ -49,6 +49,16 @@ class QgsAdvancedDigitizingDockWidget : QDockWidget
Parallel //!< Parallel
};

/**
* Determines if the dock has to record one, two or many points.
*/
enum CaptureMode
{
SinglePoint, //!< Capture a single point (e.g. for point digitizing)
TwoPoints, //!< Capture two points (e.g. for translation)
ManyPoints //!< Capture many points (e.g. line or polygon digitizing)
};

/**
* @brief The CadConstraint is an abstract class for all basic constraints (angle/distance/x/y).
* It contains all values (locked, value, relative) and pointers to corresponding widgets.
@@ -169,10 +179,10 @@ class QgsAdvancedDigitizingDockWidget : QDockWidget
* Will react on a canvas release event
*
* @param e A mouse event (may be modified)
* @param captureSegment Capture segments?
* @param mode determines if the dock has to record one, two or many points.
* @return If the event is hidden (construction mode hides events from the maptool)
*/
bool canvasReleaseEvent( QgsMapMouseEvent* e , bool captureSegment );
bool canvasReleaseEvent( QgsMapMouseEvent* e , CaptureMode mode );
/**
* Will react on a canvas move event
*
@@ -32,6 +32,7 @@ class QgsMapToolAdvancedDigitizing : QgsMapToolEdit
{
CaptureNone, //!< Do not capture
CapturePoint, //!< Capture points
CaptureSegment, //!< Capture a segment (i.e. 2 points)
CaptureLine, //!< Capture lines
CapturePolygon //!< Capture polygons
};
@@ -23,28 +23,30 @@
#include "qgsvectorlayer.h"
#include "qgstolerance.h"
#include "qgisapp.h"
#include "qgsadvanceddigitizingdockwidget.h"

#include <QMouseEvent>
#include <QSettings>
#include <limits>

QgsMapToolMoveFeature::QgsMapToolMoveFeature( QgsMapCanvas* canvas )
: QgsMapToolEdit( canvas )
: QgsMapToolAdvancedDigitizing( canvas, QgisApp::instance()->cadDockWidget() )
, mRubberBand( nullptr )
{
mToolName = tr( "Move feature" );
mCaptureMode = QgsMapToolAdvancedDigitizing::CaptureSegment;
}

QgsMapToolMoveFeature::~QgsMapToolMoveFeature()
{
delete mRubberBand;
}

void QgsMapToolMoveFeature::canvasMoveEvent( QgsMapMouseEvent* e )
void QgsMapToolMoveFeature::cadCanvasMoveEvent( QgsMapMouseEvent* e )
{
if ( mRubberBand )
{
QgsPoint pointCanvasCoords = toMapCoordinates( e->pos() );
QgsPoint pointCanvasCoords = e->mapPoint();
double offsetX = pointCanvasCoords.x() - mStartPointMapCoords.x();
double offsetY = pointCanvasCoords.y() - mStartPointMapCoords.y();
mRubberBand->setTranslationOffset( offsetX, offsetY );
@@ -53,118 +55,114 @@ void QgsMapToolMoveFeature::canvasMoveEvent( QgsMapMouseEvent* e )
}
}

void QgsMapToolMoveFeature::canvasPressEvent( QgsMapMouseEvent* e )
void QgsMapToolMoveFeature::cadCanvasReleaseEvent( QgsMapMouseEvent* e )
{
delete mRubberBand;
mRubberBand = nullptr;

QgsVectorLayer* vlayer = currentVectorLayer();
if ( !vlayer )
{
notifyNotVectorLayer();
return;
}

if ( !vlayer->isEditable() )
if ( !vlayer || !vlayer->isEditable() )
{
delete mRubberBand;
mRubberBand = nullptr;
cadDockWidget()->clear();
notifyNotEditableLayer();
return;
}

//find first geometry under mouse cursor and store iterator to it
QgsPoint layerCoords = toLayerCoordinates( vlayer, e->pos() );
QSettings settings;
double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() );
QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );

if ( vlayer->selectedFeatureCount() == 0 )
if ( !mRubberBand )
{
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ).setSubsetOfAttributes( QgsAttributeList() ) );

//find the closest feature
QgsGeometry pointGeometry = QgsGeometry::fromPoint( layerCoords );
if ( pointGeometry.isEmpty() )
//find first geometry under mouse cursor and store iterator to it
QgsPoint layerCoords = toLayerCoordinates( vlayer, e->pos() );
double searchRadius = QgsTolerance::vertexSearchRadius( mCanvas->currentLayer(), mCanvas->mapSettings() );
QgsRectangle selectRect( layerCoords.x() - searchRadius, layerCoords.y() - searchRadius,
layerCoords.x() + searchRadius, layerCoords.y() + searchRadius );

if ( vlayer->selectedFeatureCount() == 0 )
{
return;
}
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest().setFilterRect( selectRect ).setSubsetOfAttributes( QgsAttributeList() ) );

double minDistance = std::numeric_limits<double>::max();
//find the closest feature
QgsGeometry pointGeometry = QgsGeometry::fromPoint( layerCoords );
if ( pointGeometry.isEmpty() )
{
cadDockWidget()->clear();
return;
}

QgsFeature cf;
QgsFeature f;
while ( fit.nextFeature( f ) )
{
if ( f.hasGeometry() )
double minDistance = std::numeric_limits<double>::max();

QgsFeature cf;
QgsFeature f;
while ( fit.nextFeature( f ) )
{
double currentDistance = pointGeometry.distance( f.geometry() );
if ( currentDistance < minDistance )
if ( f.hasGeometry() )
{
minDistance = currentDistance;
cf = f;
double currentDistance = pointGeometry.distance( f.geometry() );
if ( currentDistance < minDistance )
{
minDistance = currentDistance;
cf = f;
}
}
}
}

if ( minDistance == std::numeric_limits<double>::max() )
if ( minDistance == std::numeric_limits<double>::max() )
{
cadDockWidget()->clear();
return;
}

mMovedFeatures.clear();
mMovedFeatures << cf.id(); //todo: take the closest feature, not the first one...

mRubberBand = createRubberBand( vlayer->geometryType() );
mRubberBand->setToGeometry( cf.geometry(), vlayer );
}
else
{
return;
mMovedFeatures = vlayer->selectedFeaturesIds();

mRubberBand = createRubberBand( vlayer->geometryType() );
QgsFeature feat;
QgsFeatureIterator it = vlayer->selectedFeaturesIterator( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );

while ( it.nextFeature( feat ) )
{
mRubberBand->addGeometry( feat.geometry(), vlayer );
}
}

mMovedFeatures.clear();
mMovedFeatures << cf.id(); //todo: take the closest feature, not the first one...
mStartPointMapCoords = e->mapPoint();
mRubberBand->setColor( QColor( 255, 0, 0, 65 ) );
mRubberBand->setWidth( 2 );
mRubberBand->show();

mRubberBand = createRubberBand( vlayer->geometryType() );
mRubberBand->setToGeometry( cf.geometry(), vlayer );
}
else
{
mMovedFeatures = vlayer->selectedFeaturesIds();

mRubberBand = createRubberBand( vlayer->geometryType() );
QgsFeature feat;
QgsFeatureIterator it = vlayer->selectedFeaturesIterator( QgsFeatureRequest().setSubsetOfAttributes( QgsAttributeList() ) );
delete mRubberBand;
mRubberBand = nullptr;

while ( it.nextFeature( feat ) )
if ( e->button() != Qt::LeftButton )
{
mRubberBand->addGeometry( feat.geometry(), vlayer );
cadDockWidget()->clear();
return;
}
}

mStartPointMapCoords = toMapCoordinates( e->pos() );
mRubberBand->setColor( QColor( 255, 0, 0, 65 ) );
mRubberBand->setWidth( 2 );
mRubberBand->show();

}

void QgsMapToolMoveFeature::canvasReleaseEvent( QgsMapMouseEvent* e )
{
if ( !mRubberBand )
{
return;
}

QgsVectorLayer* vlayer = currentVectorLayer();
if ( !vlayer )
{
return;
}

QgsPoint startPointLayerCoords = toLayerCoordinates(( QgsMapLayer* )vlayer, mStartPointMapCoords );
QgsPoint stopPointLayerCoords = toLayerCoordinates(( QgsMapLayer* )vlayer, e->pos() );
QgsPoint startPointLayerCoords = toLayerCoordinates(( QgsMapLayer* )vlayer, mStartPointMapCoords );
QgsPoint stopPointLayerCoords = toLayerCoordinates(( QgsMapLayer* )vlayer, e->mapPoint() );

double dx = stopPointLayerCoords.x() - startPointLayerCoords.x();
double dy = stopPointLayerCoords.y() - startPointLayerCoords.y();
vlayer->beginEditCommand( tr( "Feature moved" ) );
Q_FOREACH ( QgsFeatureId id, mMovedFeatures )
{
vlayer->translateFeature( id, dx, dy );
double dx = stopPointLayerCoords.x() - startPointLayerCoords.x();
double dy = stopPointLayerCoords.y() - startPointLayerCoords.y();
vlayer->beginEditCommand( tr( "Feature moved" ) );
Q_FOREACH ( QgsFeatureId id, mMovedFeatures )
{
vlayer->translateFeature( id, dx, dy );
}
delete mRubberBand;
mRubberBand = nullptr;
vlayer->endEditCommand();
vlayer->triggerRepaint();
}
delete mRubberBand;
mRubberBand = nullptr;
vlayer->endEditCommand();
vlayer->triggerRepaint();
}

//! called when map tool is being deactivated
@@ -16,21 +16,19 @@
#ifndef QGSMAPTOOLMOVEFEATURE_H
#define QGSMAPTOOLMOVEFEATURE_H

#include "qgsmaptooledit.h"
#include "qgsmaptooladvanceddigitizing.h"

/** Map tool for translating feature position by mouse drag*/
class APP_EXPORT QgsMapToolMoveFeature: public QgsMapToolEdit
class APP_EXPORT QgsMapToolMoveFeature: public QgsMapToolAdvancedDigitizing
{
Q_OBJECT
public:
QgsMapToolMoveFeature( QgsMapCanvas* canvas );
virtual ~QgsMapToolMoveFeature();

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

virtual void canvasPressEvent( QgsMapMouseEvent* e ) override;

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

//! called when map tool is being deactivated
void deactivate() override;
@@ -44,6 +42,9 @@ class APP_EXPORT QgsMapToolMoveFeature: public QgsMapToolEdit

/** Id of moved feature*/
QgsFeatureIds mMovedFeatures;

QPoint mPressPos;

};

#endif
@@ -900,7 +900,7 @@ bool QgsAdvancedDigitizingDockWidget::canvasPressEvent( QgsMapMouseEvent* e )
return mCadEnabled && mConstructionMode;
}

bool QgsAdvancedDigitizingDockWidget::canvasReleaseEvent( QgsMapMouseEvent* e, bool captureSegment )
bool QgsAdvancedDigitizingDockWidget::canvasReleaseEvent( QgsMapMouseEvent* e, CaptureMode mode )
{
if ( !mCadEnabled )
return false;
@@ -932,8 +932,8 @@ bool QgsAdvancedDigitizingDockWidget::canvasReleaseEvent( QgsMapMouseEvent* e, b

if ( e->button() == Qt::LeftButton )
{
// stop digitizing if not intermediate point and if line or polygon
if ( !mConstructionMode && !captureSegment )
// stop digitizing if not intermediate point and enough points are recorded with respect to the mode
if ( !mConstructionMode && ( mode == SinglePoint || ( mode == TwoPoints && mCadPointList.count() > 2 ) ) )
{
clearPoints();
}
@@ -70,6 +70,16 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
Parallel //!< Parallel
};

/**
* Determines if the dock has to record one, two or many points.
*/
enum CaptureMode
{
SinglePoint, //!< Capture a single point (e.g. for point digitizing)
TwoPoints, //!< Capture two points (e.g. for translation)
ManyPoints //!< Capture many points (e.g. line or polygon digitizing)
};

/** \ingroup gui
* @brief The CadConstraint is an abstract class for all basic constraints (angle/distance/x/y).
* It contains all values (locked, value, relative) and pointers to corresponding widgets.
@@ -209,10 +219,10 @@ class GUI_EXPORT QgsAdvancedDigitizingDockWidget : public QgsDockWidget, private
* Will react on a canvas release event
*
* @param e A mouse event (may be modified)
* @param captureSegment Capture segments?
* @param mode determines if the dock has to record one, two or many points.
* @return If the event is hidden (construction mode hides events from the maptool)
*/
bool canvasReleaseEvent( QgsMapMouseEvent* e , bool captureSegment );
bool canvasReleaseEvent( QgsMapMouseEvent* e , CaptureMode mode );
/**
* Will react on a canvas move event
*
@@ -43,7 +43,23 @@ void QgsMapToolAdvancedDigitizing::canvasPressEvent( QgsMapMouseEvent* e )
void QgsMapToolAdvancedDigitizing::canvasReleaseEvent( QgsMapMouseEvent* e )
{
snap( e );
if ( !mCadDockWidget->canvasReleaseEvent( e, mCaptureMode == CaptureLine || mCaptureMode == CapturePolygon ) )

QgsAdvancedDigitizingDockWidget::CaptureMode dockMode;
switch ( mCaptureMode )
{
case CaptureLine:
case CapturePolygon:
dockMode = QgsAdvancedDigitizingDockWidget::ManyPoints;
break;
case CaptureSegment:
dockMode = QgsAdvancedDigitizingDockWidget::TwoPoints;
break;
default:
dockMode = QgsAdvancedDigitizingDockWidget::SinglePoint;
break;
}

if ( !mCadDockWidget->canvasReleaseEvent( e, dockMode ) )
cadCanvasReleaseEvent( e );
}

0 comments on commit af1fee5

Please sign in to comment.
You can’t perform that action at this time.