18 #include <QCoreApplication>
43 #include <QActionGroup>
48 , mMapCanvas( canvas )
50 , mCommonAngleConstraint(
QgsSettings().value( QStringLiteral(
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
56 mAngleConstraint.reset(
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
57 mDistanceConstraint.reset(
new CadConstraint( mDistanceLineEdit, mLockDistanceButton,
nullptr, mRepeatingLockDistanceButton ) );
58 mXConstraint.reset(
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
59 mYConstraint.reset(
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
60 mZConstraint.reset(
new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
61 mMConstraint.reset(
new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
64 mMapCanvas->installEventFilter(
this );
65 mAngleLineEdit->installEventFilter(
this );
66 mDistanceLineEdit->installEventFilter(
this );
67 mXLineEdit->installEventFilter(
this );
68 mYLineEdit->installEventFilter(
this );
69 mZLineEdit->installEventFilter(
this );
70 mMLineEdit->installEventFilter(
this );
73 connect( mEnableAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::activateCad );
74 connect( mConstructionModeAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
75 connect( mParallelAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::additionalConstraintClicked );
76 connect( mPerpendicularAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::additionalConstraintClicked );
77 connect( mLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
78 connect( mLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
79 connect( mLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
80 connect( mLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
81 connect( mLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
82 connect( mLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
83 connect( mRelativeAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
84 connect( mRelativeXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
85 connect( mRelativeYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
86 connect( mRelativeZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
87 connect( mRelativeMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
88 connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
89 connect( mRepeatingLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
90 connect( mRepeatingLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
91 connect( mRepeatingLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
92 connect( mRepeatingLockZButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
93 connect( mRepeatingLockMButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
94 connect( mAngleLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
95 connect( mDistanceLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
96 connect( mXLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
97 connect( mYLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
98 connect( mZLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
99 connect( mMLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
100 connect( mAngleLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
101 connect( mDistanceLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
102 connect( mXLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
103 connect( mYLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
104 connect( mZLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
105 connect( mMLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
121 QMenu *menu =
new QMenu(
this );
123 QActionGroup *angleButtonGroup =
new QActionGroup( menu );
124 mCommonAngleActions = QMap<QAction *, double>();
125 QList< QPair< double, QString > > commonAngles;
127 const QList<double> anglesDouble( { 0.0, 5.0, 10.0, 15.0, 18.0, 22.5, 30.0, 45.0, 90.0} );
128 for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
131 menuText = tr(
"Do Not Snap to Common Angles" );
133 menuText = QString( tr(
"%1, %2, %3, %4°…" ) ).arg( *it, 0,
'f', 1 ).arg( *it * 2, 0,
'f', 1 ).arg( *it * 3, 0,
'f', 1 ).arg( *it * 4, 0,
'f', 1 );
134 commonAngles << QPair<double, QString>( *it, menuText );
136 for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
138 QAction *action =
new QAction( it->second, menu );
139 action->setCheckable(
true );
140 action->setChecked( it->first == mCommonAngleConstraint );
141 menu->addAction( action );
142 angleButtonGroup->addAction( action );
143 mCommonAngleActions.insert( action, it->first );
146 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
147 mSettingsAction->setMenu( menu );
148 mSettingsAction->setCheckable(
true );
149 mSettingsAction->setToolTip( tr(
"Snap to common angles" ) );
150 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
151 connect( menu, &QMenu::triggered,
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
154 mConstructionModeAction->setToolTip(
"<b>" + tr(
"Construction mode" ) +
"</b><br>(" + tr(
"press c to toggle on/off" ) +
")" );
155 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
156 mLockDistanceButton->setToolTip(
"<b>" + tr(
"Lock distance" ) +
"</b><br>(" + tr(
"press Ctrl + d for quick access" ) +
")" );
157 mRepeatingLockDistanceButton->setToolTip(
"<b>" + tr(
"Continuously lock distance" ) +
"</b>" );
159 mRelativeAngleButton->setToolTip(
"<b>" + tr(
"Toggles relative angle to previous segment" ) +
"</b><br>(" + tr(
"press Shift + a for quick access" ) +
")" );
160 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
161 mLockAngleButton->setToolTip(
"<b>" + tr(
"Lock angle" ) +
"</b><br>(" + tr(
"press Ctrl + a for quick access" ) +
")" );
162 mRepeatingLockAngleButton->setToolTip(
"<b>" + tr(
"Continuously lock angle" ) +
"</b>" );
164 mRelativeXButton->setToolTip(
"<b>" + tr(
"Toggles relative x to previous node" ) +
"</b><br>(" + tr(
"press Shift + x for quick access" ) +
")" );
165 mXLineEdit->setToolTip(
"<b>" + tr(
"X coordinate" ) +
"</b><br>(" + tr(
"press x for quick access" ) +
")" );
166 mLockXButton->setToolTip(
"<b>" + tr(
"Lock x coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + x for quick access" ) +
")" );
167 mRepeatingLockXButton->setToolTip(
"<b>" + tr(
"Continuously lock x coordinate" ) +
"</b>" );
169 mRelativeYButton->setToolTip(
"<b>" + tr(
"Toggles relative y to previous node" ) +
"</b><br>(" + tr(
"press Shift + y for quick access" ) +
")" );
170 mYLineEdit->setToolTip(
"<b>" + tr(
"Y coordinate" ) +
"</b><br>(" + tr(
"press y for quick access" ) +
")" );
171 mLockYButton->setToolTip(
"<b>" + tr(
"Lock y coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + y for quick access" ) +
")" );
172 mRepeatingLockYButton->setToolTip(
"<b>" + tr(
"Continuously lock y coordinate" ) +
"</b>" );
174 mRelativeZButton->setToolTip(
"<b>" + tr(
"Toggles relative z to previous node" ) +
"</b><br>(" + tr(
"press Shift + z for quick access" ) +
")" );
175 mZLineEdit->setToolTip(
"<b>" + tr(
"Z coordinate" ) +
"</b><br>(" + tr(
"press z for quick access" ) +
")" );
176 mLockZButton->setToolTip(
"<b>" + tr(
"Lock z coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + z for quick access" ) +
")" );
177 mRepeatingLockZButton->setToolTip(
"<b>" + tr(
"Continuously lock z coordinate" ) +
"</b>" );
179 mRelativeMButton->setToolTip(
"<b>" + tr(
"Toggles relative m to previous node" ) +
"</b><br>(" + tr(
"press Shift + m for quick access" ) +
")" );
180 mMLineEdit->setToolTip(
"<b>" + tr(
"M coordinate" ) +
"</b><br>(" + tr(
"press m for quick access" ) +
")" );
181 mLockMButton->setToolTip(
"<b>" + tr(
"Lock m coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + m for quick access" ) +
")" );
182 mRepeatingLockMButton->setToolTip(
"<b>" + tr(
"Continuously lock m coordinate" ) +
"</b>" );
195 mToggleFloaterAction->setChecked( mFloater->
active() );
197 updateCapacity(
true );
205 mXLineEdit->setText( value );
206 if ( mode == WidgetSetMode::ReturnPressed )
208 mXLineEdit->returnPressed();
210 else if ( mode == WidgetSetMode::FocusOut )
212 QEvent *e =
new QEvent( QEvent::FocusOut );
213 QCoreApplication::postEvent( mXLineEdit, e );
215 else if ( mode == WidgetSetMode::TextEdited )
217 mXLineEdit->textEdited( value );
222 mYLineEdit->setText( value );
223 if ( mode == WidgetSetMode::ReturnPressed )
225 mYLineEdit->returnPressed();
227 else if ( mode == WidgetSetMode::FocusOut )
229 QEvent *e =
new QEvent( QEvent::FocusOut );
230 QCoreApplication::postEvent( mYLineEdit, e );
232 else if ( mode == WidgetSetMode::TextEdited )
234 mYLineEdit->textEdited( value );
239 mZLineEdit->setText( value );
240 if ( mode == WidgetSetMode::ReturnPressed )
242 mZLineEdit->returnPressed();
244 else if ( mode == WidgetSetMode::FocusOut )
246 QEvent *e =
new QEvent( QEvent::FocusOut );
247 QCoreApplication::postEvent( mZLineEdit, e );
249 else if ( mode == WidgetSetMode::TextEdited )
251 mZLineEdit->textEdited( value );
256 mMLineEdit->setText( value );
257 if ( mode == WidgetSetMode::ReturnPressed )
259 mMLineEdit->returnPressed();
261 else if ( mode == WidgetSetMode::FocusOut )
263 QEvent *e =
new QEvent( QEvent::FocusOut );
264 QCoreApplication::postEvent( mMLineEdit, e );
266 else if ( mode == WidgetSetMode::TextEdited )
268 mMLineEdit->textEdited( value );
273 mAngleLineEdit->setText( value );
274 if ( mode == WidgetSetMode::ReturnPressed )
276 mAngleLineEdit->returnPressed();
278 else if ( mode == WidgetSetMode::FocusOut )
280 mAngleLineEdit->textEdited( value );
285 mDistanceLineEdit->setText( value );
286 if ( mode == WidgetSetMode::ReturnPressed )
288 mDistanceLineEdit->returnPressed();
290 else if ( mode == WidgetSetMode::FocusOut )
292 QEvent *e =
new QEvent( QEvent::FocusOut );
293 QCoreApplication::postEvent( mDistanceLineEdit, e );
295 else if ( mode == WidgetSetMode::TextEdited )
297 mDistanceLineEdit->textEdited( value );
302 void QgsAdvancedDigitizingDockWidget::setCadEnabled(
bool enabled )
304 mCadEnabled = enabled;
305 mEnableAction->setChecked( enabled );
306 mConstructionModeAction->setEnabled( enabled );
307 mParallelAction->setEnabled( enabled );
308 mPerpendicularAction->setEnabled( enabled );
309 mSettingsAction->setEnabled( enabled );
310 mInputWidgets->setEnabled( enabled );
311 mToggleFloaterAction->setEnabled( enabled );
314 setConstructionMode(
false );
323 bool enableZ =
false;
324 bool enableM =
false;
328 switch ( layer->type() )
341 QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
362 mRelativeZButton->setEnabled(
enable );
363 mZLabel->setEnabled(
enable );
364 mZLineEdit->setEnabled(
enable );
365 if ( mZLineEdit->isEnabled() )
366 mZLineEdit->setText( QLocale().toString(
QgsMapToolEdit( mMapCanvas ).defaultZValue(),
'f', 6 ) );
369 mLockZButton->setEnabled(
enable );
375 mRelativeMButton->setEnabled(
enable );
376 mMLabel->setEnabled(
enable );
377 mMLineEdit->setEnabled(
enable );
378 if ( mMLineEdit->isEnabled() )
379 mMLineEdit->setText( QLocale().toString(
QgsMapToolEdit( mMapCanvas ).defaultMValue(),
'f', 6 ) );
382 mLockMButton->setEnabled(
enable );
386 void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
388 enabled &= mCurrentMapToolSupportsCad;
390 mSessionActive = enabled;
392 if ( enabled && !isVisible() )
397 setCadEnabled( enabled );
400 void QgsAdvancedDigitizingDockWidget::additionalConstraintClicked(
bool activated )
406 else if ( sender() == mParallelAction )
410 else if ( sender() == mPerpendicularAction )
416 void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
418 if ( sender() == mRelativeAngleButton )
420 mAngleConstraint->setRelative( activate );
423 else if ( sender() == mRelativeXButton )
425 mXConstraint->setRelative( activate );
428 else if ( sender() == mRelativeYButton )
430 mYConstraint->setRelative( activate );
433 else if ( sender() == mRelativeZButton )
435 mZConstraint->setRelative( activate );
438 else if ( sender() == mRelativeMButton )
440 mMConstraint->setRelative( activate );
445 void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock(
bool activate )
447 if ( sender() == mRepeatingLockDistanceButton )
449 mDistanceConstraint->setRepeatingLock( activate );
451 else if ( sender() == mRepeatingLockAngleButton )
453 mAngleConstraint->setRepeatingLock( activate );
455 else if ( sender() == mRepeatingLockXButton )
457 mXConstraint->setRepeatingLock( activate );
459 else if ( sender() == mRepeatingLockYButton )
461 mYConstraint->setRepeatingLock( activate );
463 else if ( sender() == mRepeatingLockZButton )
465 mZConstraint->setRepeatingLock( activate );
467 else if ( sender() == mRepeatingLockMButton )
469 mMConstraint->setRepeatingLock( activate );
473 void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
475 mConstructionMode = enabled;
476 mConstructionModeAction->setChecked( enabled );
479 void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
482 const QMap<QAction *, double>::const_iterator ica = mCommonAngleActions.constFind( action );
483 if ( ica != mCommonAngleActions.constEnd() )
485 ica.key()->setChecked(
true );
486 mCommonAngleConstraint = ica.value();
488 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
493 QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
497 return advancedTool->layer();
511 if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
516 if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
521 if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
526 if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
531 if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
536 if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
542 if ( !mCadPointList.empty() )
544 if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
546 mXConstraint->setValue( mCadPointList.constLast().x(),
true );
548 if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
550 mYConstraint->setValue( mCadPointList.constLast().y(),
true );
552 if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
554 mZConstraint->setValue( mCadPointList.constLast().z(),
true );
556 if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
558 mMConstraint->setValue( mCadPointList.constLast().m(),
true );
565 void QgsAdvancedDigitizingDockWidget::emit pointChanged()
568 QPoint globalPos = mMapCanvas->cursor().pos();
569 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
570 QMouseEvent *e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
571 mCurrentMapTool->canvasMoveEvent( e );
577 CadConstraint *constraint =
nullptr;
578 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
580 constraint = mAngleConstraint.get();
582 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
584 constraint = mDistanceConstraint.get();
586 else if ( obj == mXLineEdit || obj == mLockXButton )
588 constraint = mXConstraint.get();
590 else if ( obj == mYLineEdit || obj == mLockYButton )
592 constraint = mYConstraint.get();
594 else if ( obj == mZLineEdit || obj == mLockZButton )
596 constraint = mZConstraint.get();
598 else if ( obj == mMLineEdit || obj == mLockMButton )
600 constraint = mMConstraint.get();
605 double QgsAdvancedDigitizingDockWidget::parseUserInput(
const QString &inputValue,
bool &ok )
const
617 const QVariant result = expr.evaluate();
618 if ( expr.hasEvalError() )
621 value = result.toDouble( &ok );
626 void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
628 if ( !constraint || textValue.isEmpty() )
637 const double value = parseUserInput( textValue, ok );
641 constraint->setValue( value, convertExpression );
646 void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
648 CadConstraint *constraint = objectToConstraint( sender() );
656 const QString textValue = constraint->lineEdit()->text();
657 if ( !textValue.isEmpty() )
660 const double value = parseUserInput( textValue, ok );
663 constraint->setValue( value );
677 if ( constraint == mXConstraint.get() )
681 else if ( constraint == mYConstraint.get() )
685 else if ( constraint == mZConstraint.get() )
689 else if ( constraint == mMConstraint.get() )
693 else if ( constraint == mDistanceConstraint.get() )
697 else if ( constraint == mAngleConstraint.get() )
705 if ( constraint == mAngleConstraint.get() )
715 void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
717 CadConstraint *constraint = objectToConstraint( sender() );
723 updateConstraintValue( constraint, textValue,
false );
726 void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
728 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
732 CadConstraint *constraint = objectToConstraint( lineEdit );
738 updateConstraintValue( constraint, lineEdit->text(),
true );
741 void QgsAdvancedDigitizingDockWidget::lockAdditionalConstraint( AdditionalConstraint constraint )
743 mAdditionalConstraint = constraint;
748 void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
750 CadCapacities newCapacities = CadCapacities();
756 if ( mCadPointList.count() > 1 )
762 if ( mCadPointList.count() > 2 )
767 if ( !updateUIwithoutChange && newCapacities == mCapacities )
777 const bool distance = mCadEnabled && newCapacities.testFlag(
Distance );
778 const bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
779 const bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
780 const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag(
RelativeCoordinates );
782 mPerpendicularAction->setEnabled( distance && absoluteAngle && snappingEnabled );
783 mParallelAction->setEnabled( distance && absoluteAngle && snappingEnabled );
786 if ( !snappingEnabled )
788 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode" ) );
789 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode" ) );
793 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
794 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
798 if ( !absoluteAngle )
804 mLockAngleButton->setEnabled( absoluteAngle );
805 mRelativeAngleButton->setEnabled( relativeAngle );
806 mAngleLineEdit->setEnabled( absoluteAngle );
808 if ( !absoluteAngle )
812 if ( !relativeAngle )
814 mAngleConstraint->setRelative(
false );
817 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
820 mAngleConstraint->setRelative(
true );
825 mLockDistanceButton->setEnabled( distance && relativeCoordinates );
826 mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
828 if ( !( distance && relativeCoordinates ) )
833 mRelativeXButton->setEnabled( relativeCoordinates );
834 mRelativeYButton->setEnabled( relativeCoordinates );
835 mRelativeZButton->setEnabled( relativeCoordinates );
836 mRelativeMButton->setEnabled( relativeCoordinates );
839 mCapacities = newCapacities;
849 constr.
value =
c->value();
858 context.
xConstraint = _constraint( mXConstraint.get() );
859 context.
yConstraint = _constraint( mYConstraint.get() );
860 context.
zConstraint = _constraint( mZConstraint.get() );
861 context.
mConstraint = _constraint( mMConstraint.get() );
872 const bool res = output.
valid;
874 mSnappedSegment.clear();
879 mSnappedSegment << edgePt0 << edgePt1;
896 mSnapIndicator->setMatch( output.
snapMatch );
897 mSnapIndicator->setVisible(
true );
901 mSnapIndicator->setVisible(
false );
930 if ( mLockZButton->isChecked() )
932 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
934 if ( mLockMButton->isChecked() )
936 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
940 updateCurrentPoint( point );
942 updateUnlockedConstraintValues( point );
950 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
957 void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPoint &point )
959 bool previousPointExist, penulPointExist;
964 if ( !mAngleConstraint->isLocked() && previousPointExist )
967 if ( penulPointExist && mAngleConstraint->relative() )
970 angle = std::atan2( previousPt.
y() - penultimatePt.
y(),
971 previousPt.
x() - penultimatePt.
x() );
973 angle = ( std::atan2( point.
y() - previousPt.
y(),
974 point.
x() - previousPt.
x()
975 ) -
angle ) * 180 / M_PI;
978 mAngleConstraint->setValue(
angle );
981 if ( !mDistanceConstraint->isLocked() && previousPointExist )
983 mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
986 if ( !mXConstraint->isLocked() )
988 if ( previousPointExist && mXConstraint->relative() )
990 mXConstraint->setValue( point.
x() - previousPt.
x() );
994 mXConstraint->setValue( point.
x() );
998 if ( !mYConstraint->isLocked() )
1000 if ( previousPointExist && mYConstraint->relative() )
1002 mYConstraint->setValue( point.
y() - previousPt.
y() );
1006 mYConstraint->setValue( point.
y() );
1010 if ( !mZConstraint->isLocked() )
1012 if ( previousPointExist && mZConstraint->relative() )
1014 mZConstraint->setValue( point.
z() - previousPt.
z() );
1018 mZConstraint->setValue( point.
z() );
1022 if ( !mMConstraint->isLocked() )
1024 if ( previousPointExist && mMConstraint->relative() )
1026 mMConstraint->setValue( point.
m() - previousPt.
m() );
1030 mMConstraint->setValue( point.
m() );
1036 QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
1049 snappingUtils->
setConfig( localConfig );
1051 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
1053 snappingUtils->
setConfig( canvasConfig );
1063 *snapped =
segment.count() == 2;
1076 bool previousPointExist, penulPointExist, snappedSegmentExist;
1079 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
1081 if ( !previousPointExist || !snappedSegmentExist )
1086 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1088 if ( mAngleConstraint->relative() && penulPointExist )
1090 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
1098 angle *= 180 / M_PI;
1100 mAngleConstraint->setValue(
angle );
1101 mAngleConstraint->setLockMode( lockMode );
1119 case Qt::Key_Backspace:
1120 case Qt::Key_Delete:
1126 case Qt::Key_Escape:
1156 case Qt::Key_Backspace:
1157 case Qt::Key_Delete:
1163 case Qt::Key_Escape:
1170 filterKeyPress( e );
1179 const auto constPoints = points;
1186 bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1190 return QgsDockWidget::eventFilter( obj, event );
1198 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1200 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
1202 return filterKeyPress( keyEvent );
1205 return QgsDockWidget::eventFilter( obj, event );
1208 bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1214 const QEvent::Type type = e->type();
1220 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1222 mXConstraint->toggleLocked();
1227 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1231 mXConstraint->toggleRelative();
1238 else if ( type == QEvent::KeyPress )
1240 mXLineEdit->setFocus();
1241 mXLineEdit->selectAll();
1250 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1252 mYConstraint->toggleLocked();
1257 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1261 mYConstraint->toggleRelative();
1268 else if ( type == QEvent::KeyPress )
1270 mYLineEdit->setFocus();
1271 mYLineEdit->selectAll();
1280 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1282 mZConstraint->toggleLocked();
1287 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1291 mZConstraint->toggleRelative();
1298 else if ( type == QEvent::KeyPress )
1300 mZLineEdit->setFocus();
1301 mZLineEdit->selectAll();
1310 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1312 mMConstraint->toggleLocked();
1317 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1321 mMConstraint->toggleRelative();
1328 else if ( type == QEvent::KeyPress )
1330 mMLineEdit->setFocus();
1331 mMLineEdit->selectAll();
1340 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1344 mAngleConstraint->toggleLocked();
1350 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1354 mAngleConstraint->toggleRelative();
1361 else if ( type == QEvent::KeyPress )
1363 mAngleLineEdit->setFocus();
1364 mAngleLineEdit->selectAll();
1373 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1377 mDistanceConstraint->toggleLocked();
1384 else if ( type == QEvent::KeyPress )
1386 mDistanceLineEdit->setFocus();
1387 mDistanceLineEdit->selectAll();
1395 if ( type == QEvent::KeyPress )
1397 setConstructionMode( !mConstructionMode );
1404 if ( type == QEvent::KeyPress )
1406 const bool parallel = mParallelAction->isChecked();
1407 const bool perpendicular = mPerpendicularAction->isChecked();
1409 if ( !parallel && !perpendicular )
1413 else if ( perpendicular )
1433 return e->isAccepted();
1441 mAngleLineEdit->setEnabled(
false );
1442 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1444 mDistanceLineEdit->setEnabled(
false );
1445 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1447 mLabelX->setText( tr(
"Long" ) );
1448 mLabelY->setText( tr(
"Lat" ) );
1450 mXConstraint->setPrecision( 8 );
1451 mYConstraint->setPrecision( 8 );
1455 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
1456 mAngleLineEdit->setToolTip( QString() );
1458 mDistanceLineEdit->setEnabled(
true );
1459 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
1461 mLabelX->setText( tr(
"x" ) );
1462 mLabelY->setText( tr(
"y" ) );
1464 mXConstraint->setPrecision( 6 );
1465 mYConstraint->setPrecision( 6 );
1468 mEnableAction->setEnabled(
true );
1469 mErrorLabel->hide();
1472 mCurrentMapToolSupportsCad =
true;
1474 if ( mSessionActive && !isVisible() )
1478 setCadEnabled( mSessionActive );
1485 mEnableAction->setEnabled(
false );
1486 mErrorLabel->setText( tr(
"CAD tools are not enabled for the current map tool" ) );
1487 mErrorLabel->show();
1490 mCurrentMapToolSupportsCad =
false;
1492 setCadEnabled(
false );
1497 mCadPaintItem->update();
1502 QgsPoint pt = pointXYToPoint( point );
1505 mCadPointList << pt;
1509 mCadPointList.insert( 0, pt );
1522 mCadPointList.removeAt( i );
1529 mCadPointList.clear();
1530 mSnappedSegment.clear();
1536 void QgsAdvancedDigitizingDockWidget::updateCurrentPoint(
const QgsPoint &point )
1540 mCadPointList << point;
1545 mCadPointList[0] = point;
1554 mLockerButton->setChecked( mode ==
HardLock );
1555 if ( mRepeatingLockButton )
1559 mRepeatingLockButton->setEnabled(
true );
1563 mRepeatingLockButton->setChecked(
false );
1564 mRepeatingLockButton->setEnabled(
false );
1577 mRepeatingLock = repeating;
1578 if ( mRepeatingLockButton )
1579 mRepeatingLockButton->setChecked( repeating );
1584 mRelative = relative;
1585 if ( mRelativeButton )
1587 mRelativeButton->setChecked( relative );
1594 if ( updateWidget && mLineEdit->isEnabled() )
1595 mLineEdit->setText( QLocale().toString( value,
'f', mPrecision ) );
1600 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
1605 setRelative( !mRelative );
1611 if ( mLineEdit->isEnabled() )
1612 mLineEdit->setText( QLocale().toString( mValue,
'f', mPrecision ) );
1620 return mCadPointList.value( 0 );
1629 QgsPoint res = mCadPointList.value( 0 );
1631 res.
setX( layerCoordinates.
x() );
1632 res.
setY( layerCoordinates.
y() );
1643 return mCadPointList.value( 1 );
1653 return mCadPointList.value( 2 );
1658 QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
1665 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
1670 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
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 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 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).
QgsCadUtils::AlignMapPointConstraint mConstraint
Constraint for M coordinate.
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
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 angleConstraint
Constraint for angle.
Structure returned from alignMapPoint() method.
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.
Class for parsing and evaluation of expressions (formerly called "search strings").
A event filter for watching for focus events on a parent object.
void focusOut()
Emitted when parent object loses focus.
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 class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
void setX(double x) SIP_HOLDGIL
Sets the point's x-coordinate.
void setY(double y) SIP_HOLDGIL
Sets the point's y-coordinate.
void setZ(double z) SIP_HOLDGIL
Sets the point's z-coordinate.
double distanceSquared(double x, double y) const SIP_HOLDGIL
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
void setM(double m) SIP_HOLDGIL
Sets the point's m-value.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsSnappingConfig snappingConfig
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.
@ AllLayers
On all vector layers.
@ SegmentFlag
On segments.
void setTypeFlag(QgsSnappingConfig::SnappingTypeFlag type)
define the type of snapping
void setMode(SnappingMode mode)
define the mode of snapping
bool enabled() const
Returns if snapping is enabled.
This class has all the configuration of snapping and can return answers to snapping queries.
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.
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
static bool hasM(Type type) SIP_HOLDGIL
Tests whether a WKB type contains m values.
Type
The WKB type describes the number of dimensions a geometry has.
static bool hasZ(Type type) SIP_HOLDGIL
Tests whether a WKB type contains the z-dimension.
@ PointCloudLayer
Point cloud layer. Added in QGIS 3.18.
@ MeshLayer
Mesh layer. Added in QGIS 3.2.
@ VectorLayer
Vector layer.
@ RasterLayer
Raster layer.
@ GroupLayer
Composite group layer. Added in QGIS 3.24.
@ VectorTileLayer
Vector tile layer. Added in QGIS 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ PluginLayer
Plugin based layer.
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...
QLineF segment(int index, QRectF rect, double radius)
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.