Skip to content

Commit

Permalink
Merge pull request #3375 from 3nids/movetoolcad
Browse files Browse the repository at this point in the history
[FEATURE] Move feature now benefits from Advanced Digitizing
  • Loading branch information
3nids committed Aug 12, 2016
2 parents 915afcf + 99ed790 commit e2cacad
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 100 deletions.
6 changes: 6 additions & 0 deletions doc/api_break.dox
Expand Up @@ -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>
Expand Down
14 changes: 12 additions & 2 deletions python/gui/qgsadvanceddigitizingdockwidget.sip
Expand Up @@ -49,6 +49,16 @@ class QgsAdvancedDigitizingDockWidget : QDockWidget
Parallel //!< Parallel
};

/**
* Determines if the dock has to record one, two or many points.
*/
enum AdvancedDigitizingMode
{
SinglePoint, //!< Capture a single point (e.g. for point digitizing)
TwoPoints, //!< Capture two points (e.g. for translation)
ManyPoints //!< Capture two or more 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.
Expand Down Expand Up @@ -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, AdvancedDigitizingMode mode );
/**
* Will react on a canvas move event
*
Expand Down
1 change: 1 addition & 0 deletions python/gui/qgsmaptooladvanceddigitizing.sip
Expand Up @@ -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
};
Expand Down
168 changes: 83 additions & 85 deletions src/app/qgsmaptoolmovefeature.cpp
Expand Up @@ -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 );
Expand All @@ -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
Expand Down
13 changes: 7 additions & 6 deletions src/app/qgsmaptoolmovefeature.h
Expand Up @@ -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;
Expand All @@ -44,6 +42,9 @@ class APP_EXPORT QgsMapToolMoveFeature: public QgsMapToolEdit

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

QPoint mPressPos;

};

#endif
6 changes: 3 additions & 3 deletions src/gui/qgsadvanceddigitizingdockwidget.cpp
Expand Up @@ -900,7 +900,7 @@ bool QgsAdvancedDigitizingDockWidget::canvasPressEvent( QgsMapMouseEvent* e )
return mCadEnabled && mConstructionMode;
}

bool QgsAdvancedDigitizingDockWidget::canvasReleaseEvent( QgsMapMouseEvent* e, bool captureSegment )
bool QgsAdvancedDigitizingDockWidget::canvasReleaseEvent( QgsMapMouseEvent* e, AdvancedDigitizingMode mode )
{
if ( !mCadEnabled )
return false;
Expand Down Expand Up @@ -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();
}
Expand Down
14 changes: 12 additions & 2 deletions src/gui/qgsadvanceddigitizingdockwidget.h
Expand Up @@ -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 AdvancedDigitizingMode
{
SinglePoint, //!< Capture a single point (e.g. for point digitizing)
TwoPoints, //!< Capture two points (e.g. for translation)
ManyPoints //!< Capture two or more 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.
Expand Down Expand Up @@ -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, AdvancedDigitizingMode mode );
/**
* Will react on a canvas move event
*
Expand Down
18 changes: 17 additions & 1 deletion src/gui/qgsmaptooladvanceddigitizing.cpp
Expand Up @@ -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::AdvancedDigitizingMode 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 );
}

Expand Down

0 comments on commit e2cacad

Please sign in to comment.