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 );
361 mRelativeZButton->setEnabled(
enable );
362 mZLabel->setEnabled(
enable );
363 mZLineEdit->setEnabled(
enable );
364 if ( mZLineEdit->isEnabled() )
365 mZLineEdit->setText( QLocale().toString(
QgsMapToolEdit( mMapCanvas ).defaultZValue(),
'f', 6 ) );
368 mLockZButton->setEnabled(
enable );
374 mRelativeMButton->setEnabled(
enable );
375 mMLabel->setEnabled(
enable );
376 mMLineEdit->setEnabled(
enable );
377 if ( mMLineEdit->isEnabled() )
378 mMLineEdit->setText( QLocale().toString(
QgsMapToolEdit( mMapCanvas ).defaultMValue(),
'f', 6 ) );
381 mLockMButton->setEnabled(
enable );
385 void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
387 enabled &= mCurrentMapToolSupportsCad;
389 mSessionActive = enabled;
391 if ( enabled && !isVisible() )
396 setCadEnabled( enabled );
399 void QgsAdvancedDigitizingDockWidget::additionalConstraintClicked(
bool activated )
405 else if ( sender() == mParallelAction )
409 else if ( sender() == mPerpendicularAction )
415 void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
417 if ( sender() == mRelativeAngleButton )
419 mAngleConstraint->setRelative( activate );
422 else if ( sender() == mRelativeXButton )
424 mXConstraint->setRelative( activate );
427 else if ( sender() == mRelativeYButton )
429 mYConstraint->setRelative( activate );
432 else if ( sender() == mRelativeZButton )
434 mZConstraint->setRelative( activate );
437 else if ( sender() == mRelativeMButton )
439 mMConstraint->setRelative( activate );
444 void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock(
bool activate )
446 if ( sender() == mRepeatingLockDistanceButton )
448 mDistanceConstraint->setRepeatingLock( activate );
450 else if ( sender() == mRepeatingLockAngleButton )
452 mAngleConstraint->setRepeatingLock( activate );
454 else if ( sender() == mRepeatingLockXButton )
456 mXConstraint->setRepeatingLock( activate );
458 else if ( sender() == mRepeatingLockYButton )
460 mYConstraint->setRepeatingLock( activate );
462 else if ( sender() == mRepeatingLockZButton )
464 mZConstraint->setRepeatingLock( activate );
466 else if ( sender() == mRepeatingLockMButton )
468 mMConstraint->setRepeatingLock( activate );
472 void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
474 mConstructionMode = enabled;
475 mConstructionModeAction->setChecked( enabled );
478 void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
481 const QMap<QAction *, double>::const_iterator ica = mCommonAngleActions.constFind( action );
482 if ( ica != mCommonAngleActions.constEnd() )
484 ica.key()->setChecked(
true );
485 mCommonAngleConstraint = ica.value();
487 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
492 QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
496 return advancedTool->layer();
510 if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
515 if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
520 if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
525 if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
530 if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
535 if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
541 if ( !mCadPointList.empty() )
543 if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
545 mXConstraint->setValue( mCadPointList.constLast().x(),
true );
547 if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
549 mYConstraint->setValue( mCadPointList.constLast().y(),
true );
551 if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
553 mZConstraint->setValue( mCadPointList.constLast().z(),
true );
555 if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
557 mMConstraint->setValue( mCadPointList.constLast().m(),
true );
564 void QgsAdvancedDigitizingDockWidget::emit pointChanged()
567 QPoint globalPos = mMapCanvas->cursor().pos();
568 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
569 QMouseEvent *e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
570 mCurrentMapTool->canvasMoveEvent( e );
576 CadConstraint *constraint =
nullptr;
577 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
579 constraint = mAngleConstraint.get();
581 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
583 constraint = mDistanceConstraint.get();
585 else if ( obj == mXLineEdit || obj == mLockXButton )
587 constraint = mXConstraint.get();
589 else if ( obj == mYLineEdit || obj == mLockYButton )
591 constraint = mYConstraint.get();
593 else if ( obj == mZLineEdit || obj == mLockZButton )
595 constraint = mZConstraint.get();
597 else if ( obj == mMLineEdit || obj == mLockMButton )
599 constraint = mMConstraint.get();
604 double QgsAdvancedDigitizingDockWidget::parseUserInput(
const QString &inputValue,
bool &ok )
const
616 const QVariant result = expr.evaluate();
617 if ( expr.hasEvalError() )
620 value = result.toDouble( &ok );
625 void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
627 if ( !constraint || textValue.isEmpty() )
636 const double value = parseUserInput( textValue, ok );
640 constraint->setValue( value, convertExpression );
645 void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
647 CadConstraint *constraint = objectToConstraint( sender() );
655 const QString textValue = constraint->lineEdit()->text();
656 if ( !textValue.isEmpty() )
659 const double value = parseUserInput( textValue, ok );
662 constraint->setValue( value );
676 if ( constraint == mXConstraint.get() )
680 else if ( constraint == mYConstraint.get() )
684 else if ( constraint == mZConstraint.get() )
688 else if ( constraint == mMConstraint.get() )
692 else if ( constraint == mDistanceConstraint.get() )
696 else if ( constraint == mAngleConstraint.get() )
704 if ( constraint == mAngleConstraint.get() )
714 void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
716 CadConstraint *constraint = objectToConstraint( sender() );
722 updateConstraintValue( constraint, textValue,
false );
725 void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
727 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
731 CadConstraint *constraint = objectToConstraint( lineEdit );
737 updateConstraintValue( constraint, lineEdit->text(),
true );
740 void QgsAdvancedDigitizingDockWidget::lockAdditionalConstraint( AdditionalConstraint constraint )
742 mAdditionalConstraint = constraint;
747 void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
749 CadCapacities newCapacities = CadCapacities();
755 if ( mCadPointList.count() > 1 )
761 if ( mCadPointList.count() > 2 )
766 if ( !updateUIwithoutChange && newCapacities == mCapacities )
776 const bool distance = mCadEnabled && newCapacities.testFlag(
Distance );
777 const bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
778 const bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
779 const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag(
RelativeCoordinates );
781 mPerpendicularAction->setEnabled( distance && absoluteAngle && snappingEnabled );
782 mParallelAction->setEnabled( distance && absoluteAngle && snappingEnabled );
785 if ( !snappingEnabled )
787 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode" ) );
788 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode" ) );
792 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
793 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
797 if ( !absoluteAngle )
803 mLockAngleButton->setEnabled( absoluteAngle );
804 mRelativeAngleButton->setEnabled( relativeAngle );
805 mAngleLineEdit->setEnabled( absoluteAngle );
807 if ( !absoluteAngle )
811 if ( !relativeAngle )
813 mAngleConstraint->setRelative(
false );
816 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
819 mAngleConstraint->setRelative(
true );
824 mLockDistanceButton->setEnabled( distance && relativeCoordinates );
825 mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
827 if ( !( distance && relativeCoordinates ) )
832 mRelativeXButton->setEnabled( relativeCoordinates );
833 mRelativeYButton->setEnabled( relativeCoordinates );
834 mRelativeZButton->setEnabled( relativeCoordinates );
835 mRelativeMButton->setEnabled( relativeCoordinates );
838 mCapacities = newCapacities;
847 constr.
value =
c->value();
856 context.
xConstraint = _constraint( mXConstraint.get() );
857 context.
yConstraint = _constraint( mYConstraint.get() );
858 context.
zConstraint = _constraint( mZConstraint.get() );
859 context.
mConstraint = _constraint( mMConstraint.get() );
870 const bool res = output.
valid;
872 mSnappedSegment.clear();
877 mSnappedSegment << edgePt0 << edgePt1;
894 mSnapIndicator->setMatch( output.
snapMatch );
895 mSnapIndicator->setVisible(
true );
899 mSnapIndicator->setVisible(
false );
928 if ( mLockZButton->isChecked() )
930 point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
932 if ( mLockMButton->isChecked() )
934 point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
938 updateCurrentPoint( point );
940 updateUnlockedConstraintValues( point );
948 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
955 void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPoint &point )
957 bool previousPointExist, penulPointExist;
962 if ( !mAngleConstraint->isLocked() && previousPointExist )
965 if ( penulPointExist && mAngleConstraint->relative() )
968 angle = std::atan2( previousPt.
y() - penultimatePt.
y(),
969 previousPt.
x() - penultimatePt.
x() );
971 angle = ( std::atan2( point.
y() - previousPt.
y(),
972 point.
x() - previousPt.
x()
973 ) -
angle ) * 180 / M_PI;
976 mAngleConstraint->setValue(
angle );
979 if ( !mDistanceConstraint->isLocked() && previousPointExist )
981 mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
984 if ( !mXConstraint->isLocked() )
986 if ( previousPointExist && mXConstraint->relative() )
988 mXConstraint->setValue( point.
x() - previousPt.
x() );
992 mXConstraint->setValue( point.
x() );
996 if ( !mYConstraint->isLocked() )
998 if ( previousPointExist && mYConstraint->relative() )
1000 mYConstraint->setValue( point.
y() - previousPt.
y() );
1004 mYConstraint->setValue( point.
y() );
1008 if ( !mZConstraint->isLocked() )
1010 if ( previousPointExist && mZConstraint->relative() )
1012 mZConstraint->setValue( point.
z() - previousPt.
z() );
1016 mZConstraint->setValue( point.
z() );
1020 if ( !mMConstraint->isLocked() )
1022 if ( previousPointExist && mMConstraint->relative() )
1024 mMConstraint->setValue( point.
m() - previousPt.
m() );
1028 mMConstraint->setValue( point.
m() );
1034 QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
1047 snappingUtils->
setConfig( localConfig );
1049 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
1051 snappingUtils->
setConfig( canvasConfig );
1061 *snapped =
segment.count() == 2;
1074 bool previousPointExist, penulPointExist, snappedSegmentExist;
1077 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
1079 if ( !previousPointExist || !snappedSegmentExist )
1084 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
1086 if ( mAngleConstraint->relative() && penulPointExist )
1088 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
1096 angle *= 180 / M_PI;
1098 mAngleConstraint->setValue(
angle );
1099 mAngleConstraint->setLockMode( lockMode );
1117 case Qt::Key_Backspace:
1118 case Qt::Key_Delete:
1124 case Qt::Key_Escape:
1154 case Qt::Key_Backspace:
1155 case Qt::Key_Delete:
1161 case Qt::Key_Escape:
1168 filterKeyPress( e );
1177 const auto constPoints = points;
1184 bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
1188 return QgsDockWidget::eventFilter( obj, event );
1196 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
1198 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
1200 return filterKeyPress( keyEvent );
1203 return QgsDockWidget::eventFilter( obj, event );
1206 bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
1212 const QEvent::Type type = e->type();
1218 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1220 mXConstraint->toggleLocked();
1225 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1229 mXConstraint->toggleRelative();
1236 else if ( type == QEvent::KeyPress )
1238 mXLineEdit->setFocus();
1239 mXLineEdit->selectAll();
1248 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1250 mYConstraint->toggleLocked();
1255 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1259 mYConstraint->toggleRelative();
1266 else if ( type == QEvent::KeyPress )
1268 mYLineEdit->setFocus();
1269 mYLineEdit->selectAll();
1278 if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
1280 mZConstraint->toggleLocked();
1285 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1289 mZConstraint->toggleRelative();
1296 else if ( type == QEvent::KeyPress )
1298 mZLineEdit->setFocus();
1299 mZLineEdit->selectAll();
1308 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1310 mMConstraint->toggleLocked();
1315 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1319 mMConstraint->toggleRelative();
1326 else if ( type == QEvent::KeyPress )
1328 mMLineEdit->setFocus();
1329 mMLineEdit->selectAll();
1338 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1342 mAngleConstraint->toggleLocked();
1348 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1352 mAngleConstraint->toggleRelative();
1359 else if ( type == QEvent::KeyPress )
1361 mAngleLineEdit->setFocus();
1362 mAngleLineEdit->selectAll();
1371 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1375 mDistanceConstraint->toggleLocked();
1382 else if ( type == QEvent::KeyPress )
1384 mDistanceLineEdit->setFocus();
1385 mDistanceLineEdit->selectAll();
1393 if ( type == QEvent::KeyPress )
1395 setConstructionMode( !mConstructionMode );
1402 if ( type == QEvent::KeyPress )
1404 const bool parallel = mParallelAction->isChecked();
1405 const bool perpendicular = mPerpendicularAction->isChecked();
1407 if ( !parallel && !perpendicular )
1411 else if ( perpendicular )
1431 return e->isAccepted();
1439 mAngleLineEdit->setEnabled(
false );
1440 mAngleLineEdit->setToolTip( tr(
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1442 mDistanceLineEdit->setEnabled(
false );
1443 mDistanceLineEdit->setToolTip( tr(
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1445 mLabelX->setText( tr(
"Long" ) );
1446 mLabelY->setText( tr(
"Lat" ) );
1448 mXConstraint->setPrecision( 8 );
1449 mYConstraint->setPrecision( 8 );
1453 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
1454 mAngleLineEdit->setToolTip( QString() );
1456 mDistanceLineEdit->setEnabled(
true );
1457 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
1459 mLabelX->setText( tr(
"x" ) );
1460 mLabelY->setText( tr(
"y" ) );
1462 mXConstraint->setPrecision( 6 );
1463 mYConstraint->setPrecision( 6 );
1466 mEnableAction->setEnabled(
true );
1467 mErrorLabel->hide();
1470 mCurrentMapToolSupportsCad =
true;
1472 if ( mSessionActive && !isVisible() )
1476 setCadEnabled( mSessionActive );
1483 mEnableAction->setEnabled(
false );
1484 mErrorLabel->setText( tr(
"CAD tools are not enabled for the current map tool" ) );
1485 mErrorLabel->show();
1488 mCurrentMapToolSupportsCad =
false;
1490 setCadEnabled(
false );
1495 mCadPaintItem->update();
1500 QgsPoint pt = pointXYToPoint( point );
1503 mCadPointList << pt;
1507 mCadPointList.insert( 0, pt );
1520 mCadPointList.removeAt( i );
1527 mCadPointList.clear();
1528 mSnappedSegment.clear();
1534 void QgsAdvancedDigitizingDockWidget::updateCurrentPoint(
const QgsPoint &point )
1538 mCadPointList << point;
1543 mCadPointList[0] = point;
1552 mLockerButton->setChecked( mode ==
HardLock );
1553 if ( mRepeatingLockButton )
1557 mRepeatingLockButton->setEnabled(
true );
1561 mRepeatingLockButton->setChecked(
false );
1562 mRepeatingLockButton->setEnabled(
false );
1575 mRepeatingLock = repeating;
1576 if ( mRepeatingLockButton )
1577 mRepeatingLockButton->setChecked( repeating );
1582 mRelative = relative;
1583 if ( mRelativeButton )
1585 mRelativeButton->setChecked( relative );
1592 if ( updateWidget && mLineEdit->isEnabled() )
1593 mLineEdit->setText( QLocale().toString( value,
'f', mPrecision ) );
1598 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
1603 setRelative( !mRelative );
1609 if ( mLineEdit->isEnabled() )
1610 mLineEdit->setText( QLocale().toString( mValue,
'f', mPrecision ) );
1618 return mCadPointList.value( 0 );
1627 QgsPoint res = mCadPointList.value( 0 );
1629 res.
setX( layerCoordinates.
x() );
1630 res.
setY( layerCoordinates.
y() );
1641 return mCadPointList.value( 1 );
1651 return mCadPointList.value( 2 );
1656 QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint(
const QgsPointXY &point )
const
1663 return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
1668 return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
The QgsAdvancedDigitizingCanvasItem class draws the graphical elements of the CAD tools (.
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
Added in 3.18.
@ VectorTileLayer
Added in 3.14.
@ AnnotationLayer
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
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.