18#include <QCoreApplication>
42#include <QActionGroup>
53 , mMapCanvas( canvas )
55 , mCommonAngleConstraint(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
61 mAngleConstraint.reset(
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
63 mAngleConstraint->setMapCanvas( mMapCanvas );
64 mDistanceConstraint.reset(
new CadConstraint( mDistanceLineEdit, mLockDistanceButton,
nullptr, mRepeatingLockDistanceButton ) );
66 mDistanceConstraint->setMapCanvas( mMapCanvas );
67 mXConstraint.reset(
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
69 mXConstraint->setMapCanvas( mMapCanvas );
70 mYConstraint.reset(
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
72 mYConstraint->setMapCanvas( mMapCanvas );
73 mZConstraint.reset(
new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
75 mZConstraint->setMapCanvas( mMapCanvas );
76 mMConstraint.reset(
new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
78 mMConstraint->setMapCanvas( mMapCanvas );
80 mLineExtensionConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
81 mXyVertexConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
82 mXyVertexConstraint->setMapCanvas( mMapCanvas );
86 mMapCanvas->installEventFilter(
this );
87 mAngleLineEdit->installEventFilter(
this );
88 mDistanceLineEdit->installEventFilter(
this );
89 mXLineEdit->installEventFilter(
this );
90 mYLineEdit->installEventFilter(
this );
91 mZLineEdit->installEventFilter(
this );
92 mMLineEdit->installEventFilter(
this );
95 connect( mEnableAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::activateCad );
96 connect( mConstructionModeAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
97 connect( mParallelAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
98 connect( mPerpendicularAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
99 connect( mLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
100 connect( mLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
101 connect( mLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
102 connect( mLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
103 connect( mLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
104 connect( mLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
105 connect( mRelativeAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
106 connect( mRelativeXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
107 connect( mRelativeYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
108 connect( mRelativeZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
109 connect( mRelativeMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
110 connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
111 connect( mRepeatingLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
112 connect( mRepeatingLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
113 connect( mRepeatingLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
114 connect( mRepeatingLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
115 connect( mRepeatingLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
116 connect( mAngleLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
117 connect( mDistanceLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
118 connect( mXLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
119 connect( mYLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
120 connect( mZLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
121 connect( mMLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
122 connect( mAngleLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
123 connect( mDistanceLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
124 connect( mXLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
125 connect( mYLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
126 connect( mZLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
127 connect( mMLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
134 whileBlocking( mAngleLineEdit )->setText( cleanedInputValue );
141 whileBlocking( mDistanceLineEdit )->setText( cleanedInputValue );
153 mCommonAngleActionsMenu =
new QMenu(
this );
155#ifndef __clang_analyzer__
156 QActionGroup *angleButtonGroup =
new QActionGroup( mCommonAngleActionsMenu );
158 QList< QPair< double, QString > > commonAngles;
159 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} );
160 for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
166 QMenu *snappingPriorityMenu =
new QMenu( tr(
"Snapping Priority" ), mCommonAngleActionsMenu );
167 QActionGroup *snappingPriorityActionGroup =
new QActionGroup( snappingPriorityMenu );
168 QAction *featuresAction =
new QAction( tr(
"Prioritize Snapping to Features" ), snappingPriorityActionGroup );
169 featuresAction->setCheckable(
true );
170 QAction *anglesAction =
new QAction( tr(
"Prioritize Snapping to Common Angles" ), snappingPriorityActionGroup );
171 anglesAction->setCheckable(
true );
172 snappingPriorityActionGroup->addAction( featuresAction );
173 snappingPriorityActionGroup->addAction( anglesAction );
174 snappingPriorityMenu->addAction( anglesAction );
175 snappingPriorityMenu->addAction( featuresAction );
176 connect( anglesAction, &QAction::changed,
this, [ = ]
178 mSnappingPrioritizeFeatures = featuresAction->isChecked();
179 settingsCadSnappingPriorityPrioritizeFeature->
setValue( featuresAction->isChecked() );
181 featuresAction->setChecked( settingsCadSnappingPriorityPrioritizeFeature->
value( ) );
182 anglesAction->setChecked( ! featuresAction->isChecked() );
183 mCommonAngleActionsMenu->addMenu( snappingPriorityMenu );
187 for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
189 QAction *action =
new QAction( it->second, mCommonAngleActionsMenu );
190 action->setCheckable(
true );
191 action->setChecked( it->first == mCommonAngleConstraint );
192 mCommonAngleActionsMenu->addAction( action );
194#ifndef __clang_analyzer__
195 angleButtonGroup->addAction( action );
197 mCommonAngleActions.insert( it->first, action );
201 QMenu *constructionSettingsMenu =
new QMenu(
this );
203 mRecordConstructionGuides =
new QAction( tr(
"Record Construction Guides" ), constructionSettingsMenu );
204 mRecordConstructionGuides->setCheckable(
true );
205 mRecordConstructionGuides->setChecked( settingsCadRecordConstructionGuides->
value() );
206 constructionSettingsMenu->addAction( mRecordConstructionGuides );
207 connect( mRecordConstructionGuides, &QAction::triggered,
this, [ = ]() { settingsCadRecordConstructionGuides->
setValue( mRecordConstructionGuides->isChecked() ); } );
209 mShowConstructionGuides =
new QAction( tr(
"Show Construction Guides" ), constructionSettingsMenu );
210 mShowConstructionGuides->setCheckable(
true );
211 mShowConstructionGuides->setChecked( settingsCadShowConstructionGuides->
value() );
212 constructionSettingsMenu->addAction( mShowConstructionGuides );
213 connect( mShowConstructionGuides, &QAction::triggered,
this, [ = ]()
215 settingsCadShowConstructionGuides->
setValue( mShowConstructionGuides->isChecked() );
219 mSnapToConstructionGuides =
new QAction( tr(
"Snap to Visible Construction Guides" ), constructionSettingsMenu );
220 mSnapToConstructionGuides->setCheckable(
true );
221 mSnapToConstructionGuides->setChecked( settingsCadSnapToConstructionGuides->
value() );
222 constructionSettingsMenu->addAction( mSnapToConstructionGuides );
223 connect( mSnapToConstructionGuides, &QAction::triggered,
this, [ = ]() { settingsCadSnapToConstructionGuides->
setValue( mSnapToConstructionGuides->isChecked() ); } );
225 constructionSettingsMenu->addSeparator();
227 mClearConstructionGuides =
new QAction( tr(
"Clear Construction Guides" ), constructionSettingsMenu );
228 constructionSettingsMenu->addAction( mClearConstructionGuides );
229 connect( mClearConstructionGuides, &QAction::triggered,
this, [ = ]()
231 resetConstructionGuides();
235 QToolButton *constructionModeToolButton = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionModeAction ) );
236 constructionModeToolButton->setPopupMode( QToolButton::MenuButtonPopup );
237 constructionModeToolButton->setMenu( constructionSettingsMenu );
238 constructionModeToolButton->setObjectName( QStringLiteral(
"ConstructionModeButton" ) );
240 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
241 mSettingsAction->setMenu( mCommonAngleActionsMenu );
242 mSettingsAction->setCheckable(
true );
243 mSettingsAction->setToolTip(
"<b>" + tr(
"Snap to common angles" ) +
"</b><br>(" + tr(
"press n to cycle through the options" ) +
")" );
244 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
245 connect( mCommonAngleActionsMenu, &QMenu::triggered,
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
248 QMenu *constructionMenu =
new QMenu(
this );
250 mLineExtensionAction =
new QAction( tr(
"Line Extension" ), constructionMenu );
251 mLineExtensionAction->setCheckable(
true );
252 constructionMenu->addAction( mLineExtensionAction );
253 connect( mLineExtensionAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
255 mXyVertexAction =
new QAction( tr(
"X/Y Point" ), constructionMenu );
256 mXyVertexAction->setCheckable(
true );
257 constructionMenu->addAction( mXyVertexAction );
258 connect( mXyVertexAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
260 auto constructionToolBar = qobject_cast< QToolButton *>( mToolbar->widgetForAction( mConstructionAction ) );
261 constructionToolBar->setPopupMode( QToolButton::InstantPopup );
262 constructionToolBar->setMenu( constructionMenu );
263 constructionToolBar->setObjectName( QStringLiteral(
"ConstructionButton" ) );
265 mConstructionAction->setMenu( mCommonAngleActionsMenu );
266 mConstructionAction->setCheckable(
true );
267 mConstructionAction->setToolTip( tr(
"Construction Tools" ) );
271 mConstructionModeAction->setToolTip(
"<b>" + tr(
"Construction mode" ) +
"</b><br>(" + tr(
"press c to toggle on/off" ) +
")" );
272 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
273 mLockDistanceButton->setToolTip(
"<b>" + tr(
"Lock distance" ) +
"</b><br>(" + tr(
"press Ctrl + d for quick access" ) +
")" );
274 mRepeatingLockDistanceButton->setToolTip(
"<b>" + tr(
"Continuously lock distance" ) +
"</b>" );
276 mRelativeAngleButton->setToolTip(
"<b>" + tr(
"Toggles relative angle to previous segment" ) +
"</b><br>(" + tr(
"press Shift + a for quick access" ) +
")" );
277 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
278 mLockAngleButton->setToolTip(
"<b>" + tr(
"Lock angle" ) +
"</b><br>(" + tr(
"press Ctrl + a for quick access" ) +
")" );
279 mRepeatingLockAngleButton->setToolTip(
"<b>" + tr(
"Continuously lock angle" ) +
"</b>" );
281 mRelativeXButton->setToolTip(
"<b>" + tr(
"Toggles relative x to previous node" ) +
"</b><br>(" + tr(
"press Shift + x for quick access" ) +
")" );
282 mXLineEdit->setToolTip(
"<b>" + tr(
"X coordinate" ) +
"</b><br>(" + tr(
"press x for quick access" ) +
")" );
283 mLockXButton->setToolTip(
"<b>" + tr(
"Lock x coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + x for quick access" ) +
")" );
284 mRepeatingLockXButton->setToolTip(
"<b>" + tr(
"Continuously lock x coordinate" ) +
"</b>" );
286 mRelativeYButton->setToolTip(
"<b>" + tr(
"Toggles relative y to previous node" ) +
"</b><br>(" + tr(
"press Shift + y for quick access" ) +
")" );
287 mYLineEdit->setToolTip(
"<b>" + tr(
"Y coordinate" ) +
"</b><br>(" + tr(
"press y for quick access" ) +
")" );
288 mLockYButton->setToolTip(
"<b>" + tr(
"Lock y coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + y for quick access" ) +
")" );
289 mRepeatingLockYButton->setToolTip(
"<b>" + tr(
"Continuously lock y coordinate" ) +
"</b>" );
291 mRelativeZButton->setToolTip(
"<b>" + tr(
"Toggles relative z to previous node" ) +
"</b><br>(" + tr(
"press Shift + z for quick access" ) +
")" );
292 mZLineEdit->setToolTip(
"<b>" + tr(
"Z coordinate" ) +
"</b><br>(" + tr(
"press z for quick access" ) +
")" );
293 mLockZButton->setToolTip(
"<b>" + tr(
"Lock z coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + z for quick access" ) +
")" );
294 mRepeatingLockZButton->setToolTip(
"<b>" + tr(
"Continuously lock z coordinate" ) +
"</b>" );
296 mRelativeMButton->setToolTip(
"<b>" + tr(
"Toggles relative m to previous node" ) +
"</b><br>(" + tr(
"press Shift + m for quick access" ) +
")" );
297 mMLineEdit->setToolTip(
"<b>" + tr(
"M coordinate" ) +
"</b><br>(" + tr(
"press m for quick access" ) +
")" );
298 mLockMButton->setToolTip(
"<b>" + tr(
"Lock m coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + m for quick access" ) +
")" );
299 mRepeatingLockMButton->setToolTip(
"<b>" + tr(
"Continuously lock m coordinate" ) +
"</b>" );
310 mFloaterActionsMenu =
new QMenu(
this );
311 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mFloaterAction ) )->setPopupMode( QToolButton::InstantPopup );
312 mFloaterAction->setMenu( mFloaterActionsMenu );
313 mFloaterAction->setCheckable(
true );
315 mFloaterAction->setChecked( mFloater->
active() );
319 QAction *action =
new QAction( tr(
"Show floater" ), mFloaterActionsMenu );
320 action->setCheckable(
true );
321 action->setChecked( mFloater->
active() );
322 mFloaterActionsMenu->addAction( action );
323 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
326 mFloaterAction->setChecked( checked );
330 mFloaterActionsMenu->addSeparator();
333 QAction *action =
new QAction( tr(
"Show distance" ), mFloaterActionsMenu );
334 action->setCheckable(
true );
335 mFloaterActionsMenu->addAction( action );
336 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
340 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/DistanceShowInFloater" ),
true ).toBool() );
344 QAction *action =
new QAction( tr(
"Show angle" ), mFloaterActionsMenu );
345 action->setCheckable(
true );
346 mFloaterActionsMenu->addAction( action );
347 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
351 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/AngleShowInFloater" ),
true ).toBool() );
355 QAction *action =
new QAction( tr(
"Show XY coordinates" ), mFloaterActionsMenu );
356 action->setCheckable(
true );
357 mFloaterActionsMenu->addAction( action );
358 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
364 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/XCoordinateShowInFloater" ),
true ).toBool() );
368 QAction *action =
new QAction( tr(
"Show Z value" ), mFloaterActionsMenu );
369 action->setCheckable(
true );
370 mFloaterActionsMenu->addAction( action );
371 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
375 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/ZCoordinateShowInFloater" ),
true ).toBool() );
379 QAction *action =
new QAction( tr(
"Show M value" ), mFloaterActionsMenu );
380 action->setCheckable(
true );
381 mFloaterActionsMenu->addAction( action );
382 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
386 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/MCoordinateShowInFloater" ),
true ).toBool() );
390 QAction *action =
new QAction( tr(
"Show bearing/azimuth" ), mFloaterActionsMenu );
391 action->setCheckable(
true );
392 mFloaterActionsMenu->addAction( action );
393 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
397 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/BearingShowInFloater" ),
false ).toBool() );
401 QAction *action =
new QAction( tr(
"Show common snapping angle" ), mFloaterActionsMenu );
402 action->setCheckable(
true );
403 mFloaterActionsMenu->addAction( action );
404 connect( action, &QAction::toggled,
this, [ = ](
bool checked )
408 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngleSnappingShowInFloater" ),
false ).toBool() );
411 updateCapacity(
true );
416 mConstructionGuidesLayer.reset();
426 return tr(
"Do Not Snap to Common Angles" );
428 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 );
433 mXLineEdit->setText( value );
436 emit mXLineEdit->returnPressed();
440 QEvent *e =
new QEvent( QEvent::FocusOut );
441 QCoreApplication::postEvent( mXLineEdit, e );
445 emit mXLineEdit->textEdited( value );
450 mYLineEdit->setText( value );
453 emit mYLineEdit->returnPressed();
457 QEvent *e =
new QEvent( QEvent::FocusOut );
458 QCoreApplication::postEvent( mYLineEdit, e );
462 emit mYLineEdit->textEdited( value );
467 mZLineEdit->setText( value );
470 emit mZLineEdit->returnPressed();
474 QEvent *e =
new QEvent( QEvent::FocusOut );
475 QCoreApplication::postEvent( mZLineEdit, e );
479 emit mZLineEdit->textEdited( value );
484 mMLineEdit->setText( value );
487 emit mMLineEdit->returnPressed();
491 QEvent *e =
new QEvent( QEvent::FocusOut );
492 QCoreApplication::postEvent( mMLineEdit, e );
496 emit mMLineEdit->textEdited( value );
501 mAngleLineEdit->setText( value );
504 emit mAngleLineEdit->returnPressed();
508 emit mAngleLineEdit->textEdited( value );
513 mDistanceLineEdit->setText( value );
516 emit mDistanceLineEdit->returnPressed();
520 QEvent *e =
new QEvent( QEvent::FocusOut );
521 QCoreApplication::postEvent( mDistanceLineEdit, e );
525 emit mDistanceLineEdit->textEdited( value );
530void QgsAdvancedDigitizingDockWidget::setCadEnabled(
bool enabled )
532 mCadEnabled = enabled;
533 mEnableAction->setChecked( enabled );
534 mConstructionModeAction->setEnabled( enabled );
535 mSettingsAction->setEnabled( enabled );
536 mInputWidgets->setEnabled( enabled );
537 mFloaterAction->setEnabled( enabled );
538 mConstructionAction->setEnabled( enabled );
543 mLineExtensionAction->setChecked(
false );
544 mXyVertexAction->setChecked(
false );
546 mParallelAction->setEnabled(
false );
547 mPerpendicularAction->setEnabled(
false );
553 setConstructionMode(
false );
569 bool enableZ =
false;
570 bool enableM =
false;
574 switch ( layer->type() )
587 QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
609 mRelativeZButton->setEnabled(
enable );
610 mZLabel->setEnabled(
enable );
611 mZLineEdit->setEnabled(
enable );
612 if ( mZLineEdit->isEnabled() )
616 mLockZButton->setEnabled(
enable );
622 mRelativeMButton->setEnabled(
enable );
623 mMLabel->setEnabled(
enable );
624 mMLineEdit->setEnabled(
enable );
625 if ( mMLineEdit->isEnabled() )
629 mLockMButton->setEnabled(
enable );
633void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
635 enabled &= mCurrentMapToolSupportsCad;
637 mSessionActive = enabled;
639 if ( enabled && !isVisible() )
644 setCadEnabled( enabled );
647void QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked(
bool activated )
653 else if ( sender() == mParallelAction )
657 else if ( sender() == mPerpendicularAction )
663void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
665 if ( sender() == mRelativeAngleButton )
667 mAngleConstraint->setRelative( activate );
670 else if ( sender() == mRelativeXButton )
672 mXConstraint->setRelative( activate );
675 else if ( sender() == mRelativeYButton )
677 mYConstraint->setRelative( activate );
680 else if ( sender() == mRelativeZButton )
682 mZConstraint->setRelative( activate );
685 else if ( sender() == mRelativeMButton )
687 mMConstraint->setRelative( activate );
692void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock(
bool activate )
694 if ( sender() == mRepeatingLockDistanceButton )
696 mDistanceConstraint->setRepeatingLock( activate );
698 else if ( sender() == mRepeatingLockAngleButton )
700 mAngleConstraint->setRepeatingLock( activate );
702 else if ( sender() == mRepeatingLockXButton )
704 mXConstraint->setRepeatingLock( activate );
706 else if ( sender() == mRepeatingLockYButton )
708 mYConstraint->setRepeatingLock( activate );
710 else if ( sender() == mRepeatingLockZButton )
712 mZConstraint->setRepeatingLock( activate );
714 else if ( sender() == mRepeatingLockMButton )
716 mMConstraint->setRepeatingLock( activate );
720void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
722 mConstructionMode = enabled;
723 mConstructionModeAction->setChecked( enabled );
727 if ( enabled && mCadPointList.size() > 1 )
729 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
734void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
737 for (
auto it = mCommonAngleActions.cbegin(); it != mCommonAngleActions.cend(); ++it )
739 if ( it.value() == action )
741 it.value()->setChecked(
true );
742 mCommonAngleConstraint = it.key();
744 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
751QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
const
755 return advancedTool->layer();
769 if ( releaseRepeatingLocks )
771 mXyVertexAction->setChecked(
false );
775 mLineExtensionAction->setChecked(
false );
782 if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
787 if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
792 if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
797 if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
802 if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
807 if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
813 if ( !mCadPointList.empty() )
815 if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
817 mXConstraint->setValue( mCadPointList.constLast().x(),
true );
819 if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
821 mYConstraint->setValue( mCadPointList.constLast().y(),
true );
823 if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
825 mZConstraint->setValue( mCadPointList.constLast().z(),
true );
827 if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
829 mMConstraint->setValue( mCadPointList.constLast().m(),
true );
835void QgsAdvancedDigitizingDockWidget::emit pointChanged()
838 QPoint globalPos = mMapCanvas->cursor().pos();
839 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
840 QMouseEvent *e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
841 mCurrentMapTool->canvasMoveEvent( e );
847 CadConstraint *constraint =
nullptr;
848 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
850 constraint = mAngleConstraint.get();
852 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
854 constraint = mDistanceConstraint.get();
856 else if ( obj == mXLineEdit || obj == mLockXButton )
858 constraint = mXConstraint.get();
860 else if ( obj == mYLineEdit || obj == mLockYButton )
862 constraint = mYConstraint.get();
864 else if ( obj == mZLineEdit || obj == mLockZButton )
866 constraint = mZConstraint.get();
868 else if ( obj == mMLineEdit || obj == mLockMButton )
870 constraint = mMConstraint.get();
872 else if ( obj == mLineExtensionAction )
874 constraint = mLineExtensionConstraint.get();
876 else if ( obj == mXyVertexAction )
878 constraint = mXyVertexConstraint.get();
883double QgsAdvancedDigitizingDockWidget::parseUserInput(
const QString &inputValue,
const Qgis::CadConstraintType type,
bool &ok )
const
894 const QVariant result = expr.evaluate();
895 if ( expr.hasEvalError() )
898 QString inputValueC { inputValue };
901 if ( inputValue.contains( QLocale().groupSeparator() ) )
903 inputValueC.remove( QLocale().groupSeparator() );
905 const QVariant resultC = exprC.evaluate();
906 if ( ! exprC.hasEvalError() )
908 value = resultC.toDouble( &ok );
913 if ( !ok && QLocale().decimalPoint() != QChar(
'.' ) && inputValueC.contains( QLocale().decimalPoint() ) )
915 QgsExpression exprC( inputValueC .replace( QLocale().decimalPoint(), QChar(
'.' ) ) );
916 const QVariant resultC = exprC.evaluate();
917 if ( ! exprC.hasEvalError() )
919 value = resultC.toDouble( &ok );
925 value = result.toDouble( &ok );
931void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
933 if ( !constraint || textValue.isEmpty() )
942 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
946 constraint->setValue( value, convertExpression );
951void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
953 CadConstraint *constraint = objectToConstraint( sender() );
961 const QString textValue = constraint->lineEdit()->text();
962 if ( !textValue.isEmpty() )
965 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
968 constraint->setValue( value );
982 if ( constraint == mXConstraint.get() )
986 else if ( constraint == mYConstraint.get() )
990 else if ( constraint == mZConstraint.get() )
994 else if ( constraint == mMConstraint.get() )
998 else if ( constraint == mDistanceConstraint.get() )
1002 else if ( constraint == mAngleConstraint.get() )
1010 if ( constraint == mAngleConstraint.get() )
1020void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
1022 CadConstraint *constraint = objectToConstraint( sender() );
1028 updateConstraintValue( constraint, textValue,
false );
1031void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
1033 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
1037 CadConstraint *constraint = objectToConstraint( lineEdit );
1043 updateConstraintValue( constraint, lineEdit->text(),
true );
1048 mBetweenLineConstraint = constraint;
1053void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint(
bool activate )
1055 CadConstraint *constraint = objectToConstraint( sender() );
1063 if ( constraint == mXyVertexConstraint.get() )
1067 else if ( constraint == mLineExtensionConstraint.get() )
1081void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
1087 if ( mCadPointList.count() > 1 )
1090 if ( !isGeographic )
1096 if ( mCadPointList.count() > 2 )
1098 if ( !isGeographic )
1101 if ( !updateUIwithoutChange && newCapacities == mCapacities )
1111 const bool distance = mCadEnabled && newCapacities.testFlag(
Distance );
1112 const bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
1113 const bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
1114 const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag(
RelativeCoordinates );
1116 mPerpendicularAction->setEnabled( distance && snappingEnabled );
1117 mParallelAction->setEnabled( distance && snappingEnabled );
1119 mLineExtensionAction->setEnabled( snappingEnabled );
1120 mXyVertexAction->setEnabled( snappingEnabled );
1124 if ( !snappingEnabled )
1126 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode." ) );
1127 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode." ) );
1128 mLineExtensionAction->setToolTip( tr(
"Snapping must be enabled to utilize line extension mode." ) );
1129 mXyVertexAction->setToolTip( tr(
"Snapping must be enabled to utilize xy point mode." ) );
1131 else if ( mCadPointList.count() <= 1 )
1133 mPerpendicularAction->setToolTip( tr(
"A first vertex should be drawn to utilize perpendicular mode." ) );
1134 mParallelAction->setToolTip( tr(
"A first vertex should be drawn to utilize parallel mode." ) );
1136 else if ( isGeographic )
1138 mPerpendicularAction->setToolTip( tr(
"Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1139 mParallelAction->setToolTip( tr(
"Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1143 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1144 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1148 if ( !absoluteAngle )
1154 mLockAngleButton->setEnabled( absoluteAngle );
1155 mRelativeAngleButton->setEnabled( relativeAngle );
1156 mAngleLineEdit->setEnabled( absoluteAngle );
1158 if ( !absoluteAngle )
1162 if ( !relativeAngle )
1164 mAngleConstraint->setRelative(
false );
1167 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
1170 mAngleConstraint->setRelative(
true );
1175 mLockDistanceButton->setEnabled( distance && relativeCoordinates );
1176 mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
1178 if ( !( distance && relativeCoordinates ) )
1183 mRelativeXButton->setEnabled( relativeCoordinates );
1184 mRelativeYButton->setEnabled( relativeCoordinates );
1185 mRelativeZButton->setEnabled( relativeCoordinates );
1186 mRelativeMButton->setEnabled( relativeCoordinates );
1189 mCapacities = newCapacities;
1197 constr.
locked =
c->isLocked();
1199 constr.
value =
c->value();
1206 if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
1212 const int lastIndex = mLockedSnapVertices.length() - 1;
1213 for (
int i = lastIndex ; i >= 0; --i )
1215 if ( mLockedSnapVertices[i].point() == snapMatch.
point() )
1217 if ( snapMatch.
point() != previouslySnap.
point() )
1219 mLockedSnapVertices.removeAt( i );
1225 if ( snapMatch.
point() != previouslySnap.
point() )
1227 mLockedSnapVertices.enqueue( snapMatch );
1230 if ( mLockedSnapVertices.count() > 3 )
1232 mLockedSnapVertices.dequeue();
1241 context.
xConstraint = _constraint( mXConstraint.get() );
1242 context.
yConstraint = _constraint( mYConstraint.get() );
1243 context.
zConstraint = _constraint( mZConstraint.get() );
1244 context.
mConstraint = _constraint( mMConstraint.get() );
1266 const bool res = output.
valid;
1268 mSnappedSegment.clear();
1273 mSnappedSegment << edgePt0 << edgePt1;
1294 mSnapIndicator->setMatch( output.
snapMatch );
1295 mSnapIndicator->setVisible(
true );
1299 mSnapIndicator->setVisible(
false );
1321 if ( mSnapMatch.
layer() )
1335 toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
1336 mLastSnapMatch = mSnapMatch;
1346 if ( mLockZButton->isChecked() )
1348 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1350 if ( mLockMButton->isChecked() )
1352 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1358 updateUnlockedConstraintValues( point );
1366 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
1373void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPoint &point )
1375 bool previousPointExist, penulPointExist;
1380 if ( !mAngleConstraint->isLocked() && previousPointExist )
1382 double prevAngle = 0.0;
1384 if ( penulPointExist && mAngleConstraint->relative() )
1387 prevAngle = std::atan2( previousPt.
y() - penultimatePt.
y(),
1388 previousPt.
x() - penultimatePt.
x() ) * 180 / M_PI;
1391 const double xAngle { std::atan2( point.
y() - previousPt.
y(),
1392 point.
x() - previousPt.
x() ) * 180 / M_PI };
1395 const double angle = std::fmod( xAngle - prevAngle, 360.0 );
1396 mAngleConstraint->setValue( angle );
1399 double bearing { std::fmod( xAngle, 360.0 ) };
1400 bearing = bearing <= 90.0 ? 90.0 - bearing : ( bearing > 90 ? 270.0 + 180.0 - bearing : 270.0 - bearing );
1407 if ( !mDistanceConstraint->isLocked() && previousPointExist )
1409 mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
1412 if ( !mXConstraint->isLocked() )
1414 if ( previousPointExist && mXConstraint->relative() )
1416 mXConstraint->setValue( point.
x() - previousPt.
x() );
1420 mXConstraint->setValue( point.
x() );
1424 if ( !mYConstraint->isLocked() )
1426 if ( previousPointExist && mYConstraint->relative() )
1428 mYConstraint->setValue( point.
y() - previousPt.
y() );
1432 mYConstraint->setValue( point.
y() );
1436 if ( !mZConstraint->isLocked() )
1438 if ( previousPointExist && mZConstraint->relative() )
1440 mZConstraint->setValue( point.
z() - previousPt.
z() );
1444 mZConstraint->setValue( point.
z() );
1448 if ( !mMConstraint->isLocked() )
1450 if ( previousPointExist && mMConstraint->relative() )
1452 mMConstraint->setValue( point.
m() - previousPt.
m() );
1456 mMConstraint->setValue( point.
m() );
1462QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
1475 snappingUtils->
setConfig( localConfig );
1477 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
1479 snappingUtils->
setConfig( canvasConfig );
1489 *snapped =
segment.count() == 2;
1502 bool previousPointExist, penulPointExist, snappedSegmentExist;
1505 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
1507 if ( !previousPointExist || !snappedSegmentExist )
1512 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1514 if ( mAngleConstraint->relative() && penulPointExist )
1516 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
1524 angle *= 180 / M_PI;
1526 mAngleConstraint->setValue( angle );
1527 mAngleConstraint->setLockMode( lockMode );
1545 case Qt::Key_Backspace:
1546 case Qt::Key_Delete:
1552 case Qt::Key_Escape:
1569 if ( !mConstructionGuideLine.
isEmpty() )
1571 mConstructionGuideLine.
clear();
1587 case Qt::Key_Backspace:
1588 case Qt::Key_Delete:
1594 case Qt::Key_Escape:
1598 if ( mConstructionGuideLine.
numPoints() >= 2 )
1600 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1601 mConstructionGuideLine.
clear();
1608 filterKeyPress( e );
1617 const auto constPoints = points;
1624bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1628 return QgsDockWidget::eventFilter( obj, event );
1636 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1638 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
1640 return filterKeyPress( keyEvent );
1643 return QgsDockWidget::eventFilter( obj, event );
1646bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1652 const QEvent::Type type = e->type();
1655 case Qt::Key_Escape:
1657 if ( type == QEvent::KeyPress && mConstructionMode && mConstructionGuideLine.
numPoints() >= 2 )
1659 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1660 mConstructionGuideLine.
clear();
1662 if ( mCadPointList.size() > 1 )
1664 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
1679 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1681 mXConstraint->toggleLocked();
1686 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1690 mXConstraint->toggleRelative();
1697 else if ( type == QEvent::KeyPress )
1699 mXLineEdit->setFocus();
1700 mXLineEdit->selectAll();
1709 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1711 mYConstraint->toggleLocked();
1716 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1720 mYConstraint->toggleRelative();
1727 else if ( type == QEvent::KeyPress )
1729 mYLineEdit->setFocus();
1730 mYLineEdit->selectAll();
1739 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1741 mZConstraint->toggleLocked();
1746 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1750 mZConstraint->toggleRelative();
1757 else if ( type == QEvent::KeyPress )
1759 mZLineEdit->setFocus();
1760 mZLineEdit->selectAll();
1769 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1771 mMConstraint->toggleLocked();
1776 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1780 mMConstraint->toggleRelative();
1787 else if ( type == QEvent::KeyPress )
1789 mMLineEdit->setFocus();
1790 mMLineEdit->selectAll();
1799 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1803 mAngleConstraint->toggleLocked();
1809 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1813 mAngleConstraint->toggleRelative();
1820 else if ( type == QEvent::KeyPress )
1822 mAngleLineEdit->setFocus();
1823 mAngleLineEdit->selectAll();
1832 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1836 mDistanceConstraint->toggleLocked();
1843 else if ( type == QEvent::KeyPress )
1845 mDistanceLineEdit->setFocus();
1846 mDistanceLineEdit->selectAll();
1854 if ( type == QEvent::KeyPress )
1856 setConstructionMode( !mConstructionMode );
1863 if ( type == QEvent::KeyPress )
1865 const bool parallel = mParallelAction->isChecked();
1866 const bool perpendicular = mPerpendicularAction->isChecked();
1868 if ( !parallel && !perpendicular )
1872 else if ( perpendicular )
1889 if ( type == QEvent::ShortcutOverride )
1891 const QList<double> constActionKeys { mCommonAngleActions.keys() };
1892 const int currentAngleActionIndex {
static_cast<int>( constActionKeys .indexOf( mCommonAngleConstraint ) ) };
1893 const QList<QAction *> constActions { mCommonAngleActions.values( ) };
1894 QAction *nextAngleAction;
1895 if ( e->modifiers() == Qt::ShiftModifier )
1897 nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
1901 nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
1903 nextAngleAction->trigger();
1913 return e->isAccepted();
1922 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1923 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1925 mLabelX->setText( tr(
"Long" ) );
1926 mLabelY->setText( tr(
"Lat" ) );
1928 mXConstraint->setPrecision( 8 );
1929 mYConstraint->setPrecision( 8 );
1933 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
1934 mAngleLineEdit->setToolTip( QString() );
1936 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
1938 mLabelX->setText( tr(
"x" ) );
1939 mLabelY->setText( tr(
"y" ) );
1941 mXConstraint->setPrecision( 6 );
1942 mYConstraint->setPrecision( 6 );
1947 mEnableAction->setEnabled(
true );
1948 mErrorLabel->hide();
1951 mCurrentMapToolSupportsCad =
true;
1953 if ( mSessionActive && !isVisible() )
1958 setCadEnabled( mSessionActive );
1960 if ( !mConstructionGuidesLayer )
1962 resetConstructionGuides();
1965 if ( mDeferredUpdateConstructionGuidesCrs )
1967 updateConstructionGuidesCrs();
1977 mEnableAction->setEnabled(
false );
1978 mErrorLabel->setText( tr(
"Advanced digitizing tools are not enabled for the current map tool" ) );
1979 mErrorLabel->show();
1982 mCurrentMapToolSupportsCad =
false;
1984 mSnapIndicator->setVisible(
false );
1986 setCadEnabled(
false );
1991 mCadPaintItem->update();
1996 if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
2001 mLockedSnapVertices.clear();
2007 QgsPoint pt = pointXYToPoint( point );
2010 mCadPointList << pt;
2014 mCadPointList.insert( 0, pt );
2023 if ( mConstructionGuideLine.
numPoints() == 2 )
2028 mConstructionGuidesLayer->dataProvider()->addFeature( feature );
2029 mConstructionGuideId = feature.
id();
2031 else if ( mConstructionGuideLine.
numPoints() > 2 )
2034 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2039 if ( !mConstructionGuideLine.
isEmpty() )
2044 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2045 mConstructionGuideLine.
clear();
2060 mCadPointList.removeAt( i );
2067 mCadPointList.clear();
2068 mSnappedSegment.clear();
2078 mCadPointList << point;
2083 mCadPointList[0] = point;
2090 if ( mode == mLockMode )
2095 mLockerButton->setChecked( mode ==
HardLock );
2096 if ( mRepeatingLockButton )
2100 mRepeatingLockButton->setEnabled(
true );
2104 mRepeatingLockButton->setChecked(
false );
2105 mRepeatingLockButton->setEnabled(
false );
2118 mRepeatingLock = repeating;
2119 if ( mRepeatingLockButton )
2120 mRepeatingLockButton->setChecked( repeating );
2125 mRelative = relative;
2126 if ( mRelativeButton )
2128 mRelativeButton->setChecked( relative );
2135 if ( updateWidget && mLineEdit->isEnabled() )
2136 mLineEdit->setText( displayValue() );
2141 switch ( mCadConstraintType )
2145 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2152 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2156 return QLocale().toString( mValue,
'f', mPrecision );
2170 return QLocale().toString( mValue,
'f', mPrecision );
2175 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
2180 setRelative( !mRelative );
2186 if ( mLineEdit->isEnabled() )
2187 mLineEdit->setText( displayValue() );
2192 return mCadConstraintType;
2197 mCadConstraintType = constraintType;
2202 mMapCanvas = mapCanvas;
2207 QString value { text.trimmed() };
2208 switch ( constraintType )
2214 if ( value.endsWith( distanceUnit ) )
2216 value.chop( distanceUnit.length() );
2223 const QString angleUnit { tr(
"°" ) };
2224 if ( value.endsWith( angleUnit ) )
2226 value.chop( angleUnit.length() );
2233 return value.trimmed();
2241 return mCadPointList.value( 0 );
2250 QgsPoint res = mCadPointList.value( 0 );
2252 res.
setX( layerCoordinates.
x() );
2253 res.
setY( layerCoordinates.
y() );
2264 return mCadPointList.value( 1 );
2274 return mCadPointList.value( 2 );
2279QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
2286 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2291 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2296 return mShowConstructionGuides ? mShowConstructionGuides->isChecked() :
false;
2301 return mSnapToConstructionGuides ? mShowConstructionGuides->isChecked() && mSnapToConstructionGuides->isChecked() :
false;
2306 return mRecordConstructionGuides ? mRecordConstructionGuides->isChecked() :
false;
2309void QgsAdvancedDigitizingDockWidget::updateConstructionGuidesCrs()
2311 if ( !mConstructionGuidesLayer )
2318 mDeferredUpdateConstructionGuidesCrs =
true;
2329 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { feature.
id(), geom } } );
2332 mDeferredUpdateConstructionGuidesCrs =
false;
2335void QgsAdvancedDigitizingDockWidget::resetConstructionGuides()
2337 if ( mConstructionGuidesLayer )
2339 mConstructionGuidesLayer.reset();
2343 mConstructionGuidesLayer = std::make_unique<QgsVectorLayer>( QStringLiteral(
"LineString?crs=%1" ).arg( mMapCanvas->
mapSettings().
destinationCrs().
authid() ),
2344 QStringLiteral(
"constructionGuides" ),
2345 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.
void clear() override
Clears the geometry, ie reset it to a null geometry.
bool isEmpty() const override
Returns true if the geometry is empty.
int numPoints() const override
Returns the number of points in the curve.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Map canvas is a class for displaying all GIS data types on a canvas.
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
void destinationCrsChanged()
Emitted when map CRS has changed.
QgsMapTool * mapTool()
Returns the currently active tool.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
Base class for all map layer types.
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsPointXY originalMapPoint() const
Returns the original, unmodified map point of the mouse cursor.
void setMapPoint(const QgsPointXY &point)
Set the (snapped) point this event points to in map coordinates.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
bool isEditable() const override
Returns true if the layer can be edited.
A context for numeric formats.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
void setY(double y)
Sets the point's y-coordinate.
void setX(double x)
Sets the point's x-coordinate.
void setM(double m)
Sets the point's m-value.
void setZ(double z)
Sets the point's z-coordinate.
double distanceSquared(double x, double y) const
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
const QgsBearingNumericFormat * bearingFormat() const
Returns the project bearing's format, which controls how bearings associated with the project are dis...
Qgis::DistanceUnit distanceUnits
static QgsProject * instance()
Returns the QgsProject singleton instance.
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsSnappingConfig snappingConfig
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
QgsProjectDisplaySettings * displaySettings
QgsCoordinateTransformContext transformContext
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
bool setValue(const T &value, const QString &dynamicKeyPart=QString()) const
Set settings value.
A boolean settings entry.
static QgsSettingsTreeNode * sTreeDigitizing
This class is a composition of two QSettings instances:
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Class that shows snapping marker on map canvas for the current snapping match.
This is a container for configuration of the snapping of the project.
void setTypeFlag(Qgis::SnappingTypes type)
define the type of snapping
void setMode(Qgis::SnappingMode mode)
define the mode of snapping
This class has all the configuration of snapping and can return answers to snapping queries.
void addExtraSnapLayer(QgsVectorLayer *vl)
Supply an extra snapping layer (typically a memory layer).
void removeExtraSnapLayer(QgsVectorLayer *vl)
Removes an extra snapping layer.
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
static Q_INVOKABLE QString toAbbreviatedString(Qgis::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
QSet< QgsFeatureId > QgsFeatureIds
QLineF segment(int index, QRectF rect, double radius)
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
QgsPoint interpolatedPoint(const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem()) const
Convenient method to return a point on an edge with linear interpolation of the Z value.
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
bool hasEdge() const
Returns true if the Match is an edge.
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
bool hasVertex() const
Returns true if the Match is a vertex.
Setting options for loading vector layers.