18 #include <QCoreApplication>
35 #include "qgssettings.h"
44 , mMapCanvas( canvas )
46 , mCommonAngleConstraint( QgsSettings().value( QStringLiteral(
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
52 mAngleConstraint.reset(
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
53 mDistanceConstraint.reset(
new CadConstraint( mDistanceLineEdit, mLockDistanceButton,
nullptr, mRepeatingLockDistanceButton ) );
54 mXConstraint.reset(
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
55 mYConstraint.reset(
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
58 mMapCanvas->installEventFilter(
this );
59 mAngleLineEdit->installEventFilter(
this );
60 mDistanceLineEdit->installEventFilter(
this );
61 mXLineEdit->installEventFilter(
this );
62 mYLineEdit->installEventFilter(
this );
65 connect( mEnableAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::activateCad );
66 connect( mConstructionModeAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
67 connect( mParallelAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::additionalConstraintClicked );
68 connect( mPerpendicularAction, &QAction::triggered,
this, &QgsAdvancedDigitizingDockWidget::additionalConstraintClicked );
69 connect( mLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
70 connect( mLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
71 connect( mLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
72 connect( mLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
73 connect( mRelativeAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
74 connect( mRelativeXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
75 connect( mRelativeYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
76 connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
77 connect( mRepeatingLockAngleButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
78 connect( mRepeatingLockXButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
79 connect( mRepeatingLockYButton, &QAbstractButton::clicked,
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
80 connect( mAngleLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
81 connect( mDistanceLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
82 connect( mXLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
83 connect( mYLineEdit, &QLineEdit::returnPressed,
this, [ = ]() { lockConstraint(); } );
84 connect( mAngleLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
85 connect( mDistanceLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
86 connect( mXLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
87 connect( mYLineEdit, &QLineEdit::textEdited,
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
99 QMenu *menu =
new QMenu(
this );
101 QActionGroup *angleButtonGroup =
new QActionGroup( menu );
102 mCommonAngleActions = QMap<QAction *, double>();
103 QList< QPair< double, QString > > commonAngles;
105 QList<double> anglesDouble( { 0.0, 5.0, 10.0, 15.0, 18.0, 22.5, 30.0, 45.0, 90.0} );
106 for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
109 menuText = tr(
"Do Not Snap to Common Angles" );
111 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 );
112 commonAngles << QPair<double, QString>( *it, menuText );
114 for ( QList< QPair<double, QString > >::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
116 QAction *action =
new QAction( it->second, menu );
117 action->setCheckable(
true );
118 action->setChecked( it->first == mCommonAngleConstraint );
119 menu->addAction( action );
120 angleButtonGroup->addAction( action );
121 mCommonAngleActions.insert( action, it->first );
124 qobject_cast< QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
125 mSettingsAction->setMenu( menu );
126 mSettingsAction->setCheckable(
true );
127 mSettingsAction->setToolTip( tr(
"Snap to common angles" ) );
128 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
129 connect( menu, &QMenu::triggered,
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
132 mConstructionModeAction->setToolTip(
"<b>" + tr(
"Construction mode" ) +
"</b><br>(" + tr(
"press c to toggle on/off" ) +
")" );
133 mDistanceLineEdit->setToolTip(
"<b>" + tr(
"Distance" ) +
"</b><br>(" + tr(
"press d for quick access" ) +
")" );
134 mLockDistanceButton->setToolTip(
"<b>" + tr(
"Lock distance" ) +
"</b><br>(" + tr(
"press Ctrl + d for quick access" ) +
")" );
135 mRepeatingLockDistanceButton->setToolTip(
"<b>" + tr(
"Continuously lock distance" ) +
"</b>" );
137 mRelativeAngleButton->setToolTip(
"<b>" + tr(
"Toggles relative angle to previous segment" ) +
"</b><br>(" + tr(
"press Shift + a for quick access" ) +
")" );
138 mAngleLineEdit->setToolTip(
"<b>" + tr(
"Angle" ) +
"</b><br>(" + tr(
"press a for quick access" ) +
")" );
139 mLockAngleButton->setToolTip(
"<b>" + tr(
"Lock angle" ) +
"</b><br>(" + tr(
"press Ctrl + a for quick access" ) +
")" );
140 mRepeatingLockAngleButton->setToolTip(
"<b>" + tr(
"Continuously lock angle" ) +
"</b>" );
142 mRelativeXButton->setToolTip(
"<b>" + tr(
"Toggles relative x to previous node" ) +
"</b><br>(" + tr(
"press Shift + x for quick access" ) +
")" );
143 mXLineEdit->setToolTip(
"<b>" + tr(
"X coordinate" ) +
"</b><br>(" + tr(
"press x for quick access" ) +
")" );
144 mLockXButton->setToolTip(
"<b>" + tr(
"Lock x coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + x for quick access" ) +
")" );
145 mRepeatingLockXButton->setToolTip(
"<b>" + tr(
"Continuously lock x coordinate" ) +
"</b>" );
147 mRelativeYButton->setToolTip(
"<b>" + tr(
"Toggles relative y to previous node" ) +
"</b><br>(" + tr(
"press Shift + y for quick access" ) +
")" );
148 mYLineEdit->setToolTip(
"<b>" + tr(
"Y coordinate" ) +
"</b><br>(" + tr(
"press y for quick access" ) +
")" );
149 mLockYButton->setToolTip(
"<b>" + tr(
"Lock y coordinate" ) +
"</b><br>(" + tr(
"press Ctrl + y for quick access" ) +
")" );
150 mRepeatingLockYButton->setToolTip(
"<b>" + tr(
"Continuously lock y coordinate" ) +
"</b>" );
161 mToggleFloaterAction->setChecked( mFloater->
active() );
163 updateCapacity(
true );
171 mXLineEdit->setText( value );
172 if ( mode == WidgetSetMode::ReturnPressed )
174 mXLineEdit->returnPressed();
176 else if ( mode == WidgetSetMode::FocusOut )
178 QEvent *e =
new QEvent( QEvent::FocusOut );
179 QCoreApplication::postEvent( mXLineEdit, e );
181 else if ( mode == WidgetSetMode::TextEdited )
183 mXLineEdit->textEdited( value );
188 mYLineEdit->setText( value );
189 if ( mode == WidgetSetMode::ReturnPressed )
191 mYLineEdit->returnPressed();
193 else if ( mode == WidgetSetMode::FocusOut )
195 QEvent *e =
new QEvent( QEvent::FocusOut );
196 QCoreApplication::postEvent( mYLineEdit, e );
198 else if ( mode == WidgetSetMode::TextEdited )
200 mYLineEdit->textEdited( value );
205 mAngleLineEdit->setText( value );
206 if ( mode == WidgetSetMode::ReturnPressed )
208 mAngleLineEdit->returnPressed();
210 else if ( mode == WidgetSetMode::FocusOut )
212 QEvent *e =
new QEvent( QEvent::FocusOut );
213 QCoreApplication::postEvent( mAngleLineEdit, e );
215 else if ( mode == WidgetSetMode::TextEdited )
217 mAngleLineEdit->textEdited( value );
222 mDistanceLineEdit->setText( value );
223 if ( mode == WidgetSetMode::ReturnPressed )
225 mDistanceLineEdit->returnPressed();
227 else if ( mode == WidgetSetMode::FocusOut )
229 QEvent *e =
new QEvent( QEvent::FocusOut );
230 QCoreApplication::postEvent( mDistanceLineEdit, e );
232 else if ( mode == WidgetSetMode::TextEdited )
234 mDistanceLineEdit->textEdited( value );
239 void QgsAdvancedDigitizingDockWidget::setCadEnabled(
bool enabled )
241 mCadEnabled = enabled;
242 mEnableAction->setChecked( enabled );
243 mConstructionModeAction->setEnabled( enabled );
244 mParallelAction->setEnabled( enabled );
245 mPerpendicularAction->setEnabled( enabled );
246 mSettingsAction->setEnabled( enabled );
247 mInputWidgets->setEnabled( enabled );
248 mToggleFloaterAction->setEnabled( enabled );
251 setConstructionMode(
false );
256 void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
258 enabled &= mCurrentMapToolSupportsCad;
260 mSessionActive = enabled;
262 if ( enabled && !isVisible() )
267 setCadEnabled( enabled );
270 void QgsAdvancedDigitizingDockWidget::additionalConstraintClicked(
bool activated )
276 else if ( sender() == mParallelAction )
280 else if ( sender() == mPerpendicularAction )
286 void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
288 if ( sender() == mRelativeAngleButton )
290 mAngleConstraint->setRelative( activate );
293 else if ( sender() == mRelativeXButton )
295 mXConstraint->setRelative( activate );
298 else if ( sender() == mRelativeYButton )
300 mYConstraint->setRelative( activate );
305 void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock(
bool activate )
307 if ( sender() == mRepeatingLockDistanceButton )
309 mDistanceConstraint->setRepeatingLock( activate );
311 else if ( sender() == mRepeatingLockAngleButton )
313 mAngleConstraint->setRepeatingLock( activate );
315 else if ( sender() == mRepeatingLockXButton )
317 mXConstraint->setRepeatingLock( activate );
319 else if ( sender() == mRepeatingLockYButton )
321 mYConstraint->setRepeatingLock( activate );
325 void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
327 mConstructionMode = enabled;
328 mConstructionModeAction->setChecked( enabled );
331 void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
334 QMap<QAction *, double>::const_iterator ica = mCommonAngleActions.constFind( action );
335 if ( ica != mCommonAngleActions.constEnd() )
337 ica.key()->setChecked(
true );
338 mCommonAngleConstraint = ica.value();
339 QgsSettings().setValue( QStringLiteral(
"/Cad/CommonAngle" ), ica.value() );
340 mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
351 if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
356 if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
361 if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
366 if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
372 if ( !mCadPointList.empty() )
374 if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
376 mXConstraint->setValue( mCadPointList.constLast().x(),
true );
378 if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
380 mYConstraint->setValue( mCadPointList.constLast().y(),
true );
387 void QgsAdvancedDigitizingDockWidget::emit pointChanged()
390 QPoint globalPos = mMapCanvas->cursor().pos();
391 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
392 QMouseEvent *e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
393 mCurrentMapTool->canvasMoveEvent( e );
399 CadConstraint *constraint =
nullptr;
400 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
402 constraint = mAngleConstraint.get();
404 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
406 constraint = mDistanceConstraint.get();
408 else if ( obj == mXLineEdit || obj == mLockXButton )
410 constraint = mXConstraint.get();
412 else if ( obj == mYLineEdit || obj == mLockYButton )
414 constraint = mYConstraint.get();
419 double QgsAdvancedDigitizingDockWidget::parseUserInput(
const QString &inputValue,
bool &ok )
const
431 QVariant result = expr.evaluate();
432 if ( expr.hasEvalError() )
435 value = result.toDouble( &ok );
440 void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint,
const QString &textValue,
bool convertExpression )
442 if ( !constraint || textValue.isEmpty() )
451 double value = parseUserInput( textValue, ok );
455 constraint->setValue( value, convertExpression );
460 void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
462 CadConstraint *constraint = objectToConstraint( sender() );
470 QString textValue = constraint->lineEdit()->text();
471 if ( !textValue.isEmpty() )
474 double value = parseUserInput( textValue, ok );
477 constraint->setValue( value );
491 if ( constraint == mXConstraint.get() )
495 else if ( constraint == mYConstraint.get() )
499 else if ( constraint == mDistanceConstraint.get() )
503 else if ( constraint == mAngleConstraint.get() )
511 if ( constraint == mAngleConstraint.get() )
521 void QgsAdvancedDigitizingDockWidget::constraintTextEdited(
const QString &textValue )
523 CadConstraint *constraint = objectToConstraint( sender() );
529 updateConstraintValue( constraint, textValue,
false );
532 void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
534 QLineEdit *lineEdit = qobject_cast< QLineEdit * >( sender()->parent() );
538 CadConstraint *constraint = objectToConstraint( lineEdit );
544 updateConstraintValue( constraint, lineEdit->text(),
true );
547 void QgsAdvancedDigitizingDockWidget::lockAdditionalConstraint( AdditionalConstraint constraint )
549 mAdditionalConstraint = constraint;
554 void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
556 CadCapacities newCapacities = CadCapacities();
558 if ( mCadPointList.count() > 1 )
562 if ( mCadPointList.count() > 2 )
566 if ( !updateUIwithoutChange && newCapacities == mCapacities )
576 bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
577 bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
580 mPerpendicularAction->setEnabled( absoluteAngle && snappingEnabled );
581 mParallelAction->setEnabled( absoluteAngle && snappingEnabled );
584 if ( !snappingEnabled )
586 mPerpendicularAction->setToolTip( tr(
"Snapping must be enabled to utilize perpendicular mode" ) );
587 mParallelAction->setToolTip( tr(
"Snapping must be enabled to utilize parallel mode" ) );
591 mPerpendicularAction->setToolTip(
"<b>" + tr(
"Perpendicular" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
592 mParallelAction->setToolTip(
"<b>" + tr(
"Parallel" ) +
"</b><br>(" + tr(
"press p to switch between perpendicular, parallel and normal mode" ) +
")" );
596 if ( !absoluteAngle )
602 mLockAngleButton->setEnabled( absoluteAngle );
603 mRelativeAngleButton->setEnabled( relativeAngle );
604 mAngleLineEdit->setEnabled( absoluteAngle );
606 if ( !absoluteAngle )
610 if ( !relativeAngle )
612 mAngleConstraint->setRelative(
false );
615 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
618 mAngleConstraint->setRelative(
true );
623 mLockDistanceButton->setEnabled( relativeCoordinates );
624 mDistanceLineEdit->setEnabled( relativeCoordinates );
626 if ( !relativeCoordinates )
631 mRelativeXButton->setEnabled( relativeCoordinates );
632 mRelativeYButton->setEnabled( relativeCoordinates );
635 mCapacities = newCapacities;
644 constr.
value =
c->value();
653 context.
xConstraint = _constraint( mXConstraint.get() );
654 context.
yConstraint = _constraint( mYConstraint.get() );
665 bool res = output.
valid;
667 mSnappedSegment.clear();
672 mSnappedSegment << edgePt0 << edgePt1;
689 mSnapIndicator->setMatch( output.
snapMatch );
690 mSnapIndicator->setVisible(
true );
694 mSnapIndicator->setVisible(
false );
712 updateCurrentPoint( point );
714 updateUnlockedConstraintValues( point );
722 emit
pushWarning( tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
729 void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues(
const QgsPointXY &point )
731 bool previousPointExist, penulPointExist;
736 if ( !mAngleConstraint->isLocked() && previousPointExist )
739 if ( penulPointExist && mAngleConstraint->relative() )
742 angle = std::atan2( previousPt.
y() - penultimatePt.
y(),
743 previousPt.
x() - penultimatePt.
x() );
745 angle = ( std::atan2( point.
y() - previousPt.
y(),
746 point.
x() - previousPt.
x()
747 ) -
angle ) * 180 / M_PI;
750 mAngleConstraint->setValue(
angle );
753 if ( !mDistanceConstraint->isLocked() && previousPointExist )
755 mDistanceConstraint->setValue( std::sqrt( previousPt.
sqrDist( point ) ) );
758 if ( !mXConstraint->isLocked() )
760 if ( previousPointExist && mXConstraint->relative() )
762 mXConstraint->setValue( point.
x() - previousPt.
x() );
766 mXConstraint->setValue( point.
x() );
770 if ( !mYConstraint->isLocked() )
772 if ( previousPointExist && mYConstraint->relative() )
774 mYConstraint->setValue( point.
y() - previousPt.
y() );
778 mYConstraint->setValue( point.
y() );
784 QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers(
const QgsPointXY &originalMapPoint,
bool *snapped )
const
799 match = snappingUtils->
snapToMap( originalMapPoint,
nullptr,
true );
801 snappingUtils->
setConfig( canvasConfig );
811 *snapped =
segment.count() == 2;
824 bool previousPointExist, penulPointExist, snappedSegmentExist;
827 mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
829 if ( !previousPointExist || !snappedSegmentExist )
834 double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
836 if ( mAngleConstraint->relative() && penulPointExist )
838 angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
848 mAngleConstraint->setValue(
angle );
849 mAngleConstraint->setLockMode( lockMode );
867 case Qt::Key_Backspace:
904 case Qt::Key_Backspace:
927 const auto constPoints = points;
934 bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
938 return QgsDockWidget::eventFilter( obj, event );
946 if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
948 if ( QKeyEvent *keyEvent =
dynamic_cast<QKeyEvent *
>( event ) )
950 return filterKeyPress( keyEvent );
953 return QgsDockWidget::eventFilter( obj, event );
956 bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
962 QEvent::Type type = e->type();
968 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
970 mXConstraint->toggleLocked();
975 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
979 mXConstraint->toggleRelative();
986 else if ( type == QEvent::KeyPress )
988 mXLineEdit->setFocus();
989 mXLineEdit->selectAll();
998 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1000 mYConstraint->toggleLocked();
1005 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1009 mYConstraint->toggleRelative();
1016 else if ( type == QEvent::KeyPress )
1018 mYLineEdit->setFocus();
1019 mYLineEdit->selectAll();
1028 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1032 mAngleConstraint->toggleLocked();
1038 else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
1042 mAngleConstraint->toggleRelative();
1049 else if ( type == QEvent::KeyPress )
1051 mAngleLineEdit->setFocus();
1052 mAngleLineEdit->selectAll();
1061 if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
1065 mDistanceConstraint->toggleLocked();
1072 else if ( type == QEvent::KeyPress )
1074 mDistanceLineEdit->setFocus();
1075 mDistanceLineEdit->selectAll();
1083 if ( type == QEvent::KeyPress )
1085 setConstructionMode( !mConstructionMode );
1092 if ( type == QEvent::KeyPress )
1094 bool parallel = mParallelAction->isChecked();
1095 bool perpendicular = mPerpendicularAction->isChecked();
1097 if ( !parallel && !perpendicular )
1101 else if ( perpendicular )
1121 return e->isAccepted();
1129 mErrorLabel->setText( tr(
"CAD tools can not be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1130 mErrorLabel->show();
1131 mEnableAction->setEnabled(
false );
1132 setCadEnabled(
false );
1136 mEnableAction->setEnabled(
true );
1137 mErrorLabel->hide();
1140 mCurrentMapToolSupportsCad =
true;
1142 if ( mSessionActive && !isVisible() )
1146 setCadEnabled( mSessionActive );
1154 mEnableAction->setEnabled(
false );
1155 mErrorLabel->setText( tr(
"CAD tools are not enabled for the current map tool" ) );
1156 mErrorLabel->show();
1159 mCurrentMapToolSupportsCad =
false;
1161 setCadEnabled(
false );
1166 mCadPaintItem->update();
1173 mCadPointList << point;
1177 mCadPointList.insert( 0, point );
1190 mCadPointList.removeAt( i );
1197 mCadPointList.clear();
1198 mSnappedSegment.clear();
1204 void QgsAdvancedDigitizingDockWidget::updateCurrentPoint(
const QgsPointXY &point )
1208 mCadPointList << point;
1213 mCadPointList[0] = point;
1222 mLockerButton->setChecked( mode ==
HardLock );
1223 if ( mRepeatingLockButton )
1227 mRepeatingLockButton->setEnabled(
true );
1231 mRepeatingLockButton->setChecked(
false );
1232 mRepeatingLockButton->setEnabled(
false );
1245 mRepeatingLock = repeating;
1246 if ( mRepeatingLockButton )
1247 mRepeatingLockButton->setChecked( repeating );
1252 mRelative = relative;
1253 if ( mRelativeButton )
1255 mRelativeButton->setChecked( relative );
1263 mLineEdit->setText( QLocale().toString( value,
'f', 6 ) );
1268 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
1273 setRelative( !mRelative );
1281 return mCadPointList.value( 0 );
1291 return mCadPointList.value( 1 );
1301 return mCadPointList.value( 2 );
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.
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.
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.
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
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
A class to represent a 2D point.
double sqrDist(double x, double y) const SIP_HOLDGIL
Returns the squared distance between this point a specified x, y coordinate.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
QgsSnappingConfig snappingConfig
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.
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)
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.
Structure defining all constraints for 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. Needed for.
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
QList< QgsPointXY > cadPointList
List of recent CAD points in map coordinates.
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)
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.