18#include <QCoreApplication>
42#include <QActionGroup>
50 , mMapCanvas( canvas )
52 , mCommonAngleConstraint(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
58 mAngleConstraint.reset(
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
60 mAngleConstraint->setMapCanvas( mMapCanvas );
61 mDistanceConstraint.reset(
new CadConstraint( mDistanceLineEdit, mLockDistanceButton,
nullptr, mRepeatingLockDistanceButton ) );
63 mDistanceConstraint->setMapCanvas( mMapCanvas );
64 mXConstraint.reset(
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
66 mXConstraint->setMapCanvas( mMapCanvas );
67 mYConstraint.reset(
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
69 mYConstraint->setMapCanvas( mMapCanvas );
70 mZConstraint.reset(
new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
72 mZConstraint->setMapCanvas( mMapCanvas );
73 mMConstraint.reset(
new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
75 mMConstraint->setMapCanvas( mMapCanvas );
77 mLineExtensionConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
78 mXyVertexConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
79 mXyVertexConstraint->setMapCanvas( mMapCanvas );
83 mMapCanvas->installEventFilter(
this );
84 mAngleLineEdit->installEventFilter(
this );
85 mDistanceLineEdit->installEventFilter(
this );
86 mXLineEdit->installEventFilter(
this );
87 mYLineEdit->installEventFilter(
this );
88 mZLineEdit->installEventFilter(
this );
89 mMLineEdit->installEventFilter(
this );
92 connect( mEnableAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::activateCad );
93 connect( mConstructionModeAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
94 connect( mParallelAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
95 connect( mPerpendicularAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
96 connect( mLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
97 connect( mLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
98 connect( mLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
99 connect( mLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
100 connect( mLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
101 connect( mLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
102 connect( mRelativeAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
103 connect( mRelativeXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
104 connect( mRelativeYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
105 connect( mRelativeZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
106 connect( mRelativeMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
107 connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
108 connect( mRepeatingLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
109 connect( mRepeatingLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
110 connect( mRepeatingLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
111 connect( mRepeatingLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
112 connect( mRepeatingLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
113 connect( mAngleLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
114 connect( mDistanceLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
115 connect( mXLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
116 connect( mYLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
117 connect( mZLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
118 connect( mMLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
119 connect( mAngleLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
120 connect( mDistanceLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
121 connect( mXLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
122 connect( mYLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
123 connect( mZLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
124 connect( mMLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
140 mCommonAngleActionsMenu =
new QMenu(
this );
142#ifndef __clang_analyzer__
143 QActionGroup *angleButtonGroup =
new QActionGroup( mCommonAngleActionsMenu );
145 mCommonAngleActions = QMap<QAction *, double>();
146 QList< QPair< double, QString > > commonAngles;
147 const QList<double> anglesDouble( { 0.0, 0.1, 0.5, 1.0, 5.0, 10.0, 15.0, 18.0, 22.5, 30.0, 45.0, 90.0} );
148 for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
154 QMenu *snappingPriorityMenu =
new QMenu( tr(
"Snapping Priority" ), mCommonAngleActionsMenu );
155 QActionGroup *snappingPriorityActionGroup =
new QActionGroup( snappingPriorityMenu );
156 QAction *featuresAction =
new QAction( tr(
"Prioritize Snapping to Features" ), snappingPriorityActionGroup );
157 featuresAction->setCheckable(
true );
158 QAction *anglesAction =
new QAction( tr(
"Prioritize Snapping to Angle" ), snappingPriorityActionGroup );
159 anglesAction->setCheckable(
true );
160 snappingPriorityActionGroup->addAction( featuresAction );
161 snappingPriorityActionGroup->addAction( anglesAction );
162 snappingPriorityMenu->addAction( anglesAction );
163 snappingPriorityMenu->addAction( featuresAction );
164 connect( anglesAction, &QAction::changed,
this, [ = ]
166 mSnappingPrioritizeFeatures = featuresAction->isChecked();
167 settingsCadSnappingPriorityPrioritizeFeature->
setValue( featuresAction->isChecked() );
169 featuresAction->setChecked( settingsCadSnappingPriorityPrioritizeFeature->
value( ) );
170 anglesAction->setChecked( ! featuresAction->isChecked() );
171 mCommonAngleActionsMenu->addMenu( snappingPriorityMenu );
175 for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
177 QAction *action =
new QAction( it->second, mCommonAngleActionsMenu );
178 action->setCheckable(
true );
179 action->setChecked( it->first == mCommonAngleConstraint );
180 mCommonAngleActionsMenu->addAction( action );
182#ifndef __clang_analyzer__
183 angleButtonGroup->addAction( action );
185 mCommonAngleActions.insert( action, it->first );
188 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
189 mSettingsAction->setMenu( mCommonAngleActionsMenu );
190 mSettingsAction->setCheckable(
true );
191 mSettingsAction->setToolTip(
"<b>" + tr(
"Snap to common angles" ) +
"</b><br>(" + tr(
"press n to cycle through the options" ) +
")" );
192 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
193 connect( mCommonAngleActionsMenu, &QMenu::triggered,
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
196 QMenu *constructionMenu =
new QMenu(
this );
198 mLineExtensionAction =
new QAction(
"Line Extension", constructionMenu );
199 mLineExtensionAction->setCheckable(
true );
200 constructionMenu->addAction( mLineExtensionAction );
201 connect( mLineExtensionAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
203 mXyVertexAction =
new QAction(
"X/Y Point", constructionMenu );
204 mXyVertexAction->setCheckable(
true );
205 constructionMenu->addAction( mXyVertexAction );
206 connect( mXyVertexAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
208 auto constructionToolBar = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionAction ) );
209 constructionToolBar->setPopupMode( QToolButton::InstantPopup );
210 constructionToolBar->setMenu( constructionMenu );
211 constructionToolBar->setObjectName( QStringLiteral(
"ConstructionButton" ) );
213 mConstructionAction->setMenu( mCommonAngleActionsMenu );
214 mConstructionAction->setCheckable(
true );
215 mConstructionAction->setToolTip( tr(
"Construction Tools" ) );
219 mConstructionModeAction->setToolTip(
"<b>" + tr(
"Construction mode" ) +
"</b><br>(" + tr(
"press c to toggle on/off" ) +
")" );
220 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
221 mLockDistanceButton->setToolTip(
"<b>" + tr(
"Lock distance" ) +
"</b><br>(" + tr(
"press Ctrl + d for quick access" ) +
")" );
222 mRepeatingLockDistanceButton->setToolTip(
"<b>" + tr(
"Continuously lock distance" ) +
"</b>" );
224 mRelativeAngleButton->setToolTip(
"<b>" + tr(
"Toggles relative angle to previous segment" ) +
"</b><br>(" + tr(
"press Shift + a for quick access" ) +
")" );
225 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
226 mLockAngleButton->setToolTip(
"<b>" + tr(
"Lock angle" ) +
"</b><br>(" + tr(
"press Ctrl + a for quick access" ) +
")" );
227 mRepeatingLockAngleButton->setToolTip(
"<b>" + tr(
"Continuously lock angle" ) +
"</b>" );
229 mRelativeXButton->setToolTip(
"<b>" + tr(
"Toggles relative x to previous node" ) +
"</b><br>(" + tr(
"press Shift + x for quick access" ) +
")" );
230 mXLineEdit->setToolTip(
"<b>" + tr(
"X coordinate" ) +
"</b><br>(" + tr(
"press x for quick access" ) +
")" );
231 mLockXButton->setToolTip(
"<b>" + tr(
"Lock x coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + x for quick access" ) +
")" );
232 mRepeatingLockXButton->setToolTip(
"<b>" + tr(
"Continuously lock x coordinate" ) +
"</b>" );
234 mRelativeYButton->setToolTip(
"<b>" + tr(
"Toggles relative y to previous node" ) +
"</b><br>(" + tr(
"press Shift + y for quick access" ) +
")" );
235 mYLineEdit->setToolTip(
"<b>" + tr(
"Y coordinate" ) +
"</b><br>(" + tr(
"press y for quick access" ) +
")" );
236 mLockYButton->setToolTip(
"<b>" + tr(
"Lock y coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + y for quick access" ) +
")" );
237 mRepeatingLockYButton->setToolTip(
"<b>" + tr(
"Continuously lock y coordinate" ) +
"</b>" );
239 mRelativeZButton->setToolTip(
"<b>" + tr(
"Toggles relative z to previous node" ) +
"</b><br>(" + tr(
"press Shift + z for quick access" ) +
")" );
240 mZLineEdit->setToolTip(
"<b>" + tr(
"Z coordinate" ) +
"</b><br>(" + tr(
"press z for quick access" ) +
")" );
241 mLockZButton->setToolTip(
"<b>" + tr(
"Lock z coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + z for quick access" ) +
")" );
242 mRepeatingLockZButton->setToolTip(
"<b>" + tr(
"Continuously lock z coordinate" ) +
"</b>" );
244 mRelativeMButton->setToolTip(
"<b>" + tr(
"Toggles relative m to previous node" ) +
"</b><br>(" + tr(
"press Shift + m for quick access" ) +
")" );
245 mMLineEdit->setToolTip(
"<b>" + tr(
"M coordinate" ) +
"</b><br>(" + tr(
"press m for quick access" ) +
")" );
246 mLockMButton->setToolTip(
"<b>" + tr(
"Lock m coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + m for quick access" ) +
")" );
247 mRepeatingLockMButton->setToolTip(
"<b>" + tr(
"Continuously lock m coordinate" ) +
"</b>" );
258 mFloaterActionsMenu =
new QMenu(
this );
259 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mFloaterAction ) )->setPopupMode( QToolButton::InstantPopup );
260 mFloaterAction->setMenu( mFloaterActionsMenu );
261 mFloaterAction->setCheckable(
true );
263 mFloaterAction->setChecked( mFloater->
active() );
267 QAction *action =
new QAction( tr(
"Show floater" ), mFloaterActionsMenu );
268 action->setCheckable(
true );
269 action->setChecked( mFloater->
active() );
270 mFloaterActionsMenu->addAction( action );
271 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
274 mFloaterAction->setChecked( checked );
278 mFloaterActionsMenu->addSeparator();
281 QAction *action =
new QAction( tr(
"Show distance" ), mFloaterActionsMenu );
282 action->setCheckable(
true );
283 mFloaterActionsMenu->addAction( action );
284 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
288 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/DistanceShowInFloater" ),
true ).toBool() );
292 QAction *action =
new QAction( tr(
"Show angle" ), mFloaterActionsMenu );
293 action->setCheckable(
true );
294 mFloaterActionsMenu->addAction( action );
295 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
299 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/AngleShowInFloater" ),
true ).toBool() );
303 QAction *action =
new QAction( tr(
"Show XY coordinates" ), mFloaterActionsMenu );
304 action->setCheckable(
true );
305 mFloaterActionsMenu->addAction( action );
306 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
312 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/XCoordinateShowInFloater" ),
true ).toBool() );
316 QAction *action =
new QAction( tr(
"Show Z value" ), mFloaterActionsMenu );
317 action->setCheckable(
true );
318 mFloaterActionsMenu->addAction( action );
319 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
323 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/ZCoordinateShowInFloater" ),
true ).toBool() );
327 QAction *action =
new QAction( tr(
"Show M value" ), mFloaterActionsMenu );
328 action->setCheckable(
true );
329 mFloaterActionsMenu->addAction( action );
330 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
334 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/MCoordinateShowInFloater" ),
true ).toBool() );
338 QAction *action =
new QAction( tr(
"Show common snapping angle" ), mFloaterActionsMenu );
339 action->setCheckable(
true );
340 mFloaterActionsMenu->addAction( action );
341 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
345 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngleSnappingShowInFloater" ),
false ).toBool() );
349 QAction *action =
new QAction( tr(
"Show bearing/azimuth" ), mFloaterActionsMenu );
350 action->setCheckable(
true );
351 mFloaterActionsMenu->addAction( action );
352 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
356 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/BearingShowInFloater" ),
false ).toBool() );
359 updateCapacity(
true );
368 return tr(
"Do Not Snap to Common Angles" );
370 return QString( tr(
"%1, %2, %3, %4°…" ) ).arg(
angle, 0,
'f', 1 ).arg(
angle * 2, 0,
'f', 1 ).arg(
angle * 3, 0,
'f', 1 ).arg(
angle * 4, 0,
'f', 1 );
375 mXLineEdit->setText( value );
376 if ( mode == WidgetSetMode::ReturnPressed )
378 emit mXLineEdit->returnPressed();
380 else if ( mode == WidgetSetMode::FocusOut )
382 QEvent *e =
new QEvent( QEvent::FocusOut );
383 QCoreApplication::postEvent( mXLineEdit, e );
385 else if ( mode == WidgetSetMode::TextEdited )
387 emit mXLineEdit->textEdited( value );
392 mYLineEdit->setText( value );
393 if ( mode == WidgetSetMode::ReturnPressed )
395 emit mYLineEdit->returnPressed();
397 else if ( mode == WidgetSetMode::FocusOut )
399 QEvent *e =
new QEvent( QEvent::FocusOut );
400 QCoreApplication::postEvent( mYLineEdit, e );
402 else if ( mode == WidgetSetMode::TextEdited )
404 emit mYLineEdit->textEdited( value );
409 mZLineEdit->setText( value );
410 if ( mode == WidgetSetMode::ReturnPressed )
412 emit mZLineEdit->returnPressed();
414 else if ( mode == WidgetSetMode::FocusOut )
416 QEvent *e =
new QEvent( QEvent::FocusOut );
417 QCoreApplication::postEvent( mZLineEdit, e );
419 else if ( mode == WidgetSetMode::TextEdited )
421 emit mZLineEdit->textEdited( value );
426 mMLineEdit->setText( value );
427 if ( mode == WidgetSetMode::ReturnPressed )
429 emit mMLineEdit->returnPressed();
431 else if ( mode == WidgetSetMode::FocusOut )
433 QEvent *e =
new QEvent( QEvent::FocusOut );
434 QCoreApplication::postEvent( mMLineEdit, e );
436 else if ( mode == WidgetSetMode::TextEdited )
438 emit mMLineEdit->textEdited( value );
443 mAngleLineEdit->setText( value );
444 if ( mode == WidgetSetMode::ReturnPressed )
446 emit mAngleLineEdit->returnPressed();
448 else if ( mode == WidgetSetMode::FocusOut )
450 emit mAngleLineEdit->textEdited( value );
455 mDistanceLineEdit->setText( value );
456 if ( mode == WidgetSetMode::ReturnPressed )
458 emit mDistanceLineEdit->returnPressed();
460 else if ( mode == WidgetSetMode::FocusOut )
462 QEvent *e =
new QEvent( QEvent::FocusOut );
463 QCoreApplication::postEvent( mDistanceLineEdit, e );
465 else if ( mode == WidgetSetMode::TextEdited )
467 emit mDistanceLineEdit->textEdited( value );
472void QgsAdvancedDigitizingDockWidget::setCadEnabled(
bool enabled )
474 mCadEnabled = enabled;
475 mEnableAction->setChecked( enabled );
476 mConstructionModeAction->setEnabled( enabled );
477 mSettingsAction->setEnabled( enabled );
478 mInputWidgets->setEnabled( enabled );
479 mFloaterAction->setEnabled( enabled );
480 mConstructionAction->setEnabled( enabled );
485 mLineExtensionAction->setChecked(
false );
486 mXyVertexAction->setChecked(
false );
488 mParallelAction->setEnabled(
false );
489 mPerpendicularAction->setEnabled(
false );
495 setConstructionMode(
false );
511 bool enableZ =
false;
512 bool enableM =
false;
516 switch ( layer->type() )
518 case Qgis::LayerType::Vector:
527 case Qgis::LayerType::Mesh:
529 QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
534 case Qgis::LayerType::Raster:
535 case Qgis::LayerType::Plugin:
536 case Qgis::LayerType::VectorTile:
537 case Qgis::LayerType::Annotation:
538 case Qgis::LayerType::PointCloud:
539 case Qgis::LayerType::Group:
550 mRelativeZButton->setEnabled(
enable );
551 mZLabel->setEnabled(
enable );
552 mZLineEdit->setEnabled(
enable );
553 if ( mZLineEdit->isEnabled() )
557 mLockZButton->setEnabled(
enable );
563 mRelativeMButton->setEnabled(
enable );
564 mMLabel->setEnabled(
enable );
565 mMLineEdit->setEnabled(
enable );
566 if ( mMLineEdit->isEnabled() )
570 mLockMButton->setEnabled(
enable );
574void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
576 enabled &= mCurrentMapToolSupportsCad;
578 mSessionActive = enabled;
580 if ( enabled && !isVisible() )
585 setCadEnabled( enabled );
588void QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked(
bool activated )
594 else if ( sender() == mParallelAction )
598 else if ( sender() == mPerpendicularAction )
604void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
606 if ( sender() == mRelativeAngleButton )
608 mAngleConstraint->setRelative( activate );
611 else if ( sender() == mRelativeXButton )
613 mXConstraint->setRelative( activate );
616 else if ( sender() == mRelativeYButton )
618 mYConstraint->setRelative( activate );
621 else if ( sender() == mRelativeZButton )
623 mZConstraint->setRelative( activate );
626 else if ( sender() == mRelativeMButton )
628 mMConstraint->setRelative( activate );
633void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock(
bool activate )
635 if ( sender() == mRepeatingLockDistanceButton )
637 mDistanceConstraint->setRepeatingLock( activate );
639 else if ( sender() == mRepeatingLockAngleButton )
641 mAngleConstraint->setRepeatingLock( activate );
643 else if ( sender() == mRepeatingLockXButton )
645 mXConstraint->setRepeatingLock( activate );
647 else if ( sender() == mRepeatingLockYButton )
649 mYConstraint->setRepeatingLock( activate );
651 else if ( sender() == mRepeatingLockZButton )
653 mZConstraint->setRepeatingLock( activate );
655 else if ( sender() == mRepeatingLockMButton )
657 mMConstraint->setRepeatingLock( activate );
661void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
663 mConstructionMode = enabled;
664 mConstructionModeAction->setChecked( enabled );
667void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
670 const QMap<QAction *, double>::const_iterator ica = mCommonAngleActions.constFind( action );
671 if ( ica != mCommonAngleActions.constEnd() )
673 ica.key()->setChecked(
true );
674 mCommonAngleConstraint = ica.value();
676 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
682QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
const
686 return advancedTool->layer();
700 if ( releaseRepeatingLocks )
702 mXyVertexAction->setChecked(
false );
706 mLineExtensionAction->setChecked(
false );
713 if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
718 if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
723 if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
728 if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
733 if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
738 if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
744 if ( !mCadPointList.empty() )
746 if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
748 mXConstraint->setValue( mCadPointList.constLast().x(),
true );
750 if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
752 mYConstraint->setValue( mCadPointList.constLast().y(),
true );
754 if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
756 mZConstraint->setValue( mCadPointList.constLast().z(),
true );
758 if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
760 mMConstraint->setValue( mCadPointList.constLast().m(),
true );
767void QgsAdvancedDigitizingDockWidget::emit pointChanged()
770 QPoint globalPos = mMapCanvas->cursor().pos();
771 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
772 QMouseEvent *e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
773 mCurrentMapTool->canvasMoveEvent( e );
779 CadConstraint *constraint =
nullptr;
780 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
782 constraint = mAngleConstraint.get();
784 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
786 constraint = mDistanceConstraint.get();
788 else if ( obj == mXLineEdit || obj == mLockXButton )
790 constraint = mXConstraint.get();
792 else if ( obj == mYLineEdit || obj == mLockYButton )
794 constraint = mYConstraint.get();
796 else if ( obj == mZLineEdit || obj == mLockZButton )
798 constraint = mZConstraint.get();
800 else if ( obj == mMLineEdit || obj == mLockMButton )
802 constraint = mMConstraint.get();
804 else if ( obj == mLineExtensionAction )
806 constraint = mLineExtensionConstraint.get();
808 else if ( obj == mXyVertexAction )
810 constraint = mXyVertexConstraint.get();
815double QgsAdvancedDigitizingDockWidget::parseUserInput(
const QString &inputValue,
const Qgis::CadConstraintType type,
bool &ok )
const
819 QString cleanedInputValue { inputValue };
823 cleanedInputValue.remove( tr(
"°" ) );
843 value *= factorUnits;
859 const QVariant result = expr.evaluate();
860 if ( expr.hasEvalError() )
863 QString inputValueC { inputValue };
866 if ( inputValue.contains( QLocale().groupSeparator() ) )
868 inputValueC.remove( QLocale().groupSeparator() );
870 const QVariant resultC = exprC.evaluate();
871 if ( ! exprC.hasEvalError() )
873 value = resultC.toDouble( &ok );
878 if ( !ok && QLocale().decimalPoint() != QChar(
'.' ) && inputValueC.contains( QLocale().decimalPoint() ) )
880 QgsExpression exprC( inputValueC .replace( QLocale().decimalPoint(), QChar(
'.' ) ) );
881 const QVariant resultC = exprC.evaluate();
882 if ( ! exprC.hasEvalError() )
884 value = resultC.toDouble( &ok );
890 value = result.toDouble( &ok );
896void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
898 if ( !constraint || textValue.isEmpty() )
907 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
911 constraint->setValue( value, convertExpression );
916void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
918 CadConstraint *constraint = objectToConstraint( sender() );
926 const QString textValue = constraint->lineEdit()->text();
927 if ( !textValue.isEmpty() )
930 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
933 constraint->setValue( value );
947 if ( constraint == mXConstraint.get() )
951 else if ( constraint == mYConstraint.get() )
955 else if ( constraint == mZConstraint.get() )
959 else if ( constraint == mMConstraint.get() )
963 else if ( constraint == mDistanceConstraint.get() )
967 else if ( constraint == mAngleConstraint.get() )
975 if ( constraint == mAngleConstraint.get() )
985void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
987 CadConstraint *constraint = objectToConstraint( sender() );
993 updateConstraintValue( constraint, textValue,
false );
996void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
998 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
1002 CadConstraint *constraint = objectToConstraint( lineEdit );
1008 updateConstraintValue( constraint, lineEdit->text(),
true );
1013 mBetweenLineConstraint = constraint;
1018void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint(
bool activate )
1020 CadConstraint *constraint = objectToConstraint( sender() );
1028 if ( constraint == mXyVertexConstraint.get() )
1032 else if ( constraint == mLineExtensionConstraint.get() )
1046void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
1048 CadCapacities newCapacities = CadCapacities();
1052 if ( mCadPointList.count() > 1 )
1055 if ( !isGeographic )
1061 if ( mCadPointList.count() > 2 )
1063 if ( !isGeographic )
1066 if ( !updateUIwithoutChange && newCapacities == mCapacities )
1076 const bool distance = mCadEnabled && newCapacities.testFlag(
Distance );
1077 const bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
1078 const bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
1079 const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag(
RelativeCoordinates );
1081 mPerpendicularAction->setEnabled( distance && snappingEnabled );
1082 mParallelAction->setEnabled( distance && snappingEnabled );
1084 mLineExtensionAction->setEnabled( snappingEnabled );
1085 mXyVertexAction->setEnabled( snappingEnabled );
1089 if ( !snappingEnabled )
1091 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode." ) );
1092 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode." ) );
1093 mLineExtensionAction->setToolTip( tr(
"Snapping must be enabled to utilize line extension mode." ) );
1094 mXyVertexAction->setToolTip( tr(
"Snapping must be enabled to utilize xy point mode." ) );
1096 else if ( mCadPointList.count() <= 1 )
1098 mPerpendicularAction->setToolTip( tr(
"A first vertex should be drawn to utilize perpendicular mode." ) );
1099 mParallelAction->setToolTip( tr(
"A first vertex should be drawn to utilize parallel mode." ) );
1101 else if ( isGeographic )
1103 mPerpendicularAction->setToolTip( tr(
"Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1104 mParallelAction->setToolTip( tr(
"Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1108 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1109 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1113 if ( !absoluteAngle )
1119 mLockAngleButton->setEnabled( absoluteAngle );
1120 mRelativeAngleButton->setEnabled( relativeAngle );
1121 mAngleLineEdit->setEnabled( absoluteAngle );
1123 if ( !absoluteAngle )
1127 if ( !relativeAngle )
1129 mAngleConstraint->setRelative(
false );
1132 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
1135 mAngleConstraint->setRelative(
true );
1140 mLockDistanceButton->setEnabled( distance && relativeCoordinates );
1141 mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
1143 if ( !( distance && relativeCoordinates ) )
1148 mRelativeXButton->setEnabled( relativeCoordinates );
1149 mRelativeYButton->setEnabled( relativeCoordinates );
1150 mRelativeZButton->setEnabled( relativeCoordinates );
1151 mRelativeMButton->setEnabled( relativeCoordinates );
1154 mCapacities = newCapacities;
1162 constr.
locked =
c->isLocked();
1164 constr.
value =
c->value();
1171 if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
1177 const int lastIndex = mLockedSnapVertices.length() - 1;
1178 for (
int i = lastIndex ; i >= 0; --i )
1180 if ( mLockedSnapVertices[i].point() == snapMatch.
point() )
1182 if ( snapMatch.
point() != previouslySnap.
point() )
1184 mLockedSnapVertices.removeAt( i );
1190 if ( snapMatch.
point() != previouslySnap.
point() )
1192 mLockedSnapVertices.enqueue( snapMatch );
1195 if ( mLockedSnapVertices.count() > 3 )
1197 mLockedSnapVertices.dequeue();
1206 context.
xConstraint = _constraint( mXConstraint.get() );
1207 context.
yConstraint = _constraint( mYConstraint.get() );
1208 context.
zConstraint = _constraint( mZConstraint.get() );
1209 context.
mConstraint = _constraint( mMConstraint.get() );
1226 const bool res = output.
valid;
1228 mSnappedSegment.clear();
1233 mSnappedSegment << edgePt0 << edgePt1;
1254 mSnapIndicator->setMatch( output.
snapMatch );
1255 mSnapIndicator->setVisible(
true );
1259 mSnapIndicator->setVisible(
false );
1280 if ( mSnapMatch.
layer() )
1292 toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
1293 mLastSnapMatch = mSnapMatch;
1303 if ( mLockZButton->isChecked() )
1305 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1307 if ( mLockMButton->isChecked() )
1309 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1315 updateUnlockedConstraintValues( point );
1323 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
1330void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPoint &point )
1332 bool previousPointExist, penulPointExist;
1337 if ( !mAngleConstraint->isLocked() && previousPointExist )
1339 double prevAngle = 0.0;
1341 if ( penulPointExist && mAngleConstraint->relative() )
1344 prevAngle = std::atan2( previousPt.
y() - penultimatePt.
y(),
1345 previousPt.
x() - penultimatePt.
x() ) * 180 / M_PI;
1348 const double xAngle { std::atan2( point.
y() - previousPt.
y(),
1349 point.
x() - previousPt.
x() ) * 180 / M_PI };
1352 const double angle = std::fmod( xAngle - prevAngle, 360.0 );
1353 mAngleConstraint->setValue(
angle );
1356 double bearing { std::fmod( xAngle, 360.0 ) };
1357 bearing = bearing <= 90.0 ? 90.0 - bearing : ( bearing > 90 ? 270.0 + 180.0 - bearing : 270.0 - bearing );
1364 if ( !mDistanceConstraint->isLocked() && previousPointExist )
1366 mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
1369 if ( !mXConstraint->isLocked() )
1371 if ( previousPointExist && mXConstraint->relative() )
1373 mXConstraint->setValue( point.
x() - previousPt.
x() );
1377 mXConstraint->setValue( point.
x() );
1381 if ( !mYConstraint->isLocked() )
1383 if ( previousPointExist && mYConstraint->relative() )
1385 mYConstraint->setValue( point.
y() - previousPt.
y() );
1389 mYConstraint->setValue( point.
y() );
1393 if ( !mZConstraint->isLocked() )
1395 if ( previousPointExist && mZConstraint->relative() )
1397 mZConstraint->setValue( point.
z() - previousPt.
z() );
1401 mZConstraint->setValue( point.
z() );
1405 if ( !mMConstraint->isLocked() )
1407 if ( previousPointExist && mMConstraint->relative() )
1409 mMConstraint->setValue( point.
m() - previousPt.
m() );
1413 mMConstraint->setValue( point.
m() );
1419QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
1431 localConfig.
setTypeFlag( Qgis::SnappingType::Segment );
1432 snappingUtils->
setConfig( localConfig );
1434 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
1436 snappingUtils->
setConfig( canvasConfig );
1446 *snapped =
segment.count() == 2;
1459 bool previousPointExist, penulPointExist, snappedSegmentExist;
1462 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
1464 if ( !previousPointExist || !snappedSegmentExist )
1469 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1471 if ( mAngleConstraint->relative() && penulPointExist )
1473 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
1481 angle *= 180 / M_PI;
1483 mAngleConstraint->setValue(
angle );
1484 mAngleConstraint->setLockMode( lockMode );
1502 case Qt::Key_Backspace:
1503 case Qt::Key_Delete:
1509 case Qt::Key_Escape:
1539 case Qt::Key_Backspace:
1540 case Qt::Key_Delete:
1546 case Qt::Key_Escape:
1553 filterKeyPress( e );
1562 const auto constPoints = points;
1569bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1573 return QgsDockWidget::eventFilter( obj, event );
1581 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1583 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
1585 return filterKeyPress( keyEvent );
1588 return QgsDockWidget::eventFilter( obj, event );
1591bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1597 const QEvent::Type type = e->type();
1603 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1605 mXConstraint->toggleLocked();
1610 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1614 mXConstraint->toggleRelative();
1621 else if ( type == QEvent::KeyPress )
1623 mXLineEdit->setFocus();
1624 mXLineEdit->selectAll();
1633 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1635 mYConstraint->toggleLocked();
1640 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1644 mYConstraint->toggleRelative();
1651 else if ( type == QEvent::KeyPress )
1653 mYLineEdit->setFocus();
1654 mYLineEdit->selectAll();
1663 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1665 mZConstraint->toggleLocked();
1670 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1674 mZConstraint->toggleRelative();
1681 else if ( type == QEvent::KeyPress )
1683 mZLineEdit->setFocus();
1684 mZLineEdit->selectAll();
1693 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1695 mMConstraint->toggleLocked();
1700 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1704 mMConstraint->toggleRelative();
1711 else if ( type == QEvent::KeyPress )
1713 mMLineEdit->setFocus();
1714 mMLineEdit->selectAll();
1723 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1727 mAngleConstraint->toggleLocked();
1733 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1737 mAngleConstraint->toggleRelative();
1744 else if ( type == QEvent::KeyPress )
1746 mAngleLineEdit->setFocus();
1747 mAngleLineEdit->selectAll();
1756 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1760 mDistanceConstraint->toggleLocked();
1767 else if ( type == QEvent::KeyPress )
1769 mDistanceLineEdit->setFocus();
1770 mDistanceLineEdit->selectAll();
1778 if ( type == QEvent::KeyPress )
1780 setConstructionMode( !mConstructionMode );
1787 if ( type == QEvent::KeyPress )
1789 const bool parallel = mParallelAction->isChecked();
1790 const bool perpendicular = mPerpendicularAction->isChecked();
1792 if ( !parallel && !perpendicular )
1796 else if ( perpendicular )
1813 if ( type == QEvent::ShortcutOverride )
1815 const QList<double> constActionValues { mCommonAngleActions.values() };
1816 const int currentAngleActionIndex {
static_cast<int>( constActionValues.indexOf( mCommonAngleConstraint ) ) };
1817 const QList<QAction *> constActions { mCommonAngleActions.keys( ) };
1818 QAction *nextAngleAction;
1819 if ( e->modifiers() == Qt::ShiftModifier )
1821 nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
1825 nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
1827 nextAngleAction->trigger();
1837 return e->isAccepted();
1846 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1847 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1849 mLabelX->setText( tr(
"Long" ) );
1850 mLabelY->setText( tr(
"Lat" ) );
1852 mXConstraint->setPrecision( 8 );
1853 mYConstraint->setPrecision( 8 );
1857 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
1858 mAngleLineEdit->setToolTip( QString() );
1860 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
1862 mLabelX->setText( tr(
"x" ) );
1863 mLabelY->setText( tr(
"y" ) );
1865 mXConstraint->setPrecision( 6 );
1866 mYConstraint->setPrecision( 6 );
1871 mEnableAction->setEnabled(
true );
1872 mErrorLabel->hide();
1875 mCurrentMapToolSupportsCad =
true;
1877 if ( mSessionActive && !isVisible() )
1881 setCadEnabled( mSessionActive );
1888 mEnableAction->setEnabled(
false );
1889 mErrorLabel->setText( tr(
"CAD tools are not enabled for the current map tool" ) );
1890 mErrorLabel->show();
1893 mCurrentMapToolSupportsCad =
false;
1895 mSnapIndicator->setVisible(
false );
1897 setCadEnabled(
false );
1902 mCadPaintItem->update();
1907 if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
1912 mLockedSnapVertices.clear();
1918 QgsPoint pt = pointXYToPoint( point );
1921 mCadPointList << pt;
1925 mCadPointList.insert( 0, pt );
1938 mCadPointList.removeAt( i );
1945 mCadPointList.clear();
1946 mSnappedSegment.clear();
1956 mCadPointList << point;
1961 mCadPointList[0] = point;
1969 mLockerButton->setChecked( mode ==
HardLock );
1970 if ( mRepeatingLockButton )
1974 mRepeatingLockButton->setEnabled(
true );
1978 mRepeatingLockButton->setChecked(
false );
1979 mRepeatingLockButton->setEnabled(
false );
1992 mRepeatingLock = repeating;
1993 if ( mRepeatingLockButton )
1994 mRepeatingLockButton->setChecked( repeating );
1999 mRelative = relative;
2000 if ( mRelativeButton )
2002 mRelativeButton->setChecked( relative );
2009 if ( updateWidget && mLineEdit->isEnabled() )
2010 mLineEdit->setText( displayValue() );
2015 switch ( mCadConstraintType )
2019 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2026 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2030 return QLocale().toString( mValue,
'f', mPrecision );
2038 const double convertedValue { mValue * factorUnits };
2047 return QLocale().toString( mValue,
'f', mPrecision );
2052 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
2057 setRelative( !mRelative );
2063 if ( mLineEdit->isEnabled() )
2064 mLineEdit->setText( displayValue() );
2069 return mCadConstraintType;
2074 mCadConstraintType = constraintType;
2079 mMapCanvas = mapCanvas;
2087 return mCadPointList.value( 0 );
2096 QgsPoint res = mCadPointList.value( 0 );
2098 res.
setX( layerCoordinates.
x() );
2099 res.
setY( layerCoordinates.
y() );
2110 return mCadPointList.value( 1 );
2120 return mCadPointList.value( 2 );
2125QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
2132 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2137 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
DistanceUnit
Units of distance.
CadConstraintType
Advanced digitizing constraint type.
@ Distance
Distance value.
@ YCoordinate
Y Coordinate value.
@ XCoordinate
X Coordinate value.
@ AllLayers
On all vector layers.
BetweenLineConstraint
Between line constraints which can be enabled.
@ NoConstraint
No additional constraint.
@ Perpendicular
Perpendicular.
WkbType
The WKB type describes the number of dimensions a geometry has.
The QgsAdvancedDigitizingCanvasItem class draws the graphical elements of the CAD tools (.
void updatePosition() override
called on changed extent or resize event to update position of the item
The QgsAdvancedDigitizingFloater class is widget that floats next to the mouse pointer,...
void setItemVisibility(const QgsAdvancedDigitizingFloater::FloaterItem &item, bool visible)
Set whether the floater item should be visible or not.
void setActive(bool active)
Set whether the floater should be active or not.
bool active()
Whether the floater is active or not.
Structure with details of one constraint.
bool locked
Whether the constraint is active, i.e. should be considered.
double value
Numeric value of the constraint (coordinate/distance in map units or angle in degrees)
bool relative
Whether the value is relative to previous value.
Defines constraints for the QgsCadUtils::alignMapPoint() method.
QgsCadUtils::AlignMapPointConstraint xyVertexConstraint
QgsCadUtils::AlignMapPointConstraint yConstraint
Constraint for Y coordinate.
QgsCadUtils::AlignMapPointConstraint xConstraint
Constraint for X coordinate.
double mapUnitsPerPixel
Map units/pixel ratio from map canvas.
void setCadPoints(const QList< QgsPoint > &points)
Sets the list of recent CAD points (in map coordinates).
void setLockedSnapVertices(const QQueue< QgsPointLocator::Match > &lockedSnapVertices)
Sets the queue of locked vertices.
QgsCadUtils::AlignMapPointConstraint mConstraint
Constraint for M coordinate.
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
bool snappingToFeaturesOverridesCommonAngle
Flag to set snapping to features priority over common angle.
QgsCadUtils::AlignMapPointConstraint zConstraint
Constraint for Z coordinate.
QgsSnappingUtils * snappingUtils
Snapping utils that will be used to snap point to map. Must not be nullptr.
QgsCadUtils::AlignMapPointConstraint commonAngleConstraint
Constraint for soft lock to a common angle.
QgsCadUtils::AlignMapPointConstraint lineExtensionConstraint
QgsCadUtils::AlignMapPointConstraint angleConstraint
Constraint for angle.
Structure returned from alignMapPoint() method.
Qgis::LineExtensionSide softLockLineExtension
QgsPointXY finalMapPoint
map point aligned according to the constraints
bool valid
Whether the combination of constraints is actually valid.
QgsPointLocator::Match snapMatch
Snapped point - only valid if actually used for something.
double softLockCommonAngle
Angle (in degrees) to which we have soft-locked ourselves (if not set it is -1)
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.
static QString formatDistance(double distance, int decimals, Qgis::DistanceUnit unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
Class for parsing and evaluation of expressions (formerly called "search strings").
A event filter for watching for focus events on a parent object.
void focusOut()
Emitted when parent object loses focus.
Map canvas is a class for displaying all GIS data types on a canvas.
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
void destinationCrsChanged()
Emitted when map CRS has changed.
QgsMapTool * mapTool()
Returns the currently active tool.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
Base class for all map layer types.
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsPointXY originalMapPoint() const
Returns the original, unmodified map point of the mouse cursor.
void setMapPoint(const QgsPointXY &point)
Set the (snapped) point this event points to in map coordinates.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
bool isEditable() const override
Returns true if the layer can be edited.
A context for numeric formats.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
void setY(double y) SIP_HOLDGIL
Sets the point's y-coordinate.
void setZ(double z) SIP_HOLDGIL
Sets the point's z-coordinate.
double distanceSquared(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
void setM(double m) SIP_HOLDGIL
Sets the point's m-value.
const QgsBearingNumericFormat * bearingFormat() const
Returns the project bearing's format, which controls how bearings associated with the project are dis...
Qgis::DistanceUnit distanceUnits
static QgsProject * instance()
Returns the QgsProject singleton instance.
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsSnappingConfig snappingConfig
QgsProjectDisplaySettings * displaySettings
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
bool setValue(const T &value, const QString &dynamicKeyPart=QString()) const
Set settings value.
A boolean settings entry.
static QgsSettingsTreeNode * sTreeDigitizing
This class is a composition of two QSettings instances:
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Class that shows snapping marker on map canvas for the current snapping match.
This is a container for configuration of the snapping of the project.
void setTypeFlag(Qgis::SnappingTypes type)
define the type of snapping
void setMode(Qgis::SnappingMode mode)
define the mode of snapping
bool enabled() const
Returns if snapping is enabled.
This class has all the configuration of snapping and can return answers to snapping queries.
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE QString toAbbreviatedString(Qgis::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
static bool hasZ(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
QLineF segment(int index, QRectF rect, double radius)
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
QgsPoint interpolatedPoint(const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem()) const
Convenient method to return a point on an edge with linear interpolation of the Z value.
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
bool hasEdge() const
Returns true if the Match is an edge.
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
bool hasVertex() const
Returns true if the Match is a vertex.