QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsadvanceddigitizingdockwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsadvanceddigitizingdockwidget.cpp - dock for CAD tools
3  ----------------------
4  begin : October 2014
5  copyright : (C) Denis Rouzaud
6  email : [email protected]
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QMenu>
17 #include <QEvent>
18 #include <QCoreApplication>
19 
20 #include <cmath>
21 
25 #include "qgsapplication.h"
26 #include "qgscadutils.h"
27 #include "qgsexpression.h"
28 #include "qgslogger.h"
29 #include "qgsmapcanvas.h"
30 #include "qgsmaptooledit.h"
31 #include "qgsmaptoolcapture.h"
33 #include "qgsmessagebaritem.h"
34 #include "qgslinestring.h"
35 #include "qgsfocuswatcher.h"
36 #include "qgssettings.h"
37 #include "qgssnappingutils.h"
38 #include "qgsproject.h"
39 #include "qgsmapmouseevent.h"
40 #include "qgsmessagelog.h"
41 #include "qgsmeshlayer.h"
42 
43 #include <QActionGroup>
44 
45 
47  : QgsDockWidget( parent )
48  , mMapCanvas( canvas )
49  , mSnapIndicator( std::make_unique< QgsSnapIndicator>( canvas ) )
50  , mCommonAngleConstraint( QgsSettings().value( QStringLiteral( "/Cad/CommonAngle" ), 0.0 ).toDouble() )
51 {
52  setupUi( this );
53 
54  mCadPaintItem = new QgsAdvancedDigitizingCanvasItem( canvas, this );
55 
56  mAngleConstraint.reset( new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
57  mDistanceConstraint.reset( new CadConstraint( mDistanceLineEdit, mLockDistanceButton, nullptr, mRepeatingLockDistanceButton ) );
58  mXConstraint.reset( new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
59  mYConstraint.reset( new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
60  mZConstraint.reset( new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
61  mMConstraint.reset( new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
62 
63  mLineExtensionConstraint.reset( new CadConstraint( new QLineEdit(), new QToolButton() ) );
64  mXyVertexConstraint.reset( new CadConstraint( new QLineEdit(), new QToolButton() ) );
65 
66  mBetweenLineConstraint = Qgis::BetweenLineConstraint::NoConstraint;
67 
68  mMapCanvas->installEventFilter( this );
69  mAngleLineEdit->installEventFilter( this );
70  mDistanceLineEdit->installEventFilter( this );
71  mXLineEdit->installEventFilter( this );
72  mYLineEdit->installEventFilter( this );
73  mZLineEdit->installEventFilter( this );
74  mMLineEdit->installEventFilter( this );
75 
76  // Connect the UI to the event filter to update constraints
77  connect( mEnableAction, &QAction::triggered, this, &QgsAdvancedDigitizingDockWidget::activateCad );
78  connect( mConstructionModeAction, &QAction::triggered, this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
79  connect( mParallelAction, &QAction::triggered, this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
80  connect( mPerpendicularAction, &QAction::triggered, this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
81  connect( mLockAngleButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
82  connect( mLockDistanceButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
83  connect( mLockXButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
84  connect( mLockYButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
85  connect( mLockZButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
86  connect( mLockMButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
87  connect( mRelativeAngleButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
88  connect( mRelativeXButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
89  connect( mRelativeYButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
90  connect( mRelativeZButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
91  connect( mRelativeMButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
92  connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
93  connect( mRepeatingLockAngleButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
94  connect( mRepeatingLockXButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
95  connect( mRepeatingLockYButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
96  connect( mRepeatingLockZButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
97  connect( mRepeatingLockMButton, &QAbstractButton::clicked, this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
98  connect( mAngleLineEdit, &QLineEdit::returnPressed, this, [ = ]() { lockConstraint(); } );
99  connect( mDistanceLineEdit, &QLineEdit::returnPressed, this, [ = ]() { lockConstraint(); } );
100  connect( mXLineEdit, &QLineEdit::returnPressed, this, [ = ]() { lockConstraint(); } );
101  connect( mYLineEdit, &QLineEdit::returnPressed, this, [ = ]() { lockConstraint(); } );
102  connect( mZLineEdit, &QLineEdit::returnPressed, this, [ = ]() { lockConstraint(); } );
103  connect( mMLineEdit, &QLineEdit::returnPressed, this, [ = ]() { lockConstraint(); } );
104  connect( mAngleLineEdit, &QLineEdit::textEdited, this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
105  connect( mDistanceLineEdit, &QLineEdit::textEdited, this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
106  connect( mXLineEdit, &QLineEdit::textEdited, this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
107  connect( mYLineEdit, &QLineEdit::textEdited, this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
108  connect( mZLineEdit, &QLineEdit::textEdited, this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
109  connect( mMLineEdit, &QLineEdit::textEdited, this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
110  //also watch for focus out events on these widgets
111  QgsFocusWatcher *angleWatcher = new QgsFocusWatcher( mAngleLineEdit );
112  connect( angleWatcher, &QgsFocusWatcher::focusOut, this, &QgsAdvancedDigitizingDockWidget::constraintFocusOut );
113  QgsFocusWatcher *distanceWatcher = new QgsFocusWatcher( mDistanceLineEdit );
114  connect( distanceWatcher, &QgsFocusWatcher::focusOut, this, &QgsAdvancedDigitizingDockWidget::constraintFocusOut );
115  QgsFocusWatcher *xWatcher = new QgsFocusWatcher( mXLineEdit );
116  connect( xWatcher, &QgsFocusWatcher::focusOut, this, &QgsAdvancedDigitizingDockWidget::constraintFocusOut );
117  QgsFocusWatcher *yWatcher = new QgsFocusWatcher( mYLineEdit );
118  connect( yWatcher, &QgsFocusWatcher::focusOut, this, &QgsAdvancedDigitizingDockWidget::constraintFocusOut );
119  QgsFocusWatcher *zWatcher = new QgsFocusWatcher( mZLineEdit );
120  connect( zWatcher, &QgsFocusWatcher::focusOut, this, &QgsAdvancedDigitizingDockWidget::constraintFocusOut );
121  QgsFocusWatcher *mWatcher = new QgsFocusWatcher( mMLineEdit );
122  connect( mWatcher, &QgsFocusWatcher::focusOut, this, &QgsAdvancedDigitizingDockWidget::constraintFocusOut );
123 
124  // config menu
125  QMenu *menu = new QMenu( this );
126  // common angles
127  QActionGroup *angleButtonGroup = new QActionGroup( menu ); // actions are exclusive for common angles
128  mCommonAngleActions = QMap<QAction *, double>();
129  QList< QPair< double, QString > > commonAngles;
130  QString menuText;
131  const QList<double> anglesDouble( { 0.0, 5.0, 10.0, 15.0, 18.0, 22.5, 30.0, 45.0, 90.0} );
132  for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
133  {
134  if ( *it == 0 )
135  menuText = tr( "Do Not Snap to Common Angles" );
136  else
137  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 );
138  commonAngles << QPair<double, QString>( *it, menuText );
139  }
140  for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
141  {
142  QAction *action = new QAction( it->second, menu );
143  action->setCheckable( true );
144  action->setChecked( it->first == mCommonAngleConstraint );
145  menu->addAction( action );
146  angleButtonGroup->addAction( action );
147  mCommonAngleActions.insert( action, it->first );
148  }
149 
150  qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
151  mSettingsAction->setMenu( menu );
152  mSettingsAction->setCheckable( true );
153  mSettingsAction->setToolTip( tr( "Snap to common angles" ) );
154  mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
155  connect( menu, &QMenu::triggered, this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
156 
157  // Construction modes
158  QMenu *constructionMenu = new QMenu( this );
159 
160  mLineExtensionAction = new QAction( "Line Extension", constructionMenu );
161  mLineExtensionAction->setCheckable( true );
162  constructionMenu->addAction( mLineExtensionAction );
163  connect( mLineExtensionAction, &QAction::triggered, this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
164 
165  mXyVertexAction = new QAction( "X/Y Point", constructionMenu );
166  mXyVertexAction->setCheckable( true );
167  constructionMenu->addAction( mXyVertexAction );
168  connect( mXyVertexAction, &QAction::triggered, this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
169 
170  auto constructionToolBar = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionAction ) );
171  constructionToolBar->setPopupMode( QToolButton::InstantPopup );
172  constructionToolBar->setMenu( constructionMenu );
173  constructionToolBar->setObjectName( QStringLiteral( "ConstructionButton" ) );
174 
175  mConstructionAction->setMenu( menu );
176  mConstructionAction->setCheckable( true );
177  mConstructionAction->setToolTip( tr( "Construction Tools" ) );
178 // connect( constructionMenu, &QMenu::triggered, this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
179 
180  // set tooltips
181  mConstructionModeAction->setToolTip( "<b>" + tr( "Construction mode" ) + "</b><br>(" + tr( "press c to toggle on/off" ) + ")" );
182  mDistanceLineEdit->setToolTip( "<b>" + tr( "Distance" ) + "</b><br>(" + tr( "press d for quick access" ) + ")" );
183  mLockDistanceButton->setToolTip( "<b>" + tr( "Lock distance" ) + "</b><br>(" + tr( "press Ctrl + d for quick access" ) + ")" );
184  mRepeatingLockDistanceButton->setToolTip( "<b>" + tr( "Continuously lock distance" ) + "</b>" );
185 
186  mRelativeAngleButton->setToolTip( "<b>" + tr( "Toggles relative angle to previous segment" ) + "</b><br>(" + tr( "press Shift + a for quick access" ) + ")" );
187  mAngleLineEdit->setToolTip( "<b>" + tr( "Angle" ) + "</b><br>(" + tr( "press a for quick access" ) + ")" );
188  mLockAngleButton->setToolTip( "<b>" + tr( "Lock angle" ) + "</b><br>(" + tr( "press Ctrl + a for quick access" ) + ")" );
189  mRepeatingLockAngleButton->setToolTip( "<b>" + tr( "Continuously lock angle" ) + "</b>" );
190 
191  mRelativeXButton->setToolTip( "<b>" + tr( "Toggles relative x to previous node" ) + "</b><br>(" + tr( "press Shift + x for quick access" ) + ")" );
192  mXLineEdit->setToolTip( "<b>" + tr( "X coordinate" ) + "</b><br>(" + tr( "press x for quick access" ) + ")" );
193  mLockXButton->setToolTip( "<b>" + tr( "Lock x coordinate" ) + "</b><br>(" + tr( "press Ctrl + x for quick access" ) + ")" );
194  mRepeatingLockXButton->setToolTip( "<b>" + tr( "Continuously lock x coordinate" ) + "</b>" );
195 
196  mRelativeYButton->setToolTip( "<b>" + tr( "Toggles relative y to previous node" ) + "</b><br>(" + tr( "press Shift + y for quick access" ) + ")" );
197  mYLineEdit->setToolTip( "<b>" + tr( "Y coordinate" ) + "</b><br>(" + tr( "press y for quick access" ) + ")" );
198  mLockYButton->setToolTip( "<b>" + tr( "Lock y coordinate" ) + "</b><br>(" + tr( "press Ctrl + y for quick access" ) + ")" );
199  mRepeatingLockYButton->setToolTip( "<b>" + tr( "Continuously lock y coordinate" ) + "</b>" );
200 
201  mRelativeZButton->setToolTip( "<b>" + tr( "Toggles relative z to previous node" ) + "</b><br>(" + tr( "press Shift + z for quick access" ) + ")" );
202  mZLineEdit->setToolTip( "<b>" + tr( "Z coordinate" ) + "</b><br>(" + tr( "press z for quick access" ) + ")" );
203  mLockZButton->setToolTip( "<b>" + tr( "Lock z coordinate" ) + "</b><br>(" + tr( "press Ctrl + z for quick access" ) + ")" );
204  mRepeatingLockZButton->setToolTip( "<b>" + tr( "Continuously lock z coordinate" ) + "</b>" );
205 
206  mRelativeMButton->setToolTip( "<b>" + tr( "Toggles relative m to previous node" ) + "</b><br>(" + tr( "press Shift + m for quick access" ) + ")" );
207  mMLineEdit->setToolTip( "<b>" + tr( "M coordinate" ) + "</b><br>(" + tr( "press m for quick access" ) + ")" );
208  mLockMButton->setToolTip( "<b>" + tr( "Lock m coordinate" ) + "</b><br>(" + tr( "press Ctrl + m for quick access" ) + ")" );
209  mRepeatingLockMButton->setToolTip( "<b>" + tr( "Continuously lock m coordinate" ) + "</b>" );
210 
211  // Create the slots/signals
212  connect( mXLineEdit, &QLineEdit::textChanged, this, &QgsAdvancedDigitizingDockWidget::valueXChanged );
213  connect( mYLineEdit, &QLineEdit::textChanged, this, &QgsAdvancedDigitizingDockWidget::valueYChanged );
214  connect( mZLineEdit, &QLineEdit::textChanged, this, &QgsAdvancedDigitizingDockWidget::valueZChanged );
215  connect( mMLineEdit, &QLineEdit::textChanged, this, &QgsAdvancedDigitizingDockWidget::valueMChanged );
216  connect( mDistanceLineEdit, &QLineEdit::textChanged, this, &QgsAdvancedDigitizingDockWidget::valueDistanceChanged );
217  connect( mAngleLineEdit, &QLineEdit::textChanged, this, &QgsAdvancedDigitizingDockWidget::valueAngleChanged );
218 
219  // Create the floater
220  mFloater = new QgsAdvancedDigitizingFloater( canvas, this );
221  connect( mToggleFloaterAction, &QAction::triggered, mFloater, &QgsAdvancedDigitizingFloater::setActive );
222  mToggleFloaterAction->setChecked( mFloater->active() );
223 
224  updateCapacity( true );
225  connect( QgsProject::instance(), &QgsProject::snappingConfigChanged, this, [ = ] { updateCapacity( true ); } );
226 
227  disable();
228 }
229 
230 void QgsAdvancedDigitizingDockWidget::setX( const QString &value, WidgetSetMode mode )
231 {
232  mXLineEdit->setText( value );
233  if ( mode == WidgetSetMode::ReturnPressed )
234  {
235  emit mXLineEdit->returnPressed();
236  }
237  else if ( mode == WidgetSetMode::FocusOut )
238  {
239  QEvent *e = new QEvent( QEvent::FocusOut );
240  QCoreApplication::postEvent( mXLineEdit, e );
241  }
242  else if ( mode == WidgetSetMode::TextEdited )
243  {
244  emit mXLineEdit->textEdited( value );
245  }
246 }
247 void QgsAdvancedDigitizingDockWidget::setY( const QString &value, WidgetSetMode mode )
248 {
249  mYLineEdit->setText( value );
250  if ( mode == WidgetSetMode::ReturnPressed )
251  {
252  emit mYLineEdit->returnPressed();
253  }
254  else if ( mode == WidgetSetMode::FocusOut )
255  {
256  QEvent *e = new QEvent( QEvent::FocusOut );
257  QCoreApplication::postEvent( mYLineEdit, e );
258  }
259  else if ( mode == WidgetSetMode::TextEdited )
260  {
261  emit mYLineEdit->textEdited( value );
262  }
263 }
264 void QgsAdvancedDigitizingDockWidget::setZ( const QString &value, WidgetSetMode mode )
265 {
266  mZLineEdit->setText( value );
267  if ( mode == WidgetSetMode::ReturnPressed )
268  {
269  emit mZLineEdit->returnPressed();
270  }
271  else if ( mode == WidgetSetMode::FocusOut )
272  {
273  QEvent *e = new QEvent( QEvent::FocusOut );
274  QCoreApplication::postEvent( mZLineEdit, e );
275  }
276  else if ( mode == WidgetSetMode::TextEdited )
277  {
278  emit mZLineEdit->textEdited( value );
279  }
280 }
281 void QgsAdvancedDigitizingDockWidget::setM( const QString &value, WidgetSetMode mode )
282 {
283  mMLineEdit->setText( value );
284  if ( mode == WidgetSetMode::ReturnPressed )
285  {
286  emit mMLineEdit->returnPressed();
287  }
288  else if ( mode == WidgetSetMode::FocusOut )
289  {
290  QEvent *e = new QEvent( QEvent::FocusOut );
291  QCoreApplication::postEvent( mMLineEdit, e );
292  }
293  else if ( mode == WidgetSetMode::TextEdited )
294  {
295  emit mMLineEdit->textEdited( value );
296  }
297 }
299 {
300  mAngleLineEdit->setText( value );
301  if ( mode == WidgetSetMode::ReturnPressed )
302  {
303  emit mAngleLineEdit->returnPressed();
304  }
305  else if ( mode == WidgetSetMode::FocusOut )
306  {
307  emit mAngleLineEdit->textEdited( value );
308  }
309 }
311 {
312  mDistanceLineEdit->setText( value );
313  if ( mode == WidgetSetMode::ReturnPressed )
314  {
315  emit mDistanceLineEdit->returnPressed();
316  }
317  else if ( mode == WidgetSetMode::FocusOut )
318  {
319  QEvent *e = new QEvent( QEvent::FocusOut );
320  QCoreApplication::postEvent( mDistanceLineEdit, e );
321  }
322  else if ( mode == WidgetSetMode::TextEdited )
323  {
324  emit mDistanceLineEdit->textEdited( value );
325  }
326 }
327 
328 
329 void QgsAdvancedDigitizingDockWidget::setCadEnabled( bool enabled )
330 {
331  mCadEnabled = enabled;
332  mEnableAction->setChecked( enabled );
333  mConstructionModeAction->setEnabled( enabled );
334  mSettingsAction->setEnabled( enabled );
335  mInputWidgets->setEnabled( enabled );
336  mToggleFloaterAction->setEnabled( enabled );
337  mConstructionAction->setEnabled( enabled );
338 
339  if ( !enabled )
340  {
341  // uncheck at deactivation
342  mLineExtensionAction->setChecked( false );
343  mXyVertexAction->setChecked( false );
344  // will be reactivated in updateCapacities
345  mParallelAction->setEnabled( false );
346  mPerpendicularAction->setEnabled( false );
347  }
348 
349 
350  clear();
352  setConstructionMode( false );
353 
354  switchZM();
355  emit cadEnabledChanged( enabled );
356 
357  mLastSnapMatch = QgsPointLocator::Match();
358 }
359 
360 
362 {
363  bool enableZ = false;
364  bool enableM = false;
365 
366  if ( QgsMapLayer *layer = targetLayer() )
367  {
368  switch ( layer->type() )
369  {
371  {
372  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer );
373  const QgsWkbTypes::Type type = vlayer->wkbType();
374  enableZ = QgsWkbTypes::hasZ( type );
375  enableM = QgsWkbTypes::hasM( type );
376  break;
377  }
378 
380  {
381  QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
382  enableZ = mlayer->isEditable();
383  break;
384  }
385 
392  break;
393  }
394  }
395 
396  setEnabledZ( enableZ );
397  setEnabledM( enableM );
398 }
399 
401 {
402  mRelativeZButton->setEnabled( enable );
403  mZLabel->setEnabled( enable );
404  mZLineEdit->setEnabled( enable );
405  if ( mZLineEdit->isEnabled() )
406  mZLineEdit->setText( QLocale().toString( QgsMapToolEdit::defaultZValue(), 'f', 6 ) );
407  else
408  mZLineEdit->clear();
409  mLockZButton->setEnabled( enable );
410  emit enabledChangedZ( enable );
411 }
412 
414 {
415  mRelativeMButton->setEnabled( enable );
416  mMLabel->setEnabled( enable );
417  mMLineEdit->setEnabled( enable );
418  if ( mMLineEdit->isEnabled() )
419  mMLineEdit->setText( QLocale().toString( QgsMapToolEdit::defaultMValue(), 'f', 6 ) );
420  else
421  mMLineEdit->clear();
422  mLockMButton->setEnabled( enable );
423  emit enabledChangedM( enable );
424 }
425 
426 void QgsAdvancedDigitizingDockWidget::activateCad( bool enabled )
427 {
428  enabled &= mCurrentMapToolSupportsCad;
429 
430  mSessionActive = enabled;
431 
432  if ( enabled && !isVisible() )
433  {
434  show();
435  }
436 
437  setCadEnabled( enabled );
438 }
439 
440 void QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked( bool activated )
441 {
442  if ( !activated )
443  {
444  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::NoConstraint );
445  }
446  else if ( sender() == mParallelAction )
447  {
448  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::Parallel );
449  }
450  else if ( sender() == mPerpendicularAction )
451  {
452  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::Perpendicular );
453  }
454 }
455 
456 void QgsAdvancedDigitizingDockWidget::setConstraintRelative( bool activate )
457 {
458  if ( sender() == mRelativeAngleButton )
459  {
460  mAngleConstraint->setRelative( activate );
461  emit relativeAngleChanged( activate );
462  }
463  else if ( sender() == mRelativeXButton )
464  {
465  mXConstraint->setRelative( activate );
466  emit relativeXChanged( activate );
467  }
468  else if ( sender() == mRelativeYButton )
469  {
470  mYConstraint->setRelative( activate );
471  emit relativeYChanged( activate );
472  }
473  else if ( sender() == mRelativeZButton )
474  {
475  mZConstraint->setRelative( activate );
476  emit relativeZChanged( activate );
477  }
478  else if ( sender() == mRelativeMButton )
479  {
480  mMConstraint->setRelative( activate );
481  emit relativeMChanged( activate );
482  }
483 }
484 
485 void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock( bool activate )
486 {
487  if ( sender() == mRepeatingLockDistanceButton )
488  {
489  mDistanceConstraint->setRepeatingLock( activate );
490  }
491  else if ( sender() == mRepeatingLockAngleButton )
492  {
493  mAngleConstraint->setRepeatingLock( activate );
494  }
495  else if ( sender() == mRepeatingLockXButton )
496  {
497  mXConstraint->setRepeatingLock( activate );
498  }
499  else if ( sender() == mRepeatingLockYButton )
500  {
501  mYConstraint->setRepeatingLock( activate );
502  }
503  else if ( sender() == mRepeatingLockZButton )
504  {
505  mZConstraint->setRepeatingLock( activate );
506  }
507  else if ( sender() == mRepeatingLockMButton )
508  {
509  mMConstraint->setRepeatingLock( activate );
510  }
511 }
512 
513 void QgsAdvancedDigitizingDockWidget::setConstructionMode( bool enabled )
514 {
515  mConstructionMode = enabled;
516  mConstructionModeAction->setChecked( enabled );
517 }
518 
519 void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
520 {
521  // common angles
522  const QMap<QAction *, double>::const_iterator ica = mCommonAngleActions.constFind( action );
523  if ( ica != mCommonAngleActions.constEnd() )
524  {
525  ica.key()->setChecked( true );
526  mCommonAngleConstraint = ica.value();
527  QgsSettings().setValue( QStringLiteral( "/Cad/CommonAngle" ), ica.value() );
528  mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
529  return;
530  }
531 }
532 
533 QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer() const
534 {
535  if ( QgsMapToolAdvancedDigitizing *advancedTool = qobject_cast< QgsMapToolAdvancedDigitizing * >( mMapCanvas->mapTool() ) )
536  {
537  return advancedTool->layer();
538  }
539  else
540  {
541  return mMapCanvas->currentLayer();
542  }
543 }
544 
545 void QgsAdvancedDigitizingDockWidget::releaseLocks( bool releaseRepeatingLocks )
546 {
547  // release all locks except construction mode
548 
549  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::NoConstraint );
550 
551  if ( releaseRepeatingLocks )
552  {
553  mXyVertexAction->setChecked( false );
554  mXyVertexConstraint->setLockMode( CadConstraint::NoLock );
555  emit softLockXyChanged( false );
556 
557  mLineExtensionAction->setChecked( false );
558  mLineExtensionConstraint->setLockMode( CadConstraint::NoLock );
559  emit softLockLineExtensionChanged( false );
560 
562  }
563 
564  if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
565  {
566  mAngleConstraint->setLockMode( CadConstraint::NoLock );
567  emit lockAngleChanged( false );
568  }
569  if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
570  {
571  mDistanceConstraint->setLockMode( CadConstraint::NoLock );
572  emit lockDistanceChanged( false );
573  }
574  if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
575  {
576  mXConstraint->setLockMode( CadConstraint::NoLock );
577  emit lockXChanged( false );
578  }
579  if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
580  {
581  mYConstraint->setLockMode( CadConstraint::NoLock );
582  emit lockYChanged( false );
583  }
584  if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
585  {
586  mZConstraint->setLockMode( CadConstraint::NoLock );
587  emit lockZChanged( false );
588  }
589  if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
590  {
591  mMConstraint->setLockMode( CadConstraint::NoLock );
592  emit lockMChanged( false );
593  }
594 
595  if ( !mCadPointList.empty() )
596  {
597  if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
598  {
599  mXConstraint->setValue( mCadPointList.constLast().x(), true );
600  }
601  if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
602  {
603  mYConstraint->setValue( mCadPointList.constLast().y(), true );
604  }
605  if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
606  {
607  mZConstraint->setValue( mCadPointList.constLast().z(), true );
608  }
609  if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
610  {
611  mMConstraint->setValue( mCadPointList.constLast().m(), true );
612  }
613  }
614 
615 }
616 
617 #if 0
618 void QgsAdvancedDigitizingDockWidget::emit pointChanged()
619 {
620  // run a fake map mouse event to update the paint item
621  QPoint globalPos = mMapCanvas->cursor().pos();
622  QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
623  QMouseEvent *e = new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
624  mCurrentMapTool->canvasMoveEvent( e );
625 }
626 #endif
627 
628 QgsAdvancedDigitizingDockWidget::CadConstraint *QgsAdvancedDigitizingDockWidget::objectToConstraint( const QObject *obj ) const
629 {
630  CadConstraint *constraint = nullptr;
631  if ( obj == mAngleLineEdit || obj == mLockAngleButton )
632  {
633  constraint = mAngleConstraint.get();
634  }
635  else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
636  {
637  constraint = mDistanceConstraint.get();
638  }
639  else if ( obj == mXLineEdit || obj == mLockXButton )
640  {
641  constraint = mXConstraint.get();
642  }
643  else if ( obj == mYLineEdit || obj == mLockYButton )
644  {
645  constraint = mYConstraint.get();
646  }
647  else if ( obj == mZLineEdit || obj == mLockZButton )
648  {
649  constraint = mZConstraint.get();
650  }
651  else if ( obj == mMLineEdit || obj == mLockMButton )
652  {
653  constraint = mMConstraint.get();
654  }
655  else if ( obj == mLineExtensionAction )
656  {
657  constraint = mLineExtensionConstraint.get();
658  }
659  else if ( obj == mXyVertexAction )
660  {
661  constraint = mXyVertexConstraint.get();
662  }
663  return constraint;
664 }
665 
666 double QgsAdvancedDigitizingDockWidget::parseUserInput( const QString &inputValue, bool &ok ) const
667 {
668  ok = false;
669  double value = qgsPermissiveToDouble( inputValue, ok );
670  if ( ok )
671  {
672  return value;
673  }
674  else
675  {
676  // try to evaluate expression
677  QgsExpression expr( inputValue );
678  const QVariant result = expr.evaluate();
679  if ( expr.hasEvalError() )
680  {
681  ok = false;
682  QString inputValueC { inputValue };
683 
684  // First: try removing group separator
685  if ( inputValue.contains( QLocale().groupSeparator() ) )
686  {
687  inputValueC.remove( QLocale().groupSeparator() );
688  QgsExpression exprC( inputValueC );
689  const QVariant resultC = exprC.evaluate();
690  if ( ! exprC.hasEvalError() )
691  {
692  value = resultC.toDouble( &ok );
693  }
694  }
695 
696  // Second: be nice with non-dot locales
697  if ( !ok && QLocale().decimalPoint() != QChar( '.' ) && inputValueC.contains( QLocale().decimalPoint() ) )
698  {
699  QgsExpression exprC( inputValueC .replace( QLocale().decimalPoint(), QChar( '.' ) ) );
700  const QVariant resultC = exprC.evaluate();
701  if ( ! exprC.hasEvalError() )
702  {
703  value = resultC.toDouble( &ok );
704  }
705  }
706  }
707  else
708  {
709  value = result.toDouble( &ok );
710  }
711  return value;
712  }
713 }
714 
715 void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint, const QString &textValue, bool convertExpression )
716 {
717  if ( !constraint || textValue.isEmpty() )
718  {
719  return;
720  }
721 
722  if ( constraint->lockMode() == CadConstraint::NoLock )
723  return;
724 
725  bool ok;
726  const double value = parseUserInput( textValue, ok );
727  if ( !ok )
728  return;
729 
730  constraint->setValue( value, convertExpression );
731  // run a fake map mouse event to update the paint item
732  emit pointChangedV2( mCadPointList.value( 0 ) );
733 }
734 
735 void QgsAdvancedDigitizingDockWidget::lockConstraint( bool activate /* default true */ )
736 {
737  CadConstraint *constraint = objectToConstraint( sender() );
738  if ( !constraint )
739  {
740  return;
741  }
742 
743  if ( activate )
744  {
745  const QString textValue = constraint->lineEdit()->text();
746  if ( !textValue.isEmpty() )
747  {
748  bool ok;
749  const double value = parseUserInput( textValue, ok );
750  if ( ok )
751  {
752  constraint->setValue( value );
753  }
754  else
755  {
756  activate = false;
757  }
758  }
759  else
760  {
761  activate = false;
762  }
763  }
764  constraint->setLockMode( activate ? CadConstraint::HardLock : CadConstraint::NoLock );
765 
766  if ( constraint == mXConstraint.get() )
767  {
768  emit lockXChanged( activate );
769  }
770  else if ( constraint == mYConstraint.get() )
771  {
772  emit lockYChanged( activate );
773  }
774  else if ( constraint == mZConstraint.get() )
775  {
776  emit lockZChanged( activate );
777  }
778  else if ( constraint == mMConstraint.get() )
779  {
780  emit lockMChanged( activate );
781  }
782  else if ( constraint == mDistanceConstraint.get() )
783  {
784  emit lockDistanceChanged( activate );
785  }
786  else if ( constraint == mAngleConstraint.get() )
787  {
788  emit lockAngleChanged( activate );
789  }
790 
791  if ( activate )
792  {
793  // deactivate perpendicular/parallel if angle has been activated
794  if ( constraint == mAngleConstraint.get() )
795  {
796  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::NoConstraint );
797  }
798 
799  // run a fake map mouse event to update the paint item
800  emit pointChangedV2( mCadPointList.value( 0 ) );
801  }
802 }
803 
804 void QgsAdvancedDigitizingDockWidget::constraintTextEdited( const QString &textValue )
805 {
806  CadConstraint *constraint = objectToConstraint( sender() );
807  if ( !constraint )
808  {
809  return;
810  }
811 
812  updateConstraintValue( constraint, textValue, false );
813 }
814 
815 void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
816 {
817  QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
818  if ( !lineEdit )
819  return;
820 
821  CadConstraint *constraint = objectToConstraint( lineEdit );
822  if ( !constraint )
823  {
824  return;
825  }
826 
827  updateConstraintValue( constraint, lineEdit->text(), true );
828 }
829 
830 void QgsAdvancedDigitizingDockWidget::lockBetweenLineConstraint( Qgis::BetweenLineConstraint constraint )
831 {
832  mBetweenLineConstraint = constraint;
833  mPerpendicularAction->setChecked( constraint == Qgis::BetweenLineConstraint::Perpendicular );
834  mParallelAction->setChecked( constraint == Qgis::BetweenLineConstraint::Parallel );
835 }
836 
837 void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint( bool activate /* default true */ )
838 {
839  CadConstraint *constraint = objectToConstraint( sender() );
840  if ( !constraint )
841  {
842  return;
843  }
844 
845  constraint->setLockMode( activate ? CadConstraint::SoftLock : CadConstraint::NoLock );
846 
847  if ( constraint == mXyVertexConstraint.get() )
848  {
849  emit softLockXyChanged( activate );
850  }
851  else if ( constraint == mLineExtensionConstraint.get() )
852  {
853  emit softLockLineExtensionChanged( activate );
854  }
855 
856  if ( activate )
857  {
858  // run a fake map mouse event to update the paint item
859  emit pointChangedV2( mCadPointList.value( 0 ) );
860  }
861 
862  clearLockedSnapVertices( false );
863 }
864 
865 void QgsAdvancedDigitizingDockWidget::updateCapacity( bool updateUIwithoutChange )
866 {
867  CadCapacities newCapacities = CadCapacities();
868  const bool isGeographic = mMapCanvas->mapSettings().destinationCrs().isGeographic();
869 
870  // first point is the mouse point (it doesn't count)
871  if ( mCadPointList.count() > 1 )
872  {
873  newCapacities |= RelativeCoordinates;
874  if ( !isGeographic )
875  {
876  newCapacities |= AbsoluteAngle;
877  newCapacities |= Distance;
878  }
879  }
880  if ( mCadPointList.count() > 2 )
881  {
882  if ( !isGeographic )
883  newCapacities |= RelativeAngle;
884  }
885  if ( !updateUIwithoutChange && newCapacities == mCapacities )
886  {
887  return;
888  }
889 
890  const bool snappingEnabled = QgsProject::instance()->snappingConfig().enabled();
891 
892  // update the UI according to new capacities
893  // still keep the old to compare
894 
895  const bool distance = mCadEnabled && newCapacities.testFlag( Distance );
896  const bool relativeAngle = mCadEnabled && newCapacities.testFlag( RelativeAngle );
897  const bool absoluteAngle = mCadEnabled && newCapacities.testFlag( AbsoluteAngle );
898  const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag( RelativeCoordinates );
899 
900  mPerpendicularAction->setEnabled( distance && snappingEnabled );
901  mParallelAction->setEnabled( distance && snappingEnabled );
902 
903  mLineExtensionAction->setEnabled( snappingEnabled );
904  mXyVertexAction->setEnabled( snappingEnabled );
905  clearLockedSnapVertices( false );
906 
907  //update tooltips on buttons
908  if ( !snappingEnabled )
909  {
910  mPerpendicularAction->setToolTip( tr( "Snapping must be enabled to utilize perpendicular mode." ) );
911  mParallelAction->setToolTip( tr( "Snapping must be enabled to utilize parallel mode." ) );
912  mLineExtensionAction->setToolTip( tr( "Snapping must be enabled to utilize line extension mode." ) );
913  mXyVertexAction->setToolTip( tr( "Snapping must be enabled to utilize xy point mode." ) );
914  }
915  else if ( mCadPointList.count() <= 1 )
916  {
917  mPerpendicularAction->setToolTip( tr( "A first vertex should be drawn to utilize perpendicular mode." ) );
918  mParallelAction->setToolTip( tr( "A first vertex should be drawn to utilize parallel mode." ) );
919  }
920  else if ( isGeographic )
921  {
922  mPerpendicularAction->setToolTip( tr( "Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
923  mParallelAction->setToolTip( tr( "Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
924  }
925  else
926  {
927  mPerpendicularAction->setToolTip( "<b>" + tr( "Perpendicular" ) + "</b><br>(" + tr( "press p to switch between perpendicular, parallel and normal mode" ) + ")" );
928  mParallelAction->setToolTip( "<b>" + tr( "Parallel" ) + "</b><br>(" + tr( "press p to switch between perpendicular, parallel and normal mode" ) + ")" );
929  }
930 
931 
932  if ( !absoluteAngle )
933  {
934  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::NoConstraint );
935  }
936 
937  // absolute angle = azimuth, relative = from previous line
938  mLockAngleButton->setEnabled( absoluteAngle );
939  mRelativeAngleButton->setEnabled( relativeAngle );
940  mAngleLineEdit->setEnabled( absoluteAngle );
941  emit enabledChangedAngle( absoluteAngle );
942  if ( !absoluteAngle )
943  {
944  mAngleConstraint->setLockMode( CadConstraint::NoLock );
945  }
946  if ( !relativeAngle )
947  {
948  mAngleConstraint->setRelative( false );
949  emit relativeAngleChanged( false );
950  }
951  else if ( relativeAngle && !mCapacities.testFlag( RelativeAngle ) )
952  {
953  // set angle mode to relative if can do and wasn't available before
954  mAngleConstraint->setRelative( true );
955  emit relativeAngleChanged( true );
956  }
957 
958  // distance is always relative
959  mLockDistanceButton->setEnabled( distance && relativeCoordinates );
960  mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
961  emit enabledChangedDistance( distance && relativeCoordinates );
962  if ( !( distance && relativeCoordinates ) )
963  {
964  mDistanceConstraint->setLockMode( CadConstraint::NoLock );
965  }
966 
967  mRelativeXButton->setEnabled( relativeCoordinates );
968  mRelativeYButton->setEnabled( relativeCoordinates );
969  mRelativeZButton->setEnabled( relativeCoordinates );
970  mRelativeMButton->setEnabled( relativeCoordinates );
971 
972  // update capacities
973  mCapacities = newCapacities;
974  mCadPaintItem->updatePosition();
975 }
976 
977 
979 {
981  constr.locked = c->isLocked();
982  constr.relative = c->relative();
983  constr.value = c->value();
984  return constr;
985 }
986 
987 void QgsAdvancedDigitizingDockWidget::toggleLockedSnapVertex( const QgsPointLocator::Match &snapMatch, QgsPointLocator::Match previouslySnap )
988 {
989  // do nothing if not activated
990  if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
991  {
992  return;
993  }
994 
995  // if the first is same actual, not toggle if previously snapped
996  const int lastIndex = mLockedSnapVertices.length() - 1;
997  for ( int i = lastIndex ; i >= 0; --i )
998  {
999  if ( mLockedSnapVertices[i].point() == snapMatch.point() )
1000  {
1001  if ( snapMatch.point() != previouslySnap.point() )
1002  {
1003  mLockedSnapVertices.removeAt( i );
1004  }
1005  return;
1006  }
1007  }
1008 
1009  if ( snapMatch.point() != previouslySnap.point() )
1010  {
1011  mLockedSnapVertices.enqueue( snapMatch );
1012  }
1013 
1014  if ( mLockedSnapVertices.count() > 3 )
1015  {
1016  mLockedSnapVertices.dequeue();
1017  }
1018 }
1019 
1021 {
1023  context.snappingUtils = mMapCanvas->snappingUtils();
1024  context.mapUnitsPerPixel = mMapCanvas->mapUnitsPerPixel();
1025  context.xConstraint = _constraint( mXConstraint.get() );
1026  context.yConstraint = _constraint( mYConstraint.get() );
1027  context.zConstraint = _constraint( mZConstraint.get() );
1028  context.mConstraint = _constraint( mMConstraint.get() );
1029  context.distanceConstraint = _constraint( mDistanceConstraint.get() );
1030  context.angleConstraint = _constraint( mAngleConstraint.get() );
1031 
1032  context.lineExtensionConstraint = _constraint( mLineExtensionConstraint.get() );
1033  context.xyVertexConstraint = _constraint( mXyVertexConstraint.get() );
1034 
1035  context.setCadPoints( mCadPointList );
1036  context.setLockedSnapVertices( mLockedSnapVertices );
1037 
1040  context.commonAngleConstraint.value = mCommonAngleConstraint;
1041 
1043 
1044  const bool res = output.valid;
1045  QgsPoint point = pointXYToPoint( output.finalMapPoint );
1046  mSnappedSegment.clear();
1047  if ( output.snapMatch.hasEdge() )
1048  {
1049  QgsPointXY edgePt0, edgePt1;
1050  output.snapMatch.edgePoints( edgePt0, edgePt1 );
1051  mSnappedSegment << edgePt0 << edgePt1;
1052  }
1053  if ( mAngleConstraint->lockMode() != CadConstraint::HardLock )
1054  {
1055  if ( output.softLockCommonAngle != -1 )
1056  {
1057  mAngleConstraint->setLockMode( CadConstraint::SoftLock );
1058  mAngleConstraint->setValue( output.softLockCommonAngle );
1059  }
1060  else
1061  {
1062  mAngleConstraint->setLockMode( CadConstraint::NoLock );
1063  }
1064  }
1065 
1066  mSoftLockLineExtension = output.softLockLineExtension;
1067  mSoftLockX = output.softLockX;
1068  mSoftLockY = output.softLockY;
1069 
1070  if ( output.snapMatch.isValid() )
1071  {
1072  mSnapIndicator->setMatch( output.snapMatch );
1073  mSnapIndicator->setVisible( true );
1074  }
1075  else
1076  {
1077  mSnapIndicator->setVisible( false );
1078  }
1079 
1080  /*
1081  * Ensure that Z and M are passed
1082  * It will be dropped as needed later.
1083  */
1086 
1087  /*
1088  * Constraints are applied in 2D, they are always called when using the tool
1089  * but they do not take into account if when you snap on a vertex it has
1090  * a Z value.
1091  * To get the value we use the snapPoint method. However, we only apply it
1092  * when the snapped point corresponds to the constrained point or on an edge
1093  * if the topological editing is activated. Also, we don't apply it if
1094  * the point is not linked to a layer.
1095  */
1096  e->setMapPoint( point );
1097  mSnapMatch = context.snappingUtils->snapToMap( point, nullptr, true );
1098  if ( mSnapMatch.layer() )
1099  {
1100  if ( ( ( mSnapMatch.hasVertex() || mSnapMatch.hasLineEndpoint() ) && ( point == mSnapMatch.point() ) )
1101  || ( mSnapMatch.hasEdge() && QgsProject::instance()->topologicalEditing() ) )
1102  {
1103  e->snapPoint();
1104  point = mSnapMatch.interpolatedPoint( mMapCanvas->mapSettings().destinationCrs() );
1105  }
1106  }
1107 
1108  if ( mSnapMatch.hasVertex() || mSnapMatch.hasLineEndpoint() )
1109  {
1110  toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
1111  mLastSnapMatch = mSnapMatch;
1112  }
1113  else
1114  {
1115  mLastSnapMatch = QgsPointLocator::Match();
1116  }
1117 
1118  /*
1119  * And if M or Z lock button is activated get the value of the input.
1120  */
1121  if ( mLockZButton->isChecked() )
1122  {
1123  point.setZ( QLocale().toDouble( mZLineEdit->text() ) );
1124  }
1125  if ( mLockMButton->isChecked() )
1126  {
1127  point.setM( QLocale().toDouble( mMLineEdit->text() ) );
1128  }
1129 
1130  // update the point list
1131  updateCurrentPoint( point );
1132 
1133  updateUnlockedConstraintValues( point );
1134 
1135  if ( res )
1136  {
1137  emit popWarning();
1138  }
1139  else
1140  {
1141  emit pushWarning( tr( "Some constraints are incompatible. Resulting point might be incorrect." ) );
1142  }
1143 
1144  return res;
1145 }
1146 
1147 
1148 void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues( const QgsPoint &point )
1149 {
1150  bool previousPointExist, penulPointExist;
1151  const QgsPoint previousPt = previousPointV2( &previousPointExist );
1152  const QgsPoint penultimatePt = penultimatePointV2( &penulPointExist );
1153 
1154  // --- angle
1155  if ( !mAngleConstraint->isLocked() && previousPointExist )
1156  {
1157  double angle = 0.0;
1158  if ( penulPointExist && mAngleConstraint->relative() )
1159  {
1160  // previous angle
1161  angle = std::atan2( previousPt.y() - penultimatePt.y(),
1162  previousPt.x() - penultimatePt.x() );
1163  }
1164  angle = ( std::atan2( point.y() - previousPt.y(),
1165  point.x() - previousPt.x()
1166  ) - angle ) * 180 / M_PI;
1167  // modulus
1168  angle = std::fmod( angle, 360.0 );
1169  mAngleConstraint->setValue( angle );
1170  }
1171  // --- distance
1172  if ( !mDistanceConstraint->isLocked() && previousPointExist )
1173  {
1174  mDistanceConstraint->setValue( std::sqrt( previousPt.distanceSquared( point ) ) );
1175  }
1176  // --- X
1177  if ( !mXConstraint->isLocked() )
1178  {
1179  if ( previousPointExist && mXConstraint->relative() )
1180  {
1181  mXConstraint->setValue( point.x() - previousPt.x() );
1182  }
1183  else
1184  {
1185  mXConstraint->setValue( point.x() );
1186  }
1187  }
1188  // --- Y
1189  if ( !mYConstraint->isLocked() )
1190  {
1191  if ( previousPointExist && mYConstraint->relative() )
1192  {
1193  mYConstraint->setValue( point.y() - previousPt.y() );
1194  }
1195  else
1196  {
1197  mYConstraint->setValue( point.y() );
1198  }
1199  }
1200  // --- Z
1201  if ( !mZConstraint->isLocked() )
1202  {
1203  if ( previousPointExist && mZConstraint->relative() )
1204  {
1205  mZConstraint->setValue( point.z() - previousPt.z() );
1206  }
1207  else
1208  {
1209  mZConstraint->setValue( point.z() );
1210  }
1211  }
1212  // --- M
1213  if ( !mMConstraint->isLocked() )
1214  {
1215  if ( previousPointExist && mMConstraint->relative() )
1216  {
1217  mMConstraint->setValue( point.m() - previousPt.m() );
1218  }
1219  else
1220  {
1221  mMConstraint->setValue( point.m() );
1222  }
1223  }
1224 }
1225 
1226 
1227 QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers( const QgsPointXY &originalMapPoint, bool *snapped ) const
1228 {
1229  QList<QgsPointXY> segment;
1230  QgsPointXY pt1, pt2;
1231  QgsPointLocator::Match match;
1232 
1233  QgsSnappingUtils *snappingUtils = mMapCanvas->snappingUtils();
1234 
1235  const QgsSnappingConfig canvasConfig = snappingUtils->config();
1236  QgsSnappingConfig localConfig = snappingUtils->config();
1237 
1238  localConfig.setMode( Qgis::SnappingMode::AllLayers );
1239  localConfig.setTypeFlag( Qgis::SnappingType::Segment );
1240  snappingUtils->setConfig( localConfig );
1241 
1242  match = snappingUtils->snapToMap( originalMapPoint, nullptr, true );
1243 
1244  snappingUtils->setConfig( canvasConfig );
1245 
1246  if ( match.isValid() && match.hasEdge() )
1247  {
1248  match.edgePoints( pt1, pt2 );
1249  segment << pt1 << pt2;
1250  }
1251 
1252  if ( snapped )
1253  {
1254  *snapped = segment.count() == 2;
1255  }
1256 
1257  return segment;
1258 }
1259 
1261 {
1262  if ( mBetweenLineConstraint == Qgis::BetweenLineConstraint::NoConstraint )
1263  {
1264  return false;
1265  }
1266 
1267  bool previousPointExist, penulPointExist, snappedSegmentExist;
1268  const QgsPoint previousPt = previousPointV2( &previousPointExist );
1269  const QgsPoint penultimatePt = penultimatePointV2( &penulPointExist );
1270  mSnappedSegment = snapSegmentToAllLayers( e->originalMapPoint(), &snappedSegmentExist );
1271 
1272  if ( !previousPointExist || !snappedSegmentExist )
1273  {
1274  return false;
1275  }
1276 
1277  double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1278 
1279  if ( mAngleConstraint->relative() && penulPointExist )
1280  {
1281  angle -= std::atan2( previousPt.y() - penultimatePt.y(), previousPt.x() - penultimatePt.x() );
1282  }
1283 
1284  if ( mBetweenLineConstraint == Qgis::BetweenLineConstraint::Perpendicular )
1285  {
1286  angle += M_PI_2;
1287  }
1288 
1289  angle *= 180 / M_PI;
1290 
1291  mAngleConstraint->setValue( angle );
1292  mAngleConstraint->setLockMode( lockMode );
1293  if ( lockMode == CadConstraint::HardLock )
1294  {
1295  mBetweenLineConstraint = Qgis::BetweenLineConstraint::NoConstraint;
1296  }
1297 
1298  return true;
1299 }
1300 
1302 {
1303  // event on map tool
1304 
1305  if ( !mCadEnabled )
1306  return false;
1307 
1308  switch ( e->key() )
1309  {
1310  case Qt::Key_Backspace:
1311  case Qt::Key_Delete:
1312  {
1314  releaseLocks( false );
1315  break;
1316  }
1317  case Qt::Key_Escape:
1318  {
1319  releaseLocks();
1320  break;
1321  }
1322  default:
1323  {
1324  keyPressEvent( e );
1325  break;
1326  }
1327  }
1328  // for map tools, continues with key press in any case
1329  return false;
1330 }
1331 
1333 {
1334  clearPoints();
1335  releaseLocks();
1336 }
1337 
1339 {
1340  // event on dock (this)
1341 
1342  if ( !mCadEnabled )
1343  return;
1344 
1345  switch ( e->key() )
1346  {
1347  case Qt::Key_Backspace:
1348  case Qt::Key_Delete:
1349  {
1351  releaseLocks( false );
1352  break;
1353  }
1354  case Qt::Key_Escape:
1355  {
1356  releaseLocks();
1357  break;
1358  }
1359  default:
1360  {
1361  filterKeyPress( e );
1362  break;
1363  }
1364  }
1365 }
1366 
1367 void QgsAdvancedDigitizingDockWidget::setPoints( const QList<QgsPointXY> &points )
1368 {
1369  clearPoints();
1370  const auto constPoints = points;
1371  for ( const QgsPointXY &pt : constPoints )
1372  {
1373  addPoint( pt );
1374  }
1375 }
1376 
1377 bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1378 {
1379  if ( !cadEnabled() )
1380  {
1381  return QgsDockWidget::eventFilter( obj, event );
1382  }
1383 
1384  // event for line edits and map canvas
1385  // we have to catch both KeyPress events and ShortcutOverride events. This is because
1386  // the Ctrl+D and Ctrl+A shortcuts for locking distance/angle clash with the global
1387  // "remove layer" and "select all" shortcuts. Catching ShortcutOverride events allows
1388  // us to intercept these keystrokes before they are caught by the global shortcuts
1389  if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1390  {
1391  if ( QKeyEvent *keyEvent = dynamic_cast<QKeyEvent *>( event ) )
1392  {
1393  return filterKeyPress( keyEvent );
1394  }
1395  }
1396  return QgsDockWidget::eventFilter( obj, event );
1397 }
1398 
1399 bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1400 {
1401  // we need to be careful here -- because this method is called on both KeyPress events AND
1402  // ShortcutOverride events, we have to take care that we don't trigger the handling for BOTH
1403  // these event types for a single key press. I.e. pressing "A" may first call trigger a
1404  // ShortcutOverride event (sometimes, not always!) followed immediately by a KeyPress event.
1405  const QEvent::Type type = e->type();
1406  switch ( e->key() )
1407  {
1408  case Qt::Key_X:
1409  {
1410  // modifier+x ONLY caught for ShortcutOverride events...
1411  if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1412  {
1413  mXConstraint->toggleLocked();
1414  emit lockXChanged( mXConstraint->isLocked() );
1415  emit pointChangedV2( mCadPointList.value( 0 ) );
1416  e->accept();
1417  }
1418  else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1419  {
1420  if ( mCapacities.testFlag( RelativeCoordinates ) )
1421  {
1422  mXConstraint->toggleRelative();
1423  emit relativeXChanged( mXConstraint->relative() );
1424  emit pointChangedV2( mCadPointList.value( 0 ) );
1425  e->accept();
1426  }
1427  }
1428  // .. but "X" alone ONLY caught for KeyPress events (see comment at start of function)
1429  else if ( type == QEvent::KeyPress )
1430  {
1431  mXLineEdit->setFocus();
1432  mXLineEdit->selectAll();
1433  emit focusOnXRequested();
1434  e->accept();
1435  }
1436  break;
1437  }
1438  case Qt::Key_Y:
1439  {
1440  // modifier+y ONLY caught for ShortcutOverride events...
1441  if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1442  {
1443  mYConstraint->toggleLocked();
1444  emit lockYChanged( mYConstraint->isLocked() );
1445  emit pointChangedV2( mCadPointList.value( 0 ) );
1446  e->accept();
1447  }
1448  else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1449  {
1450  if ( mCapacities.testFlag( RelativeCoordinates ) )
1451  {
1452  mYConstraint->toggleRelative();
1453  emit relativeYChanged( mYConstraint->relative() );
1454  emit pointChangedV2( mCadPointList.value( 0 ) );
1455  e->accept();
1456  }
1457  }
1458  // .. but "y" alone ONLY caught for KeyPress events (see comment at start of function)
1459  else if ( type == QEvent::KeyPress )
1460  {
1461  mYLineEdit->setFocus();
1462  mYLineEdit->selectAll();
1463  emit focusOnYRequested();
1464  e->accept();
1465  }
1466  break;
1467  }
1468  case Qt::Key_Z:
1469  {
1470  // modifier+z ONLY caught for ShortcutOverride events...
1471  if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1472  {
1473  mZConstraint->toggleLocked();
1474  emit lockZChanged( mZConstraint->isLocked() );
1475  emit pointChangedV2( mCadPointList.value( 0 ) );
1476  e->accept();
1477  }
1478  else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1479  {
1480  if ( mCapacities.testFlag( RelativeCoordinates ) )
1481  {
1482  mZConstraint->toggleRelative();
1483  emit relativeZChanged( mZConstraint->relative() );
1484  emit pointChangedV2( mCadPointList.value( 0 ) );
1485  e->accept();
1486  }
1487  }
1488  // .. but "z" alone ONLY caught for KeyPress events (see comment at start of function)
1489  else if ( type == QEvent::KeyPress )
1490  {
1491  mZLineEdit->setFocus();
1492  mZLineEdit->selectAll();
1493  emit focusOnZRequested();
1494  e->accept();
1495  }
1496  break;
1497  }
1498  case Qt::Key_M:
1499  {
1500  // modifier+m ONLY caught for ShortcutOverride events...
1501  if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1502  {
1503  mMConstraint->toggleLocked();
1504  emit lockMChanged( mMConstraint->isLocked() );
1505  emit pointChangedV2( mCadPointList.value( 0 ) );
1506  e->accept();
1507  }
1508  else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1509  {
1510  if ( mCapacities.testFlag( RelativeCoordinates ) )
1511  {
1512  mMConstraint->toggleRelative();
1513  emit relativeMChanged( mMConstraint->relative() );
1514  emit pointChangedV2( mCadPointList.value( 0 ) );
1515  e->accept();
1516  }
1517  }
1518  // .. but "m" alone ONLY caught for KeyPress events (see comment at start of function)
1519  else if ( type == QEvent::KeyPress )
1520  {
1521  mMLineEdit->setFocus();
1522  mMLineEdit->selectAll();
1523  emit focusOnMRequested();
1524  e->accept();
1525  }
1526  break;
1527  }
1528  case Qt::Key_A:
1529  {
1530  // modifier+a ONLY caught for ShortcutOverride events...
1531  if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1532  {
1533  if ( mCapacities.testFlag( AbsoluteAngle ) )
1534  {
1535  mAngleConstraint->toggleLocked();
1536  emit lockAngleChanged( mAngleConstraint->isLocked() );
1537  emit pointChangedV2( mCadPointList.value( 0 ) );
1538  e->accept();
1539  }
1540  }
1541  else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1542  {
1543  if ( mCapacities.testFlag( RelativeAngle ) )
1544  {
1545  mAngleConstraint->toggleRelative();
1546  emit relativeAngleChanged( mAngleConstraint->relative() );
1547  emit pointChangedV2( mCadPointList.value( 0 ) );
1548  e->accept();
1549  }
1550  }
1551  // .. but "a" alone ONLY caught for KeyPress events (see comment at start of function)
1552  else if ( type == QEvent::KeyPress )
1553  {
1554  mAngleLineEdit->setFocus();
1555  mAngleLineEdit->selectAll();
1556  emit focusOnAngleRequested();
1557  e->accept();
1558  }
1559  break;
1560  }
1561  case Qt::Key_D:
1562  {
1563  // modifier+d ONLY caught for ShortcutOverride events...
1564  if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1565  {
1566  if ( mCapacities.testFlag( RelativeCoordinates ) && mCapacities.testFlag( Distance ) )
1567  {
1568  mDistanceConstraint->toggleLocked();
1569  emit lockDistanceChanged( mDistanceConstraint->isLocked() );
1570  emit pointChangedV2( mCadPointList.value( 0 ) );
1571  e->accept();
1572  }
1573  }
1574  // .. but "d" alone ONLY caught for KeyPress events (see comment at start of function)
1575  else if ( type == QEvent::KeyPress )
1576  {
1577  mDistanceLineEdit->setFocus();
1578  mDistanceLineEdit->selectAll();
1579  emit focusOnDistanceRequested();
1580  e->accept();
1581  }
1582  break;
1583  }
1584  case Qt::Key_C:
1585  {
1586  if ( type == QEvent::KeyPress )
1587  {
1588  setConstructionMode( !mConstructionMode );
1589  e->accept();
1590  }
1591  break;
1592  }
1593  case Qt::Key_P:
1594  {
1595  if ( type == QEvent::KeyPress )
1596  {
1597  const bool parallel = mParallelAction->isChecked();
1598  const bool perpendicular = mPerpendicularAction->isChecked();
1599 
1600  if ( !parallel && !perpendicular )
1601  {
1602  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::Perpendicular );
1603  }
1604  else if ( perpendicular )
1605  {
1606  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::Parallel );
1607  }
1608  else
1609  {
1610  lockBetweenLineConstraint( Qgis::BetweenLineConstraint::NoConstraint );
1611  }
1612  e->accept();
1613 
1614  // run a fake map mouse event to update the paint item
1615  emit pointChangedV2( mCadPointList.value( 0 ) );
1616  }
1617  break;
1618  }
1619  default:
1620  {
1621  return false; // continues
1622  }
1623  }
1624  return e->isAccepted();
1625 }
1626 
1628 {
1629  // most of theses lines can be moved to updateCapacity
1630  connect( mMapCanvas, &QgsMapCanvas::destinationCrsChanged, this, &QgsAdvancedDigitizingDockWidget::enable, Qt::UniqueConnection );
1631  if ( mMapCanvas->mapSettings().destinationCrs().isGeographic() )
1632  {
1633  mAngleLineEdit->setToolTip( tr( "Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1634  mDistanceLineEdit->setToolTip( tr( "Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1635 
1636  mLabelX->setText( tr( "Long" ) );
1637  mLabelY->setText( tr( "Lat" ) );
1638 
1639  mXConstraint->setPrecision( 8 );
1640  mYConstraint->setPrecision( 8 );
1641  }
1642  else
1643  {
1644  mAngleLineEdit->setToolTip( "<b>" + tr( "Angle" ) + "</b><br>(" + tr( "press a for quick access" ) + ")" );
1645  mAngleLineEdit->setToolTip( QString() );
1646 
1647  mDistanceLineEdit->setToolTip( "<b>" + tr( "Distance" ) + "</b><br>(" + tr( "press d for quick access" ) + ")" );
1648 
1649  mLabelX->setText( tr( "x" ) );
1650  mLabelY->setText( tr( "y" ) );
1651 
1652  mXConstraint->setPrecision( 6 );
1653  mYConstraint->setPrecision( 6 );
1654  }
1655 
1656  updateCapacity();
1657 
1658  mEnableAction->setEnabled( true );
1659  mErrorLabel->hide();
1660  mCadWidget->show();
1661 
1662  mCurrentMapToolSupportsCad = true;
1663 
1664  if ( mSessionActive && !isVisible() )
1665  {
1666  show();
1667  }
1668  setCadEnabled( mSessionActive );
1669 }
1670 
1672 {
1674 
1675  mEnableAction->setEnabled( false );
1676  mErrorLabel->setText( tr( "CAD tools are not enabled for the current map tool" ) );
1677  mErrorLabel->show();
1678  mCadWidget->hide();
1679 
1680  mCurrentMapToolSupportsCad = false;
1681 
1682  mSnapIndicator->setVisible( false );
1683 
1684  setCadEnabled( false );
1685 }
1686 
1688 {
1689  mCadPaintItem->update();
1690 }
1691 
1693 {
1694  if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
1695  {
1696  return;
1697  }
1698 
1699  mLockedSnapVertices.clear();
1700 }
1701 
1702 
1704 {
1705  QgsPoint pt = pointXYToPoint( point );
1706  if ( !pointsCount() )
1707  {
1708  mCadPointList << pt;
1709  }
1710  else
1711  {
1712  mCadPointList.insert( 0, pt );
1713  }
1714 
1715  updateCapacity();
1717 }
1718 
1720 {
1721  if ( !pointsCount() )
1722  return;
1723 
1724  const int i = pointsCount() > 1 ? 1 : 0;
1725  mCadPointList.removeAt( i );
1726  updateCapacity();
1728 }
1729 
1731 {
1732  mCadPointList.clear();
1733  mSnappedSegment.clear();
1734 
1735  updateCapacity();
1737 }
1738 
1739 void QgsAdvancedDigitizingDockWidget::updateCurrentPoint( const QgsPoint &point )
1740 {
1741  if ( !pointsCount() )
1742  {
1743  mCadPointList << point;
1744  updateCapacity();
1745  }
1746  else
1747  {
1748  mCadPointList[0] = point;
1749  }
1751 }
1752 
1753 
1755 {
1756  mLockMode = mode;
1757  mLockerButton->setChecked( mode == HardLock );
1758  if ( mRepeatingLockButton )
1759  {
1760  if ( mode == HardLock )
1761  {
1762  mRepeatingLockButton->setEnabled( true );
1763  }
1764  else
1765  {
1766  mRepeatingLockButton->setChecked( false );
1767  mRepeatingLockButton->setEnabled( false );
1768  }
1769  }
1770 
1771  if ( mode == NoLock )
1772  {
1773  mLineEdit->clear();
1774  }
1775 
1776 }
1777 
1779 {
1780  mRepeatingLock = repeating;
1781  if ( mRepeatingLockButton )
1782  mRepeatingLockButton->setChecked( repeating );
1783 }
1784 
1786 {
1787  mRelative = relative;
1788  if ( mRelativeButton )
1789  {
1790  mRelativeButton->setChecked( relative );
1791  }
1792 }
1793 
1794 void QgsAdvancedDigitizingDockWidget::CadConstraint::setValue( double value, bool updateWidget )
1795 {
1796  mValue = value;
1797  if ( updateWidget && mLineEdit->isEnabled() )
1798  mLineEdit->setText( QLocale().toString( value, 'f', mPrecision ) );
1799 }
1800 
1802 {
1803  setLockMode( mLockMode == HardLock ? NoLock : HardLock );
1804 }
1805 
1807 {
1808  setRelative( !mRelative );
1809 }
1810 
1812 {
1813  mPrecision = precision;
1814  if ( mLineEdit->isEnabled() )
1815  mLineEdit->setText( QLocale().toString( mValue, 'f', mPrecision ) );
1816 }
1817 
1819 {
1820  if ( exist )
1821  *exist = pointsCount() > 0;
1822  if ( pointsCount() > 0 )
1823  return mCadPointList.value( 0 );
1824  else
1825  return QgsPoint();
1826 }
1827 
1829 {
1830  if ( pointsCount() > 0 && layer )
1831  {
1832  QgsPoint res = mCadPointList.value( 0 );
1833  const QgsPointXY layerCoordinates = mMapCanvas->mapSettings().mapToLayerCoordinates( layer, res );
1834  res.setX( layerCoordinates.x() );
1835  res.setY( layerCoordinates.y() );
1836  return res;
1837  }
1838  return QgsPoint();
1839 }
1840 
1842 {
1843  if ( exist )
1844  *exist = pointsCount() > 1;
1845  if ( pointsCount() > 1 )
1846  return mCadPointList.value( 1 );
1847  else
1848  return QgsPoint();
1849 }
1850 
1852 {
1853  if ( exist )
1854  *exist = pointsCount() > 2;
1855  if ( pointsCount() > 2 )
1856  return mCadPointList.value( 2 );
1857  else
1858  return QgsPoint();
1859 }
1860 
1861 QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint( const QgsPointXY &point ) const
1862 {
1863  return QgsPoint( point.x(), point.y(), getLineZ(), getLineM() );
1864 }
1865 
1867 {
1868  return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
1869 }
1870 
1872 {
1873  return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
1874 }
QgsAdvancedDigitizingDockWidget::penultimatePointV2
QgsPoint penultimatePointV2(bool *exists=nullptr) const
The penultimate point.
Definition: qgsadvanceddigitizingdockwidget.cpp:1851
qgsPermissiveToDouble
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...
Definition: qgis.cpp:71
QgsAdvancedDigitizingDockWidget::currentPointV2
QgsPoint currentPointV2(bool *exists=nullptr) const
The last point.
Definition: qgsadvanceddigitizingdockwidget.cpp:1818
QgsCadUtils::AlignMapPointContext::xyVertexConstraint
QgsCadUtils::AlignMapPointConstraint xyVertexConstraint
Definition: qgscadutils.h:135
QgsCadUtils::alignMapPoint
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.
Definition: qgscadutils.cpp:39
qgsmaptooladvanceddigitizing.h
QgsAdvancedDigitizingCanvasItem
The QgsAdvancedDigitizingCanvasItem class draws the graphical elements of the CAD tools (.
Definition: qgsadvanceddigitizingcanvasitem.h:38
QgsAdvancedDigitizingDockWidget::enabledChangedZ
void enabledChangedZ(bool enabled)
Emitted whenever the Z field is enabled or disabled.
QgsAdvancedDigitizingDockWidget::lockMChanged
void lockMChanged(bool locked)
Emitted whenever the M parameter is locked.
QgsPointXY::y
double y
Definition: qgspointxy.h:63
QgsAdvancedDigitizingDockWidget::removePreviousPoint
void removePreviousPoint()
Remove previous point in the CAD point list.
Definition: qgsadvanceddigitizingdockwidget.cpp:1719
QgsVectorLayer::wkbType
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
Definition: qgsvectorlayer.cpp:725
QgsMapSettings::mapToLayerCoordinates
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
Definition: qgsmapsettings.cpp:633
QgsSnappingConfig::setTypeFlag
void setTypeFlag(Qgis::SnappingTypes type)
define the type of snapping
Definition: qgssnappingconfig.cpp:339
qgsmessagebaritem.h
QgsMapLayerType::MeshLayer
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
qgslinestring.h
QgsMapCanvas::destinationCrsChanged
void destinationCrsChanged()
Emitted when map CRS has changed.
qgsmapcanvas.h
QgsAdvancedDigitizingDockWidget::pointsCount
int pointsCount() const
The number of points in the CAD point helper list.
Definition: qgsadvanceddigitizingdockwidget.h:430
QgsMapLayerType::VectorLayer
@ VectorLayer
Vector layer.
QgsMapCanvas::mapTool
QgsMapTool * mapTool()
Returns the currently active tool.
Definition: qgsmapcanvas.cpp:2769
QgsAdvancedDigitizingDockWidget::getLineZ
double getLineZ() const
Convenient method to get the Z value from the line edit wiget.
Definition: qgsadvanceddigitizingdockwidget.cpp:1866
QgsPoint
Point geometry type, with support for z-dimension and m-values.
Definition: qgspoint.h:48
QgsPoint::setM
void setM(double m) SIP_HOLDGIL
Sets the point's m-value.
Definition: qgspoint.h:336
QgsAdvancedDigitizingDockWidget::setAngle
void setAngle(const QString &value, WidgetSetMode mode)
Set the angle value on the widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:298
qgsexpression.h
QgsAdvancedDigitizingDockWidget::valueZChanged
void valueZChanged(const QString &value)
Emitted whenever the Z value changes (either the mouse moved, or the user changed the input).
QgsAdvancedDigitizingDockWidget::lockXChanged
void lockXChanged(bool locked)
Emitted whenever the X parameter is locked.
QgsMapCanvas::mapSettings
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Definition: qgsmapcanvas.cpp:437
QgsAdvancedDigitizingDockWidget::CadConstraint::setLockMode
void setLockMode(LockMode mode)
Set the lock mode.
Definition: qgsadvanceddigitizingdockwidget.cpp:1754
QgsAdvancedDigitizingDockWidget::focusOnMRequested
void focusOnMRequested()
Emitted whenever the M field should get the focus using the shortcuts (M).
QgsAdvancedDigitizingFloater::setActive
void setActive(bool active)
Set whether the floater should be active or not.
Definition: qgsadvanceddigitizingfloater.cpp:151
QgsMapMouseEvent::snapPoint
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
Definition: qgsmapmouseevent.cpp:43
QgsAdvancedDigitizingDockWidget::setZ
void setZ(const QString &value, WidgetSetMode mode)
Set the Z value on the widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:264
QgsAdvancedDigitizingDockWidget::CadConstraint::NoLock
@ NoLock
Definition: qgsadvanceddigitizingdockwidget.h:97
QgsMapLayerType::AnnotationLayer
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
QgsAdvancedDigitizingDockWidget::focusOnZRequested
void focusOnZRequested()
Emitted whenever the Z field should get the focus using the shortcuts (Z).
QgsCadUtils::AlignMapPointContext::commonAngleConstraint
QgsCadUtils::AlignMapPointConstraint commonAngleConstraint
Constraint for soft lock to a common angle.
Definition: qgscadutils.h:132
QgsAdvancedDigitizingDockWidget::setDistance
void setDistance(const QString &value, WidgetSetMode mode)
Set the distance value on the widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:310
QgsPointLocator::Match::edgePoints
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
Definition: qgspointlocator.h:255
QgsSnappingUtils::config
QgsSnappingConfig config
Definition: qgssnappingutils.h:54
QgsMapToolEdit::defaultMValue
static double defaultMValue()
Returns default M value.
Definition: qgsmaptooledit.cpp:42
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
QgsAdvancedDigitizingDockWidget::CadConstraint::setRelative
void setRelative(bool relative)
Set if the constraint should be treated relative.
Definition: qgsadvanceddigitizingdockwidget.cpp:1785
QgsAdvancedDigitizingDockWidget::getLineM
double getLineM() const
Convenient method to get the M value from the line edit wiget.
Definition: qgsadvanceddigitizingdockwidget.cpp:1871
QgsPoint::z
double z
Definition: qgspoint.h:71
QgsAdvancedDigitizingDockWidget::keyPressEvent
void keyPressEvent(QKeyEvent *e) override
Definition: qgsadvanceddigitizingdockwidget.cpp:1338
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:480
QgsAdvancedDigitizingDockWidget::valueMChanged
void valueMChanged(const QString &value)
Emitted whenever the M value changes (either the mouse moved, or the user changed the input).
QgsAdvancedDigitizingDockWidget::QgsAdvancedDigitizingDockWidget
QgsAdvancedDigitizingDockWidget(QgsMapCanvas *canvas, QWidget *parent=nullptr)
Create an advanced digitizing dock widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:46
QgsSettings
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QgsAdvancedDigitizingDockWidget::AbsoluteAngle
@ AbsoluteAngle
Azimuth.
Definition: qgsadvanceddigitizingdockwidget.h:63
QgsWkbTypes::Type
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:69
QgsFocusWatcher
A event filter for watching for focus events on a parent object. Usually QObjects must subclass and o...
Definition: qgsfocuswatcher.h:33
QgsAdvancedDigitizingCanvasItem::updatePosition
void updatePosition() override
called on changed extent or resize event to update position of the item
Definition: qgsadvanceddigitizingcanvasitem.cpp:334
QgsAdvancedDigitizingDockWidget::WidgetSetMode
WidgetSetMode
Type of interaction to simulate when editing values from external widget.
Definition: qgsadvanceddigitizingdockwidget.h:76
QgsAdvancedDigitizingDockWidget::releaseLocks
void releaseLocks(bool releaseRepeatingLocks=true)
unlock all constraints
Definition: qgsadvanceddigitizingdockwidget.cpp:545
QgsPointLocator::Match::point
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
Definition: qgspointlocator.h:238
QgsAdvancedDigitizingDockWidget::alignToSegment
bool alignToSegment(QgsMapMouseEvent *e, QgsAdvancedDigitizingDockWidget::CadConstraint::LockMode lockMode=QgsAdvancedDigitizingDockWidget::CadConstraint::HardLock)
align to segment for between line constraint.
Definition: qgsadvanceddigitizingdockwidget.cpp:1260
QgsAdvancedDigitizingDockWidget::valueDistanceChanged
void valueDistanceChanged(const QString &value)
Emitted whenever the distance value changes (either the mouse moved, or the user changed the input).
QgsCadUtils::AlignMapPointContext::xConstraint
QgsCadUtils::AlignMapPointConstraint xConstraint
Constraint for X coordinate.
Definition: qgscadutils.h:112
QgsCadUtils::AlignMapPointContext::lineExtensionConstraint
QgsCadUtils::AlignMapPointConstraint lineExtensionConstraint
Definition: qgscadutils.h:134
QgsAdvancedDigitizingDockWidget::focusOnAngleRequested
void focusOnAngleRequested()
Emitted whenever the angle field should get the focus using the shortcuts (A).
QgsCadUtils::AlignMapPointConstraint
Structure with details of one constraint.
Definition: qgscadutils.h:43
QgsAdvancedDigitizingDockWidget::lockDistanceChanged
void lockDistanceChanged(bool locked)
Emitted whenever the distance parameter is locked.
QgsAdvancedDigitizingDockWidget::enable
void enable()
Enables the tool (call this when an appropriate map tool is set and in the condition to make use of c...
Definition: qgsadvanceddigitizingdockwidget.cpp:1627
QgsAdvancedDigitizingDockWidget::CadConstraint::setRepeatingLock
void setRepeatingLock(bool repeating)
Sets whether a repeating lock is set for the constraint.
Definition: qgsadvanceddigitizingdockwidget.cpp:1778
Qgis::BetweenLineConstraint::Parallel
@ Parallel
Parallel.
QgsPointLocator::Match::hasVertex
bool hasVertex() const
Returns true if the Match is a vertex.
Definition: qgspointlocator.h:211
QgsAdvancedDigitizingDockWidget::Distance
@ Distance
Distance.
Definition: qgsadvanceddigitizingdockwidget.h:66
QgsSnapIndicator
Class that shows snapping marker on map canvas for the current snapping match.
Definition: qgssnapindicator.h:32
QgsAdvancedDigitizingDockWidget::relativeYChanged
void relativeYChanged(bool relative)
Emitted whenever the Y parameter is toggled between absolute and relative.
QgsMapCanvas::snappingUtils
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
Definition: qgsmapcanvas.cpp:2935
QgsCadUtils::AlignMapPointContext::snappingUtils
QgsSnappingUtils * snappingUtils
Snapping utils that will be used to snap point to map. Must not be nullptr.
Definition: qgscadutils.h:107
QgsPointLocator::Match::interpolatedPoint
QgsPoint interpolatedPoint(const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem()) const
Convenient method to return a point on an edge with linear interpolation of the Z value.
Definition: qgspointlocator.h:267
QgsAdvancedDigitizingDockWidget::disable
void disable()
Disable the widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:1671
QgsCadUtils::AlignMapPointConstraint::locked
bool locked
Whether the constraint is active, i.e. should be considered.
Definition: qgscadutils.h:57
QgsAdvancedDigitizingDockWidget::valueXChanged
void valueXChanged(const QString &value)
Emitted whenever the X value changes (either the mouse moved, or the user changed the input).
qgsapplication.h
QgsAdvancedDigitizingDockWidget::clearPoints
void clearPoints()
Removes all points from the CAD point list.
Definition: qgsadvanceddigitizingdockwidget.cpp:1730
QgsCadUtils::AlignMapPointOutput::finalMapPoint
QgsPointXY finalMapPoint
map point aligned according to the constraints
Definition: qgscadutils.h:76
QgsAdvancedDigitizingDockWidget::pointChangedV2
void pointChangedV2(const QgsPoint &point)
Sometimes a constraint may change the current point out of a mouse event.
Qgis::BetweenLineConstraint::NoConstraint
@ NoConstraint
No additional constraint.
QgsSnappingUtils::snapToMap
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
Definition: qgssnappingutils.cpp:257
QgsPoint::y
double y
Definition: qgspoint.h:70
QgsPointLocator::Match::hasEdge
bool hasEdge() const
Returns true if the Match is an edge.
Definition: qgspointlocator.h:213
precision
int precision
Definition: qgswfsgetfeature.cpp:103
QgsCoordinateReferenceSystem::isGeographic
bool isGeographic
Definition: qgscoordinatereferencesystem.h:216
QgsAdvancedDigitizingDockWidget::CadConstraint::toggleRelative
void toggleRelative()
Toggle relative mode.
Definition: qgsadvanceddigitizingdockwidget.cpp:1806
QgsAdvancedDigitizingDockWidget::focusOnXRequested
void focusOnXRequested()
Emitted whenever the X field should get the focus using the shortcuts (X).
QgsProject::topologicalEditing
bool topologicalEditing
Definition: qgsproject.h:120
Qgis::BetweenLineConstraint::Perpendicular
@ Perpendicular
Perpendicular.
QgsCadUtils::AlignMapPointOutput::snapMatch
QgsPointLocator::Match snapMatch
Snapped point - only valid if actually used for something.
Definition: qgscadutils.h:82
QgsAdvancedDigitizingDockWidget::CadConstraint::LockMode
LockMode
The lock mode.
Definition: qgsadvanceddigitizingdockwidget.h:95
QgsMapLayerType::GroupLayer
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
QgsAdvancedDigitizingDockWidget::setX
void setX(const QString &value, WidgetSetMode mode)
Set the X value on the widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:230
QgsAdvancedDigitizingDockWidget::cadEnabledChanged
void cadEnabledChanged(bool enabled)
Signals for external widgets that need to update according to current values.
QgsPointLocator::Match::hasLineEndpoint
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
Definition: qgspointlocator.h:226
QgsAdvancedDigitizingDockWidget::enabledChangedDistance
void enabledChangedDistance(bool enabled)
Emitted whenever the distance field is enabled or disabled.
QgsAdvancedDigitizingDockWidget::enabledChangedAngle
void enabledChangedAngle(bool enabled)
Emitted whenever the angle field is enabled or disabled.
QgsCadUtils::AlignMapPointContext::setLockedSnapVertices
void setLockedSnapVertices(const QQueue< QgsPointLocator::Match > &lockedSnapVertices)
Sets the queue of locked vertices.
Definition: qgscadutils.h:186
QgsMeshLayer
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:98
QgsMapLayerType::RasterLayer
@ RasterLayer
Raster layer.
QgsCadUtils::AlignMapPointConstraint::value
double value
Numeric value of the constraint (coordinate/distance in map units or angle in degrees)
Definition: qgscadutils.h:61
QgsPoint::setX
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
Definition: qgspoint.h:297
QgsWkbTypes::hasM
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:1130
QgsPoint::distanceSquared
double distanceSquared(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
Definition: qgspoint.h:384
QgsPointLocator::Match::isValid
bool isValid() const
Definition: qgspointlocator.h:209
QgsAdvancedDigitizingDockWidget::CadConstraint
The CadConstraint is an abstract class for all basic constraints (angle/distance/x/y)....
Definition: qgsadvanceddigitizingdockwidget.h:88
QgsAdvancedDigitizingDockWidget::applyConstraints
bool applyConstraints(QgsMapMouseEvent *e)
apply the CAD constraints.
Definition: qgsadvanceddigitizingdockwidget.cpp:1020
QgsPoint::m
double m
Definition: qgspoint.h:72
QgsAdvancedDigitizingDockWidget::relativeMChanged
void relativeMChanged(bool relative)
Emitted whenever the M parameter is toggled between absolute and relative.
QgsCadUtils::AlignMapPointContext::distanceConstraint
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
Definition: qgscadutils.h:128
QgsAdvancedDigitizingDockWidget::lockAngleChanged
void lockAngleChanged(bool locked)
Emitted whenever the angle parameter is locked.
qgsadvanceddigitizingcanvasitem.h
QgsAdvancedDigitizingDockWidget::clear
void clear()
Clear any cached previous clicks and helper lines.
Definition: qgsadvanceddigitizingdockwidget.cpp:1332
QgsAdvancedDigitizingDockWidget::CadConstraint::setPrecision
void setPrecision(int precision)
Sets the numeric precision (decimal places) to show in the associated widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:1811
QgsSnappingConfig
This is a container for configuration of the snapping of the project.
Definition: qgssnappingconfig.h:37
QgsMapToolEdit::defaultZValue
static double defaultZValue()
Returns default Z value.
Definition: qgsmaptooledit.cpp:37
QgsPointLocator::Match::layer
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
Definition: qgspointlocator.h:247
QgsSettings::setValue
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Definition: qgssettings.cpp:279
qgsfocuswatcher.h
qgsadvanceddigitizingfloater.h
QgsFocusWatcher::focusOut
void focusOut()
Emitted when parent object loses focus.
QgsCadUtils::AlignMapPointContext::mapUnitsPerPixel
double mapUnitsPerPixel
Map units/pixel ratio from map canvas.
Definition: qgscadutils.h:109
Qgis::SnappingMode::AllLayers
@ AllLayers
On all vector layers.
QgsSnappingUtils
This class has all the configuration of snapping and can return answers to snapping queries.
Definition: qgssnappingutils.h:50
QgsCadUtils::AlignMapPointOutput::softLockLineExtension
Qgis::LineExtensionSide softLockLineExtension
Definition: qgscadutils.h:93
QgsCadUtils::AlignMapPointContext
Defines constraints for the QgsCadUtils::alignMapPoint() method.
Definition: qgscadutils.h:103
QgsAdvancedDigitizingDockWidget::CadConstraint::SoftLock
@ SoftLock
Definition: qgsadvanceddigitizingdockwidget.h:98
qgsmeshlayer.h
QgsPointLocator::Match
Definition: qgspointlocator.h:187
QgsPointXY
A class to represent a 2D point.
Definition: qgspointxy.h:58
QgsAdvancedDigitizingDockWidget::valueAngleChanged
void valueAngleChanged(const QString &value)
Emitted whenever the angle value changes (either the mouse moved, or the user changed the input).
QgsAdvancedDigitizingDockWidget::canvasKeyPressEventFilter
bool canvasKeyPressEventFilter(QKeyEvent *e)
Filter key events to e.g.
Definition: qgsadvanceddigitizingdockwidget.cpp:1301
QgsMapSettings::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Definition: qgsmapsettings.cpp:358
QgsAdvancedDigitizingDockWidget::CadConstraint::HardLock
@ HardLock
Definition: qgsadvanceddigitizingdockwidget.h:99
QgsCadUtils::AlignMapPointOutput::softLockCommonAngle
double softLockCommonAngle
Angle (in degrees) to which we have soft-locked ourselves (if not set it is -1)
Definition: qgscadutils.h:91
QgsCadUtils::AlignMapPointOutput::valid
bool valid
Whether the combination of constraints is actually valid.
Definition: qgscadutils.h:73
QgsAdvancedDigitizingDockWidget::softLockXyChanged
void softLockXyChanged(bool locked)
Emitted whenever the soft x/y extension parameter is locked.
QgsAdvancedDigitizingDockWidget::updateCadPaintItem
void updateCadPaintItem()
Updates canvas item that displays constraints on the ma.
Definition: qgsadvanceddigitizingdockwidget.cpp:1687
QgsAdvancedDigitizingDockWidget::RelativeCoordinates
@ RelativeCoordinates
This corresponds to distance and relative coordinates.
Definition: qgsadvanceddigitizingdockwidget.h:65
Qgis::BetweenLineConstraint
BetweenLineConstraint
Between line constraints which can be enabled.
Definition: qgis.h:1782
QgsMapMouseEvent
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas....
Definition: qgsmapmouseevent.h:35
QgsAdvancedDigitizingDockWidget::currentPointLayerCoordinates
QgsPoint currentPointLayerCoordinates(QgsMapLayer *layer) const
Returns the last CAD point, in a map layer's coordinates.
Definition: qgsadvanceddigitizingdockwidget.cpp:1828
QgsAdvancedDigitizingDockWidget::softLockLineExtensionChanged
void softLockLineExtensionChanged(bool locked)
Emitted whenever the soft line extension parameter is locked.
qgsadvanceddigitizingdockwidget.h
QgsAdvancedDigitizingDockWidget::setEnabledZ
void setEnabledZ(bool enable)
Sets whether Z is enabled.
Definition: qgsadvanceddigitizingdockwidget.cpp:400
QgsCadUtils::AlignMapPointOutput::softLockY
double softLockY
Definition: qgscadutils.h:95
c
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
Definition: porting_processing.dox:1
QgsCadUtils::AlignMapPointContext::setCadPoints
void setCadPoints(const QList< QgsPoint > &points)
Sets the list of recent CAD points (in map coordinates).
Definition: qgscadutils.h:160
QgsAdvancedDigitizingDockWidget::popWarning
void popWarning()
Remove any previously emitted warnings (if any)
QgsAdvancedDigitizingDockWidget::setM
void setM(const QString &value, WidgetSetMode mode)
Set the M value on the widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:281
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsMapLayer
Base class for all map layer types. This is the base class for all map layer types (vector,...
Definition: qgsmaplayer.h:72
QgsAdvancedDigitizingDockWidget::valueYChanged
void valueYChanged(const QString &value)
Emitted whenever the Y value changes (either the mouse moved, or the user changed the input).
qgsmaptooledit.h
QgsProject::snappingConfig
QgsSnappingConfig snappingConfig
Definition: qgsproject.h:113
qgscadutils.h
QgsPointXY::x
double x
Definition: qgspointxy.h:62
QgsAdvancedDigitizingDockWidget::relativeXChanged
void relativeXChanged(bool relative)
Emitted whenever the X parameter is toggled between absolute and relative.
QgsAdvancedDigitizingDockWidget::setEnabledM
void setEnabledM(bool enable)
Sets whether M is enabled.
Definition: qgsadvanceddigitizingdockwidget.cpp:413
qgssettings.h
QgsAdvancedDigitizingFloater::active
bool active()
Whether the floater is active or not.
Definition: qgsadvanceddigitizingfloater.cpp:146
QgsDockWidget
QgsDockWidget subclass with more fine-grained control over how the widget is closed or opened.
Definition: qgsdockwidget.h:31
QgsMapLayerType::VectorTileLayer
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
QgsAdvancedDigitizingDockWidget::focusOnDistanceRequested
void focusOnDistanceRequested()
Emitted whenever the distance field should get the focus using the shortcuts (D).
QgsAdvancedDigitizingDockWidget::addPoint
void addPoint(const QgsPointXY &point)
Adds point to the CAD point list.
Definition: qgsadvanceddigitizingdockwidget.cpp:1703
qgsmaptoolcapture.h
QgsWkbTypes::hasZ
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:1080
QgsCadUtils::AlignMapPointContext::mConstraint
QgsCadUtils::AlignMapPointConstraint mConstraint
Constraint for M coordinate.
Definition: qgscadutils.h:126
QgsCadUtils::AlignMapPointOutput::softLockX
double softLockX
Definition: qgscadutils.h:94
segment
QLineF segment(int index, QRectF rect, double radius)
Definition: qgsshapegenerator.cpp:25
QgsMapCanvas::currentLayer
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
Definition: qgsmapcanvas.cpp:614
QgsCadUtils::AlignMapPointContext::zConstraint
QgsCadUtils::AlignMapPointConstraint zConstraint
Constraint for Z coordinate.
Definition: qgscadutils.h:120
QgsAdvancedDigitizingDockWidget::CadConstraint::setValue
void setValue(double value, bool updateWidget=true)
Set the value of the constraint.
Definition: qgsadvanceddigitizingdockwidget.cpp:1794
QgsAdvancedDigitizingDockWidget::relativeAngleChanged
void relativeAngleChanged(bool relative)
Emitted whenever the angleX parameter is toggled between absolute and relative.
QgsPoint::setY
void setY(double y) SIP_HOLDGIL
Sets the point's y-coordinate.
Definition: qgspoint.h:308
QgsAdvancedDigitizingDockWidget::setPoints
void setPoints(const QList< QgsPointXY > &points)
Configures list of current CAD points.
Definition: qgsadvanceddigitizingdockwidget.cpp:1367
qgslogger.h
QgsAdvancedDigitizingDockWidget::previousPointV2
QgsPoint previousPointV2(bool *exists=nullptr) const
The previous point.
Definition: qgsadvanceddigitizingdockwidget.cpp:1841
QgsAdvancedDigitizingDockWidget::focusOnYRequested
void focusOnYRequested()
Emitted whenever the Y field should get the focus using the shortcuts (Y).
QgsCadUtils::AlignMapPointContext::yConstraint
QgsCadUtils::AlignMapPointConstraint yConstraint
Constraint for Y coordinate.
Definition: qgscadutils.h:114
QgsAdvancedDigitizingDockWidget::setY
void setY(const QString &value, WidgetSetMode mode)
Set the Y value on the widget.
Definition: qgsadvanceddigitizingdockwidget.cpp:247
QgsAdvancedDigitizingDockWidget::lockYChanged
void lockYChanged(bool locked)
Emitted whenever the Y parameter is locked.
QgsAdvancedDigitizingFloater
The QgsAdvancedDigitizingFloater class is widget that floats next to the mouse pointer,...
Definition: qgsadvanceddigitizingfloater.h:40
QgsPoint::setZ
void setZ(double z) SIP_HOLDGIL
Sets the point's z-coordinate.
Definition: qgspoint.h:321
QgsMapCanvas::mapUnitsPerPixel
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
Definition: qgsmapcanvas.cpp:2628
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsCadUtils::AlignMapPointOutput
Structure returned from alignMapPoint() method.
Definition: qgscadutils.h:69
qgsmapmouseevent.h
QgsProject::snappingConfigChanged
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsMapLayerType::PointCloudLayer
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
QgsAdvancedDigitizingDockWidget::lockZChanged
void lockZChanged(bool locked)
Emitted whenever the Z parameter is locked.
QgsMapToolAdvancedDigitizing
The QgsMapToolAdvancedDigitizing class is a QgsMapTool which gives event directly in map coordinates ...
Definition: qgsmaptooladvanceddigitizing.h:36
MathUtils::angle
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)
Definition: MathUtils.cpp:786
QgsAdvancedDigitizingDockWidget::RelativeAngle
@ RelativeAngle
Also for parallel and perpendicular.
Definition: qgsadvanceddigitizingdockwidget.h:64
QgsAdvancedDigitizingDockWidget::switchZM
void switchZM()
Determines if Z or M will be enabled.
Definition: qgsadvanceddigitizingdockwidget.cpp:361
QgsCadUtils::AlignMapPointConstraint::relative
bool relative
Whether the value is relative to previous value.
Definition: qgscadutils.h:59
QgsMapMouseEvent::originalMapPoint
QgsPointXY originalMapPoint() const
Returns the original, unmodified map point of the mouse cursor.
Definition: qgsmapmouseevent.h:112
QgsAdvancedDigitizingDockWidget::cadEnabled
bool cadEnabled() const
determines if CAD tools are enabled or if map tools behaves "nomally"
Definition: qgsadvanceddigitizingdockwidget.h:261
QgsAdvancedDigitizingDockWidget::clearLockedSnapVertices
void clearLockedSnapVertices(bool force=true)
Removes all points from the locked snap vertex list.
Definition: qgsadvanceddigitizingdockwidget.cpp:1692
QgsAdvancedDigitizingDockWidget::relativeZChanged
void relativeZChanged(bool relative)
Emitted whenever the Z parameter is toggled between absolute and relative.
QgsMapMouseEvent::setMapPoint
void setMapPoint(const QgsPointXY &point)
Set the (snapped) point this event points to in map coordinates.
Definition: qgsmapmouseevent.cpp:68
QgsPoint::x
double x
Definition: qgspoint.h:69
qgsproject.h
QgsAdvancedDigitizingDockWidget::pushWarning
void pushWarning(const QString &message)
Push a warning.
QgsMapLayerType::PluginLayer
@ PluginLayer
Plugin based layer.
QgsAdvancedDigitizingDockWidget::CadConstraint::toggleLocked
void toggleLocked()
Toggle lock mode.
Definition: qgsadvanceddigitizingdockwidget.cpp:1801
QgsSnappingConfig::setMode
void setMode(Qgis::SnappingMode mode)
define the mode of snapping
Definition: qgssnappingconfig.cpp:253
QgsSnappingUtils::setConfig
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
Definition: qgssnappingutils.cpp:560
QgsAdvancedDigitizingDockWidget::enabledChangedM
void enabledChangedM(bool enabled)
Emitted whenever the M field is enabled or disabled.
QgsCadUtils::AlignMapPointContext::angleConstraint
QgsCadUtils::AlignMapPointConstraint angleConstraint
Constraint for angle.
Definition: qgscadutils.h:130
QgsSnappingConfig::enabled
bool enabled() const
Returns if snapping is enabled.
Definition: qgssnappingconfig.cpp:234
QgsMeshLayer::isEditable
bool isEditable() const override
Returns true if the layer can be edited.
Definition: qgsmeshlayer.cpp:1759
qgssnappingutils.h
qgsmessagelog.h