18#include <QCoreApplication>
23#include "moc_qgsadvanceddigitizingdockwidget.cpp"
46#include <QActionGroup>
57 , mMapCanvas( canvas )
58 , mUserInputWidget( userInputWidget )
60 , mCommonAngleConstraint(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
66 mAngleConstraint.reset(
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
68 mAngleConstraint->setMapCanvas( mMapCanvas );
69 mDistanceConstraint.reset(
new CadConstraint( mDistanceLineEdit, mLockDistanceButton,
nullptr, mRepeatingLockDistanceButton ) );
71 mDistanceConstraint->setMapCanvas( mMapCanvas );
72 mXConstraint.reset(
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
74 mXConstraint->setMapCanvas( mMapCanvas );
75 mYConstraint.reset(
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
77 mYConstraint->setMapCanvas( mMapCanvas );
78 mZConstraint.reset(
new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
80 mZConstraint->setMapCanvas( mMapCanvas );
81 mMConstraint.reset(
new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
83 mMConstraint->setMapCanvas( mMapCanvas );
85 mLineExtensionConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
86 mXyVertexConstraint.reset(
new CadConstraint(
new QLineEdit(),
new QToolButton() ) );
87 mXyVertexConstraint->setMapCanvas( mMapCanvas );
91 mMapCanvas->installEventFilter(
this );
92 mAngleLineEdit->installEventFilter(
this );
93 mDistanceLineEdit->installEventFilter(
this );
94 mXLineEdit->installEventFilter(
this );
95 mYLineEdit->installEventFilter(
this );
96 mZLineEdit->installEventFilter(
this );
97 mMLineEdit->installEventFilter(
this );
100 connect( mEnableAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::activateCad );
101 connect( mConstructionModeAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
102 connect( mParallelAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
103 connect( mPerpendicularAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
104 connect( mLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
105 connect( mLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
106 connect( mLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
107 connect( mLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
108 connect( mLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
109 connect( mLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
110 connect( mRelativeAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
111 connect( mRelativeXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
112 connect( mRelativeYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
113 connect( mRelativeZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
114 connect( mRelativeMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
115 connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
116 connect( mRepeatingLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
117 connect( mRepeatingLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
118 connect( mRepeatingLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
119 connect( mRepeatingLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
120 connect( mRepeatingLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
121 connect( mAngleLineEdit, &QLineEdit::returnPressed,
this, [=]() { lockConstraint(); } );
122 connect( mDistanceLineEdit, &QLineEdit::returnPressed,
this, [=]() { lockConstraint(); } );
123 connect( mXLineEdit, &QLineEdit::returnPressed,
this, [=]() { lockConstraint(); } );
124 connect( mYLineEdit, &QLineEdit::returnPressed,
this, [=]() { lockConstraint(); } );
125 connect( mZLineEdit, &QLineEdit::returnPressed,
this, [=]() { lockConstraint(); } );
126 connect( mMLineEdit, &QLineEdit::returnPressed,
this, [=]() { lockConstraint(); } );
127 connect( mAngleLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
128 connect( mDistanceLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
129 connect( mXLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
130 connect( mYLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
131 connect( mZLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
132 connect( mMLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
138 whileBlocking( mAngleLineEdit )->setText( cleanedInputValue );
144 whileBlocking( mDistanceLineEdit )->setText( cleanedInputValue );
156 mCommonAngleActionsMenu =
new QMenu(
this );
158#ifndef __clang_analyzer__
159 QActionGroup *angleButtonGroup =
new QActionGroup( mCommonAngleActionsMenu );
161 QList<QPair<double, QString>> commonAngles;
162 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 } );
163 for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
169 QMenu *snappingPriorityMenu =
new QMenu( tr(
"Snapping Priority" ), mCommonAngleActionsMenu );
170 QActionGroup *snappingPriorityActionGroup =
new QActionGroup( snappingPriorityMenu );
171 QAction *featuresAction =
new QAction( tr(
"Prioritize Snapping to Features" ), snappingPriorityActionGroup );
172 featuresAction->setCheckable(
true );
173 QAction *anglesAction =
new QAction( tr(
"Prioritize Snapping to Common Angles" ), snappingPriorityActionGroup );
174 anglesAction->setCheckable(
true );
175 snappingPriorityActionGroup->addAction( featuresAction );
176 snappingPriorityActionGroup->addAction( anglesAction );
177 snappingPriorityMenu->addAction( anglesAction );
178 snappingPriorityMenu->addAction( featuresAction );
179 connect( anglesAction, &QAction::changed,
this, [=] {
180 mSnappingPrioritizeFeatures = featuresAction->isChecked();
181 settingsCadSnappingPriorityPrioritizeFeature->
setValue( featuresAction->isChecked() );
183 featuresAction->setChecked( settingsCadSnappingPriorityPrioritizeFeature->
value() );
184 anglesAction->setChecked( !featuresAction->isChecked() );
185 mCommonAngleActionsMenu->addMenu( snappingPriorityMenu );
188 for ( QList<QPair<double, QString>>::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
190 QAction *action =
new QAction( it->second, mCommonAngleActionsMenu );
191 action->setCheckable(
true );
192 action->setChecked( it->first == mCommonAngleConstraint );
193 mCommonAngleActionsMenu->addAction( action );
195#ifndef __clang_analyzer__
196 angleButtonGroup->addAction( action );
198 mCommonAngleActions.insert( it->first, action );
202 QMenu *constructionSettingsMenu =
new QMenu(
this );
204 mRecordConstructionGuides =
new QAction( tr(
"Record Construction Guides" ), constructionSettingsMenu );
205 mRecordConstructionGuides->setCheckable(
true );
206 mRecordConstructionGuides->setChecked( settingsCadRecordConstructionGuides->
value() );
207 constructionSettingsMenu->addAction( mRecordConstructionGuides );
208 connect( mRecordConstructionGuides, &QAction::triggered,
this, [=]() { settingsCadRecordConstructionGuides->
setValue( mRecordConstructionGuides->isChecked() ); } );
210 mShowConstructionGuides =
new QAction( tr(
"Show Construction Guides" ), constructionSettingsMenu );
211 mShowConstructionGuides->setCheckable(
true );
212 mShowConstructionGuides->setChecked( settingsCadShowConstructionGuides->
value() );
213 constructionSettingsMenu->addAction( mShowConstructionGuides );
214 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, [=]() {
230 resetConstructionGuides();
234 QToolButton *constructionModeToolButton = qobject_cast<QToolButton *>( mToolbar->widgetForAction( mConstructionModeAction ) );
235 constructionModeToolButton->setPopupMode( QToolButton::MenuButtonPopup );
236 constructionModeToolButton->setMenu( constructionSettingsMenu );
237 constructionModeToolButton->setObjectName( QStringLiteral(
"ConstructionModeButton" ) );
240 QMenu *toolsMenu =
new QMenu(
this );
241 connect( toolsMenu, &QMenu::aboutToShow,
this, [=]() {
244 for (
const QString &name : toolMetadataNames )
247 QAction *toolAction =
new QAction( toolMetadata->
icon(), toolMetadata->
visibleName(), toolsMenu );
248 connect( toolAction, &QAction::triggered,
this, [=]() {
251 toolsMenu->addAction( toolAction );
254 qobject_cast<QToolButton *>( mToolbar->widgetForAction( mToolsAction ) )->setPopupMode( QToolButton::InstantPopup );
255 mToolsAction->setMenu( toolsMenu );
257 qobject_cast<QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
258 mSettingsAction->setMenu( mCommonAngleActionsMenu );
259 mSettingsAction->setCheckable(
true );
260 mSettingsAction->setToolTip(
"<b>" + tr(
"Snap to common angles" ) +
"</b><br>(" + tr(
"press n to cycle through the options" ) +
")" );
261 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
262 connect( mCommonAngleActionsMenu, &QMenu::triggered,
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
265 QMenu *constructionMenu =
new QMenu(
this );
267 mLineExtensionAction =
new QAction( tr(
"Line Extension" ), constructionMenu );
268 mLineExtensionAction->setCheckable(
true );
269 constructionMenu->addAction( mLineExtensionAction );
270 connect( mLineExtensionAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
272 mXyVertexAction =
new QAction( tr(
"X/Y Point" ), constructionMenu );
273 mXyVertexAction->setCheckable(
true );
274 constructionMenu->addAction( mXyVertexAction );
275 connect( mXyVertexAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
277 auto constructionToolBar = qobject_cast<QToolButton *>( mToolbar->widgetForAction( mConstructionAction ) );
278 constructionToolBar->setPopupMode( QToolButton::InstantPopup );
279 constructionToolBar->setMenu( constructionMenu );
280 constructionToolBar->setObjectName( QStringLiteral(
"ConstructionButton" ) );
282 mConstructionAction->setMenu( mCommonAngleActionsMenu );
283 mConstructionAction->setCheckable(
true );
284 mConstructionAction->setToolTip( tr(
"Construction Tools" ) );
288 mConstructionModeAction->setToolTip(
"<b>" + tr(
"Construction mode" ) +
"</b><br>(" + tr(
"press c to toggle on/off" ) +
")" );
289 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
290 mLockDistanceButton->setToolTip(
"<b>" + tr(
"Lock distance" ) +
"</b><br>(" + tr(
"press Ctrl + d for quick access" ) +
")" );
291 mRepeatingLockDistanceButton->setToolTip(
"<b>" + tr(
"Continuously lock distance" ) +
"</b>" );
293 mRelativeAngleButton->setToolTip(
"<b>" + tr(
"Toggles relative angle to previous segment" ) +
"</b><br>(" + tr(
"press Shift + a for quick access" ) +
")" );
294 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
295 mLockAngleButton->setToolTip(
"<b>" + tr(
"Lock angle" ) +
"</b><br>(" + tr(
"press Ctrl + a for quick access" ) +
")" );
296 mRepeatingLockAngleButton->setToolTip(
"<b>" + tr(
"Continuously lock angle" ) +
"</b>" );
298 mRelativeXButton->setToolTip(
"<b>" + tr(
"Toggles relative x to previous node" ) +
"</b><br>(" + tr(
"press Shift + x for quick access" ) +
")" );
299 mXLineEdit->setToolTip(
"<b>" + tr(
"X coordinate" ) +
"</b><br>(" + tr(
"press x for quick access" ) +
")" );
300 mLockXButton->setToolTip(
"<b>" + tr(
"Lock x coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + x for quick access" ) +
")" );
301 mRepeatingLockXButton->setToolTip(
"<b>" + tr(
"Continuously lock x coordinate" ) +
"</b>" );
303 mRelativeYButton->setToolTip(
"<b>" + tr(
"Toggles relative y to previous node" ) +
"</b><br>(" + tr(
"press Shift + y for quick access" ) +
")" );
304 mYLineEdit->setToolTip(
"<b>" + tr(
"Y coordinate" ) +
"</b><br>(" + tr(
"press y for quick access" ) +
")" );
305 mLockYButton->setToolTip(
"<b>" + tr(
"Lock y coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + y for quick access" ) +
")" );
306 mRepeatingLockYButton->setToolTip(
"<b>" + tr(
"Continuously lock y coordinate" ) +
"</b>" );
308 mRelativeZButton->setToolTip(
"<b>" + tr(
"Toggles relative z to previous node" ) +
"</b><br>(" + tr(
"press Shift + z for quick access" ) +
")" );
309 mZLineEdit->setToolTip(
"<b>" + tr(
"Z coordinate" ) +
"</b><br>(" + tr(
"press z for quick access" ) +
")" );
310 mLockZButton->setToolTip(
"<b>" + tr(
"Lock z coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + z for quick access" ) +
")" );
311 mRepeatingLockZButton->setToolTip(
"<b>" + tr(
"Continuously lock z coordinate" ) +
"</b>" );
313 mRelativeMButton->setToolTip(
"<b>" + tr(
"Toggles relative m to previous node" ) +
"</b><br>(" + tr(
"press Shift + m for quick access" ) +
")" );
314 mMLineEdit->setToolTip(
"<b>" + tr(
"M coordinate" ) +
"</b><br>(" + tr(
"press m for quick access" ) +
")" );
315 mLockMButton->setToolTip(
"<b>" + tr(
"Lock m coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + m for quick access" ) +
")" );
316 mRepeatingLockMButton->setToolTip(
"<b>" + tr(
"Continuously lock m coordinate" ) +
"</b>" );
327 mFloaterActionsMenu =
new QMenu(
this );
328 qobject_cast<QToolButton *>( mToolbar->widgetForAction( mFloaterAction ) )->setPopupMode( QToolButton::InstantPopup );
329 mFloaterAction->setMenu( mFloaterActionsMenu );
330 mFloaterAction->setCheckable(
true );
332 mFloaterAction->setChecked( mFloater->
active() );
336 QAction *action =
new QAction( tr(
"Show floater" ), mFloaterActionsMenu );
337 action->setCheckable(
true );
338 action->setChecked( mFloater->
active() );
339 mFloaterActionsMenu->addAction( action );
340 connect( action, &QAction::toggled,
this, [=](
bool checked ) {
342 mFloaterAction->setChecked( checked );
346 mFloaterActionsMenu->addSeparator();
349 QAction *action =
new QAction( tr(
"Show distance" ), mFloaterActionsMenu );
350 action->setCheckable(
true );
351 mFloaterActionsMenu->addAction( action );
352 connect( action, &QAction::toggled,
this, [=](
bool checked ) {
355 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/DistanceShowInFloater" ),
true ).toBool() );
359 QAction *action =
new QAction( tr(
"Show angle" ), mFloaterActionsMenu );
360 action->setCheckable(
true );
361 mFloaterActionsMenu->addAction( action );
362 connect( action, &QAction::toggled,
this, [=](
bool checked ) {
365 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/AngleShowInFloater" ),
true ).toBool() );
369 QAction *action =
new QAction( tr(
"Show XY coordinates" ), mFloaterActionsMenu );
370 action->setCheckable(
true );
371 mFloaterActionsMenu->addAction( action );
372 connect( action, &QAction::toggled,
this, [=](
bool checked ) {
377 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/XCoordinateShowInFloater" ),
true ).toBool() );
381 QAction *action =
new QAction( tr(
"Show Z value" ), mFloaterActionsMenu );
382 action->setCheckable(
true );
383 mFloaterActionsMenu->addAction( action );
384 connect( action, &QAction::toggled,
this, [=](
bool checked ) {
387 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/ZCoordinateShowInFloater" ),
true ).toBool() );
391 QAction *action =
new QAction( tr(
"Show M value" ), mFloaterActionsMenu );
392 action->setCheckable(
true );
393 mFloaterActionsMenu->addAction( action );
394 connect( action, &QAction::toggled,
this, [=](
bool checked ) {
397 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/MCoordinateShowInFloater" ),
true ).toBool() );
401 QAction *action =
new QAction( tr(
"Show bearing/azimuth" ), mFloaterActionsMenu );
402 action->setCheckable(
true );
403 mFloaterActionsMenu->addAction( action );
404 connect( action, &QAction::toggled,
this, [=](
bool checked ) {
407 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/BearingShowInFloater" ),
false ).toBool() );
411 QAction *action =
new QAction( tr(
"Show common snapping angle" ), mFloaterActionsMenu );
412 action->setCheckable(
true );
413 mFloaterActionsMenu->addAction( action );
414 connect( action, &QAction::toggled,
this, [=](
bool checked ) {
417 action->setChecked(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngleSnappingShowInFloater" ),
false ).toBool() );
420 updateCapacity(
true );
424 mConstructionGuidesLayer.reset();
435 mCurrentTool->deleteLater();
442 return tr(
"Do Not Snap to Common Angles" );
444 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 );
449 mXLineEdit->setText( value );
452 emit mXLineEdit->returnPressed();
456 QEvent *e =
new QEvent( QEvent::FocusOut );
457 QCoreApplication::postEvent( mXLineEdit, e );
461 emit mXLineEdit->textEdited( value );
466 mYLineEdit->setText( value );
469 emit mYLineEdit->returnPressed();
473 QEvent *e =
new QEvent( QEvent::FocusOut );
474 QCoreApplication::postEvent( mYLineEdit, e );
478 emit mYLineEdit->textEdited( value );
483 mZLineEdit->setText( value );
486 emit mZLineEdit->returnPressed();
490 QEvent *e =
new QEvent( QEvent::FocusOut );
491 QCoreApplication::postEvent( mZLineEdit, e );
495 emit mZLineEdit->textEdited( value );
500 mMLineEdit->setText( value );
503 emit mMLineEdit->returnPressed();
507 QEvent *e =
new QEvent( QEvent::FocusOut );
508 QCoreApplication::postEvent( mMLineEdit, e );
512 emit mMLineEdit->textEdited( value );
517 mAngleLineEdit->setText( value );
520 emit mAngleLineEdit->returnPressed();
524 emit mAngleLineEdit->textEdited( value );
529 mDistanceLineEdit->setText( value );
532 emit mDistanceLineEdit->returnPressed();
536 QEvent *e =
new QEvent( QEvent::FocusOut );
537 QCoreApplication::postEvent( mDistanceLineEdit, e );
541 emit mDistanceLineEdit->textEdited( value );
546void QgsAdvancedDigitizingDockWidget::setCadEnabled(
bool enabled )
548 mCadEnabled = enabled;
549 mEnableAction->setChecked( enabled );
550 mConstructionModeAction->setEnabled( enabled );
551 mSettingsAction->setEnabled( enabled );
552 mInputWidgets->setEnabled( enabled );
553 mFloaterAction->setEnabled( enabled );
554 mConstructionAction->setEnabled( enabled );
555 mToolsAction->setEnabled( enabled );
560 mLineExtensionAction->setChecked(
false );
561 mXyVertexAction->setChecked(
false );
563 mParallelAction->setEnabled(
false );
564 mPerpendicularAction->setEnabled(
false );
567 mCurrentTool->deleteLater();
574 setConstructionMode(
false );
590 bool enableZ =
false;
591 bool enableM =
false;
595 switch ( layer->type() )
608 QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
630 mRelativeZButton->setEnabled(
enable );
631 mZLabel->setEnabled(
enable );
632 mZLineEdit->setEnabled(
enable );
633 if ( mZLineEdit->isEnabled() )
637 mLockZButton->setEnabled(
enable );
643 mRelativeMButton->setEnabled(
enable );
644 mMLabel->setEnabled(
enable );
645 mMLineEdit->setEnabled(
enable );
646 if ( mMLineEdit->isEnabled() )
650 mLockMButton->setEnabled(
enable );
654void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
656 enabled &= mCurrentMapToolSupportsCad;
658 mSessionActive = enabled;
660 if ( enabled && !isVisible() )
665 setCadEnabled( enabled );
672 mCurrentTool->deleteLater();
673 mCurrentTool =
nullptr;
680 if ( QWidget *toolWidget = mCurrentTool->createWidget() )
682 toolWidget->setParent( mUserInputWidget );
691 return mCurrentTool.data();
694void QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked(
bool activated )
700 else if ( sender() == mParallelAction )
704 else if ( sender() == mPerpendicularAction )
710void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
712 if ( sender() == mRelativeAngleButton )
714 mAngleConstraint->setRelative( activate );
717 else if ( sender() == mRelativeXButton )
719 mXConstraint->setRelative( activate );
722 else if ( sender() == mRelativeYButton )
724 mYConstraint->setRelative( activate );
727 else if ( sender() == mRelativeZButton )
729 mZConstraint->setRelative( activate );
732 else if ( sender() == mRelativeMButton )
734 mMConstraint->setRelative( activate );
739void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock(
bool activate )
741 if ( sender() == mRepeatingLockDistanceButton )
743 mDistanceConstraint->setRepeatingLock( activate );
745 else if ( sender() == mRepeatingLockAngleButton )
747 mAngleConstraint->setRepeatingLock( activate );
749 else if ( sender() == mRepeatingLockXButton )
751 mXConstraint->setRepeatingLock( activate );
753 else if ( sender() == mRepeatingLockYButton )
755 mYConstraint->setRepeatingLock( activate );
757 else if ( sender() == mRepeatingLockZButton )
759 mZConstraint->setRepeatingLock( activate );
761 else if ( sender() == mRepeatingLockMButton )
763 mMConstraint->setRepeatingLock( activate );
767void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
769 mConstructionMode = enabled;
770 mConstructionModeAction->setChecked( enabled );
774 if ( enabled && mCadPointList.size() > 1 )
776 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
781void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
784 for (
auto it = mCommonAngleActions.cbegin(); it != mCommonAngleActions.cend(); ++it )
786 if ( it.value() == action )
788 it.value()->setChecked(
true );
789 mCommonAngleConstraint = it.key();
791 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
798QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
const
802 return advancedTool->layer();
816 if ( releaseRepeatingLocks )
818 mXyVertexAction->setChecked(
false );
822 mLineExtensionAction->setChecked(
false );
829 if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
834 if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
839 if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
844 if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
849 if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
854 if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
860 if ( !mCadPointList.empty() )
862 if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
864 mXConstraint->setValue( mCadPointList.constLast().x(),
true );
866 if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
868 mYConstraint->setValue( mCadPointList.constLast().y(),
true );
870 if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
872 mZConstraint->setValue( mCadPointList.constLast().z(),
true );
874 if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
876 mMConstraint->setValue( mCadPointList.constLast().m(),
true );
882void QgsAdvancedDigitizingDockWidget::emit pointChanged()
885 QPoint globalPos = mMapCanvas->cursor().pos();
886 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
887 QMouseEvent *e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
888 mCurrentMapTool->canvasMoveEvent( e );
894 CadConstraint *constraint =
nullptr;
895 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
897 constraint = mAngleConstraint.get();
899 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
901 constraint = mDistanceConstraint.get();
903 else if ( obj == mXLineEdit || obj == mLockXButton )
905 constraint = mXConstraint.get();
907 else if ( obj == mYLineEdit || obj == mLockYButton )
909 constraint = mYConstraint.get();
911 else if ( obj == mZLineEdit || obj == mLockZButton )
913 constraint = mZConstraint.get();
915 else if ( obj == mMLineEdit || obj == mLockMButton )
917 constraint = mMConstraint.get();
919 else if ( obj == mLineExtensionAction )
921 constraint = mLineExtensionConstraint.get();
923 else if ( obj == mXyVertexAction )
925 constraint = mXyVertexConstraint.get();
930double QgsAdvancedDigitizingDockWidget::parseUserInput(
const QString &inputValue,
const Qgis::CadConstraintType type,
bool &ok )
const
941 const QVariant result = expr.evaluate();
942 if ( expr.hasEvalError() )
945 QString inputValueC { inputValue };
948 if ( inputValue.contains( QLocale().groupSeparator() ) )
950 inputValueC.remove( QLocale().groupSeparator() );
952 const QVariant resultC = exprC.evaluate();
953 if ( !exprC.hasEvalError() )
955 value = resultC.toDouble( &ok );
960 if ( !ok && QLocale().decimalPoint() != QChar(
'.' ) && inputValueC.contains( QLocale().decimalPoint() ) )
962 QgsExpression exprC( inputValueC.replace( QLocale().decimalPoint(), QChar(
'.' ) ) );
963 const QVariant resultC = exprC.evaluate();
964 if ( !exprC.hasEvalError() )
966 value = resultC.toDouble( &ok );
972 value = result.toDouble( &ok );
987void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
989 if ( !constraint || textValue.isEmpty() )
998 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
1002 constraint->setValue( value, convertExpression );
1007void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
1009 CadConstraint *constraint = objectToConstraint( sender() );
1017 const QString textValue = constraint->lineEdit()->text();
1018 if ( !textValue.isEmpty() )
1021 const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
1024 constraint->setValue( value );
1038 if ( constraint == mXConstraint.get() )
1042 else if ( constraint == mYConstraint.get() )
1046 else if ( constraint == mZConstraint.get() )
1050 else if ( constraint == mMConstraint.get() )
1054 else if ( constraint == mDistanceConstraint.get() )
1058 else if ( constraint == mAngleConstraint.get() )
1066 if ( constraint == mAngleConstraint.get() )
1076void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
1078 CadConstraint *constraint = objectToConstraint( sender() );
1084 updateConstraintValue( constraint, textValue,
false );
1087void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
1089 QLineEdit *lineEdit = qobject_cast<QLineEdit *>( sender()->parent() );
1093 CadConstraint *constraint = objectToConstraint( lineEdit );
1099 updateConstraintValue( constraint, lineEdit->text(),
true );
1104 mBetweenLineConstraint = constraint;
1109void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint(
bool activate )
1111 CadConstraint *constraint = objectToConstraint( sender() );
1119 if ( constraint == mXyVertexConstraint.get() )
1123 else if ( constraint == mLineExtensionConstraint.get() )
1137void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
1143 if ( mCadPointList.count() > 1 )
1146 if ( !isGeographic )
1152 if ( mCadPointList.count() > 2 )
1154 if ( !isGeographic )
1157 if ( !updateUIwithoutChange && newCapacities == mCapacities )
1167 const bool distance = mCadEnabled && newCapacities.testFlag(
Distance );
1168 const bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
1169 const bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
1170 const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag(
RelativeCoordinates );
1172 mPerpendicularAction->setEnabled( distance && snappingEnabled );
1173 mParallelAction->setEnabled( distance && snappingEnabled );
1175 mLineExtensionAction->setEnabled( snappingEnabled );
1176 mXyVertexAction->setEnabled( snappingEnabled );
1180 if ( !snappingEnabled )
1182 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode." ) );
1183 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode." ) );
1184 mLineExtensionAction->setToolTip( tr(
"Snapping must be enabled to utilize line extension mode." ) );
1185 mXyVertexAction->setToolTip( tr(
"Snapping must be enabled to utilize xy point mode." ) );
1187 else if ( mCadPointList.count() <= 1 )
1189 mPerpendicularAction->setToolTip( tr(
"A first vertex should be drawn to utilize perpendicular mode." ) );
1190 mParallelAction->setToolTip( tr(
"A first vertex should be drawn to utilize parallel mode." ) );
1192 else if ( isGeographic )
1194 mPerpendicularAction->setToolTip( tr(
"Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1195 mParallelAction->setToolTip( tr(
"Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1199 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1200 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
1204 if ( !absoluteAngle )
1210 mLockAngleButton->setEnabled( absoluteAngle );
1211 mRelativeAngleButton->setEnabled( relativeAngle );
1212 mAngleLineEdit->setEnabled( absoluteAngle );
1214 if ( !absoluteAngle )
1218 if ( !relativeAngle )
1220 mAngleConstraint->setRelative(
false );
1223 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
1226 mAngleConstraint->setRelative(
true );
1231 mLockDistanceButton->setEnabled( distance && relativeCoordinates );
1232 mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
1234 if ( !( distance && relativeCoordinates ) )
1239 mRelativeXButton->setEnabled( relativeCoordinates );
1240 mRelativeYButton->setEnabled( relativeCoordinates );
1241 mRelativeZButton->setEnabled( relativeCoordinates );
1242 mRelativeMButton->setEnabled( relativeCoordinates );
1245 mCapacities = newCapacities;
1253 constr.
locked =
c->isLocked();
1255 constr.
value =
c->value();
1262 if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
1268 const int lastIndex = mLockedSnapVertices.length() - 1;
1269 for (
int i = lastIndex; i >= 0; --i )
1271 if ( mLockedSnapVertices[i].point() == snapMatch.
point() )
1273 if ( snapMatch.
point() != previouslySnap.
point() )
1275 mLockedSnapVertices.removeAt( i );
1281 if ( snapMatch.
point() != previouslySnap.
point() )
1283 mLockedSnapVertices.enqueue( snapMatch );
1286 if ( mLockedSnapVertices.count() > 3 )
1288 mLockedSnapVertices.dequeue();
1297 context.
xConstraint = _constraint( mXConstraint.get() );
1298 context.
yConstraint = _constraint( mYConstraint.get() );
1299 context.
zConstraint = _constraint( mZConstraint.get() );
1300 context.
mConstraint = _constraint( mMConstraint.get() );
1327 const bool res = output.
valid;
1329 mSnappedSegment.clear();
1334 mSnappedSegment << edgePt0 << edgePt1;
1355 mSnapIndicator->setMatch( output.
snapMatch );
1356 mSnapIndicator->setVisible(
true );
1360 mSnapIndicator->setVisible(
false );
1382 if ( mSnapMatch.
layer() )
1398 toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
1399 mLastSnapMatch = mSnapMatch;
1409 if ( mLockZButton->isChecked() )
1411 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1413 if ( mLockMButton->isChecked() )
1415 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1421 updateUnlockedConstraintValues( point );
1429 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
1436void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPoint &point )
1438 bool previousPointExist, penulPointExist;
1443 if ( !mAngleConstraint->isLocked() && previousPointExist )
1445 double prevAngle = 0.0;
1447 if ( penulPointExist && mAngleConstraint->relative() )
1450 prevAngle = std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() ) * 180 / M_PI;
1453 const double xAngle { std::atan2( point.
y() - previousPt.
y(), point.
x() - previousPt.
x() ) * 180 / M_PI };
1456 const double angle = std::fmod( xAngle - prevAngle, 360.0 );
1457 mAngleConstraint->setValue( angle );
1460 double bearing { std::fmod( xAngle, 360.0 ) };
1461 bearing = bearing <= 90.0 ? 90.0 - bearing : ( bearing > 90 ? 270.0 + 180.0 - bearing : 270.0 - bearing );
1467 if ( !mDistanceConstraint->isLocked() && previousPointExist )
1469 mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
1472 if ( !mXConstraint->isLocked() )
1474 if ( previousPointExist && mXConstraint->relative() )
1476 mXConstraint->setValue( point.
x() - previousPt.
x() );
1480 mXConstraint->setValue( point.
x() );
1484 if ( !mYConstraint->isLocked() )
1486 if ( previousPointExist && mYConstraint->relative() )
1488 mYConstraint->setValue( point.
y() - previousPt.
y() );
1492 mYConstraint->setValue( point.
y() );
1496 if ( !mZConstraint->isLocked() )
1498 if ( previousPointExist && mZConstraint->relative() )
1500 mZConstraint->setValue( point.
z() - previousPt.
z() );
1504 mZConstraint->setValue( point.
z() );
1508 if ( !mMConstraint->isLocked() )
1510 if ( previousPointExist && mMConstraint->relative() )
1512 mMConstraint->setValue( point.
m() - previousPt.
m() );
1516 mMConstraint->setValue( point.
m() );
1522QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
1535 snappingUtils->
setConfig( localConfig );
1537 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
1539 snappingUtils->
setConfig( canvasConfig );
1549 *snapped =
segment.count() == 2;
1559 mCurrentTool->canvasPressEvent( event );
1564 event->setAccepted(
false );
1576 mCurrentTool->canvasMoveEvent( event );
1584 if ( event->button() == Qt::RightButton )
1588 mCurrentTool->canvasReleaseEvent( event );
1589 if ( !event->isAccepted() )
1601 event->setAccepted(
false );
1607 mCurrentTool->canvasReleaseEvent( event );
1608 if ( !event->isAccepted() )
1619 if ( mLockZButton->isChecked() )
1621 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
1623 if ( mLockMButton->isChecked() )
1625 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
1636 event->setAccepted(
false );
1648 bool previousPointExist, penulPointExist, snappedSegmentExist;
1651 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
1653 if ( !previousPointExist || !snappedSegmentExist )
1658 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1660 if ( mAngleConstraint->relative() && penulPointExist )
1662 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
1670 angle *= 180 / M_PI;
1672 mAngleConstraint->setValue( angle );
1673 mAngleConstraint->setLockMode( lockMode );
1691 case Qt::Key_Backspace:
1692 case Qt::Key_Delete:
1698 case Qt::Key_Escape:
1717 mCurrentTool->deleteLater();
1720 if ( !mConstructionGuideLine.
isEmpty() )
1722 mConstructionGuideLine.
clear();
1738 case Qt::Key_Backspace:
1739 case Qt::Key_Delete:
1745 case Qt::Key_Escape:
1749 if ( mConstructionGuideLine.
numPoints() >= 2 )
1751 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1752 mConstructionGuideLine.
clear();
1757 mCurrentTool->deleteLater();
1764 filterKeyPress( e );
1773 const auto constPoints = points;
1782 mDistanceConstraint->toggleLocked();
1787bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1791 return QgsDockWidget::eventFilter( obj, event );
1799 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1801 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
1803 return filterKeyPress( keyEvent );
1806 return QgsDockWidget::eventFilter( obj, event );
1809bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1815 const QEvent::Type type = e->type();
1818 case Qt::Key_Escape:
1820 if ( type == QEvent::KeyPress && mCurrentTool )
1822 mCurrentTool->deleteLater();
1824 else if ( type == QEvent::KeyPress && mConstructionMode && mConstructionGuideLine.
numPoints() >= 2 )
1826 mConstructionGuidesLayer->dataProvider()->deleteFeatures(
QgsFeatureIds() << mConstructionGuideId );
1827 mConstructionGuideLine.
clear();
1829 if ( mCadPointList.size() > 1 )
1831 mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
1846 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1848 mXConstraint->toggleLocked();
1853 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1857 mXConstraint->toggleRelative();
1864 else if ( type == QEvent::KeyPress )
1866 mXLineEdit->setFocus();
1867 mXLineEdit->selectAll();
1876 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1878 mYConstraint->toggleLocked();
1883 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1887 mYConstraint->toggleRelative();
1894 else if ( type == QEvent::KeyPress )
1896 mYLineEdit->setFocus();
1897 mYLineEdit->selectAll();
1906 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1908 mZConstraint->toggleLocked();
1913 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1917 mZConstraint->toggleRelative();
1924 else if ( type == QEvent::KeyPress )
1926 mZLineEdit->setFocus();
1927 mZLineEdit->selectAll();
1936 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1938 mMConstraint->toggleLocked();
1943 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1947 mMConstraint->toggleRelative();
1954 else if ( type == QEvent::KeyPress )
1956 mMLineEdit->setFocus();
1957 mMLineEdit->selectAll();
1966 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1970 mAngleConstraint->toggleLocked();
1976 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1980 mAngleConstraint->toggleRelative();
1987 else if ( type == QEvent::KeyPress )
1989 mAngleLineEdit->setFocus();
1990 mAngleLineEdit->selectAll();
1999 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
2008 else if ( type == QEvent::KeyPress )
2010 mDistanceLineEdit->setFocus();
2011 mDistanceLineEdit->selectAll();
2019 if ( type == QEvent::KeyPress )
2021 setConstructionMode( !mConstructionMode );
2028 if ( type == QEvent::KeyPress )
2030 const bool parallel = mParallelAction->isChecked();
2031 const bool perpendicular = mPerpendicularAction->isChecked();
2033 if ( !parallel && !perpendicular )
2037 else if ( perpendicular )
2054 if ( type == QEvent::ShortcutOverride )
2056 const QList<double> constActionKeys { mCommonAngleActions.keys() };
2057 const int currentAngleActionIndex {
static_cast<int>( constActionKeys.indexOf( mCommonAngleConstraint ) ) };
2058 const QList<QAction *> constActions { mCommonAngleActions.values() };
2059 QAction *nextAngleAction;
2060 if ( e->modifiers() == Qt::ShiftModifier )
2062 nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
2066 nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
2068 nextAngleAction->trigger();
2078 return e->isAccepted();
2087 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
2088 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
2090 mLabelX->setText( tr(
"Long" ) );
2091 mLabelY->setText( tr(
"Lat" ) );
2093 mXConstraint->setPrecision( 8 );
2094 mYConstraint->setPrecision( 8 );
2098 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
2099 mAngleLineEdit->setToolTip( QString() );
2101 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
2103 mLabelX->setText( tr(
"x" ) );
2104 mLabelY->setText( tr(
"y" ) );
2106 mXConstraint->setPrecision( 6 );
2107 mYConstraint->setPrecision( 6 );
2112 mEnableAction->setEnabled(
true );
2113 mErrorLabel->hide();
2116 mCurrentMapToolSupportsCad =
true;
2118 if ( mSessionActive && !isVisible() )
2123 setCadEnabled( mSessionActive );
2125 if ( !mConstructionGuidesLayer )
2127 resetConstructionGuides();
2130 if ( mDeferredUpdateConstructionGuidesCrs )
2132 updateConstructionGuidesCrs();
2142 mEnableAction->setEnabled(
false );
2143 mErrorLabel->setText( tr(
"Advanced digitizing tools are not enabled for the current map tool" ) );
2144 mErrorLabel->show();
2147 mCurrentMapToolSupportsCad =
false;
2149 mSnapIndicator->setVisible(
false );
2151 setCadEnabled(
false );
2156 mCadPaintItem->update();
2161 if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
2166 mLockedSnapVertices.clear();
2171 QgsPoint pt = pointXYToPoint( point );
2174 mCadPointList << pt;
2178 mCadPointList.insert( 0, pt );
2187 if ( mConstructionGuideLine.
numPoints() == 2 )
2192 mConstructionGuidesLayer->dataProvider()->addFeature( feature );
2193 mConstructionGuideId = feature.
id();
2195 else if ( mConstructionGuideLine.
numPoints() > 2 )
2198 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2203 if ( !mConstructionGuideLine.
isEmpty() )
2208 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
2209 mConstructionGuideLine.
clear();
2224 mCadPointList.removeAt( i );
2231 mCadPointList.clear();
2232 mSnappedSegment.clear();
2242 mCadPointList << point;
2247 mCadPointList[0] = point;
2254 if ( mode == mLockMode )
2259 mLockerButton->setChecked( mode ==
HardLock );
2260 if ( mRepeatingLockButton )
2264 mRepeatingLockButton->setEnabled(
true );
2268 mRepeatingLockButton->setChecked(
false );
2269 mRepeatingLockButton->setEnabled(
false );
2281 mRepeatingLock = repeating;
2282 if ( mRepeatingLockButton )
2283 mRepeatingLockButton->setChecked( repeating );
2288 mRelative = relative;
2289 if ( mRelativeButton )
2291 mRelativeButton->setChecked( relative );
2298 if ( updateWidget && mLineEdit->isEnabled() )
2299 mLineEdit->setText( displayValue() );
2304 switch ( mCadConstraintType )
2308 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2315 return QLocale().toString( mValue,
'f', mPrecision ).append( tr(
" °" ) );
2319 return QLocale().toString( mValue,
'f', mPrecision );
2336 return QLocale().toString( mValue,
'f', mPrecision );
2341 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
2346 setRelative( !mRelative );
2352 if ( mLineEdit->isEnabled() )
2353 mLineEdit->setText( displayValue() );
2358 return mCadConstraintType;
2363 mCadConstraintType = constraintType;
2368 mMapCanvas = mapCanvas;
2373 QString value { text.trimmed() };
2374 switch ( constraintType )
2380 if ( value.endsWith( distanceUnit ) )
2382 value.chop( distanceUnit.length() );
2389 const QString angleUnit { tr(
"°" ) };
2390 if ( value.endsWith( angleUnit ) )
2392 value.chop( angleUnit.length() );
2399 return value.trimmed();
2407 return mCadPointList.value( 0 );
2416 QgsPoint res = mCadPointList.value( 0 );
2418 res.
setX( layerCoordinates.
x() );
2419 res.
setY( layerCoordinates.
y() );
2430 return mCadPointList.value( 1 );
2440 return mCadPointList.value( 2 );
2445QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
2452 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2457 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
2462 return mShowConstructionGuides ? mShowConstructionGuides->isChecked() :
false;
2467 return mSnapToConstructionGuides ? mShowConstructionGuides->isChecked() && mSnapToConstructionGuides->isChecked() :
false;
2472 return mRecordConstructionGuides ? mRecordConstructionGuides->isChecked() :
false;
2475void QgsAdvancedDigitizingDockWidget::updateConstructionGuidesCrs()
2477 if ( !mConstructionGuidesLayer )
2484 mDeferredUpdateConstructionGuidesCrs =
true;
2495 mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { feature.
id(), geom } } );
2498 mDeferredUpdateConstructionGuidesCrs =
false;
2501void QgsAdvancedDigitizingDockWidget::resetConstructionGuides()
2503 if ( mConstructionGuidesLayer )
2505 mConstructionGuidesLayer.reset();
2509 mConstructionGuidesLayer = std::make_unique<QgsVectorLayer>( QStringLiteral(
"LineString?crs=%1" ).arg( mMapCanvas->
mapSettings().
destinationCrs().
authid() ), QStringLiteral(
"constructionGuides" ), QStringLiteral(
"memory" ), options );
DistanceUnit
Units of distance.
CadConstraintType
Advanced digitizing constraint type.
@ Distance
Distance value.
@ YCoordinate
Y Coordinate value.
@ XCoordinate
X Coordinate value.
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
@ AllLayers
On all vector layers.
BetweenLineConstraint
Between line constraints which can be enabled.
@ NoConstraint
No additional constraint.
@ Perpendicular
Perpendicular.
WkbType
The WKB type describes the number of dimensions a geometry has.
The QgsAdvancedDigitizingCanvasItem class draws the graphical elements of the CAD tools (.
void updatePosition() override
called on changed extent or resize event to update position of the item
The QgsAdvancedDigitizingFloater class is widget that floats next to the mouse pointer,...
void setItemVisibility(const QgsAdvancedDigitizingFloater::FloaterItem &item, bool visible)
Set whether the floater item should be visible or not.
void setActive(bool active)
Set whether the floater should be active or not.
bool active()
Whether the floater is active or not.
Structure with details of one constraint.
bool locked
Whether the constraint is active, i.e. should be considered.
double value
Numeric value of the constraint (coordinate/distance in map units or angle in degrees)
bool relative
Whether the value is relative to previous value.
Defines constraints for the QgsCadUtils::alignMapPoint() method.
QgsCadUtils::AlignMapPointConstraint xyVertexConstraint
QgsCadUtils::AlignMapPointConstraint yConstraint
Constraint for Y coordinate.
QgsCadUtils::AlignMapPointConstraint xConstraint
Constraint for X coordinate.
double mapUnitsPerPixel
Map units/pixel ratio from map canvas.
void setCadPoints(const QList< QgsPoint > &points)
Sets the list of recent CAD points (in map coordinates).
void setLockedSnapVertices(const QQueue< QgsPointLocator::Match > &lockedSnapVertices)
Sets the queue of locked vertices.
QgsCadUtils::AlignMapPointConstraint mConstraint
Constraint for M coordinate.
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
bool snappingToFeaturesOverridesCommonAngle
Flag to set snapping to features priority over common angle.
QgsCadUtils::AlignMapPointConstraint zConstraint
Constraint for Z coordinate.
QgsSnappingUtils * snappingUtils
Snapping utils that will be used to snap point to map. Must not be nullptr.
QgsCadUtils::AlignMapPointConstraint commonAngleConstraint
Constraint for soft lock to a common angle.
QgsCadUtils::AlignMapPointConstraint lineExtensionConstraint
QgsCadUtils::AlignMapPointConstraint angleConstraint
Constraint for angle.
Structure returned from alignMapPoint() method.
Qgis::LineExtensionSide softLockLineExtension
QgsPointXY finalMapPoint
map point aligned according to the constraints
bool valid
Whether the combination of constraints is actually valid.
QgsPointLocator::Match snapMatch
Snapped point - only valid if actually used for something.
double softLockCommonAngle
Angle (in degrees) to which we have soft-locked ourselves (if not set it is -1)
static QgsCadUtils::AlignMapPointOutput alignMapPoint(const QgsPointXY &originalMapPoint, const QgsCadUtils::AlignMapPointContext &ctx)
Applies X/Y/angle/distance constraints from the given context to a map point.
static QString formatDistance(double distance, int decimals, Qgis::DistanceUnit unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
Class for parsing and evaluation of expressions (formerly called "search strings").
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
This class wraps a request for features to a vector layer (or directly its vector data provider).
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
A event filter for watching for focus events on a parent object.
void focusIn()
Emitted when parent object gains focus.
void focusOut()
Emitted when parent object loses focus.
A geometry is the spatial representation of a feature.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
static QgsGui * instance()
Returns a pointer to the singleton instance.
static QgsAdvancedDigitizingToolsRegistry * advancedDigitizingToolsRegistry()
Returns the global advanced digitizing tools registry, used for registering advanced digitizing tools...
void clear() override
Clears the geometry, ie reset it to a null geometry.
bool isEmpty() const override
Returns true if the geometry is empty.
int numPoints() const override
Returns the number of points in the curve.
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
Map canvas is a class for displaying all GIS data types on a canvas.
QgsMapTool * mapTool() const
Returns the currently active tool.
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
void destinationCrsChanged()
Emitted when map CRS has changed.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
Base class for all map layer types.
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsPointXY originalMapPoint() const
Returns the original, unmodified map point of the mouse cursor.
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
void setMapPoint(const QgsPointXY &point)
Set the (snapped) point this event points to in map coordinates.
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
Qgis::DistanceUnit mapUnits() const
Returns the units of the map's geographical coordinates - used for scale calculation.
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
bool isEditable() const override
Returns true if the layer can be edited.
A context for numeric formats.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
void setY(double y)
Sets the point's y-coordinate.
void setX(double x)
Sets the point's x-coordinate.
void setM(double m)
Sets the point's m-value.
void setZ(double z)
Sets the point's z-coordinate.
double distanceSquared(double x, double y) const
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
const QgsBearingNumericFormat * bearingFormat() const
Returns the project bearing's format, which controls how bearings associated with the project are dis...
Qgis::DistanceUnit distanceUnits
static QgsProject * instance()
Returns the QgsProject singleton instance.
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsSnappingConfig snappingConfig
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
QgsProjectDisplaySettings * displaySettings
QgsCoordinateTransformContext transformContext
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
bool setValue(const T &value, const QString &dynamicKeyPart=QString()) const
Set settings value.
A boolean settings entry.
static QgsSettingsTreeNode * sTreeDigitizing
This class is a composition of two QSettings instances:
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Class that shows snapping marker on map canvas for the current snapping match.
This is a container for configuration of the snapping of the project.
void setTypeFlag(Qgis::SnappingTypes type)
define the type of snapping
void setMode(Qgis::SnappingMode mode)
define the mode of snapping
This class has all the configuration of snapping and can return answers to snapping queries.
void addExtraSnapLayer(QgsVectorLayer *vl)
Supply an extra snapping layer (typically a memory layer).
void removeExtraSnapLayer(QgsVectorLayer *vl)
Removes an extra snapping layer.
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
static Q_INVOKABLE QString toAbbreviatedString(Qgis::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
static bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
static bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
QSet< QgsFeatureId > QgsFeatureIds
QLineF segment(int index, QRectF rect, double radius)
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
QgsPoint interpolatedPoint(const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem()) const
Convenient method to return a point on an edge with linear interpolation of the Z value.
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
bool hasEdge() const
Returns true if the Match is an edge.
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
bool hasVertex() const
Returns true if the Match is a vertex.
Setting options for loading vector layers.