18#include <QCoreApplication>
45#include <QActionGroup>
56 , mMapCanvas( canvas )
57 , mUserInputWidget( userInputWidget )
59 , mCommonAngleConstraint(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
65 mAngleConstraint.reset(
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
67 mAngleConstraint->setMapCanvas( mMapCanvas );
68 mDistanceConstraint.reset(
new CadConstraint( mDistanceLineEdit, mLockDistanceButton,
nullptr, mRepeatingLockDistanceButton ) );
70 mDistanceConstraint->setMapCanvas( mMapCanvas );
71 mXConstraint.reset(
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
73 mXConstraint->setMapCanvas( mMapCanvas );
74 mYConstraint.reset(
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
76 mYConstraint->setMapCanvas( mMapCanvas );
77 mZConstraint.reset(
new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
79 mZConstraint->setMapCanvas( mMapCanvas );
80 mMConstraint.reset(
new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
82 mMConstraint->setMapCanvas( mMapCanvas );
84 mLineExtensionConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
85 mXyVertexConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
86 mXyVertexConstraint->setMapCanvas( mMapCanvas );
90 mMapCanvas->installEventFilter(
this );
91 mAngleLineEdit->installEventFilter(
this );
92 mDistanceLineEdit->installEventFilter(
this );
93 mXLineEdit->installEventFilter(
this );
94 mYLineEdit->installEventFilter(
this );
95 mZLineEdit->installEventFilter(
this );
96 mMLineEdit->installEventFilter(
this );
99 connect( mEnableAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::activateCad );
100 connect( mConstructionModeAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
101 connect( mParallelAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
102 connect( mPerpendicularAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
103 connect( mLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
104 connect( mLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
105 connect( mLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
106 connect( mLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
107 connect( mLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
108 connect( mLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
109 connect( mRelativeAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
110 connect( mRelativeXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
111 connect( mRelativeYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
112 connect( mRelativeZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
113 connect( mRelativeMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
114 connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
115 connect( mRepeatingLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
116 connect( mRepeatingLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
117 connect( mRepeatingLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
118 connect( mRepeatingLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
119 connect( mRepeatingLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
120 connect( mAngleLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
121 connect( mDistanceLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
122 connect( mXLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
123 connect( mYLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
124 connect( mZLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
125 connect( mMLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
126 connect( mAngleLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
127 connect( mDistanceLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
128 connect( mXLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
129 connect( mYLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
130 connect( mZLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
131 connect( mMLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
138 whileBlocking( mAngleLineEdit )->setText( cleanedInputValue );
145 whileBlocking( mDistanceLineEdit )->setText( cleanedInputValue );
157 mCommonAngleActionsMenu =
new QMenu(
this );
159#ifndef __clang_analyzer__
160 QActionGroup *angleButtonGroup =
new QActionGroup( mCommonAngleActionsMenu );
162 QList< QPair< double, QString > > commonAngles;
163 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} );
164 for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
170 QMenu *snappingPriorityMenu =
new QMenu( tr(
"Snapping Priority" ), mCommonAngleActionsMenu );
171 QActionGroup *snappingPriorityActionGroup =
new QActionGroup( snappingPriorityMenu );
172 QAction *featuresAction =
new QAction( tr(
"Prioritize Snapping to Features" ), snappingPriorityActionGroup );
173 featuresAction->setCheckable(
true );
174 QAction *anglesAction =
new QAction( tr(
"Prioritize Snapping to Common Angles" ), snappingPriorityActionGroup );
175 anglesAction->setCheckable(
true );
176 snappingPriorityActionGroup->addAction( featuresAction );
177 snappingPriorityActionGroup->addAction( anglesAction );
178 snappingPriorityMenu->addAction( anglesAction );
179 snappingPriorityMenu->addAction( featuresAction );
180 connect( anglesAction, &QAction::changed,
this, [ = ]
182 mSnappingPrioritizeFeatures = featuresAction->isChecked();
183 settingsCadSnappingPriorityPrioritizeFeature->
setValue( featuresAction->isChecked() );
185 featuresAction->setChecked( settingsCadSnappingPriorityPrioritizeFeature->
value( ) );
186 anglesAction->setChecked( ! featuresAction->isChecked() );
187 mCommonAngleActionsMenu->addMenu( snappingPriorityMenu );
190 for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
192 QAction *action =
new QAction( it->second, mCommonAngleActionsMenu );
193 action->setCheckable(
true );
194 action->setChecked( it->first == mCommonAngleConstraint );
195 mCommonAngleActionsMenu->addAction( action );
197#ifndef __clang_analyzer__
198 angleButtonGroup->addAction( action );
200 mCommonAngleActions.insert( it->first, action );
204 QMenu *constructionSettingsMenu =
new QMenu(
this );
206 mRecordConstructionGuides =
new QAction( tr(
"Record Construction Guides" ), constructionSettingsMenu );
207 mRecordConstructionGuides->setCheckable(
true );
208 mRecordConstructionGuides->setChecked( settingsCadRecordConstructionGuides->
value() );
209 constructionSettingsMenu->addAction( mRecordConstructionGuides );
210 connect( mRecordConstructionGuides, &QAction::triggered,
this, [ = ]() { settingsCadRecordConstructionGuides->
setValue( mRecordConstructionGuides->isChecked() ); } );
212 mShowConstructionGuides =
new QAction( tr(
"Show Construction Guides" ), constructionSettingsMenu );
213 mShowConstructionGuides->setCheckable(
true );
214 mShowConstructionGuides->setChecked( settingsCadShowConstructionGuides->
value() );
215 constructionSettingsMenu->addAction( mShowConstructionGuides );
216 connect( mShowConstructionGuides, &QAction::triggered,
this, [ = ]()
218 settingsCadShowConstructionGuides->
setValue( mShowConstructionGuides->isChecked() );
222 mSnapToConstructionGuides =
new QAction( tr(
"Snap to Visible Construction Guides" ), constructionSettingsMenu );
223 mSnapToConstructionGuides->setCheckable(
true );
224 mSnapToConstructionGuides->setChecked( settingsCadSnapToConstructionGuides->
value() );
225 constructionSettingsMenu->addAction( mSnapToConstructionGuides );
226 connect( mSnapToConstructionGuides, &QAction::triggered,
this, [ = ]() { settingsCadSnapToConstructionGuides->
setValue( mSnapToConstructionGuides->isChecked() ); } );
228 constructionSettingsMenu->addSeparator();
230 mClearConstructionGuides =
new QAction( tr(
"Clear Construction Guides" ), constructionSettingsMenu );
231 constructionSettingsMenu->addAction( mClearConstructionGuides );
232 connect( mClearConstructionGuides, &QAction::triggered,
this, [ = ]()
234 resetConstructionGuides();
238 QToolButton *constructionModeToolButton = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionModeAction ) );
239 constructionModeToolButton->setPopupMode( QToolButton::MenuButtonPopup );
240 constructionModeToolButton->setMenu( constructionSettingsMenu );
241 constructionModeToolButton->setObjectName( QStringLiteral(
"ConstructionModeButton" ) );
244 QMenu *toolsMenu =
new QMenu(
this );
245 connect( toolsMenu, &QMenu::aboutToShow,
this, [ = ]()
249 for (
const QString &name : toolMetadataNames )
252 QAction *toolAction =
new QAction( toolMetadata->
icon(), toolMetadata->
visibleName(), toolsMenu );
253 connect( toolAction, &QAction::triggered,
this, [ = ]()
257 toolsMenu->addAction( toolAction );
260 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mToolsAction ) )->setPopupMode( QToolButton::InstantPopup );
261 mToolsAction->setMenu( toolsMenu );
263 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
264 mSettingsAction->setMenu( mCommonAngleActionsMenu );
265 mSettingsAction->setCheckable(
true );
266 mSettingsAction->setToolTip(
"<b>" + tr(
"Snap to common angles" ) +
"</b><br>(" + tr(
"press n to cycle through the options" ) +
")" );
267 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
268 connect( mCommonAngleActionsMenu, &QMenu::triggered,
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
271 QMenu *constructionMenu =
new QMenu(
this );
273 mLineExtensionAction =
new QAction( tr(
"Line Extension" ), constructionMenu );
274 mLineExtensionAction->setCheckable(
true );
275 constructionMenu->addAction( mLineExtensionAction );
276 connect( mLineExtensionAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
278 mXyVertexAction =
new QAction( tr(
"X/Y Point" ), constructionMenu );
279 mXyVertexAction->setCheckable(
true );
280 constructionMenu->addAction( mXyVertexAction );
281 connect( mXyVertexAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
283 auto constructionToolBar = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionAction ) );
284 constructionToolBar->setPopupMode( QToolButton::InstantPopup );
285 constructionToolBar->setMenu( constructionMenu );
286 constructionToolBar->setObjectName( QStringLiteral(
"ConstructionButton" ) );
288 mConstructionAction->setMenu( mCommonAngleActionsMenu );
289 mConstructionAction->setCheckable(
true );
290 mConstructionAction->setToolTip( tr(
"Construction Tools" ) );
294 mConstructionModeAction->setToolTip(
"<b>" + tr(
"Construction mode" ) +
"</b><br>(" + tr(
"press c to toggle on/off" ) +
")" );
295 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
296 mLockDistanceButton->setToolTip(
"<b>" + tr(
"Lock distance" ) +
"</b><br>(" + tr(
"press Ctrl + d for quick access" ) +
")" );
297 mRepeatingLockDistanceButton->setToolTip(
"<b>" + tr(
"Continuously lock distance" ) +
"</b>" );
299 mRelativeAngleButton->setToolTip(
"<b>" + tr(
"Toggles relative angle to previous segment" ) +
"</b><br>(" + tr(
"press Shift + a for quick access" ) +
")" );
300 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
301 mLockAngleButton->setToolTip(
"<b>" + tr(
"Lock angle" ) +
"</b><br>(" + tr(
"press Ctrl + a for quick access" ) +
")" );
302 mRepeatingLockAngleButton->setToolTip(
"<b>" + tr(
"Continuously lock angle" ) +
"</b>" );
304 mRelativeXButton->setToolTip(
"<b>" + tr(
"Toggles relative x to previous node" ) +
"</b><br>(" + tr(
"press Shift + x for quick access" ) +
")" );
305 mXLineEdit->setToolTip(
"<b>" + tr(
"X coordinate" ) +
"</b><br>(" + tr(
"press x for quick access" ) +
")" );
306 mLockXButton->setToolTip(
"<b>" + tr(
"Lock x coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + x for quick access" ) +
")" );
307 mRepeatingLockXButton->setToolTip(
"<b>" + tr(
"Continuously lock x coordinate" ) +
"</b>" );
309 mRelativeYButton->setToolTip(
"<b>" + tr(
"Toggles relative y to previous node" ) +
"</b><br>(" + tr(
"press Shift + y for quick access" ) +
")" );
310 mYLineEdit->setToolTip(
"<b>" + tr(
"Y coordinate" ) +
"</b><br>(" + tr(
"press y for quick access" ) +
")" );
311 mLockYButton->setToolTip(
"<b>" + tr(
"Lock y coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + y for quick access" ) +
")" );
312 mRepeatingLockYButton->setToolTip(
"<b>" + tr(
"Continuously lock y coordinate" ) +
"</b>" );
314 mRelativeZButton->setToolTip(
"<b>" + tr(
"Toggles relative z to previous node" ) +
"</b><br>(" + tr(
"press Shift + z for quick access" ) +
")" );
315 mZLineEdit->setToolTip(
"<b>" + tr(
"Z coordinate" ) +
"</b><br>(" + tr(
"press z for quick access" ) +
")" );
316 mLockZButton->setToolTip(
"<b>" + tr(
"Lock z coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + z for quick access" ) +
")" );
317 mRepeatingLockZButton->setToolTip(
"<b>" + tr(
"Continuously lock z coordinate" ) +
"</b>" );
319 mRelativeMButton->setToolTip(
"<b>" + tr(
"Toggles relative m to previous node" ) +
"</b><br>(" + tr(
"press Shift + m for quick access" ) +
")" );
320 mMLineEdit->setToolTip(
"<b>" + tr(
"M coordinate" ) +
"</b><br>(" + tr(
"press m for quick access" ) +
")" );
321 mLockMButton->setToolTip(
"<b>" + tr(
"Lock m coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + m for quick access" ) +
")" );
322 mRepeatingLockMButton->setToolTip(
"<b>" + tr(
"Continuously lock m coordinate" ) +
"</b>" );
333 mFloaterActionsMenu =
new QMenu(
this );
334 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mFloaterAction ) )->setPopupMode( QToolButton::InstantPopup );
335 mFloaterAction->setMenu( mFloaterActionsMenu );
336 mFloaterAction->setCheckable(
true );
338 mFloaterAction->setChecked( mFloater->
active() );
342 QAction *action =
new QAction( tr(
"Show floater" ), mFloaterActionsMenu );
343 action->setCheckable(
true );
344 action->setChecked( mFloater->
active() );
345 mFloaterActionsMenu->addAction( action );
346 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
349 mFloaterAction->setChecked( checked );
353 mFloaterActionsMenu->addSeparator();
356 QAction *action =
new QAction( tr(
"Show distance" ), mFloaterActionsMenu );
357 action->setCheckable(
true );
358 mFloaterActionsMenu->addAction( action );
359 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
363 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/DistanceShowInFloater" ),
true ).toBool() );
367 QAction *action =
new QAction( tr(
"Show angle" ), mFloaterActionsMenu );
368 action->setCheckable(
true );
369 mFloaterActionsMenu->addAction( action );
370 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
374 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/AngleShowInFloater" ),
true ).toBool() );
378 QAction *action =
new QAction( tr(
"Show XY coordinates" ), mFloaterActionsMenu );
379 action->setCheckable(
true );
380 mFloaterActionsMenu->addAction( action );
381 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
387 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/XCoordinateShowInFloater" ),
true ).toBool() );
391 QAction *action =
new QAction( tr(
"Show Z value" ), mFloaterActionsMenu );
392 action->setCheckable(
true );
393 mFloaterActionsMenu->addAction( action );
394 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
398 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/ZCoordinateShowInFloater" ),
true ).toBool() );
402 QAction *action =
new QAction( tr(
"Show M value" ), mFloaterActionsMenu );
403 action->setCheckable(
true );
404 mFloaterActionsMenu->addAction( action );
405 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
409 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/MCoordinateShowInFloater" ),
true ).toBool() );
413 QAction *action =
new QAction( tr(
"Show bearing/azimuth" ), mFloaterActionsMenu );
414 action->setCheckable(
true );
415 mFloaterActionsMenu->addAction( action );
416 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
420 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/BearingShowInFloater" ),
false ).toBool() );
424 QAction *action =
new QAction( tr(
"Show common snapping angle" ), mFloaterActionsMenu );
425 action->setCheckable(
true );
426 mFloaterActionsMenu->addAction( action );
427 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
431 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngleSnappingShowInFloater" ),
false ).toBool() );
434 updateCapacity(
true );
439 mConstructionGuidesLayer.reset();
450 mCurrentTool->deleteLater();
457 return tr(
"Do Not Snap to Common Angles" );
459 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 );
464 mXLineEdit->setText( value );
467 emit mXLineEdit->returnPressed();
471 QEvent *e =
new QEvent( QEvent::FocusOut );
472 QCoreApplication::postEvent( mXLineEdit, e );
476 emit mXLineEdit->textEdited( value );
481 mYLineEdit->setText( value );
484 emit mYLineEdit->returnPressed();
488 QEvent *e =
new QEvent( QEvent::FocusOut );
489 QCoreApplication::postEvent( mYLineEdit, e );
493 emit mYLineEdit->textEdited( value );
498 mZLineEdit->setText( value );
501 emit mZLineEdit->returnPressed();
505 QEvent *e =
new QEvent( QEvent::FocusOut );
506 QCoreApplication::postEvent( mZLineEdit, e );
510 emit mZLineEdit->textEdited( value );
515 mMLineEdit->setText( value );
518 emit mMLineEdit->returnPressed();
522 QEvent *e =
new QEvent( QEvent::FocusOut );
523 QCoreApplication::postEvent( mMLineEdit, e );
527 emit mMLineEdit->textEdited( value );
532 mAngleLineEdit->setText( value );
535 emit mAngleLineEdit->returnPressed();
539 emit mAngleLineEdit->textEdited( value );
544 mDistanceLineEdit->setText( value );
547 emit mDistanceLineEdit->returnPressed();
551 QEvent *e =
new QEvent( QEvent::FocusOut );
552 QCoreApplication::postEvent( mDistanceLineEdit, e );
556 emit mDistanceLineEdit->textEdited( value );
561void QgsAdvancedDigitizingDockWidget::setCadEnabled(
bool enabled )
563 mCadEnabled = enabled;
564 mEnableAction->setChecked( enabled );
565 mConstructionModeAction->setEnabled( enabled );
566 mSettingsAction->setEnabled( enabled );
567 mInputWidgets->setEnabled( enabled );
568 mFloaterAction->setEnabled( enabled );
569 mConstructionAction->setEnabled( enabled );
570 mToolsAction->setEnabled( enabled );
575 mLineExtensionAction->setChecked(
false );
576 mXyVertexAction->setChecked(
false );
578 mParallelAction->setEnabled(
false );
579 mPerpendicularAction->setEnabled(
false );
582 mCurrentTool->deleteLater();
589 setConstructionMode(
false );
605 bool enableZ =
false;
606 bool enableM =
false;
610 switch ( layer->type() )
623 QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
645 mRelativeZButton->setEnabled(
enable );
646 mZLabel->setEnabled(
enable );
647 mZLineEdit->setEnabled(
enable );
648 if ( mZLineEdit->isEnabled() )
652 mLockZButton->setEnabled(
enable );
658 mRelativeMButton->setEnabled(
enable );
659 mMLabel->setEnabled(
enable );
660 mMLineEdit->setEnabled(
enable );
661 if ( mMLineEdit->isEnabled() )
665 mLockMButton->setEnabled(
enable );
669void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
671 enabled &= mCurrentMapToolSupportsCad;
673 mSessionActive = enabled;
675 if ( enabled && !isVisible() )
680 setCadEnabled( enabled );
687 mCurrentTool->deleteLater();
688 mCurrentTool =
nullptr;
695 if ( QWidget *toolWidget = mCurrentTool->createWidget() )
697 toolWidget->setParent( mUserInputWidget );
706 return mCurrentTool.data();
709void QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked(
bool activated )
715 else if ( sender() == mParallelAction )
719 else if ( sender() == mPerpendicularAction )
725void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
727 if ( sender() == mRelativeAngleButton )
729 mAngleConstraint->setRelative( activate );
732 else if ( sender() == mRelativeXButton )
734 mXConstraint->setRelative( activate );
737 else if ( sender() == mRelativeYButton )
739 mYConstraint->setRelative( activate );
742 else if ( sender() == mRelativeZButton )
744 mZConstraint->setRelative( activate );
747 else if ( sender() == mRelativeMButton )
749 mMConstraint->setRelative( activate );
754void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock(
bool activate )
756 if ( sender() == mRepeatingLockDistanceButton )
758 mDistanceConstraint->setRepeatingLock( activate );
760 else if ( sender() == mRepeatingLockAngleButton )
762 mAngleConstraint->setRepeatingLock( activate );
764 else if ( sender() == mRepeatingLockXButton )
766 mXConstraint->setRepeatingLock( activate );
768 else if ( sender() == mRepeatingLockYButton )
770 mYConstraint->setRepeatingLock( activate );
772 else if ( sender() == mRepeatingLockZButton )
774 mZConstraint->setRepeatingLock( activate );
776 else if ( sender() == mRepeatingLockMButton )
778 mMConstraint->setRepeatingLock( activate );
782void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
784 mConstructionMode = enabled;
785 mConstructionModeAction->setChecked( enabled );
789 if ( enabled && mCadPointList.size() > 1 )
791 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
796void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
799 for (
auto it = mCommonAngleActions.cbegin(); it != mCommonAngleActions.cend(); ++it )
801 if ( it.value() == action )
803 it.value()->setChecked(
true );
804 mCommonAngleConstraint = it.key();
806 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
813QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
const
817 return advancedTool->layer();
831 if ( releaseRepeatingLocks )
833 mXyVertexAction->setChecked(
false );
837 mLineExtensionAction->setChecked(
false );
844 if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
849 if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
854 if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
859 if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
864 if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
869 if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
875 if ( !mCadPointList.empty() )
877 if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
879 mXConstraint->setValue( mCadPointList.constLast().x(),
true );
881 if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
883 mYConstraint->setValue( mCadPointList.constLast().y(),
true );
885 if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
887 mZConstraint->setValue( mCadPointList.constLast().z(),
true );
889 if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
891 mMConstraint->setValue( mCadPointList.constLast().m(),
true );
897void QgsAdvancedDigitizingDockWidget::emit pointChanged()
900 QPoint globalPos = mMapCanvas->cursor().pos();
901 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
902 QMouseEvent *e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
903 mCurrentMapTool->canvasMoveEvent( e );
909 CadConstraint *constraint =
nullptr;
910 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
912 constraint = mAngleConstraint.get();
914 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
916 constraint = mDistanceConstraint.get();
918 else if ( obj == mXLineEdit || obj == mLockXButton )
920 constraint = mXConstraint.get();
922 else if ( obj == mYLineEdit || obj == mLockYButton )
924 constraint = mYConstraint.get();
926 else if ( obj == mZLineEdit || obj == mLockZButton )
928 constraint = mZConstraint.get();
930 else if ( obj == mMLineEdit || obj == mLockMButton )
932 constraint = mMConstraint.get();
934 else if ( obj == mLineExtensionAction )
936 constraint = mLineExtensionConstraint.get();
938 else if ( obj == mXyVertexAction )
940 constraint = mXyVertexConstraint.get();
945double QgsAdvancedDigitizingDockWidget::parseUserInput(
const QString &inputValue,
const Qgis::CadConstraintType type,
bool &ok )
const
956 const QVariant result = expr.evaluate();
957 if ( expr.hasEvalError() )
960 QString inputValueC { inputValue };
963 if ( inputValue.contains( QLocale().groupSeparator() ) )
965 inputValueC.remove( QLocale().groupSeparator() );
967 const QVariant resultC = exprC.evaluate();
968 if ( ! exprC.hasEvalError() )
970 value = resultC.toDouble( &ok );
975 if ( !ok && QLocale().decimalPoint() != QChar(
'.' ) && inputValueC.contains( QLocale().decimalPoint() ) )
977 QgsExpression exprC( inputValueC .replace( QLocale().decimalPoint(), QChar(
'.' ) ) );
978 const QVariant resultC = exprC.evaluate();
979 if ( ! exprC.hasEvalError() )
981 value = resultC.toDouble( &ok );
987 value = result.toDouble( &ok );
993void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
995 if ( !constraint || textValue.isEmpty() )
1004 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
1008 constraint->setValue( value, convertExpression );
1013void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
1015 CadConstraint *constraint = objectToConstraint( sender() );
1023 const QString textValue = constraint->lineEdit()->text();
1024 if ( !textValue.isEmpty() )
1027 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
1030 constraint->setValue( value );
1044 if ( constraint == mXConstraint.get() )
1048 else if ( constraint == mYConstraint.get() )
1052 else if ( constraint == mZConstraint.get() )
1056 else if ( constraint == mMConstraint.get() )
1060 else if ( constraint == mDistanceConstraint.get() )
1064 else if ( constraint == mAngleConstraint.get() )
1072 if ( constraint == mAngleConstraint.get() )
1082void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
1084 CadConstraint *constraint = objectToConstraint( sender() );
1090 updateConstraintValue( constraint, textValue,
false );
1093void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
1095 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
1099 CadConstraint *constraint = objectToConstraint( lineEdit );
1105 updateConstraintValue( constraint, lineEdit->text(),
true );
1110 mBetweenLineConstraint = constraint;
1115void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint(
bool activate )
1117 CadConstraint *constraint = objectToConstraint( sender() );
1125 if ( constraint == mXyVertexConstraint.get() )
1129 else if ( constraint == mLineExtensionConstraint.get() )
1143void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
1149 if ( mCadPointList.count() > 1 )
1152 if ( !isGeographic )
1158 if ( mCadPointList.count() > 2 )
1160 if ( !isGeographic )
1163 if ( !updateUIwithoutChange && newCapacities == mCapacities )
1173 const bool distance = mCadEnabled && newCapacities.testFlag(
Distance );
1174 const bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
1175 const bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
1176 const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag(
RelativeCoordinates );
1178 mPerpendicularAction->setEnabled( distance && snappingEnabled );
1179 mParallelAction->setEnabled( distance && snappingEnabled );
1181 mLineExtensionAction->setEnabled( snappingEnabled );
1182 mXyVertexAction->setEnabled( snappingEnabled );
1186 if ( !snappingEnabled )
1188 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode." ) );
1189 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode." ) );
1190 mLineExtensionAction->setToolTip( tr(
"Snapping must be enabled to utilize line extension mode." ) );
1191 mXyVertexAction->setToolTip( tr(
"Snapping must be enabled to utilize xy point mode." ) );
1193 else if ( mCadPointList.count() <= 1 )
1195 mPerpendicularAction->setToolTip( tr(
"A first vertex should be drawn to utilize perpendicular mode." ) );
1196 mParallelAction->setToolTip( tr(
"A first vertex should be drawn to utilize parallel mode." ) );
1198 else if ( isGeographic )
1200 mPerpendicularAction->setToolTip( tr(
"Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1201 mParallelAction->setToolTip( tr(
"Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1205 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1206 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1210 if ( !absoluteAngle )
1216 mLockAngleButton->setEnabled( absoluteAngle );
1217 mRelativeAngleButton->setEnabled( relativeAngle );
1218 mAngleLineEdit->setEnabled( absoluteAngle );
1220 if ( !absoluteAngle )
1224 if ( !relativeAngle )
1226 mAngleConstraint->setRelative(
false );
1229 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
1232 mAngleConstraint->setRelative(
true );
1237 mLockDistanceButton->setEnabled( distance && relativeCoordinates );
1238 mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
1240 if ( !( distance && relativeCoordinates ) )
1245 mRelativeXButton->setEnabled( relativeCoordinates );
1246 mRelativeYButton->setEnabled( relativeCoordinates );
1247 mRelativeZButton->setEnabled( relativeCoordinates );
1248 mRelativeMButton->setEnabled( relativeCoordinates );
1251 mCapacities = newCapacities;
1259 constr.
locked =
c->isLocked();
1261 constr.
value =
c->value();
1268 if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
1274 const int lastIndex = mLockedSnapVertices.length() - 1;
1275 for (
int i = lastIndex ; i >= 0; --i )
1277 if ( mLockedSnapVertices[i].point() == snapMatch.
point() )
1279 if ( snapMatch.
point() != previouslySnap.
point() )
1281 mLockedSnapVertices.removeAt( i );
1287 if ( snapMatch.
point() != previouslySnap.
point() )
1289 mLockedSnapVertices.enqueue( snapMatch );
1292 if ( mLockedSnapVertices.count() > 3 )
1294 mLockedSnapVertices.dequeue();
1303 context.
xConstraint = _constraint( mXConstraint.get() );
1304 context.
yConstraint = _constraint( mYConstraint.get() );
1305 context.
zConstraint = _constraint( mZConstraint.get() );
1306 context.
mConstraint = _constraint( mMConstraint.get() );
1328 const bool res = output.
valid;
1330 mSnappedSegment.clear();
1335 mSnappedSegment << edgePt0 << edgePt1;
1356 mSnapIndicator->setMatch( output.
snapMatch );
1357 mSnapIndicator->setVisible(
true );
1361 mSnapIndicator->setVisible(
false );
1383 if ( mSnapMatch.
layer() )
1397 toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
1398 mLastSnapMatch = mSnapMatch;
1408 if ( mLockZButton->isChecked() )
1410 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1412 if ( mLockMButton->isChecked() )
1414 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1420 updateUnlockedConstraintValues( point );
1428 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
1435void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPoint &point )
1437 bool previousPointExist, penulPointExist;
1442 if ( !mAngleConstraint->isLocked() && previousPointExist )
1444 double prevAngle = 0.0;
1446 if ( penulPointExist && mAngleConstraint->relative() )
1449 prevAngle = std::atan2( previousPt.
y() - penultimatePt.
y(),
1450 previousPt.
x() - penultimatePt.
x() ) * 180 / M_PI;
1453 const double xAngle { std::atan2( point.
y() - previousPt.
y(),
1454 point.
x() - previousPt.
x() ) * 180 / M_PI };
1457 const double angle = std::fmod( xAngle - prevAngle, 360.0 );
1458 mAngleConstraint->setValue( angle );
1461 double bearing { std::fmod( xAngle, 360.0 ) };
1462 bearing = bearing <= 90.0 ? 90.0 - bearing : ( bearing > 90 ? 270.0 + 180.0 - bearing : 270.0 - bearing );
1469 if ( !mDistanceConstraint->isLocked() && previousPointExist )
1471 mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
1474 if ( !mXConstraint->isLocked() )
1476 if ( previousPointExist && mXConstraint->relative() )
1478 mXConstraint->setValue( point.
x() - previousPt.
x() );
1482 mXConstraint->setValue( point.
x() );
1486 if ( !mYConstraint->isLocked() )
1488 if ( previousPointExist && mYConstraint->relative() )
1490 mYConstraint->setValue( point.
y() - previousPt.
y() );
1494 mYConstraint->setValue( point.
y() );
1498 if ( !mZConstraint->isLocked() )
1500 if ( previousPointExist && mZConstraint->relative() )
1502 mZConstraint->setValue( point.
z() - previousPt.
z() );
1506 mZConstraint->setValue( point.
z() );
1510 if ( !mMConstraint->isLocked() )
1512 if ( previousPointExist && mMConstraint->relative() )
1514 mMConstraint->setValue( point.
m() - previousPt.
m() );
1518 mMConstraint->setValue( point.
m() );
1524QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
1537 snappingUtils->
setConfig( localConfig );
1539 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
1541 snappingUtils->
setConfig( canvasConfig );
1551 *snapped =
segment.count() == 2;
1561 mCurrentTool->canvasPressEvent( event );
1566 event->setAccepted(
false );
1578 mCurrentTool->canvasMoveEvent( event );
1586 if ( event->button() == Qt::RightButton )
1590 mCurrentTool->canvasReleaseEvent( event );
1591 if ( !event->isAccepted() )
1603 event->setAccepted(
false );
1609 mCurrentTool->canvasReleaseEvent( event );
1610 if ( !event->isAccepted() )
1621 if ( mLockZButton->isChecked() )
1623 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1625 if ( mLockMButton->isChecked() )
1627 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1638 event->setAccepted(
false );
1650 bool previousPointExist, penulPointExist, snappedSegmentExist;
1653 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
1655 if ( !previousPointExist || !snappedSegmentExist )
1660 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1662 if ( mAngleConstraint->relative() && penulPointExist )
1664 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
1672 angle *= 180 / M_PI;
1674 mAngleConstraint->setValue( angle );
1675 mAngleConstraint->setLockMode( lockMode );
1693 case Qt::Key_Backspace:
1694 case Qt::Key_Delete:
1700 case Qt::Key_Escape:
1719 mCurrentTool->deleteLater();
1722 if ( !mConstructionGuideLine.
isEmpty() )
1724 mConstructionGuideLine.
clear();
1740 case Qt::Key_Backspace:
1741 case Qt::Key_Delete:
1747 case Qt::Key_Escape:
1751 if ( mConstructionGuideLine.
numPoints() >= 2 )
1753 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1754 mConstructionGuideLine.
clear();
1759 mCurrentTool->deleteLater();
1766 filterKeyPress( e );
1775 const auto constPoints = points;
1784 mDistanceConstraint->toggleLocked();
1789bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1793 return QgsDockWidget::eventFilter( obj, event );
1801 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1803 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
1805 return filterKeyPress( keyEvent );
1808 return QgsDockWidget::eventFilter( obj, event );
1811bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1817 const QEvent::Type type = e->type();
1820 case Qt::Key_Escape:
1822 if ( type == QEvent::KeyPress && mCurrentTool )
1824 mCurrentTool->deleteLater();
1826 else if ( type == QEvent::KeyPress && mConstructionMode && mConstructionGuideLine.
numPoints() >= 2 )
1828 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1829 mConstructionGuideLine.
clear();
1831 if ( mCadPointList.size() > 1 )
1833 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
1848 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1850 mXConstraint->toggleLocked();
1855 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1859 mXConstraint->toggleRelative();
1866 else if ( type == QEvent::KeyPress )
1868 mXLineEdit->setFocus();
1869 mXLineEdit->selectAll();
1878 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1880 mYConstraint->toggleLocked();
1885 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1889 mYConstraint->toggleRelative();
1896 else if ( type == QEvent::KeyPress )
1898 mYLineEdit->setFocus();
1899 mYLineEdit->selectAll();
1908 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1910 mZConstraint->toggleLocked();
1915 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1919 mZConstraint->toggleRelative();
1926 else if ( type == QEvent::KeyPress )
1928 mZLineEdit->setFocus();
1929 mZLineEdit->selectAll();
1938 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1940 mMConstraint->toggleLocked();
1945 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1949 mMConstraint->toggleRelative();
1956 else if ( type == QEvent::KeyPress )
1958 mMLineEdit->setFocus();
1959 mMLineEdit->selectAll();
1968 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1972 mAngleConstraint->toggleLocked();
1978 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1982 mAngleConstraint->toggleRelative();
1989 else if ( type == QEvent::KeyPress )
1991 mAngleLineEdit->setFocus();
1992 mAngleLineEdit->selectAll();
2001 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
2010 else if ( type == QEvent::KeyPress )
2012 mDistanceLineEdit->setFocus();
2013 mDistanceLineEdit->selectAll();
2021 if ( type == QEvent::KeyPress )
2023 setConstructionMode( !mConstructionMode );
2030 if ( type == QEvent::KeyPress )
2032 const bool parallel = mParallelAction->isChecked();
2033 const bool perpendicular = mPerpendicularAction->isChecked();
2035 if ( !parallel && !perpendicular )
2039 else if ( perpendicular )
2056 if ( type == QEvent::ShortcutOverride )
2058 const QList<double> constActionKeys { mCommonAngleActions.keys() };
2059 const int currentAngleActionIndex {
static_cast<int>( constActionKeys .indexOf( mCommonAngleConstraint ) ) };
2060 const QList<QAction *> constActions { mCommonAngleActions.values( ) };
2061 QAction *nextAngleAction;
2062 if ( e->modifiers() == Qt::ShiftModifier )
2064 nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
2068 nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
2070 nextAngleAction->trigger();
2080 return e->isAccepted();
2089 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
2090 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
2092 mLabelX->setText( tr(
"Long" ) );
2093 mLabelY->setText( tr(
"Lat" ) );
2095 mXConstraint->setPrecision( 8 );
2096 mYConstraint->setPrecision( 8 );
2100 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
2101 mAngleLineEdit->setToolTip( QString() );
2103 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
2105 mLabelX->setText( tr(
"x" ) );
2106 mLabelY->setText( tr(
"y" ) );
2108 mXConstraint->setPrecision( 6 );
2109 mYConstraint->setPrecision( 6 );
2114 mEnableAction->setEnabled(
true );
2115 mErrorLabel->hide();
2118 mCurrentMapToolSupportsCad =
true;
2120 if ( mSessionActive && !isVisible() )
2125 setCadEnabled( mSessionActive );
2127 if ( !mConstructionGuidesLayer )
2129 resetConstructionGuides();
2132 if ( mDeferredUpdateConstructionGuidesCrs )
2134 updateConstructionGuidesCrs();
2144 mEnableAction->setEnabled(
false );
2145 mErrorLabel->setText( tr(
"Advanced digitizing tools are not enabled for the current map tool" ) );
2146 mErrorLabel->show();
2149 mCurrentMapToolSupportsCad =
false;
2151 mSnapIndicator->setVisible(
false );
2153 setCadEnabled(
false );
2158 mCadPaintItem->update();
2163 if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
2168 mLockedSnapVertices.clear();
2173 QgsPoint pt = pointXYToPoint( point );
2176 mCadPointList << pt;
2180 mCadPointList.insert( 0, pt );
2189 if ( mConstructionGuideLine.
numPoints() == 2 )
2194 mConstructionGuidesLayer->dataProvider()->addFeature( feature );
2195 mConstructionGuideId = feature.
id();
2197 else if ( mConstructionGuideLine.
numPoints() > 2 )
2200 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2205 if ( !mConstructionGuideLine.
isEmpty() )
2210 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2211 mConstructionGuideLine.
clear();
2226 mCadPointList.removeAt( i );
2233 mCadPointList.clear();
2234 mSnappedSegment.clear();
2244 mCadPointList << point;
2249 mCadPointList[0] = point;
2256 if ( mode == mLockMode )
2261 mLockerButton->setChecked( mode ==
HardLock );
2262 if ( mRepeatingLockButton )
2266 mRepeatingLockButton->setEnabled(
true );
2270 mRepeatingLockButton->setChecked(
false );
2271 mRepeatingLockButton->setEnabled(
false );
2284 mRepeatingLock = repeating;
2285 if ( mRepeatingLockButton )
2286 mRepeatingLockButton->setChecked( repeating );
2291 mRelative = relative;
2292 if ( mRelativeButton )
2294 mRelativeButton->setChecked( relative );
2301 if ( updateWidget && mLineEdit->isEnabled() )
2302 mLineEdit->setText( displayValue() );
2307 switch ( mCadConstraintType )
2311 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2318 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2322 return QLocale().toString( mValue,
'f', mPrecision );
2336 return QLocale().toString( mValue,
'f', mPrecision );
2341 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
2346 setRelative( !mRelative );
2352 if ( mLineEdit->isEnabled() )
2353 mLineEdit->setText( displayValue() );
2358 return mCadConstraintType;
2363 mCadConstraintType = constraintType;
2368 mMapCanvas = mapCanvas;
2373 QString value { text.trimmed() };
2374 switch ( constraintType )
2380 if ( value.endsWith( distanceUnit ) )
2382 value.chop( distanceUnit.length() );
2389 const QString angleUnit { tr(
"°" ) };
2390 if ( value.endsWith( angleUnit ) )
2392 value.chop( angleUnit.length() );
2399 return value.trimmed();
2407 return mCadPointList.value( 0 );
2416 QgsPoint res = mCadPointList.value( 0 );
2418 res.
setX( layerCoordinates.
x() );
2419 res.
setY( layerCoordinates.
y() );
2430 return mCadPointList.value( 1 );
2440 return mCadPointList.value( 2 );
2445QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
2452 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2457 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2462 return mShowConstructionGuides ? mShowConstructionGuides->isChecked() :
false;
2467 return mSnapToConstructionGuides ? mShowConstructionGuides->isChecked() && mSnapToConstructionGuides->isChecked() :
false;
2472 return mRecordConstructionGuides ? mRecordConstructionGuides->isChecked() :
false;
2475void QgsAdvancedDigitizingDockWidget::updateConstructionGuidesCrs()
2477 if ( !mConstructionGuidesLayer )
2484 mDeferredUpdateConstructionGuidesCrs =
true;
2495 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { feature.
id(), geom } } );
2498 mDeferredUpdateConstructionGuidesCrs =
false;
2501void QgsAdvancedDigitizingDockWidget::resetConstructionGuides()
2503 if ( mConstructionGuidesLayer )
2505 mConstructionGuidesLayer.reset();
2509 mConstructionGuidesLayer = std::make_unique<QgsVectorLayer>( QStringLiteral(
"LineString?crs=%1" ).arg( mMapCanvas->
mapSettings().
destinationCrs().
authid() ),
2510 QStringLiteral(
"constructionGuides" ),
2511 QStringLiteral(
"memory" ),
DistanceUnit
Units of distance.
CadConstraintType
Advanced digitizing constraint type.
@ Distance
Distance value.
@ YCoordinate
Y Coordinate value.
@ XCoordinate
X Coordinate value.
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ 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").
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
A event filter for watching for focus events on a parent object.
void focusIn()
Emitted when parent object gains focus.
void focusOut()
Emitted when parent object loses focus.
A geometry is the spatial representation of a feature.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
static QgsGui * instance()
Returns a pointer to the singleton instance.
static QgsAdvancedDigitizingToolsRegistry * advancedDigitizingToolsRegistry()
Returns the global advanced digitizing tools registry, used for registering advanced digitizing tools...
void clear() override
Clears the geometry, ie reset it to a null geometry.
bool isEmpty() const override
Returns true if the geometry is empty.
int numPoints() const override
Returns the number of points in the curve.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
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.
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
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 setY(double y)
Sets the point's y-coordinate.
void setX(double x)
Sets the point's x-coordinate.
void setM(double m)
Sets the point's m-value.
void setZ(double z)
Sets the point's z-coordinate.
double distanceSquared(double x, double y) const
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
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
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
QgsProjectDisplaySettings * displaySettings
QgsCoordinateTransformContext transformContext
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
This class has all the configuration of snapping and can return answers to snapping queries.
void addExtraSnapLayer(QgsVectorLayer *vl)
Supply an extra snapping layer (typically a memory layer).
void removeExtraSnapLayer(QgsVectorLayer *vl)
Removes an extra snapping layer.
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 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)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type)
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...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
QSet< QgsFeatureId > QgsFeatureIds
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.
Setting options for loading vector layers.