18#include <QCoreApplication>
23#include "moc_qgsadvanceddigitizingdockwidget.cpp"
46#include <QActionGroup>
57 , mMapCanvas( canvas )
58 , mUserInputWidget( userInputWidget )
60 , mCommonAngleConstraint(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
66 mAngleConstraint.reset(
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
68 mAngleConstraint->setMapCanvas( mMapCanvas );
69 mDistanceConstraint.reset(
new CadConstraint( mDistanceLineEdit, mLockDistanceButton,
nullptr, mRepeatingLockDistanceButton ) );
71 mDistanceConstraint->setMapCanvas( mMapCanvas );
72 mXConstraint.reset(
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
74 mXConstraint->setMapCanvas( mMapCanvas );
75 mYConstraint.reset(
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
77 mYConstraint->setMapCanvas( mMapCanvas );
78 mZConstraint.reset(
new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
80 mZConstraint->setMapCanvas( mMapCanvas );
81 mMConstraint.reset(
new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
83 mMConstraint->setMapCanvas( mMapCanvas );
85 mLineExtensionConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
86 mXyVertexConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
87 mXyVertexConstraint->setMapCanvas( mMapCanvas );
91 mMapCanvas->installEventFilter(
this );
92 mAngleLineEdit->installEventFilter(
this );
93 mDistanceLineEdit->installEventFilter(
this );
94 mXLineEdit->installEventFilter(
this );
95 mYLineEdit->installEventFilter(
this );
96 mZLineEdit->installEventFilter(
this );
97 mMLineEdit->installEventFilter(
this );
100 connect( mEnableAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::activateCad );
101 connect( mConstructionModeAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
102 connect( mParallelAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
103 connect( mPerpendicularAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
104 connect( mLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
105 connect( mLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
106 connect( mLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
107 connect( mLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
108 connect( mLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
109 connect( mLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
110 connect( mRelativeAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
111 connect( mRelativeXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
112 connect( mRelativeYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
113 connect( mRelativeZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
114 connect( mRelativeMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
115 connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
116 connect( mRepeatingLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
117 connect( mRepeatingLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
118 connect( mRepeatingLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
119 connect( mRepeatingLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
120 connect( mRepeatingLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
121 connect( mAngleLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
122 connect( mDistanceLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
123 connect( mXLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
124 connect( mYLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
125 connect( mZLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
126 connect( mMLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
127 connect( mAngleLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
128 connect( mDistanceLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
129 connect( mXLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
130 connect( mYLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
131 connect( mZLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
132 connect( mMLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
139 whileBlocking( mAngleLineEdit )->setText( cleanedInputValue );
146 whileBlocking( mDistanceLineEdit )->setText( cleanedInputValue );
158 mCommonAngleActionsMenu =
new QMenu(
this );
160#ifndef __clang_analyzer__
161 QActionGroup *angleButtonGroup =
new QActionGroup( mCommonAngleActionsMenu );
163 QList< QPair< double, QString > > commonAngles;
164 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} );
165 for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
171 QMenu *snappingPriorityMenu =
new QMenu( tr(
"Snapping Priority" ), mCommonAngleActionsMenu );
172 QActionGroup *snappingPriorityActionGroup =
new QActionGroup( snappingPriorityMenu );
173 QAction *featuresAction =
new QAction( tr(
"Prioritize Snapping to Features" ), snappingPriorityActionGroup );
174 featuresAction->setCheckable(
true );
175 QAction *anglesAction =
new QAction( tr(
"Prioritize Snapping to Common Angles" ), snappingPriorityActionGroup );
176 anglesAction->setCheckable(
true );
177 snappingPriorityActionGroup->addAction( featuresAction );
178 snappingPriorityActionGroup->addAction( anglesAction );
179 snappingPriorityMenu->addAction( anglesAction );
180 snappingPriorityMenu->addAction( featuresAction );
181 connect( anglesAction, &QAction::changed,
this, [ = ]
183 mSnappingPrioritizeFeatures = featuresAction->isChecked();
184 settingsCadSnappingPriorityPrioritizeFeature->
setValue( featuresAction->isChecked() );
186 featuresAction->setChecked( settingsCadSnappingPriorityPrioritizeFeature->
value( ) );
187 anglesAction->setChecked( ! featuresAction->isChecked() );
188 mCommonAngleActionsMenu->addMenu( snappingPriorityMenu );
191 for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
193 QAction *action =
new QAction( it->second, mCommonAngleActionsMenu );
194 action->setCheckable(
true );
195 action->setChecked( it->first == mCommonAngleConstraint );
196 mCommonAngleActionsMenu->addAction( action );
198#ifndef __clang_analyzer__
199 angleButtonGroup->addAction( action );
201 mCommonAngleActions.insert( it->first, action );
205 QMenu *constructionSettingsMenu =
new QMenu(
this );
207 mRecordConstructionGuides =
new QAction( tr(
"Record Construction Guides" ), constructionSettingsMenu );
208 mRecordConstructionGuides->setCheckable(
true );
209 mRecordConstructionGuides->setChecked( settingsCadRecordConstructionGuides->
value() );
210 constructionSettingsMenu->addAction( mRecordConstructionGuides );
211 connect( mRecordConstructionGuides, &QAction::triggered,
this, [ = ]() { settingsCadRecordConstructionGuides->
setValue( mRecordConstructionGuides->isChecked() ); } );
213 mShowConstructionGuides =
new QAction( tr(
"Show Construction Guides" ), constructionSettingsMenu );
214 mShowConstructionGuides->setCheckable(
true );
215 mShowConstructionGuides->setChecked( settingsCadShowConstructionGuides->
value() );
216 constructionSettingsMenu->addAction( mShowConstructionGuides );
217 connect( mShowConstructionGuides, &QAction::triggered,
this, [ = ]()
219 settingsCadShowConstructionGuides->
setValue( mShowConstructionGuides->isChecked() );
223 mSnapToConstructionGuides =
new QAction( tr(
"Snap to Visible Construction Guides" ), constructionSettingsMenu );
224 mSnapToConstructionGuides->setCheckable(
true );
225 mSnapToConstructionGuides->setChecked( settingsCadSnapToConstructionGuides->
value() );
226 constructionSettingsMenu->addAction( mSnapToConstructionGuides );
227 connect( mSnapToConstructionGuides, &QAction::triggered,
this, [ = ]() { settingsCadSnapToConstructionGuides->
setValue( mSnapToConstructionGuides->isChecked() ); } );
229 constructionSettingsMenu->addSeparator();
231 mClearConstructionGuides =
new QAction( tr(
"Clear Construction Guides" ), constructionSettingsMenu );
232 constructionSettingsMenu->addAction( mClearConstructionGuides );
233 connect( mClearConstructionGuides, &QAction::triggered,
this, [ = ]()
235 resetConstructionGuides();
239 QToolButton *constructionModeToolButton = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionModeAction ) );
240 constructionModeToolButton->setPopupMode( QToolButton::MenuButtonPopup );
241 constructionModeToolButton->setMenu( constructionSettingsMenu );
242 constructionModeToolButton->setObjectName( QStringLiteral(
"ConstructionModeButton" ) );
245 QMenu *toolsMenu =
new QMenu(
this );
246 connect( toolsMenu, &QMenu::aboutToShow,
this, [ = ]()
250 for (
const QString &name : toolMetadataNames )
253 QAction *toolAction =
new QAction( toolMetadata->
icon(), toolMetadata->
visibleName(), toolsMenu );
254 connect( toolAction, &QAction::triggered,
this, [ = ]()
258 toolsMenu->addAction( toolAction );
261 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mToolsAction ) )->setPopupMode( QToolButton::InstantPopup );
262 mToolsAction->setMenu( toolsMenu );
264 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
265 mSettingsAction->setMenu( mCommonAngleActionsMenu );
266 mSettingsAction->setCheckable(
true );
267 mSettingsAction->setToolTip(
"<b>" + tr(
"Snap to common angles" ) +
"</b><br>(" + tr(
"press n to cycle through the options" ) +
")" );
268 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
269 connect( mCommonAngleActionsMenu, &QMenu::triggered,
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
272 QMenu *constructionMenu =
new QMenu(
this );
274 mLineExtensionAction =
new QAction( tr(
"Line Extension" ), constructionMenu );
275 mLineExtensionAction->setCheckable(
true );
276 constructionMenu->addAction( mLineExtensionAction );
277 connect( mLineExtensionAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
279 mXyVertexAction =
new QAction( tr(
"X/Y Point" ), constructionMenu );
280 mXyVertexAction->setCheckable(
true );
281 constructionMenu->addAction( mXyVertexAction );
282 connect( mXyVertexAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
284 auto constructionToolBar = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionAction ) );
285 constructionToolBar->setPopupMode( QToolButton::InstantPopup );
286 constructionToolBar->setMenu( constructionMenu );
287 constructionToolBar->setObjectName( QStringLiteral(
"ConstructionButton" ) );
289 mConstructionAction->setMenu( mCommonAngleActionsMenu );
290 mConstructionAction->setCheckable(
true );
291 mConstructionAction->setToolTip( tr(
"Construction Tools" ) );
295 mConstructionModeAction->setToolTip(
"<b>" + tr(
"Construction mode" ) +
"</b><br>(" + tr(
"press c to toggle on/off" ) +
")" );
296 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
297 mLockDistanceButton->setToolTip(
"<b>" + tr(
"Lock distance" ) +
"</b><br>(" + tr(
"press Ctrl + d for quick access" ) +
")" );
298 mRepeatingLockDistanceButton->setToolTip(
"<b>" + tr(
"Continuously lock distance" ) +
"</b>" );
300 mRelativeAngleButton->setToolTip(
"<b>" + tr(
"Toggles relative angle to previous segment" ) +
"</b><br>(" + tr(
"press Shift + a for quick access" ) +
")" );
301 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
302 mLockAngleButton->setToolTip(
"<b>" + tr(
"Lock angle" ) +
"</b><br>(" + tr(
"press Ctrl + a for quick access" ) +
")" );
303 mRepeatingLockAngleButton->setToolTip(
"<b>" + tr(
"Continuously lock angle" ) +
"</b>" );
305 mRelativeXButton->setToolTip(
"<b>" + tr(
"Toggles relative x to previous node" ) +
"</b><br>(" + tr(
"press Shift + x for quick access" ) +
")" );
306 mXLineEdit->setToolTip(
"<b>" + tr(
"X coordinate" ) +
"</b><br>(" + tr(
"press x for quick access" ) +
")" );
307 mLockXButton->setToolTip(
"<b>" + tr(
"Lock x coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + x for quick access" ) +
")" );
308 mRepeatingLockXButton->setToolTip(
"<b>" + tr(
"Continuously lock x coordinate" ) +
"</b>" );
310 mRelativeYButton->setToolTip(
"<b>" + tr(
"Toggles relative y to previous node" ) +
"</b><br>(" + tr(
"press Shift + y for quick access" ) +
")" );
311 mYLineEdit->setToolTip(
"<b>" + tr(
"Y coordinate" ) +
"</b><br>(" + tr(
"press y for quick access" ) +
")" );
312 mLockYButton->setToolTip(
"<b>" + tr(
"Lock y coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + y for quick access" ) +
")" );
313 mRepeatingLockYButton->setToolTip(
"<b>" + tr(
"Continuously lock y coordinate" ) +
"</b>" );
315 mRelativeZButton->setToolTip(
"<b>" + tr(
"Toggles relative z to previous node" ) +
"</b><br>(" + tr(
"press Shift + z for quick access" ) +
")" );
316 mZLineEdit->setToolTip(
"<b>" + tr(
"Z coordinate" ) +
"</b><br>(" + tr(
"press z for quick access" ) +
")" );
317 mLockZButton->setToolTip(
"<b>" + tr(
"Lock z coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + z for quick access" ) +
")" );
318 mRepeatingLockZButton->setToolTip(
"<b>" + tr(
"Continuously lock z coordinate" ) +
"</b>" );
320 mRelativeMButton->setToolTip(
"<b>" + tr(
"Toggles relative m to previous node" ) +
"</b><br>(" + tr(
"press Shift + m for quick access" ) +
")" );
321 mMLineEdit->setToolTip(
"<b>" + tr(
"M coordinate" ) +
"</b><br>(" + tr(
"press m for quick access" ) +
")" );
322 mLockMButton->setToolTip(
"<b>" + tr(
"Lock m coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + m for quick access" ) +
")" );
323 mRepeatingLockMButton->setToolTip(
"<b>" + tr(
"Continuously lock m coordinate" ) +
"</b>" );
334 mFloaterActionsMenu =
new QMenu(
this );
335 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mFloaterAction ) )->setPopupMode( QToolButton::InstantPopup );
336 mFloaterAction->setMenu( mFloaterActionsMenu );
337 mFloaterAction->setCheckable(
true );
339 mFloaterAction->setChecked( mFloater->
active() );
343 QAction *action =
new QAction( tr(
"Show floater" ), mFloaterActionsMenu );
344 action->setCheckable(
true );
345 action->setChecked( mFloater->
active() );
346 mFloaterActionsMenu->addAction( action );
347 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
350 mFloaterAction->setChecked( checked );
354 mFloaterActionsMenu->addSeparator();
357 QAction *action =
new QAction( tr(
"Show distance" ), mFloaterActionsMenu );
358 action->setCheckable(
true );
359 mFloaterActionsMenu->addAction( action );
360 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
364 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/DistanceShowInFloater" ),
true ).toBool() );
368 QAction *action =
new QAction( tr(
"Show angle" ), mFloaterActionsMenu );
369 action->setCheckable(
true );
370 mFloaterActionsMenu->addAction( action );
371 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
375 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/AngleShowInFloater" ),
true ).toBool() );
379 QAction *action =
new QAction( tr(
"Show XY coordinates" ), mFloaterActionsMenu );
380 action->setCheckable(
true );
381 mFloaterActionsMenu->addAction( action );
382 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
388 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/XCoordinateShowInFloater" ),
true ).toBool() );
392 QAction *action =
new QAction( tr(
"Show Z value" ), mFloaterActionsMenu );
393 action->setCheckable(
true );
394 mFloaterActionsMenu->addAction( action );
395 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
399 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/ZCoordinateShowInFloater" ),
true ).toBool() );
403 QAction *action =
new QAction( tr(
"Show M value" ), mFloaterActionsMenu );
404 action->setCheckable(
true );
405 mFloaterActionsMenu->addAction( action );
406 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
410 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/MCoordinateShowInFloater" ),
true ).toBool() );
414 QAction *action =
new QAction( tr(
"Show bearing/azimuth" ), mFloaterActionsMenu );
415 action->setCheckable(
true );
416 mFloaterActionsMenu->addAction( action );
417 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
421 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/BearingShowInFloater" ),
false ).toBool() );
425 QAction *action =
new QAction( tr(
"Show common snapping angle" ), mFloaterActionsMenu );
426 action->setCheckable(
true );
427 mFloaterActionsMenu->addAction( action );
428 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
432 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngleSnappingShowInFloater" ),
false ).toBool() );
435 updateCapacity(
true );
440 mConstructionGuidesLayer.reset();
451 mCurrentTool->deleteLater();
458 return tr(
"Do Not Snap to Common Angles" );
460 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 );
465 mXLineEdit->setText( value );
468 emit mXLineEdit->returnPressed();
472 QEvent *e =
new QEvent( QEvent::FocusOut );
473 QCoreApplication::postEvent( mXLineEdit, e );
477 emit mXLineEdit->textEdited( value );
482 mYLineEdit->setText( value );
485 emit mYLineEdit->returnPressed();
489 QEvent *e =
new QEvent( QEvent::FocusOut );
490 QCoreApplication::postEvent( mYLineEdit, e );
494 emit mYLineEdit->textEdited( value );
499 mZLineEdit->setText( value );
502 emit mZLineEdit->returnPressed();
506 QEvent *e =
new QEvent( QEvent::FocusOut );
507 QCoreApplication::postEvent( mZLineEdit, e );
511 emit mZLineEdit->textEdited( value );
516 mMLineEdit->setText( value );
519 emit mMLineEdit->returnPressed();
523 QEvent *e =
new QEvent( QEvent::FocusOut );
524 QCoreApplication::postEvent( mMLineEdit, e );
528 emit mMLineEdit->textEdited( value );
533 mAngleLineEdit->setText( value );
536 emit mAngleLineEdit->returnPressed();
540 emit mAngleLineEdit->textEdited( value );
545 mDistanceLineEdit->setText( value );
548 emit mDistanceLineEdit->returnPressed();
552 QEvent *e =
new QEvent( QEvent::FocusOut );
553 QCoreApplication::postEvent( mDistanceLineEdit, e );
557 emit mDistanceLineEdit->textEdited( value );
562void QgsAdvancedDigitizingDockWidget::setCadEnabled(
bool enabled )
564 mCadEnabled = enabled;
565 mEnableAction->setChecked( enabled );
566 mConstructionModeAction->setEnabled( enabled );
567 mSettingsAction->setEnabled( enabled );
568 mInputWidgets->setEnabled( enabled );
569 mFloaterAction->setEnabled( enabled );
570 mConstructionAction->setEnabled( enabled );
571 mToolsAction->setEnabled( enabled );
576 mLineExtensionAction->setChecked(
false );
577 mXyVertexAction->setChecked(
false );
579 mParallelAction->setEnabled(
false );
580 mPerpendicularAction->setEnabled(
false );
583 mCurrentTool->deleteLater();
590 setConstructionMode(
false );
606 bool enableZ =
false;
607 bool enableM =
false;
611 switch ( layer->type() )
624 QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
646 mRelativeZButton->setEnabled(
enable );
647 mZLabel->setEnabled(
enable );
648 mZLineEdit->setEnabled(
enable );
649 if ( mZLineEdit->isEnabled() )
653 mLockZButton->setEnabled(
enable );
659 mRelativeMButton->setEnabled(
enable );
660 mMLabel->setEnabled(
enable );
661 mMLineEdit->setEnabled(
enable );
662 if ( mMLineEdit->isEnabled() )
666 mLockMButton->setEnabled(
enable );
670void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
672 enabled &= mCurrentMapToolSupportsCad;
674 mSessionActive = enabled;
676 if ( enabled && !isVisible() )
681 setCadEnabled( enabled );
688 mCurrentTool->deleteLater();
689 mCurrentTool =
nullptr;
696 if ( QWidget *toolWidget = mCurrentTool->createWidget() )
698 toolWidget->setParent( mUserInputWidget );
707 return mCurrentTool.data();
710void QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked(
bool activated )
716 else if ( sender() == mParallelAction )
720 else if ( sender() == mPerpendicularAction )
726void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
728 if ( sender() == mRelativeAngleButton )
730 mAngleConstraint->setRelative( activate );
733 else if ( sender() == mRelativeXButton )
735 mXConstraint->setRelative( activate );
738 else if ( sender() == mRelativeYButton )
740 mYConstraint->setRelative( activate );
743 else if ( sender() == mRelativeZButton )
745 mZConstraint->setRelative( activate );
748 else if ( sender() == mRelativeMButton )
750 mMConstraint->setRelative( activate );
755void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock(
bool activate )
757 if ( sender() == mRepeatingLockDistanceButton )
759 mDistanceConstraint->setRepeatingLock( activate );
761 else if ( sender() == mRepeatingLockAngleButton )
763 mAngleConstraint->setRepeatingLock( activate );
765 else if ( sender() == mRepeatingLockXButton )
767 mXConstraint->setRepeatingLock( activate );
769 else if ( sender() == mRepeatingLockYButton )
771 mYConstraint->setRepeatingLock( activate );
773 else if ( sender() == mRepeatingLockZButton )
775 mZConstraint->setRepeatingLock( activate );
777 else if ( sender() == mRepeatingLockMButton )
779 mMConstraint->setRepeatingLock( activate );
783void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
785 mConstructionMode = enabled;
786 mConstructionModeAction->setChecked( enabled );
790 if ( enabled && mCadPointList.size() > 1 )
792 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
797void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
800 for (
auto it = mCommonAngleActions.cbegin(); it != mCommonAngleActions.cend(); ++it )
802 if ( it.value() == action )
804 it.value()->setChecked(
true );
805 mCommonAngleConstraint = it.key();
807 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
814QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
const
818 return advancedTool->layer();
832 if ( releaseRepeatingLocks )
834 mXyVertexAction->setChecked(
false );
838 mLineExtensionAction->setChecked(
false );
845 if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
850 if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
855 if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
860 if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
865 if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
870 if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
876 if ( !mCadPointList.empty() )
878 if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
880 mXConstraint->setValue( mCadPointList.constLast().x(),
true );
882 if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
884 mYConstraint->setValue( mCadPointList.constLast().y(),
true );
886 if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
888 mZConstraint->setValue( mCadPointList.constLast().z(),
true );
890 if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
892 mMConstraint->setValue( mCadPointList.constLast().m(),
true );
898void QgsAdvancedDigitizingDockWidget::emit pointChanged()
901 QPoint globalPos = mMapCanvas->cursor().pos();
902 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
903 QMouseEvent *e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
904 mCurrentMapTool->canvasMoveEvent( e );
910 CadConstraint *constraint =
nullptr;
911 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
913 constraint = mAngleConstraint.get();
915 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
917 constraint = mDistanceConstraint.get();
919 else if ( obj == mXLineEdit || obj == mLockXButton )
921 constraint = mXConstraint.get();
923 else if ( obj == mYLineEdit || obj == mLockYButton )
925 constraint = mYConstraint.get();
927 else if ( obj == mZLineEdit || obj == mLockZButton )
929 constraint = mZConstraint.get();
931 else if ( obj == mMLineEdit || obj == mLockMButton )
933 constraint = mMConstraint.get();
935 else if ( obj == mLineExtensionAction )
937 constraint = mLineExtensionConstraint.get();
939 else if ( obj == mXyVertexAction )
941 constraint = mXyVertexConstraint.get();
946double QgsAdvancedDigitizingDockWidget::parseUserInput(
const QString &inputValue,
const Qgis::CadConstraintType type,
bool &ok )
const
957 const QVariant result = expr.evaluate();
958 if ( expr.hasEvalError() )
961 QString inputValueC { inputValue };
964 if ( inputValue.contains( QLocale().groupSeparator() ) )
966 inputValueC.remove( QLocale().groupSeparator() );
968 const QVariant resultC = exprC.evaluate();
969 if ( ! exprC.hasEvalError() )
971 value = resultC.toDouble( &ok );
976 if ( !ok && QLocale().decimalPoint() != QChar(
'.' ) && inputValueC.contains( QLocale().decimalPoint() ) )
978 QgsExpression exprC( inputValueC .replace( QLocale().decimalPoint(), QChar(
'.' ) ) );
979 const QVariant resultC = exprC.evaluate();
980 if ( ! exprC.hasEvalError() )
982 value = resultC.toDouble( &ok );
988 value = result.toDouble( &ok );
1003void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
1005 if ( !constraint || textValue.isEmpty() )
1014 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
1018 constraint->setValue( value, convertExpression );
1023void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
1025 CadConstraint *constraint = objectToConstraint( sender() );
1033 const QString textValue = constraint->lineEdit()->text();
1034 if ( !textValue.isEmpty() )
1037 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
1040 constraint->setValue( value );
1054 if ( constraint == mXConstraint.get() )
1058 else if ( constraint == mYConstraint.get() )
1062 else if ( constraint == mZConstraint.get() )
1066 else if ( constraint == mMConstraint.get() )
1070 else if ( constraint == mDistanceConstraint.get() )
1074 else if ( constraint == mAngleConstraint.get() )
1082 if ( constraint == mAngleConstraint.get() )
1092void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
1094 CadConstraint *constraint = objectToConstraint( sender() );
1100 updateConstraintValue( constraint, textValue,
false );
1103void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
1105 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
1109 CadConstraint *constraint = objectToConstraint( lineEdit );
1115 updateConstraintValue( constraint, lineEdit->text(),
true );
1120 mBetweenLineConstraint = constraint;
1125void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint(
bool activate )
1127 CadConstraint *constraint = objectToConstraint( sender() );
1135 if ( constraint == mXyVertexConstraint.get() )
1139 else if ( constraint == mLineExtensionConstraint.get() )
1153void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
1159 if ( mCadPointList.count() > 1 )
1162 if ( !isGeographic )
1168 if ( mCadPointList.count() > 2 )
1170 if ( !isGeographic )
1173 if ( !updateUIwithoutChange && newCapacities == mCapacities )
1183 const bool distance = mCadEnabled && newCapacities.testFlag(
Distance );
1184 const bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
1185 const bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
1186 const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag(
RelativeCoordinates );
1188 mPerpendicularAction->setEnabled( distance && snappingEnabled );
1189 mParallelAction->setEnabled( distance && snappingEnabled );
1191 mLineExtensionAction->setEnabled( snappingEnabled );
1192 mXyVertexAction->setEnabled( snappingEnabled );
1196 if ( !snappingEnabled )
1198 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode." ) );
1199 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode." ) );
1200 mLineExtensionAction->setToolTip( tr(
"Snapping must be enabled to utilize line extension mode." ) );
1201 mXyVertexAction->setToolTip( tr(
"Snapping must be enabled to utilize xy point mode." ) );
1203 else if ( mCadPointList.count() <= 1 )
1205 mPerpendicularAction->setToolTip( tr(
"A first vertex should be drawn to utilize perpendicular mode." ) );
1206 mParallelAction->setToolTip( tr(
"A first vertex should be drawn to utilize parallel mode." ) );
1208 else if ( isGeographic )
1210 mPerpendicularAction->setToolTip( tr(
"Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1211 mParallelAction->setToolTip( tr(
"Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1215 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1216 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1220 if ( !absoluteAngle )
1226 mLockAngleButton->setEnabled( absoluteAngle );
1227 mRelativeAngleButton->setEnabled( relativeAngle );
1228 mAngleLineEdit->setEnabled( absoluteAngle );
1230 if ( !absoluteAngle )
1234 if ( !relativeAngle )
1236 mAngleConstraint->setRelative(
false );
1239 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
1242 mAngleConstraint->setRelative(
true );
1247 mLockDistanceButton->setEnabled( distance && relativeCoordinates );
1248 mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
1250 if ( !( distance && relativeCoordinates ) )
1255 mRelativeXButton->setEnabled( relativeCoordinates );
1256 mRelativeYButton->setEnabled( relativeCoordinates );
1257 mRelativeZButton->setEnabled( relativeCoordinates );
1258 mRelativeMButton->setEnabled( relativeCoordinates );
1261 mCapacities = newCapacities;
1269 constr.
locked =
c->isLocked();
1271 constr.
value =
c->value();
1278 if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
1284 const int lastIndex = mLockedSnapVertices.length() - 1;
1285 for (
int i = lastIndex ; i >= 0; --i )
1287 if ( mLockedSnapVertices[i].point() == snapMatch.
point() )
1289 if ( snapMatch.
point() != previouslySnap.
point() )
1291 mLockedSnapVertices.removeAt( i );
1297 if ( snapMatch.
point() != previouslySnap.
point() )
1299 mLockedSnapVertices.enqueue( snapMatch );
1302 if ( mLockedSnapVertices.count() > 3 )
1304 mLockedSnapVertices.dequeue();
1313 context.
xConstraint = _constraint( mXConstraint.get() );
1314 context.
yConstraint = _constraint( mYConstraint.get() );
1315 context.
zConstraint = _constraint( mZConstraint.get() );
1316 context.
mConstraint = _constraint( mMConstraint.get() );
1338 const bool res = output.
valid;
1340 mSnappedSegment.clear();
1345 mSnappedSegment << edgePt0 << edgePt1;
1366 mSnapIndicator->setMatch( output.
snapMatch );
1367 mSnapIndicator->setVisible(
true );
1371 mSnapIndicator->setVisible(
false );
1393 if ( mSnapMatch.
layer() )
1409 toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
1410 mLastSnapMatch = mSnapMatch;
1420 if ( mLockZButton->isChecked() )
1422 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1424 if ( mLockMButton->isChecked() )
1426 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1432 updateUnlockedConstraintValues( point );
1440 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
1447void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPoint &point )
1449 bool previousPointExist, penulPointExist;
1454 if ( !mAngleConstraint->isLocked() && previousPointExist )
1456 double prevAngle = 0.0;
1458 if ( penulPointExist && mAngleConstraint->relative() )
1461 prevAngle = std::atan2( previousPt.
y() - penultimatePt.
y(),
1462 previousPt.
x() - penultimatePt.
x() ) * 180 / M_PI;
1465 const double xAngle { std::atan2( point.
y() - previousPt.
y(),
1466 point.
x() - previousPt.
x() ) * 180 / M_PI };
1469 const double angle = std::fmod( xAngle - prevAngle, 360.0 );
1470 mAngleConstraint->setValue( angle );
1473 double bearing { std::fmod( xAngle, 360.0 ) };
1474 bearing = bearing <= 90.0 ? 90.0 - bearing : ( bearing > 90 ? 270.0 + 180.0 - bearing : 270.0 - bearing );
1481 if ( !mDistanceConstraint->isLocked() && previousPointExist )
1483 mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
1486 if ( !mXConstraint->isLocked() )
1488 if ( previousPointExist && mXConstraint->relative() )
1490 mXConstraint->setValue( point.
x() - previousPt.
x() );
1494 mXConstraint->setValue( point.
x() );
1498 if ( !mYConstraint->isLocked() )
1500 if ( previousPointExist && mYConstraint->relative() )
1502 mYConstraint->setValue( point.
y() - previousPt.
y() );
1506 mYConstraint->setValue( point.
y() );
1510 if ( !mZConstraint->isLocked() )
1512 if ( previousPointExist && mZConstraint->relative() )
1514 mZConstraint->setValue( point.
z() - previousPt.
z() );
1518 mZConstraint->setValue( point.
z() );
1522 if ( !mMConstraint->isLocked() )
1524 if ( previousPointExist && mMConstraint->relative() )
1526 mMConstraint->setValue( point.
m() - previousPt.
m() );
1530 mMConstraint->setValue( point.
m() );
1536QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
1549 snappingUtils->
setConfig( localConfig );
1551 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
1553 snappingUtils->
setConfig( canvasConfig );
1563 *snapped =
segment.count() == 2;
1573 mCurrentTool->canvasPressEvent( event );
1578 event->setAccepted(
false );
1590 mCurrentTool->canvasMoveEvent( event );
1598 if ( event->button() == Qt::RightButton )
1602 mCurrentTool->canvasReleaseEvent( event );
1603 if ( !event->isAccepted() )
1615 event->setAccepted(
false );
1621 mCurrentTool->canvasReleaseEvent( event );
1622 if ( !event->isAccepted() )
1633 if ( mLockZButton->isChecked() )
1635 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1637 if ( mLockMButton->isChecked() )
1639 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1650 event->setAccepted(
false );
1662 bool previousPointExist, penulPointExist, snappedSegmentExist;
1665 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
1667 if ( !previousPointExist || !snappedSegmentExist )
1672 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1674 if ( mAngleConstraint->relative() && penulPointExist )
1676 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
1684 angle *= 180 / M_PI;
1686 mAngleConstraint->setValue( angle );
1687 mAngleConstraint->setLockMode( lockMode );
1705 case Qt::Key_Backspace:
1706 case Qt::Key_Delete:
1712 case Qt::Key_Escape:
1731 mCurrentTool->deleteLater();
1734 if ( !mConstructionGuideLine.
isEmpty() )
1736 mConstructionGuideLine.
clear();
1752 case Qt::Key_Backspace:
1753 case Qt::Key_Delete:
1759 case Qt::Key_Escape:
1763 if ( mConstructionGuideLine.
numPoints() >= 2 )
1765 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1766 mConstructionGuideLine.
clear();
1771 mCurrentTool->deleteLater();
1778 filterKeyPress( e );
1787 const auto constPoints = points;
1796 mDistanceConstraint->toggleLocked();
1801bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1805 return QgsDockWidget::eventFilter( obj, event );
1813 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1815 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
1817 return filterKeyPress( keyEvent );
1820 return QgsDockWidget::eventFilter( obj, event );
1823bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1829 const QEvent::Type type = e->type();
1832 case Qt::Key_Escape:
1834 if ( type == QEvent::KeyPress && mCurrentTool )
1836 mCurrentTool->deleteLater();
1838 else if ( type == QEvent::KeyPress && mConstructionMode && mConstructionGuideLine.
numPoints() >= 2 )
1840 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1841 mConstructionGuideLine.
clear();
1843 if ( mCadPointList.size() > 1 )
1845 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
1860 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1862 mXConstraint->toggleLocked();
1867 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1871 mXConstraint->toggleRelative();
1878 else if ( type == QEvent::KeyPress )
1880 mXLineEdit->setFocus();
1881 mXLineEdit->selectAll();
1890 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1892 mYConstraint->toggleLocked();
1897 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1901 mYConstraint->toggleRelative();
1908 else if ( type == QEvent::KeyPress )
1910 mYLineEdit->setFocus();
1911 mYLineEdit->selectAll();
1920 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1922 mZConstraint->toggleLocked();
1927 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1931 mZConstraint->toggleRelative();
1938 else if ( type == QEvent::KeyPress )
1940 mZLineEdit->setFocus();
1941 mZLineEdit->selectAll();
1950 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1952 mMConstraint->toggleLocked();
1957 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1961 mMConstraint->toggleRelative();
1968 else if ( type == QEvent::KeyPress )
1970 mMLineEdit->setFocus();
1971 mMLineEdit->selectAll();
1980 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1984 mAngleConstraint->toggleLocked();
1990 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1994 mAngleConstraint->toggleRelative();
2001 else if ( type == QEvent::KeyPress )
2003 mAngleLineEdit->setFocus();
2004 mAngleLineEdit->selectAll();
2013 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
2022 else if ( type == QEvent::KeyPress )
2024 mDistanceLineEdit->setFocus();
2025 mDistanceLineEdit->selectAll();
2033 if ( type == QEvent::KeyPress )
2035 setConstructionMode( !mConstructionMode );
2042 if ( type == QEvent::KeyPress )
2044 const bool parallel = mParallelAction->isChecked();
2045 const bool perpendicular = mPerpendicularAction->isChecked();
2047 if ( !parallel && !perpendicular )
2051 else if ( perpendicular )
2068 if ( type == QEvent::ShortcutOverride )
2070 const QList<double> constActionKeys { mCommonAngleActions.keys() };
2071 const int currentAngleActionIndex {
static_cast<int>( constActionKeys .indexOf( mCommonAngleConstraint ) ) };
2072 const QList<QAction *> constActions { mCommonAngleActions.values( ) };
2073 QAction *nextAngleAction;
2074 if ( e->modifiers() == Qt::ShiftModifier )
2076 nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
2080 nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
2082 nextAngleAction->trigger();
2092 return e->isAccepted();
2101 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
2102 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
2104 mLabelX->setText( tr(
"Long" ) );
2105 mLabelY->setText( tr(
"Lat" ) );
2107 mXConstraint->setPrecision( 8 );
2108 mYConstraint->setPrecision( 8 );
2112 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
2113 mAngleLineEdit->setToolTip( QString() );
2115 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
2117 mLabelX->setText( tr(
"x" ) );
2118 mLabelY->setText( tr(
"y" ) );
2120 mXConstraint->setPrecision( 6 );
2121 mYConstraint->setPrecision( 6 );
2126 mEnableAction->setEnabled(
true );
2127 mErrorLabel->hide();
2130 mCurrentMapToolSupportsCad =
true;
2132 if ( mSessionActive && !isVisible() )
2137 setCadEnabled( mSessionActive );
2139 if ( !mConstructionGuidesLayer )
2141 resetConstructionGuides();
2144 if ( mDeferredUpdateConstructionGuidesCrs )
2146 updateConstructionGuidesCrs();
2156 mEnableAction->setEnabled(
false );
2157 mErrorLabel->setText( tr(
"Advanced digitizing tools are not enabled for the current map tool" ) );
2158 mErrorLabel->show();
2161 mCurrentMapToolSupportsCad =
false;
2163 mSnapIndicator->setVisible(
false );
2165 setCadEnabled(
false );
2170 mCadPaintItem->update();
2175 if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
2180 mLockedSnapVertices.clear();
2185 QgsPoint pt = pointXYToPoint( point );
2188 mCadPointList << pt;
2192 mCadPointList.insert( 0, pt );
2201 if ( mConstructionGuideLine.
numPoints() == 2 )
2206 mConstructionGuidesLayer->dataProvider()->addFeature( feature );
2207 mConstructionGuideId = feature.
id();
2209 else if ( mConstructionGuideLine.
numPoints() > 2 )
2212 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2217 if ( !mConstructionGuideLine.
isEmpty() )
2222 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2223 mConstructionGuideLine.
clear();
2238 mCadPointList.removeAt( i );
2245 mCadPointList.clear();
2246 mSnappedSegment.clear();
2256 mCadPointList << point;
2261 mCadPointList[0] = point;
2268 if ( mode == mLockMode )
2273 mLockerButton->setChecked( mode ==
HardLock );
2274 if ( mRepeatingLockButton )
2278 mRepeatingLockButton->setEnabled(
true );
2282 mRepeatingLockButton->setChecked(
false );
2283 mRepeatingLockButton->setEnabled(
false );
2296 mRepeatingLock = repeating;
2297 if ( mRepeatingLockButton )
2298 mRepeatingLockButton->setChecked( repeating );
2303 mRelative = relative;
2304 if ( mRelativeButton )
2306 mRelativeButton->setChecked( relative );
2313 if ( updateWidget && mLineEdit->isEnabled() )
2314 mLineEdit->setText( displayValue() );
2319 switch ( mCadConstraintType )
2323 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2330 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2334 return QLocale().toString( mValue,
'f', mPrecision );
2351 return QLocale().toString( mValue,
'f', mPrecision );
2356 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
2361 setRelative( !mRelative );
2367 if ( mLineEdit->isEnabled() )
2368 mLineEdit->setText( displayValue() );
2373 return mCadConstraintType;
2378 mCadConstraintType = constraintType;
2383 mMapCanvas = mapCanvas;
2388 QString value { text.trimmed() };
2389 switch ( constraintType )
2395 if ( value.endsWith( distanceUnit ) )
2397 value.chop( distanceUnit.length() );
2404 const QString angleUnit { tr(
"°" ) };
2405 if ( value.endsWith( angleUnit ) )
2407 value.chop( angleUnit.length() );
2414 return value.trimmed();
2422 return mCadPointList.value( 0 );
2431 QgsPoint res = mCadPointList.value( 0 );
2433 res.
setX( layerCoordinates.
x() );
2434 res.
setY( layerCoordinates.
y() );
2445 return mCadPointList.value( 1 );
2455 return mCadPointList.value( 2 );
2460QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
2467 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2472 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2477 return mShowConstructionGuides ? mShowConstructionGuides->isChecked() :
false;
2482 return mSnapToConstructionGuides ? mShowConstructionGuides->isChecked() && mSnapToConstructionGuides->isChecked() :
false;
2487 return mRecordConstructionGuides ? mRecordConstructionGuides->isChecked() :
false;
2490void QgsAdvancedDigitizingDockWidget::updateConstructionGuidesCrs()
2492 if ( !mConstructionGuidesLayer )
2499 mDeferredUpdateConstructionGuidesCrs =
true;
2510 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { feature.
id(), geom } } );
2513 mDeferredUpdateConstructionGuidesCrs =
false;
2516void QgsAdvancedDigitizingDockWidget::resetConstructionGuides()
2518 if ( mConstructionGuidesLayer )
2520 mConstructionGuidesLayer.reset();
2524 mConstructionGuidesLayer = std::make_unique<QgsVectorLayer>( QStringLiteral(
"LineString?crs=%1" ).arg( mMapCanvas->
mapSettings().
destinationCrs().
authid() ),
2525 QStringLiteral(
"constructionGuides" ),
2526 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.