18 #include <QCoreApplication> 
   35 #include "qgssettings.h" 
   44   , mMapCanvas( canvas )
 
   46   , mCommonAngleConstraint( QgsSettings().value( QStringLiteral( 
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
 
   52   mAngleConstraint.reset( 
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
 
   53   mDistanceConstraint.reset( 
new CadConstraint( mDistanceLineEdit, mLockDistanceButton, 
nullptr, mRepeatingLockDistanceButton ) );
 
   54   mXConstraint.reset( 
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
 
   55   mYConstraint.reset( 
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
 
   58   mMapCanvas->installEventFilter( 
this );
 
   59   mAngleLineEdit->installEventFilter( 
this );
 
   60   mDistanceLineEdit->installEventFilter( 
this );
 
   61   mXLineEdit->installEventFilter( 
this );
 
   62   mYLineEdit->installEventFilter( 
this );
 
   65   connect( mEnableAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::activateCad );
 
   66   connect( mConstructionModeAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
 
   67   connect( mParallelAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::additionalConstraintClicked );
 
   68   connect( mPerpendicularAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::additionalConstraintClicked );
 
   69   connect( mLockAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
   70   connect( mLockDistanceButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
   71   connect( mLockXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
   72   connect( mLockYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
   73   connect( mRelativeAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
   74   connect( mRelativeXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
   75   connect( mRelativeYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
   76   connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
   77   connect( mRepeatingLockAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
   78   connect( mRepeatingLockXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
   79   connect( mRepeatingLockYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
   80   connect( mAngleLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
   81   connect( mDistanceLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
   82   connect( mXLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
   83   connect( mYLineEdit, &QLineEdit::returnPressed, 
this, [ = ]() { lockConstraint(); } );
 
   84   connect( mAngleLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
   85   connect( mDistanceLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
   86   connect( mXLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
   87   connect( mYLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
   99   QMenu *menu = 
new QMenu( 
this );
 
  101   QActionGroup *angleButtonGroup = 
new QActionGroup( menu ); 
 
  102   mCommonAngleActions = QMap<QAction *, double>();
 
  103   QList< QPair< double, QString > > commonAngles;
 
  105   QList<double> anglesDouble( { 0.0, 5.0, 10.0, 15.0, 18.0, 22.5, 30.0, 45.0, 90.0} );
 
  106   for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
 
  109       menuText = tr( 
"Do Not Snap to Common Angles" );
 
  111       menuText = QString( tr( 
"%1, %2, %3, %4°…" ) ).arg( *it, 0, 
'f', 1 ).arg( *it * 2, 0, 
'f', 1 ).arg( *it * 3, 0, 
'f', 1 ).arg( *it * 4, 0, 
'f', 1 );
 
  112     commonAngles << QPair<double, QString>( *it, menuText );
 
  114   for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
 
  116     QAction *action = 
new QAction( it->second, menu );
 
  117     action->setCheckable( 
true );
 
  118     action->setChecked( it->first == mCommonAngleConstraint );
 
  119     menu->addAction( action );
 
  120     angleButtonGroup->addAction( action );
 
  121     mCommonAngleActions.insert( action, it->first );
 
  124   qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
 
  125   mSettingsAction->setMenu( menu );
 
  126   mSettingsAction->setCheckable( 
true );
 
  127   mSettingsAction->setToolTip( tr( 
"Snap to common angles" ) );
 
  128   mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
 
  129   connect( menu, &QMenu::triggered, 
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
 
  132   mConstructionModeAction->setToolTip( 
"<b>" + tr( 
"Construction mode" ) + 
"</b><br>(" + tr( 
"press c to toggle on/off" ) + 
")" );
 
  133   mDistanceLineEdit->setToolTip( 
"<b>" + tr( 
"Distance" ) + 
"</b><br>(" + tr( 
"press d for quick access" ) + 
")" );
 
  134   mLockDistanceButton->setToolTip( 
"<b>" + tr( 
"Lock distance" ) + 
"</b><br>(" + tr( 
"press Ctrl + d for quick access" ) + 
")" );
 
  135   mRepeatingLockDistanceButton->setToolTip( 
"<b>" + tr( 
"Continuously lock distance" ) + 
"</b>" );
 
  137   mRelativeAngleButton->setToolTip( 
"<b>" + tr( 
"Toggles relative angle to previous segment" ) + 
"</b><br>(" + tr( 
"press Shift + a for quick access" ) + 
")" );
 
  138   mAngleLineEdit->setToolTip( 
"<b>" + tr( 
"Angle" ) + 
"</b><br>(" + tr( 
"press a for quick access" ) + 
")" );
 
  139   mLockAngleButton->setToolTip( 
"<b>" + tr( 
"Lock angle" ) + 
"</b><br>(" + tr( 
"press Ctrl + a for quick access" ) + 
")" );
 
  140   mRepeatingLockAngleButton->setToolTip( 
"<b>" + tr( 
"Continuously lock angle" ) + 
"</b>" );
 
  142   mRelativeXButton->setToolTip( 
"<b>" + tr( 
"Toggles relative x to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + x for quick access" ) + 
")" );
 
  143   mXLineEdit->setToolTip( 
"<b>" + tr( 
"X coordinate" ) + 
"</b><br>(" + tr( 
"press x for quick access" ) + 
")" );
 
  144   mLockXButton->setToolTip( 
"<b>" + tr( 
"Lock x coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + x for quick access" ) + 
")" );
 
  145   mRepeatingLockXButton->setToolTip( 
"<b>" + tr( 
"Continuously lock x coordinate" ) + 
"</b>" );
 
  147   mRelativeYButton->setToolTip( 
"<b>" + tr( 
"Toggles relative y to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + y for quick access" ) + 
")" );
 
  148   mYLineEdit->setToolTip( 
"<b>" + tr( 
"Y coordinate" ) + 
"</b><br>(" + tr( 
"press y for quick access" ) + 
")" );
 
  149   mLockYButton->setToolTip( 
"<b>" + tr( 
"Lock y coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + y for quick access" ) + 
")" );
 
  150   mRepeatingLockYButton->setToolTip( 
"<b>" + tr( 
"Continuously lock y coordinate" ) + 
"</b>" );
 
  161   mToggleFloaterAction->setChecked( mFloater->
active() );
 
  163   updateCapacity( 
true );
 
  171   mXLineEdit->setText( value );
 
  172   if ( mode == WidgetSetMode::ReturnPressed )
 
  174     mXLineEdit->returnPressed();
 
  176   else if ( mode == WidgetSetMode::FocusOut )
 
  178     QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  179     QCoreApplication::postEvent( mXLineEdit, e );
 
  181   else if ( mode == WidgetSetMode::TextEdited )
 
  183     mXLineEdit->textEdited( value );
 
  188   mYLineEdit->setText( value );
 
  189   if ( mode == WidgetSetMode::ReturnPressed )
 
  191     mYLineEdit->returnPressed();
 
  193   else if ( mode == WidgetSetMode::FocusOut )
 
  195     QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  196     QCoreApplication::postEvent( mYLineEdit, e );
 
  198   else if ( mode == WidgetSetMode::TextEdited )
 
  200     mYLineEdit->textEdited( value );
 
  205   mAngleLineEdit->setText( value );
 
  206   if ( mode == WidgetSetMode::ReturnPressed )
 
  208     mAngleLineEdit->returnPressed();
 
  210   else if ( mode == WidgetSetMode::FocusOut )
 
  212     QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  213     QCoreApplication::postEvent( mAngleLineEdit, e );
 
  215   else if ( mode == WidgetSetMode::TextEdited )
 
  217     mAngleLineEdit->textEdited( value );
 
  222   mDistanceLineEdit->setText( value );
 
  223   if ( mode == WidgetSetMode::ReturnPressed )
 
  225     mDistanceLineEdit->returnPressed();
 
  227   else if ( mode == WidgetSetMode::FocusOut )
 
  229     QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  230     QCoreApplication::postEvent( mDistanceLineEdit, e );
 
  232   else if ( mode == WidgetSetMode::TextEdited )
 
  234     mDistanceLineEdit->textEdited( value );
 
  239 void QgsAdvancedDigitizingDockWidget::setCadEnabled( 
bool enabled )
 
  241   mCadEnabled = enabled;
 
  242   mEnableAction->setChecked( enabled );
 
  243   mConstructionModeAction->setEnabled( enabled );
 
  244   mParallelAction->setEnabled( enabled );
 
  245   mPerpendicularAction->setEnabled( enabled );
 
  246   mSettingsAction->setEnabled( enabled );
 
  247   mInputWidgets->setEnabled( enabled );
 
  248   mToggleFloaterAction->setEnabled( enabled );
 
  251   setConstructionMode( 
false );
 
  256 void QgsAdvancedDigitizingDockWidget::activateCad( 
bool enabled )
 
  258   enabled &= mCurrentMapToolSupportsCad;
 
  260   mSessionActive = enabled;
 
  262   if ( enabled && !isVisible() )
 
  267   setCadEnabled( enabled );
 
  270 void QgsAdvancedDigitizingDockWidget::additionalConstraintClicked( 
bool activated )
 
  276   else if ( sender() == mParallelAction )
 
  280   else if ( sender() == mPerpendicularAction )
 
  286 void QgsAdvancedDigitizingDockWidget::setConstraintRelative( 
bool activate )
 
  288   if ( sender() == mRelativeAngleButton )
 
  290     mAngleConstraint->setRelative( activate );
 
  293   else if ( sender() == mRelativeXButton )
 
  295     mXConstraint->setRelative( activate );
 
  298   else if ( sender() == mRelativeYButton )
 
  300     mYConstraint->setRelative( activate );
 
  305 void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock( 
bool activate )
 
  307   if ( sender() == mRepeatingLockDistanceButton )
 
  309     mDistanceConstraint->setRepeatingLock( activate );
 
  311   else if ( sender() == mRepeatingLockAngleButton )
 
  313     mAngleConstraint->setRepeatingLock( activate );
 
  315   else if ( sender() == mRepeatingLockXButton )
 
  317     mXConstraint->setRepeatingLock( activate );
 
  319   else if ( sender() == mRepeatingLockYButton )
 
  321     mYConstraint->setRepeatingLock( activate );
 
  325 void QgsAdvancedDigitizingDockWidget::setConstructionMode( 
bool enabled )
 
  327   mConstructionMode = enabled;
 
  328   mConstructionModeAction->setChecked( enabled );
 
  331 void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
 
  334   QMap<QAction *, double>::const_iterator ica = mCommonAngleActions.constFind( action );
 
  335   if ( ica != mCommonAngleActions.constEnd() )
 
  337     ica.key()->setChecked( 
true );
 
  338     mCommonAngleConstraint = ica.value();
 
  339     QgsSettings().setValue( QStringLiteral( 
"/Cad/CommonAngle" ), ica.value() );
 
  340     mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
 
  351   if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
 
  356   if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
 
  361   if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
 
  366   if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
 
  372   if ( !mCadPointList.empty() )
 
  374     if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
 
  376       mXConstraint->setValue( mCadPointList.constLast().x(), 
true );
 
  378     if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
 
  380       mYConstraint->setValue( mCadPointList.constLast().y(), 
true );
 
  387 void QgsAdvancedDigitizingDockWidget::emit pointChanged()
 
  390   QPoint globalPos = mMapCanvas->cursor().pos();
 
  391   QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
 
  392   QMouseEvent *e = 
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
 
  393   mCurrentMapTool->canvasMoveEvent( e );
 
  399   CadConstraint *constraint = 
nullptr;
 
  400   if ( obj == mAngleLineEdit || obj == mLockAngleButton )
 
  402     constraint = mAngleConstraint.get();
 
  404   else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
 
  406     constraint = mDistanceConstraint.get();
 
  408   else if ( obj == mXLineEdit  || obj == mLockXButton )
 
  410     constraint = mXConstraint.get();
 
  412   else if ( obj == mYLineEdit  || obj == mLockYButton )
 
  414     constraint = mYConstraint.get();
 
  419 double QgsAdvancedDigitizingDockWidget::parseUserInput( 
const QString &inputValue, 
bool &ok )
 const 
  431     QVariant result = expr.evaluate();
 
  432     if ( expr.hasEvalError() )
 
  435       value = result.toDouble( &ok );
 
  440 void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint, 
const QString &textValue, 
bool convertExpression )
 
  442   if ( !constraint || textValue.isEmpty() )
 
  451   double value = parseUserInput( textValue, ok );
 
  455   constraint->setValue( value, convertExpression );
 
  460 void QgsAdvancedDigitizingDockWidget::lockConstraint( 
bool activate  )
 
  462   CadConstraint *constraint = objectToConstraint( sender() );
 
  470     QString textValue = constraint->lineEdit()->text();
 
  471     if ( !textValue.isEmpty() )
 
  474       double value = parseUserInput( textValue, ok );
 
  477         constraint->setValue( value );
 
  491   if ( constraint == mXConstraint.get() )
 
  495   else if ( constraint == mYConstraint.get() )
 
  499   else if ( constraint == mDistanceConstraint.get() )
 
  503   else if ( constraint == mAngleConstraint.get() )
 
  511     if ( constraint == mAngleConstraint.get() )
 
  521 void QgsAdvancedDigitizingDockWidget::constraintTextEdited( 
const QString &textValue )
 
  523   CadConstraint *constraint = objectToConstraint( sender() );
 
  529   updateConstraintValue( constraint, textValue, 
false );
 
  532 void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
 
  534   QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
 
  538   CadConstraint *constraint = objectToConstraint( lineEdit );
 
  544   updateConstraintValue( constraint, lineEdit->text(), 
true );
 
  547 void QgsAdvancedDigitizingDockWidget::lockAdditionalConstraint( AdditionalConstraint constraint )
 
  549   mAdditionalConstraint = constraint;
 
  554 void QgsAdvancedDigitizingDockWidget::updateCapacity( 
bool updateUIwithoutChange )
 
  556   CadCapacities newCapacities = CadCapacities();
 
  558   if ( mCadPointList.count() > 1 )
 
  562   if ( mCadPointList.count() > 2 )
 
  566   if ( !updateUIwithoutChange && newCapacities == mCapacities )
 
  576   bool relativeAngle = mCadEnabled && newCapacities.testFlag( 
RelativeAngle );
 
  577   bool absoluteAngle = mCadEnabled && newCapacities.testFlag( 
AbsoluteAngle );
 
  580   mPerpendicularAction->setEnabled( absoluteAngle && snappingEnabled );
 
  581   mParallelAction->setEnabled( absoluteAngle && snappingEnabled );
 
  584   if ( !snappingEnabled )
 
  586     mPerpendicularAction->setToolTip( tr( 
"Snapping must be enabled to utilize perpendicular mode" ) );
 
  587     mParallelAction->setToolTip( tr( 
"Snapping must be enabled to utilize parallel mode" ) );
 
  591     mPerpendicularAction->setToolTip( 
"<b>" + tr( 
"Perpendicular" ) + 
"</b><br>(" + tr( 
"press p to switch between perpendicular, parallel and normal mode" ) + 
")" );
 
  592     mParallelAction->setToolTip( 
"<b>" + tr( 
"Parallel" ) + 
"</b><br>(" + tr( 
"press p to switch between perpendicular, parallel and normal mode" ) + 
")" );
 
  596   if ( !absoluteAngle )
 
  602   mLockAngleButton->setEnabled( absoluteAngle );
 
  603   mRelativeAngleButton->setEnabled( relativeAngle );
 
  604   mAngleLineEdit->setEnabled( absoluteAngle );
 
  606   if ( !absoluteAngle )
 
  610   if ( !relativeAngle )
 
  612     mAngleConstraint->setRelative( 
false );
 
  615   else if ( relativeAngle && !mCapacities.testFlag( 
RelativeAngle ) )
 
  618     mAngleConstraint->setRelative( 
true );
 
  623   mLockDistanceButton->setEnabled( relativeCoordinates );
 
  624   mDistanceLineEdit->setEnabled( relativeCoordinates );
 
  626   if ( !relativeCoordinates )
 
  631   mRelativeXButton->setEnabled( relativeCoordinates );
 
  632   mRelativeYButton->setEnabled( relativeCoordinates );
 
  635   mCapacities = newCapacities;
 
  644   constr.
value = 
c->value();
 
  653   context.
xConstraint = _constraint( mXConstraint.get() );
 
  654   context.
yConstraint = _constraint( mYConstraint.get() );
 
  665   bool res = output.
valid;
 
  667   mSnappedSegment.clear();
 
  672     mSnappedSegment << edgePt0 << edgePt1;
 
  689     mSnapIndicator->setMatch( output.
snapMatch );
 
  690     mSnapIndicator->setVisible( 
true );
 
  694     mSnapIndicator->setVisible( 
false );
 
  712   updateCurrentPoint( point );
 
  714   updateUnlockedConstraintValues( point );
 
  722     emit 
pushWarning( tr( 
"Some constraints are incompatible. Resulting point might be incorrect." ) );
 
  729 void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues( 
const QgsPointXY &point )
 
  731   bool previousPointExist, penulPointExist;
 
  736   if ( !mAngleConstraint->isLocked() && previousPointExist )
 
  739     if ( penulPointExist && mAngleConstraint->relative() )
 
  742       angle = std::atan2( previousPt.
y() - penultimatePt.
y(),
 
  743                           previousPt.
x() - penultimatePt.
x() );
 
  745     angle = ( std::atan2( point.
y() - previousPt.
y(),
 
  746                           point.
x() - previousPt.
x()
 
  747                         ) - 
angle ) * 180 / M_PI;
 
  750     mAngleConstraint->setValue( 
angle );
 
  753   if ( !mDistanceConstraint->isLocked() && previousPointExist )
 
  755     mDistanceConstraint->setValue( std::sqrt( previousPt.
sqrDist( point ) ) );
 
  758   if ( !mXConstraint->isLocked() )
 
  760     if ( previousPointExist && mXConstraint->relative() )
 
  762       mXConstraint->setValue( point.
x() - previousPt.
x() );
 
  766       mXConstraint->setValue( point.
x() );
 
  770   if ( !mYConstraint->isLocked() )
 
  772     if ( previousPointExist && mYConstraint->relative() )
 
  774       mYConstraint->setValue( point.
y() - previousPt.
y() );
 
  778       mYConstraint->setValue( point.
y() );
 
  784 QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers( 
const QgsPointXY &originalMapPoint, 
bool *snapped )
 const 
  799   match = snappingUtils->
snapToMap( originalMapPoint, 
nullptr, 
true );
 
  801   snappingUtils->
setConfig( canvasConfig );
 
  811     *snapped = 
segment.count() == 2;
 
  824   bool previousPointExist, penulPointExist, snappedSegmentExist;
 
  827   mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
 
  829   if ( !previousPointExist || !snappedSegmentExist )
 
  834   double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
 
  836   if ( mAngleConstraint->relative() && penulPointExist )
 
  838     angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
 
  848   mAngleConstraint->setValue( 
angle );
 
  849   mAngleConstraint->setLockMode( lockMode );
 
  867     case Qt::Key_Backspace:
 
  904     case Qt::Key_Backspace:
 
  927   const auto constPoints = points;
 
  934 bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
 
  938     return QgsDockWidget::eventFilter( obj, event );
 
  946   if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
 
  948     if ( QKeyEvent *keyEvent = 
dynamic_cast<QKeyEvent *
>( event ) )
 
  950       return filterKeyPress( keyEvent );
 
  953   return QgsDockWidget::eventFilter( obj, event );
 
  956 bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
 
  962   QEvent::Type type = e->type();
 
  968       if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
  970         mXConstraint->toggleLocked();
 
  975       else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
  979           mXConstraint->toggleRelative();
 
  986       else if ( type == QEvent::KeyPress )
 
  988         mXLineEdit->setFocus();
 
  989         mXLineEdit->selectAll();
 
  998       if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1000         mYConstraint->toggleLocked();
 
 1005       else if ( type == QEvent::ShortcutOverride &&  e->modifiers() == Qt::ShiftModifier )
 
 1009           mYConstraint->toggleRelative();
 
 1016       else if ( type == QEvent::KeyPress )
 
 1018         mYLineEdit->setFocus();
 
 1019         mYLineEdit->selectAll();
 
 1028       if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1032           mAngleConstraint->toggleLocked();
 
 1038       else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
 1042           mAngleConstraint->toggleRelative();
 
 1049       else if ( type == QEvent::KeyPress )
 
 1051         mAngleLineEdit->setFocus();
 
 1052         mAngleLineEdit->selectAll();
 
 1061       if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1065           mDistanceConstraint->toggleLocked();
 
 1072       else if ( type == QEvent::KeyPress )
 
 1074         mDistanceLineEdit->setFocus();
 
 1075         mDistanceLineEdit->selectAll();
 
 1083       if ( type == QEvent::KeyPress )
 
 1085         setConstructionMode( !mConstructionMode );
 
 1092       if ( type == QEvent::KeyPress )
 
 1094         bool parallel = mParallelAction->isChecked();
 
 1095         bool perpendicular = mPerpendicularAction->isChecked();
 
 1097         if ( !parallel && !perpendicular )
 
 1101         else if ( perpendicular )
 
 1121   return e->isAccepted();
 
 1129     mErrorLabel->setText( tr( 
"CAD tools can not be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 1130     mErrorLabel->show();
 
 1131     mEnableAction->setEnabled( 
false );
 
 1132     setCadEnabled( 
false );
 
 1136     mEnableAction->setEnabled( 
true );
 
 1137     mErrorLabel->hide();
 
 1140     mCurrentMapToolSupportsCad = 
true;
 
 1142     if ( mSessionActive && !isVisible() )
 
 1146     setCadEnabled( mSessionActive );
 
 1154   mEnableAction->setEnabled( 
false );
 
 1155   mErrorLabel->setText( tr( 
"CAD tools are not enabled for the current map tool" ) );
 
 1156   mErrorLabel->show();
 
 1159   mCurrentMapToolSupportsCad = 
false;
 
 1161   setCadEnabled( 
false );
 
 1166   mCadPaintItem->update();
 
 1173     mCadPointList << point;
 
 1177     mCadPointList.insert( 0, point );
 
 1190   mCadPointList.removeAt( i );
 
 1197   mCadPointList.clear();
 
 1198   mSnappedSegment.clear();
 
 1204 void QgsAdvancedDigitizingDockWidget::updateCurrentPoint( 
const QgsPointXY &point )
 
 1208     mCadPointList << point;
 
 1213     mCadPointList[0] = point;
 
 1222   mLockerButton->setChecked( mode == 
HardLock );
 
 1223   if ( mRepeatingLockButton )
 
 1227       mRepeatingLockButton->setEnabled( 
true );
 
 1231       mRepeatingLockButton->setChecked( 
false );
 
 1232       mRepeatingLockButton->setEnabled( 
false );
 
 1245   mRepeatingLock = repeating;
 
 1246   if ( mRepeatingLockButton )
 
 1247     mRepeatingLockButton->setChecked( repeating );
 
 1252   mRelative = relative;
 
 1253   if ( mRelativeButton )
 
 1255     mRelativeButton->setChecked( relative );
 
 1263     mLineEdit->setText( QLocale().toString( value, 
'f', 6 ) );
 
 1268   setLockMode( mLockMode == HardLock ? NoLock : HardLock );
 
 1273   setRelative( !mRelative );
 
 1281     return mCadPointList.value( 0 );
 
 1291     return mCadPointList.value( 1 );
 
 1301     return mCadPointList.value( 2 );
 
The QgsAdvancedDigitizingCanvasItem class draws the graphical elements of the CAD tools (.
The QgsAdvancedDigitizingFloater class is widget that floats next to the mouse pointer,...
void setActive(bool active)
Set whether the floater should be active or not.
bool active()
Whether the floater is active or not.
static QgsCadUtils::AlignMapPointOutput alignMapPoint(const QgsPointXY &originalMapPoint, const QgsCadUtils::AlignMapPointContext &ctx)
Applies X/Y/angle/distance constraints from the given context to a map point.
Class for parsing and evaluation of expressions (formerly called "search strings").
A event filter for watching for focus events on a parent object.
void focusOut()
Emitted when parent object loses focus.
Map canvas is a class for displaying all GIS data types on a canvas.
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
void destinationCrsChanged()
Emitted when map CRS has changed.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsPointXY originalMapPoint() const
Returns the original, unmodified map point of the mouse cursor.
void setMapPoint(const QgsPointXY &point)
Set the (snapped) point this event points to in map coordinates.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
A class to represent a 2D point.
double sqrDist(double x, double y) const SIP_HOLDGIL
Returns the squared distance between this point a specified x, y coordinate.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsSnappingConfig snappingConfig
Class that shows snapping marker on map canvas for the current snapping match.
This is a container for configuration of the snapping of the project.
@ AllLayers
On all vector layers.
@ SegmentFlag
On segments.
void setTypeFlag(QgsSnappingConfig::SnappingTypeFlag type)
define the type of snapping
void setMode(SnappingMode mode)
define the mode of snapping
bool enabled() const
Returns if snapping is enabled.
This class has all the configuration of snapping and can return answers to snapping queries.
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
QLineF segment(int index, QRectF rect, double radius)
Structure with details of one constraint.
bool locked
Whether the constraint is active, i.e. should be considered.
double value
Numeric value of the constraint (coordinate/distance in map units or angle in degrees)
bool relative
Whether the value is relative to previous value.
Structure defining all constraints for alignMapPoint() method.
QgsCadUtils::AlignMapPointConstraint yConstraint
Constraint for Y coordinate.
QgsCadUtils::AlignMapPointConstraint xConstraint
Constraint for X coordinate.
double mapUnitsPerPixel
Map units/pixel ratio from map canvas. Needed for.
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
QList< QgsPointXY > cadPointList
List of recent CAD points in map coordinates.
QgsSnappingUtils * snappingUtils
Snapping utils that will be used to snap point to map. Must not be nullptr.
QgsCadUtils::AlignMapPointConstraint commonAngleConstraint
Constraint for soft lock to a common angle.
QgsCadUtils::AlignMapPointConstraint angleConstraint
Constraint for angle.
Structure returned from alignMapPoint() method.
QgsPointXY finalMapPoint
map point aligned according to the constraints
bool valid
Whether the combination of constraints is actually valid.
QgsPointLocator::Match snapMatch
Snapped point - only valid if actually used for something.
double softLockCommonAngle
Angle (in degrees) to which we have soft-locked ourselves (if not set it is -1)
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
bool hasEdge() const
Returns true if the Match is an edge.
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
bool hasVertex() const
Returns true if the Match is a vertex.