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 );
1002void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
1004 if ( !constraint || textValue.isEmpty() )
1013 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
1017 constraint->setValue( value, convertExpression );
1022void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
1024 CadConstraint *constraint = objectToConstraint( sender() );
1032 const QString textValue = constraint->lineEdit()->text();
1033 if ( !textValue.isEmpty() )
1036 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
1039 constraint->setValue( value );
1053 if ( constraint == mXConstraint.get() )
1057 else if ( constraint == mYConstraint.get() )
1061 else if ( constraint == mZConstraint.get() )
1065 else if ( constraint == mMConstraint.get() )
1069 else if ( constraint == mDistanceConstraint.get() )
1073 else if ( constraint == mAngleConstraint.get() )
1081 if ( constraint == mAngleConstraint.get() )
1091void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
1093 CadConstraint *constraint = objectToConstraint( sender() );
1099 updateConstraintValue( constraint, textValue,
false );
1102void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
1104 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
1108 CadConstraint *constraint = objectToConstraint( lineEdit );
1114 updateConstraintValue( constraint, lineEdit->text(),
true );
1119 mBetweenLineConstraint = constraint;
1124void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint(
bool activate )
1126 CadConstraint *constraint = objectToConstraint( sender() );
1134 if ( constraint == mXyVertexConstraint.get() )
1138 else if ( constraint == mLineExtensionConstraint.get() )
1152void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
1158 if ( mCadPointList.count() > 1 )
1161 if ( !isGeographic )
1167 if ( mCadPointList.count() > 2 )
1169 if ( !isGeographic )
1172 if ( !updateUIwithoutChange && newCapacities == mCapacities )
1182 const bool distance = mCadEnabled && newCapacities.testFlag(
Distance );
1183 const bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
1184 const bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
1185 const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag(
RelativeCoordinates );
1187 mPerpendicularAction->setEnabled( distance && snappingEnabled );
1188 mParallelAction->setEnabled( distance && snappingEnabled );
1190 mLineExtensionAction->setEnabled( snappingEnabled );
1191 mXyVertexAction->setEnabled( snappingEnabled );
1195 if ( !snappingEnabled )
1197 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode." ) );
1198 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode." ) );
1199 mLineExtensionAction->setToolTip( tr(
"Snapping must be enabled to utilize line extension mode." ) );
1200 mXyVertexAction->setToolTip( tr(
"Snapping must be enabled to utilize xy point mode." ) );
1202 else if ( mCadPointList.count() <= 1 )
1204 mPerpendicularAction->setToolTip( tr(
"A first vertex should be drawn to utilize perpendicular mode." ) );
1205 mParallelAction->setToolTip( tr(
"A first vertex should be drawn to utilize parallel mode." ) );
1207 else if ( isGeographic )
1209 mPerpendicularAction->setToolTip( tr(
"Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1210 mParallelAction->setToolTip( tr(
"Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1214 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1215 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1219 if ( !absoluteAngle )
1225 mLockAngleButton->setEnabled( absoluteAngle );
1226 mRelativeAngleButton->setEnabled( relativeAngle );
1227 mAngleLineEdit->setEnabled( absoluteAngle );
1229 if ( !absoluteAngle )
1233 if ( !relativeAngle )
1235 mAngleConstraint->setRelative(
false );
1238 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
1241 mAngleConstraint->setRelative(
true );
1246 mLockDistanceButton->setEnabled( distance && relativeCoordinates );
1247 mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
1249 if ( !( distance && relativeCoordinates ) )
1254 mRelativeXButton->setEnabled( relativeCoordinates );
1255 mRelativeYButton->setEnabled( relativeCoordinates );
1256 mRelativeZButton->setEnabled( relativeCoordinates );
1257 mRelativeMButton->setEnabled( relativeCoordinates );
1260 mCapacities = newCapacities;
1268 constr.
locked =
c->isLocked();
1270 constr.
value =
c->value();
1277 if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
1283 const int lastIndex = mLockedSnapVertices.length() - 1;
1284 for (
int i = lastIndex ; i >= 0; --i )
1286 if ( mLockedSnapVertices[i].point() == snapMatch.
point() )
1288 if ( snapMatch.
point() != previouslySnap.
point() )
1290 mLockedSnapVertices.removeAt( i );
1296 if ( snapMatch.
point() != previouslySnap.
point() )
1298 mLockedSnapVertices.enqueue( snapMatch );
1301 if ( mLockedSnapVertices.count() > 3 )
1303 mLockedSnapVertices.dequeue();
1312 context.
xConstraint = _constraint( mXConstraint.get() );
1313 context.
yConstraint = _constraint( mYConstraint.get() );
1314 context.
zConstraint = _constraint( mZConstraint.get() );
1315 context.
mConstraint = _constraint( mMConstraint.get() );
1337 const bool res = output.
valid;
1339 mSnappedSegment.clear();
1344 mSnappedSegment << edgePt0 << edgePt1;
1365 mSnapIndicator->setMatch( output.
snapMatch );
1366 mSnapIndicator->setVisible(
true );
1370 mSnapIndicator->setVisible(
false );
1392 if ( mSnapMatch.
layer() )
1408 toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
1409 mLastSnapMatch = mSnapMatch;
1419 if ( mLockZButton->isChecked() )
1421 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1423 if ( mLockMButton->isChecked() )
1425 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1431 updateUnlockedConstraintValues( point );
1439 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
1446void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPoint &point )
1448 bool previousPointExist, penulPointExist;
1453 if ( !mAngleConstraint->isLocked() && previousPointExist )
1455 double prevAngle = 0.0;
1457 if ( penulPointExist && mAngleConstraint->relative() )
1460 prevAngle = std::atan2( previousPt.
y() - penultimatePt.
y(),
1461 previousPt.
x() - penultimatePt.
x() ) * 180 / M_PI;
1464 const double xAngle { std::atan2( point.
y() - previousPt.
y(),
1465 point.
x() - previousPt.
x() ) * 180 / M_PI };
1468 const double angle = std::fmod( xAngle - prevAngle, 360.0 );
1469 mAngleConstraint->setValue( angle );
1472 double bearing { std::fmod( xAngle, 360.0 ) };
1473 bearing = bearing <= 90.0 ? 90.0 - bearing : ( bearing > 90 ? 270.0 + 180.0 - bearing : 270.0 - bearing );
1480 if ( !mDistanceConstraint->isLocked() && previousPointExist )
1482 mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
1485 if ( !mXConstraint->isLocked() )
1487 if ( previousPointExist && mXConstraint->relative() )
1489 mXConstraint->setValue( point.
x() - previousPt.
x() );
1493 mXConstraint->setValue( point.
x() );
1497 if ( !mYConstraint->isLocked() )
1499 if ( previousPointExist && mYConstraint->relative() )
1501 mYConstraint->setValue( point.
y() - previousPt.
y() );
1505 mYConstraint->setValue( point.
y() );
1509 if ( !mZConstraint->isLocked() )
1511 if ( previousPointExist && mZConstraint->relative() )
1513 mZConstraint->setValue( point.
z() - previousPt.
z() );
1517 mZConstraint->setValue( point.
z() );
1521 if ( !mMConstraint->isLocked() )
1523 if ( previousPointExist && mMConstraint->relative() )
1525 mMConstraint->setValue( point.
m() - previousPt.
m() );
1529 mMConstraint->setValue( point.
m() );
1535QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
1548 snappingUtils->
setConfig( localConfig );
1550 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
1552 snappingUtils->
setConfig( canvasConfig );
1562 *snapped =
segment.count() == 2;
1572 mCurrentTool->canvasPressEvent( event );
1577 event->setAccepted(
false );
1589 mCurrentTool->canvasMoveEvent( event );
1597 if ( event->button() == Qt::RightButton )
1601 mCurrentTool->canvasReleaseEvent( event );
1602 if ( !event->isAccepted() )
1614 event->setAccepted(
false );
1620 mCurrentTool->canvasReleaseEvent( event );
1621 if ( !event->isAccepted() )
1632 if ( mLockZButton->isChecked() )
1634 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1636 if ( mLockMButton->isChecked() )
1638 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1649 event->setAccepted(
false );
1661 bool previousPointExist, penulPointExist, snappedSegmentExist;
1664 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
1666 if ( !previousPointExist || !snappedSegmentExist )
1671 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1673 if ( mAngleConstraint->relative() && penulPointExist )
1675 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
1683 angle *= 180 / M_PI;
1685 mAngleConstraint->setValue( angle );
1686 mAngleConstraint->setLockMode( lockMode );
1704 case Qt::Key_Backspace:
1705 case Qt::Key_Delete:
1711 case Qt::Key_Escape:
1730 mCurrentTool->deleteLater();
1733 if ( !mConstructionGuideLine.
isEmpty() )
1735 mConstructionGuideLine.
clear();
1751 case Qt::Key_Backspace:
1752 case Qt::Key_Delete:
1758 case Qt::Key_Escape:
1762 if ( mConstructionGuideLine.
numPoints() >= 2 )
1764 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1765 mConstructionGuideLine.
clear();
1770 mCurrentTool->deleteLater();
1777 filterKeyPress( e );
1786 const auto constPoints = points;
1795 mDistanceConstraint->toggleLocked();
1800bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1804 return QgsDockWidget::eventFilter( obj, event );
1812 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1814 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
1816 return filterKeyPress( keyEvent );
1819 return QgsDockWidget::eventFilter( obj, event );
1822bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1828 const QEvent::Type type = e->type();
1831 case Qt::Key_Escape:
1833 if ( type == QEvent::KeyPress && mCurrentTool )
1835 mCurrentTool->deleteLater();
1837 else if ( type == QEvent::KeyPress && mConstructionMode && mConstructionGuideLine.
numPoints() >= 2 )
1839 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1840 mConstructionGuideLine.
clear();
1842 if ( mCadPointList.size() > 1 )
1844 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
1859 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1861 mXConstraint->toggleLocked();
1866 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1870 mXConstraint->toggleRelative();
1877 else if ( type == QEvent::KeyPress )
1879 mXLineEdit->setFocus();
1880 mXLineEdit->selectAll();
1889 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1891 mYConstraint->toggleLocked();
1896 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1900 mYConstraint->toggleRelative();
1907 else if ( type == QEvent::KeyPress )
1909 mYLineEdit->setFocus();
1910 mYLineEdit->selectAll();
1919 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1921 mZConstraint->toggleLocked();
1926 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1930 mZConstraint->toggleRelative();
1937 else if ( type == QEvent::KeyPress )
1939 mZLineEdit->setFocus();
1940 mZLineEdit->selectAll();
1949 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1951 mMConstraint->toggleLocked();
1956 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1960 mMConstraint->toggleRelative();
1967 else if ( type == QEvent::KeyPress )
1969 mMLineEdit->setFocus();
1970 mMLineEdit->selectAll();
1979 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1983 mAngleConstraint->toggleLocked();
1989 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1993 mAngleConstraint->toggleRelative();
2000 else if ( type == QEvent::KeyPress )
2002 mAngleLineEdit->setFocus();
2003 mAngleLineEdit->selectAll();
2012 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
2021 else if ( type == QEvent::KeyPress )
2023 mDistanceLineEdit->setFocus();
2024 mDistanceLineEdit->selectAll();
2032 if ( type == QEvent::KeyPress )
2034 setConstructionMode( !mConstructionMode );
2041 if ( type == QEvent::KeyPress )
2043 const bool parallel = mParallelAction->isChecked();
2044 const bool perpendicular = mPerpendicularAction->isChecked();
2046 if ( !parallel && !perpendicular )
2050 else if ( perpendicular )
2067 if ( type == QEvent::ShortcutOverride )
2069 const QList<double> constActionKeys { mCommonAngleActions.keys() };
2070 const int currentAngleActionIndex {
static_cast<int>( constActionKeys .indexOf( mCommonAngleConstraint ) ) };
2071 const QList<QAction *> constActions { mCommonAngleActions.values( ) };
2072 QAction *nextAngleAction;
2073 if ( e->modifiers() == Qt::ShiftModifier )
2075 nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
2079 nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
2081 nextAngleAction->trigger();
2091 return e->isAccepted();
2100 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
2101 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
2103 mLabelX->setText( tr(
"Long" ) );
2104 mLabelY->setText( tr(
"Lat" ) );
2106 mXConstraint->setPrecision( 8 );
2107 mYConstraint->setPrecision( 8 );
2111 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
2112 mAngleLineEdit->setToolTip( QString() );
2114 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
2116 mLabelX->setText( tr(
"x" ) );
2117 mLabelY->setText( tr(
"y" ) );
2119 mXConstraint->setPrecision( 6 );
2120 mYConstraint->setPrecision( 6 );
2125 mEnableAction->setEnabled(
true );
2126 mErrorLabel->hide();
2129 mCurrentMapToolSupportsCad =
true;
2131 if ( mSessionActive && !isVisible() )
2136 setCadEnabled( mSessionActive );
2138 if ( !mConstructionGuidesLayer )
2140 resetConstructionGuides();
2143 if ( mDeferredUpdateConstructionGuidesCrs )
2145 updateConstructionGuidesCrs();
2155 mEnableAction->setEnabled(
false );
2156 mErrorLabel->setText( tr(
"Advanced digitizing tools are not enabled for the current map tool" ) );
2157 mErrorLabel->show();
2160 mCurrentMapToolSupportsCad =
false;
2162 mSnapIndicator->setVisible(
false );
2164 setCadEnabled(
false );
2169 mCadPaintItem->update();
2174 if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
2179 mLockedSnapVertices.clear();
2184 QgsPoint pt = pointXYToPoint( point );
2187 mCadPointList << pt;
2191 mCadPointList.insert( 0, pt );
2200 if ( mConstructionGuideLine.
numPoints() == 2 )
2205 mConstructionGuidesLayer->dataProvider()->addFeature( feature );
2206 mConstructionGuideId = feature.
id();
2208 else if ( mConstructionGuideLine.
numPoints() > 2 )
2211 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2216 if ( !mConstructionGuideLine.
isEmpty() )
2221 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2222 mConstructionGuideLine.
clear();
2237 mCadPointList.removeAt( i );
2244 mCadPointList.clear();
2245 mSnappedSegment.clear();
2255 mCadPointList << point;
2260 mCadPointList[0] = point;
2267 if ( mode == mLockMode )
2272 mLockerButton->setChecked( mode ==
HardLock );
2273 if ( mRepeatingLockButton )
2277 mRepeatingLockButton->setEnabled(
true );
2281 mRepeatingLockButton->setChecked(
false );
2282 mRepeatingLockButton->setEnabled(
false );
2295 mRepeatingLock = repeating;
2296 if ( mRepeatingLockButton )
2297 mRepeatingLockButton->setChecked( repeating );
2302 mRelative = relative;
2303 if ( mRelativeButton )
2305 mRelativeButton->setChecked( relative );
2312 if ( updateWidget && mLineEdit->isEnabled() )
2313 mLineEdit->setText( displayValue() );
2318 switch ( mCadConstraintType )
2322 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2329 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2333 return QLocale().toString( mValue,
'f', mPrecision );
2350 return QLocale().toString( mValue,
'f', mPrecision );
2355 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
2360 setRelative( !mRelative );
2366 if ( mLineEdit->isEnabled() )
2367 mLineEdit->setText( displayValue() );
2372 return mCadConstraintType;
2377 mCadConstraintType = constraintType;
2382 mMapCanvas = mapCanvas;
2387 QString value { text.trimmed() };
2388 switch ( constraintType )
2394 if ( value.endsWith( distanceUnit ) )
2396 value.chop( distanceUnit.length() );
2403 const QString angleUnit { tr(
"°" ) };
2404 if ( value.endsWith( angleUnit ) )
2406 value.chop( angleUnit.length() );
2413 return value.trimmed();
2421 return mCadPointList.value( 0 );
2430 QgsPoint res = mCadPointList.value( 0 );
2432 res.
setX( layerCoordinates.
x() );
2433 res.
setY( layerCoordinates.
y() );
2444 return mCadPointList.value( 1 );
2454 return mCadPointList.value( 2 );
2459QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
2466 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2471 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2476 return mShowConstructionGuides ? mShowConstructionGuides->isChecked() :
false;
2481 return mSnapToConstructionGuides ? mShowConstructionGuides->isChecked() && mSnapToConstructionGuides->isChecked() :
false;
2486 return mRecordConstructionGuides ? mRecordConstructionGuides->isChecked() :
false;
2489void QgsAdvancedDigitizingDockWidget::updateConstructionGuidesCrs()
2491 if ( !mConstructionGuidesLayer )
2498 mDeferredUpdateConstructionGuidesCrs =
true;
2509 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { feature.
id(), geom } } );
2512 mDeferredUpdateConstructionGuidesCrs =
false;
2515void QgsAdvancedDigitizingDockWidget::resetConstructionGuides()
2517 if ( mConstructionGuidesLayer )
2519 mConstructionGuidesLayer.reset();
2523 mConstructionGuidesLayer = std::make_unique<QgsVectorLayer>( QStringLiteral(
"LineString?crs=%1" ).arg( mMapCanvas->
mapSettings().
destinationCrs().
authid() ),
2524 QStringLiteral(
"constructionGuides" ),
2525 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.
QgsMapTool * mapTool() const
Returns the currently active tool.
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
void destinationCrsChanged()
Emitted when map CRS has changed.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
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
Qgis::DistanceUnit mapUnits() const
Returns the units of the map's geographical coordinates - used for scale calculation.
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 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)
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.