Skip to content

Commit

Permalink
allow overriding project snapping settings from advanced digitzing tools
Browse files Browse the repository at this point in the history
therefore snapping to all layers can be applied, and snapping to segment can be turned on when enabling parallel/perpendicular constraints
  • Loading branch information
3nids committed Jan 23, 2015
1 parent dfc2dc7 commit 7e0f646
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 60 deletions.
51 changes: 32 additions & 19 deletions src/app/qgsadvanceddigitizingdockwidget.cpp
Expand Up @@ -24,7 +24,6 @@
#include "qgsexpression.h"
#include "qgslogger.h"
#include "qgsmapcanvas.h"
#include "qgsmapmouseevent.h"
#include "qgsmaptoolcapture.h"
#include "qgsmaptooladvanceddigitizing.h"
#include "qgsmessagebaritem.h"
Expand Down Expand Up @@ -88,7 +87,7 @@ QgsAdvancedDigitizingDockWidget::QgsAdvancedDigitizingDockWidget( QgsMapCanvas*
, mCurrentMapTool( 0 )
, mCadEnabled( false )
, mConstructionMode( false )
, mSnappingEnabled( true )
, mSnappingMode(( QgsMapMouseEvent::SnappingMode ) QSettings().value( "/Cad/SnappingMode", ( int )QgsMapMouseEvent::SnapProjectConfig ).toInt() )
, mCommonAngleConstraint( QSettings().value( "/Cad/CommonAngle", 90 ).toInt() )
, mCadPointList( QList<QgsPoint>() )
, mPointSnapped( false )
Expand Down Expand Up @@ -147,28 +146,40 @@ QgsAdvancedDigitizingDockWidget::QgsAdvancedDigitizingDockWidget( QgsMapCanvas*
// config menu
QMenu *menu = new QMenu( this );
// common angles
QActionGroup* actionGroup = new QActionGroup( menu ); // actions are exclusive for common angles
QActionGroup* angleButtonGroup = new QActionGroup( menu ); // actions are exclusive for common angles
mCommonAngleActions = QMap<QAction*, int>();
QList< QPair< int, QString > > commonAngles;
commonAngles << QPair<int, QString>( 0, tr( "Do not snap to common angles" ) );
commonAngles << QPair<int, QString>( 30, tr( "Snap to 30%1 angles" ).arg( QString::fromUtf8( "°" ) ) );
commonAngles << QPair<int, QString>( 45, tr( "Snap to 45%1 angles" ).arg( QString::fromUtf8( "°" ) ) );
commonAngles << QPair<int, QString>( 90, tr( "Snap to 90%1 angles" ).arg( QString::fromUtf8( "°" ) ) );
commonAngles << QPair<int, QString>( 0, tr( "Do not snap to common angles" ) );
for ( QList< QPair< int, QString > >::const_iterator it = commonAngles.begin(); it != commonAngles.end(); ++it )
{
QAction* action = new QAction( it->second, menu );
action->setCheckable( true );
action->setChecked( it->first == mCommonAngleConstraint );
menu->addAction( action );
actionGroup->addAction( action );
angleButtonGroup->addAction( action );
mCommonAngleActions.insert( action, it->first );
}
// snapping on layers
menu->addSeparator();
mSnappingEnabledAction = new QAction( tr( "Snap on layers" ), menu );
mSnappingEnabledAction->setCheckable( true );
mSnappingEnabledAction->setChecked( mSnappingEnabled );
menu->addAction( mSnappingEnabledAction );
QActionGroup* snapButtonGroup = new QActionGroup( menu ); // actions are exclusive for snapping modes
mSnappingActions = QMap<QAction*, QgsMapMouseEvent::SnappingMode>();
QList< QPair< QgsMapMouseEvent::SnappingMode, QString > > snappingModes;
snappingModes << QPair<QgsMapMouseEvent::SnappingMode, QString>( QgsMapMouseEvent::NoSnapping, tr( "Do not snap to vertices or segment" ) );
snappingModes << QPair<QgsMapMouseEvent::SnappingMode, QString>( QgsMapMouseEvent::SnapProjectConfig, tr( "Snap according to project configuration" ) );
snappingModes << QPair<QgsMapMouseEvent::SnappingMode, QString>( QgsMapMouseEvent::SnapAllLayers, tr( "Snap to all layers" ) );
for ( QList< QPair< QgsMapMouseEvent::SnappingMode, QString > >::const_iterator it = snappingModes.begin(); it != snappingModes.end(); ++it )
{
QAction* action = new QAction( it->second, menu );
action->setCheckable( true );
action->setChecked( it->first == mSnappingMode );
menu->addAction( action );
snapButtonGroup->addAction( action );
mSnappingActions.insert( action, it->first );
}

mSettingsButton->setMenu( menu );
connect( mSettingsButton, SIGNAL( triggered( QAction* ) ), this, SLOT( settingsButtonTriggered( QAction* ) ) );

Expand Down Expand Up @@ -314,20 +325,22 @@ void QgsAdvancedDigitizingDockWidget::setConstructionMode( bool enabled )
void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction* action )
{
// snapping
if ( action == mSnappingEnabledAction )
QMap<QAction*, QgsMapMouseEvent::SnappingMode>::const_iterator isn = mSnappingActions.find( action );
if ( isn != mSnappingActions.end() )
{
mSnappingEnabled = !mSnappingEnabled;
mSnappingEnabledAction->setChecked( mSnappingEnabled );
isn.key()->setChecked( true );
mSnappingMode = isn.value();
QSettings().setValue( "/Cad/SnappingMode", ( int )isn.value() );
return;
}

// common angles
QMap<QAction*, int>::const_iterator i = mCommonAngleActions.find( action );
if ( i != mCommonAngleActions.end() )
QMap<QAction*, int>::const_iterator ica = mCommonAngleActions.find( action );
if ( ica != mCommonAngleActions.end() )
{
i.key()->setChecked( true );
mCommonAngleConstraint = i.value();
QSettings().setValue( "/Cad/CommonAngle", i.value() );
ica.key()->setChecked( true );
mCommonAngleConstraint = ica.value();
QSettings().setValue( "/Cad/CommonAngle", ica.value() );
return;
}
}
Expand Down Expand Up @@ -508,7 +521,7 @@ bool QgsAdvancedDigitizingDockWidget::applyConstraints( QgsMapMouseEvent* e )
QgsDebugMsg( QString( "Y: %1 %2 %3" ).arg( mYConstraint->isLocked() ).arg( mYConstraint->relative() ).arg( mYConstraint->value() ) );

QgsPoint point = e->mapPoint( &mPointSnapped );
mSnappedSegment = e->snappedSegment();
mSnappedSegment = e->snapSegment();

bool previousPointExist, penulPointExist;
QgsPoint previousPt = previousPoint( &previousPointExist );
Expand Down Expand Up @@ -809,7 +822,7 @@ bool QgsAdvancedDigitizingDockWidget::alignToSegment( QgsMapMouseEvent* e, CadCo
bool previousPointExist, penulPointExist, mSnappedSegmentExist;
QgsPoint previousPt = previousPoint( &previousPointExist );
QgsPoint penultimatePt = penultimatePoint( &penulPointExist );
QList<QgsPoint> mSnappedSegment = e->snappedSegment( &mSnappedSegmentExist );
QList<QgsPoint> mSnappedSegment = e->snapSegment( &mSnappedSegmentExist, true );

if ( !previousPointExist || !mSnappedSegmentExist )
{
Expand Down
14 changes: 8 additions & 6 deletions src/app/qgsadvanceddigitizingdockwidget.h
Expand Up @@ -18,13 +18,15 @@

#include <QDockWidget>

#include "qgsmapmouseevent.h"

#include <ui_qgsadvanceddigitizingdockwidgetbase.h>


class QgsAdvancedDigitizingCanvasItem;
class QgsMapCanvas;
class QgsMapTool;
class QgsMapToolAdvancedDigitizing;
class QgsMapMouseEvent;
class QgsMessageBarItem;
class QgsPoint;

Expand All @@ -36,8 +38,8 @@ static const double SoftConstraintToleranceDegrees = 10;
/**
* @brief The QgsAdvancedDigitizingDock class is a dockable widget
* used to handle the CAD tools on top of a selection of map tools.
* This class is used for the GUI by inhereting QDockWidget and
* for constraining the map tool events by inheriting QgsMapToolMapEventFilter.
* It handles both the UI and the constraints. Constraints are applied
* by implemeting filters called from QgsMapToolAdvancedDigitizing.
*/
class APP_EXPORT QgsAdvancedDigitizingDockWidget : public QDockWidget, private Ui::QgsAdvancedDigitizingDockWidgetBase
{
Expand Down Expand Up @@ -127,7 +129,7 @@ class APP_EXPORT QgsAdvancedDigitizingDockWidget : public QDockWidget, private U
virtual bool canvasMoveEventFilter( QgsMapMouseEvent* e );
virtual bool canvasKeyPressEventFilter( QKeyEvent *e );

bool snappingEnabled() {return mSnappingEnabled;}
QgsMapMouseEvent::SnappingMode snappingMode() {return mSnappingMode;}

//! key press event on the dock
void keyPressEvent( QKeyEvent* e ) override;
Expand Down Expand Up @@ -238,7 +240,7 @@ class APP_EXPORT QgsAdvancedDigitizingDockWidget : public QDockWidget, private U
//! is CAD currently enabled for current map tool
bool mCadEnabled;
bool mConstructionMode;
bool mSnappingEnabled;
QgsMapMouseEvent::SnappingMode mSnappingMode;

// constraints
CadConstraint* mAngleConstraint;
Expand All @@ -260,7 +262,7 @@ class APP_EXPORT QgsAdvancedDigitizingDockWidget : public QDockWidget, private U
// UI
QAction* mEnableAction;
QMap< QAction*, int > mCommonAngleActions; // map the common angle actions with their angle values
QAction* mSnappingEnabledAction;
QMap< QAction*, QgsMapMouseEvent::SnappingMode > mSnappingActions; // map the snapping mode actions with their values
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsAdvancedDigitizingDockWidget::CadCapacities )
Expand Down
81 changes: 61 additions & 20 deletions src/app/qgsmapmouseevent.cpp
Expand Up @@ -21,42 +21,67 @@
#include "qgisapp.h"
#include "qgssnappingutils.h"

QgsMapMouseEvent::QgsMapMouseEvent( QgsMapToolAdvancedDigitizing* mapTool, QMouseEvent* event , bool doSnap )
QgsMapMouseEvent::QgsMapMouseEvent( QgsMapToolAdvancedDigitizing* mapTool, QMouseEvent* event , SnappingMode mode )
: QMouseEvent( event->type(), event->pos(), event->globalPos(), event->button(), event->buttons(), event->modifiers() )
, mMapPoint( mapTool->canvas()->mapSettings().mapToPixel().toMapCoordinates( event->pos() ) )
, mMapTool( mapTool )
, mSnapMatch( QgsPointLocator::Match() )
, mSnappingMode( mode )
{
mOriginalPoint = mMapPoint;

if ( doSnap )
snapPoint();
snapPoint();
}

struct VertexOnlyFilter : public QgsPointLocator::MatchFilter
{
bool acceptMatch( const QgsPointLocator::Match& m ) override { return m.hasVertex(); }
};

struct EdgesOnlyFilter : public QgsPointLocator::MatchFilter
{
bool acceptMatch( const QgsPointLocator::Match& m ) override { return m.hasEdge(); }
};

QgsMapMouseEvent::QgsMapMouseEvent( QgsMapToolAdvancedDigitizing* mapTool, QgsPoint point,
Qt::MouseButton button, Qt::KeyboardModifiers modifiers,
QEvent::Type eventType, bool doSnap )
QEvent::Type eventType, SnappingMode mode )
: QMouseEvent( eventType,
mapToPixelCoordinates( mapTool->canvas(), point ),
mapTool->canvas()->mapToGlobal( mapToPixelCoordinates( mapTool->canvas(), point ) ),
button, button, modifiers )
, mMapPoint( point )
, mOriginalPoint( point )
, mMapTool( mapTool )
, mSnapMatch( QgsPointLocator::Match() )
, mSnappingMode( mode )
{
if ( doSnap )
snapPoint();
snapPoint();
}

void QgsMapMouseEvent::setPoint( const QgsPoint& point )
{
mMapPoint.set( point.x(), point.y() );
}

bool QgsMapMouseEvent::snapPoint()
void QgsMapMouseEvent::snapPoint()
{
mSnapMatch = mMapTool->canvas()->snappingUtils()->snapToMap( mMapPoint );
if ( mSnappingMode == NoSnapping )
return;

QgsSnappingUtils* snappingUtils = mMapTool->canvas()->snappingUtils();
QgsSnappingUtils::SnapToMapMode canvasMode = snappingUtils->snapToMapMode();
if ( mSnappingMode == SnapAllLayers )
{
snappingUtils->setSnapToMapMode( QgsSnappingUtils::SnapAllLayers );
VertexOnlyFilter filter;
mSnapMatch = snappingUtils->snapToMap( mMapPoint, &filter );
snappingUtils->setSnapToMapMode( canvasMode );
}
else
{
mSnapMatch = snappingUtils->snapToMap( mMapPoint );
}
mMapPoint = mSnapMatch.isValid() ? mSnapMatch.point() : mOriginalPoint;
return mSnapMatch.isValid();
}

QPoint QgsMapMouseEvent::mapToPixelCoordinates( QgsMapCanvas* canvas, const QgsPoint& point )
Expand All @@ -78,25 +103,41 @@ QgsPoint QgsMapMouseEvent::mapPoint( bool* snappedPoint ) const
return mMapPoint;
}

struct EdgesOnlyFilter : public QgsPointLocator::MatchFilter
{
bool acceptMatch( const QgsPointLocator::Match& m ) override { return m.hasEdge(); }
};

QList<QgsPoint> QgsMapMouseEvent::snappedSegment( bool* snapped ) const
QList<QgsPoint> QgsMapMouseEvent::snapSegment( bool* snapped, bool allLayers ) const
{
QList<QgsPoint> segment = QList<QgsPoint>();
QgsPoint pt1, pt2;

if ( mSnapMatch.hasEdge() )
{
QgsPoint pt1, pt2;
mSnapMatch.edgePoints( pt1, pt2 );
segment << pt1 << pt2;
}
else

else if ( mSnappingMode != NoSnapping )
{
// run snapToMap with only segments
QgsPointLocator::Match match;
EdgesOnlyFilter filter;
mMapTool->canvas()->snappingUtils()->snapToMap( mMapPoint, &filter );
QgsPoint point;
if ( mSnappingMode == SnapProjectConfig && !allLayers )
{
// run snapToMap with only segments
match = mMapTool->canvas()->snappingUtils()->snapToMap( point, &filter );
}
else if ( mSnappingMode == SnapAllLayers || allLayers )
{
// run snapToMap with only segments on all layers
QgsSnappingUtils* snappingUtils = mMapTool->canvas()->snappingUtils();
QgsSnappingUtils::SnapToMapMode canvasMode = snappingUtils->snapToMapMode();
snappingUtils->setSnapToMapMode( QgsSnappingUtils::SnapAllLayers );
match = snappingUtils->snapToMap( point, &filter );
snappingUtils->setSnapToMapMode( canvasMode );
}
if ( match.isValid() && match.hasEdge() )
{
match.edgePoints( pt1, pt2 );
segment << pt1 << pt2;
}
}

if ( snapped )
Expand Down
24 changes: 17 additions & 7 deletions src/app/qgsmapmouseevent.h
Expand Up @@ -27,11 +27,19 @@ class QgsMapToolAdvancedDigitizing;
class APP_EXPORT QgsMapMouseEvent : public QMouseEvent
{
public:
explicit QgsMapMouseEvent( QgsMapToolAdvancedDigitizing* mapTool, QMouseEvent* event, bool doSnap = false );

enum SnappingMode
{
NoSnapping,
SnapProjectConfig, //!< snap according to the configuration set in the snapping settings
SnapAllLayers, //!< snap to all rendered layers (tolerance and type from defaultSettings())
};

explicit QgsMapMouseEvent( QgsMapToolAdvancedDigitizing* mapTool, QMouseEvent* event, SnappingMode mode = NoSnapping );

explicit QgsMapMouseEvent( QgsMapToolAdvancedDigitizing* mapTool, QgsPoint point,
Qt::MouseButton button, Qt::KeyboardModifiers modifiers,
QEvent::Type eventType = QEvent::MouseButtonRelease, bool doSnap = false );
QEvent::Type eventType = QEvent::MouseButtonRelease, SnappingMode mode = NoSnapping );

//! returns the corresponding map tool
QgsMapToolAdvancedDigitizing* mapTool() {return mMapTool;}
Expand All @@ -40,7 +48,9 @@ class APP_EXPORT QgsMapMouseEvent : public QMouseEvent
void setPoint( const QgsPoint& point );

//! returns the first snapped segment
QList<QgsPoint> snappedSegment( bool* snapped = 0 ) const;
//! @param snapped if given, determines if a segment has been snapped
//! @param allLayers if true, override snapping mode
QList<QgsPoint> snapSegment( bool* snapped = 0, bool allLayers = false ) const;

/**
* @brief mapPoint returns the point in coordinates
Expand All @@ -49,14 +59,13 @@ class APP_EXPORT QgsMapMouseEvent : public QMouseEvent
*/
QgsPoint mapPoint( bool* snappedPoint = 0 ) const;

private:
/**
* @brief snapPoint will snap the points using the map canvas snapper
* @brief snapPoint will snap the points using the map canvas snapping utils configuration
* @note if snapping did not succeeded, the map point will be reset to its original position
*/
bool snapPoint();
void snapPoint();


private:
static QPoint mapToPixelCoordinates( QgsMapCanvas* canvas, const QgsPoint& point );

QgsPoint mMapPoint;
Expand All @@ -65,6 +74,7 @@ class APP_EXPORT QgsMapMouseEvent : public QMouseEvent

QgsMapToolAdvancedDigitizing* mMapTool;
QgsPointLocator::Match mSnapMatch;
SnappingMode mSnappingMode;
};

#endif // QGSMAPMOUSEEVENT_H

0 comments on commit 7e0f646

Please sign in to comment.