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 ( mConstructionMode && mConstructionGuideLine.
numPoints() >= 2 )
1659 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1660 mConstructionGuideLine.
clear();
1662 if ( mCadPointList.size() > 1 )
1664 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
1674 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1676 mXConstraint->toggleLocked();
1681 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1685 mXConstraint->toggleRelative();
1692 else if ( type == QEvent::KeyPress )
1694 mXLineEdit->setFocus();
1695 mXLineEdit->selectAll();
1704 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1706 mYConstraint->toggleLocked();
1711 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1715 mYConstraint->toggleRelative();
1722 else if ( type == QEvent::KeyPress )
1724 mYLineEdit->setFocus();
1725 mYLineEdit->selectAll();
1734 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1736 mZConstraint->toggleLocked();
1741 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1745 mZConstraint->toggleRelative();
1752 else if ( type == QEvent::KeyPress )
1754 mZLineEdit->setFocus();
1755 mZLineEdit->selectAll();
1764 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1766 mMConstraint->toggleLocked();
1771 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1775 mMConstraint->toggleRelative();
1782 else if ( type == QEvent::KeyPress )
1784 mMLineEdit->setFocus();
1785 mMLineEdit->selectAll();
1794 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1798 mAngleConstraint->toggleLocked();
1804 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1808 mAngleConstraint->toggleRelative();
1815 else if ( type == QEvent::KeyPress )
1817 mAngleLineEdit->setFocus();
1818 mAngleLineEdit->selectAll();
1827 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1831 mDistanceConstraint->toggleLocked();
1838 else if ( type == QEvent::KeyPress )
1840 mDistanceLineEdit->setFocus();
1841 mDistanceLineEdit->selectAll();
1849 if ( type == QEvent::KeyPress )
1851 setConstructionMode( !mConstructionMode );
1858 if ( type == QEvent::KeyPress )
1860 const bool parallel = mParallelAction->isChecked();
1861 const bool perpendicular = mPerpendicularAction->isChecked();
1863 if ( !parallel && !perpendicular )
1867 else if ( perpendicular )
1884 if ( type == QEvent::ShortcutOverride )
1886 const QList<double> constActionKeys { mCommonAngleActions.keys() };
1887 const int currentAngleActionIndex {
static_cast<int>( constActionKeys .indexOf( mCommonAngleConstraint ) ) };
1888 const QList<QAction *> constActions { mCommonAngleActions.values( ) };
1889 QAction *nextAngleAction;
1890 if ( e->modifiers() == Qt::ShiftModifier )
1892 nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
1896 nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
1898 nextAngleAction->trigger();
1908 return e->isAccepted();
1917 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1918 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1920 mLabelX->setText( tr(
"Long" ) );
1921 mLabelY->setText( tr(
"Lat" ) );
1923 mXConstraint->setPrecision( 8 );
1924 mYConstraint->setPrecision( 8 );
1928 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
1929 mAngleLineEdit->setToolTip( QString() );
1931 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
1933 mLabelX->setText( tr(
"x" ) );
1934 mLabelY->setText( tr(
"y" ) );
1936 mXConstraint->setPrecision( 6 );
1937 mYConstraint->setPrecision( 6 );
1942 mEnableAction->setEnabled(
true );
1943 mErrorLabel->hide();
1946 mCurrentMapToolSupportsCad =
true;
1948 if ( mSessionActive && !isVisible() )
1953 setCadEnabled( mSessionActive );
1955 if ( !mConstructionGuidesLayer )
1957 resetConstructionGuides();
1960 if ( mDeferredUpdateConstructionGuidesCrs )
1962 updateConstructionGuidesCrs();
1972 mEnableAction->setEnabled(
false );
1973 mErrorLabel->setText( tr(
"Advanced digitizing tools are not enabled for the current map tool" ) );
1974 mErrorLabel->show();
1977 mCurrentMapToolSupportsCad =
false;
1979 mSnapIndicator->setVisible(
false );
1981 setCadEnabled(
false );
1986 mCadPaintItem->update();
1991 if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
1996 mLockedSnapVertices.clear();
2002 QgsPoint pt = pointXYToPoint( point );
2005 mCadPointList << pt;
2009 mCadPointList.insert( 0, pt );
2018 if ( mConstructionGuideLine.
numPoints() == 2 )
2023 mConstructionGuidesLayer->dataProvider()->addFeature( feature );
2024 mConstructionGuideId = feature.
id();
2026 else if ( mConstructionGuideLine.
numPoints() > 2 )
2029 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2034 if ( !mConstructionGuideLine.
isEmpty() )
2039 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2040 mConstructionGuideLine.
clear();
2055 mCadPointList.removeAt( i );
2062 mCadPointList.clear();
2063 mSnappedSegment.clear();
2073 mCadPointList << point;
2078 mCadPointList[0] = point;
2085 if ( mode == mLockMode )
2090 mLockerButton->setChecked( mode ==
HardLock );
2091 if ( mRepeatingLockButton )
2095 mRepeatingLockButton->setEnabled(
true );
2099 mRepeatingLockButton->setChecked(
false );
2100 mRepeatingLockButton->setEnabled(
false );
2113 mRepeatingLock = repeating;
2114 if ( mRepeatingLockButton )
2115 mRepeatingLockButton->setChecked( repeating );
2120 mRelative = relative;
2121 if ( mRelativeButton )
2123 mRelativeButton->setChecked( relative );
2130 if ( updateWidget && mLineEdit->isEnabled() )
2131 mLineEdit->setText( displayValue() );
2136 switch ( mCadConstraintType )
2140 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2147 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2151 return QLocale().toString( mValue,
'f', mPrecision );
2165 return QLocale().toString( mValue,
'f', mPrecision );
2170 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
2175 setRelative( !mRelative );
2181 if ( mLineEdit->isEnabled() )
2182 mLineEdit->setText( displayValue() );
2187 return mCadConstraintType;
2192 mCadConstraintType = constraintType;
2197 mMapCanvas = mapCanvas;
2202 QString value { text.trimmed() };
2203 switch ( constraintType )
2209 if ( value.endsWith( distanceUnit ) )
2211 value.chop( distanceUnit.length() );
2218 const QString angleUnit { tr(
"°" ) };
2219 if ( value.endsWith( angleUnit ) )
2221 value.chop( angleUnit.length() );
2228 return value.trimmed();
2236 return mCadPointList.value( 0 );
2245 QgsPoint res = mCadPointList.value( 0 );
2247 res.
setX( layerCoordinates.
x() );
2248 res.
setY( layerCoordinates.
y() );
2259 return mCadPointList.value( 1 );
2269 return mCadPointList.value( 2 );
2274QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
2281 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2286 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2291 return mShowConstructionGuides ? mShowConstructionGuides->isChecked() :
false;
2296 return mSnapToConstructionGuides ? mShowConstructionGuides->isChecked() && mSnapToConstructionGuides->isChecked() :
false;
2301 return mRecordConstructionGuides ? mRecordConstructionGuides->isChecked() :
false;
2304void QgsAdvancedDigitizingDockWidget::updateConstructionGuidesCrs()
2306 if ( !mConstructionGuidesLayer )
2313 mDeferredUpdateConstructionGuidesCrs =
true;
2324 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { feature.
id(), geom } } );
2327 mDeferredUpdateConstructionGuidesCrs =
false;
2330void QgsAdvancedDigitizingDockWidget::resetConstructionGuides()
2332 if ( mConstructionGuidesLayer )
2334 mConstructionGuidesLayer.reset();
2338 mConstructionGuidesLayer = std::make_unique<QgsVectorLayer>( QStringLiteral(
"LineString?crs=%1" ).arg( mMapCanvas->
mapSettings().
destinationCrs().
authid() ),
2339 QStringLiteral(
"constructionGuides" ),
2340 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.