18#include <QCoreApplication> 
   23#include "moc_qgsadvanceddigitizingdockwidget.cpp" 
   46#include <QActionGroup> 
   57  , mMapCanvas( canvas )
 
   58  , mUserInputWidget( userInputWidget )
 
   60  , mCommonAngleConstraint( 
QgsSettings().value( QStringLiteral( 
"/Cad/CommonAngle" ), 0.0 ).toDouble() )
 
   66  mAngleConstraint.reset( 
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton, mRepeatingLockAngleButton ) );
 
   68  mAngleConstraint->setMapCanvas( mMapCanvas );
 
   69  mDistanceConstraint.reset( 
new CadConstraint( mDistanceLineEdit, mLockDistanceButton, 
nullptr, mRepeatingLockDistanceButton ) );
 
   71  mDistanceConstraint->setMapCanvas( mMapCanvas );
 
   72  mXConstraint.reset( 
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton, mRepeatingLockXButton ) );
 
   74  mXConstraint->setMapCanvas( mMapCanvas );
 
   75  mYConstraint.reset( 
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton, mRepeatingLockYButton ) );
 
   77  mYConstraint->setMapCanvas( mMapCanvas );
 
   78  mZConstraint.reset( 
new CadConstraint( mZLineEdit, mLockZButton, mRelativeZButton, mRepeatingLockZButton ) );
 
   80  mZConstraint->setMapCanvas( mMapCanvas );
 
   81  mMConstraint.reset( 
new CadConstraint( mMLineEdit, mLockMButton, mRelativeMButton, mRepeatingLockMButton ) );
 
   83  mMConstraint->setMapCanvas( mMapCanvas );
 
   85  mLineExtensionConstraint.reset( 
new CadConstraint( 
new QLineEdit(), 
new QToolButton() ) );
 
   86  mXyVertexConstraint.reset( 
new CadConstraint( 
new QLineEdit(), 
new QToolButton() ) );
 
   87  mXyVertexConstraint->setMapCanvas( mMapCanvas );
 
   91  mMapCanvas->installEventFilter( 
this );
 
   92  mAngleLineEdit->installEventFilter( 
this );
 
   93  mDistanceLineEdit->installEventFilter( 
this );
 
   94  mXLineEdit->installEventFilter( 
this );
 
   95  mYLineEdit->installEventFilter( 
this );
 
   96  mZLineEdit->installEventFilter( 
this );
 
   97  mMLineEdit->installEventFilter( 
this );
 
  100  connect( mEnableAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::activateCad );
 
  101  connect( mConstructionModeAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::setConstructionMode );
 
  102  connect( mParallelAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
 
  103  connect( mPerpendicularAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked );
 
  104  connect( mLockAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  105  connect( mLockDistanceButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  106  connect( mLockXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  107  connect( mLockYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  108  connect( mLockZButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  109  connect( mLockMButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::lockConstraint );
 
  110  connect( mRelativeAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  111  connect( mRelativeXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  112  connect( mRelativeYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  113  connect( mRelativeZButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  114  connect( mRelativeMButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRelative );
 
  115  connect( mRepeatingLockDistanceButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  116  connect( mRepeatingLockAngleButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  117  connect( mRepeatingLockXButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  118  connect( mRepeatingLockYButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  119  connect( mRepeatingLockZButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  120  connect( mRepeatingLockMButton, &QAbstractButton::clicked, 
this, &QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock );
 
  121  connect( mAngleLineEdit, &QLineEdit::returnPressed, 
this, [
this]() { lockConstraint(); } );
 
  122  connect( mDistanceLineEdit, &QLineEdit::returnPressed, 
this, [
this]() { lockConstraint(); } );
 
  123  connect( mXLineEdit, &QLineEdit::returnPressed, 
this, [
this]() { lockConstraint(); } );
 
  124  connect( mYLineEdit, &QLineEdit::returnPressed, 
this, [
this]() { lockConstraint(); } );
 
  125  connect( mZLineEdit, &QLineEdit::returnPressed, 
this, [
this]() { lockConstraint(); } );
 
  126  connect( mMLineEdit, &QLineEdit::returnPressed, 
this, [
this]() { lockConstraint(); } );
 
  127  connect( mAngleLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  128  connect( mDistanceLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  129  connect( mXLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  130  connect( mYLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  131  connect( mZLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  132  connect( mMLineEdit, &QLineEdit::textEdited, 
this, &QgsAdvancedDigitizingDockWidget::constraintTextEdited );
 
  138    whileBlocking( mAngleLineEdit )->setText( cleanedInputValue );
 
  144    whileBlocking( mDistanceLineEdit )->setText( cleanedInputValue );
 
  156  mCommonAngleActionsMenu = 
new QMenu( 
this );
 
  158#ifndef __clang_analyzer__ 
  159  QActionGroup *angleButtonGroup = 
new QActionGroup( mCommonAngleActionsMenu ); 
 
  161  QList<QPair<double, QString>> commonAngles;
 
  162  const QList<double> anglesDouble( { 0.0, 0.1, 0.5, 1.0, 5.0, 10.0, 15.0, 18.0, 22.5, 30.0, 45.0, 90.0 } );
 
  163  for ( QList<double>::const_iterator it = anglesDouble.constBegin(); it != anglesDouble.constEnd(); ++it )
 
  169    QMenu *snappingPriorityMenu = 
new QMenu( tr( 
"Snapping Priority" ), mCommonAngleActionsMenu );
 
  170    QActionGroup *snappingPriorityActionGroup = 
new QActionGroup( snappingPriorityMenu );
 
  171    QAction *featuresAction = 
new QAction( tr( 
"Prioritize Snapping to Features" ), snappingPriorityActionGroup );
 
  172    featuresAction->setCheckable( 
true );
 
  173    QAction *anglesAction = 
new QAction( tr( 
"Prioritize Snapping to Common Angles" ), snappingPriorityActionGroup );
 
  174    anglesAction->setCheckable( 
true );
 
  175    snappingPriorityActionGroup->addAction( featuresAction );
 
  176    snappingPriorityActionGroup->addAction( anglesAction );
 
  177    snappingPriorityMenu->addAction( anglesAction );
 
  178    snappingPriorityMenu->addAction( featuresAction );
 
  179    connect( anglesAction, &QAction::changed, 
this, [
this, featuresAction] {
 
  180      mSnappingPrioritizeFeatures = featuresAction->isChecked();
 
  181      settingsCadSnappingPriorityPrioritizeFeature->
setValue( featuresAction->isChecked() );
 
  183    featuresAction->setChecked( settingsCadSnappingPriorityPrioritizeFeature->
value() );
 
  184    anglesAction->setChecked( !featuresAction->isChecked() );
 
  185    mCommonAngleActionsMenu->addMenu( snappingPriorityMenu );
 
  188  for ( QList<QPair<double, QString>>::const_iterator it = commonAngles.constBegin(); it != commonAngles.constEnd(); ++it )
 
  190    QAction *action = 
new QAction( it->second, mCommonAngleActionsMenu );
 
  191    action->setCheckable( 
true );
 
  192    action->setChecked( it->first == mCommonAngleConstraint );
 
  193    mCommonAngleActionsMenu->addAction( action );
 
  195#ifndef __clang_analyzer__ 
  196    angleButtonGroup->addAction( action );
 
  198    mCommonAngleActions.insert( it->first, action );
 
  202  QMenu *constructionSettingsMenu = 
new QMenu( 
this );
 
  204  mRecordConstructionGuides = 
new QAction( tr( 
"Record Construction Guides" ), constructionSettingsMenu );
 
  205  mRecordConstructionGuides->setCheckable( 
true );
 
  206  mRecordConstructionGuides->setChecked( settingsCadRecordConstructionGuides->
value() );
 
  207  constructionSettingsMenu->addAction( mRecordConstructionGuides );
 
  208  connect( mRecordConstructionGuides, &QAction::triggered, 
this, [
this]() { settingsCadRecordConstructionGuides->
setValue( mRecordConstructionGuides->isChecked() ); } );
 
  210  mShowConstructionGuides = 
new QAction( tr( 
"Show Construction Guides" ), constructionSettingsMenu );
 
  211  mShowConstructionGuides->setCheckable( 
true );
 
  212  mShowConstructionGuides->setChecked( settingsCadShowConstructionGuides->
value() );
 
  213  constructionSettingsMenu->addAction( mShowConstructionGuides );
 
  214  connect( mShowConstructionGuides, &QAction::triggered, 
this, [
this]() {
 
  215    settingsCadShowConstructionGuides->
setValue( mShowConstructionGuides->isChecked() );
 
  219  mSnapToConstructionGuides = 
new QAction( tr( 
"Snap to Visible Construction Guides" ), constructionSettingsMenu );
 
  220  mSnapToConstructionGuides->setCheckable( 
true );
 
  221  mSnapToConstructionGuides->setChecked( settingsCadSnapToConstructionGuides->
value() );
 
  222  constructionSettingsMenu->addAction( mSnapToConstructionGuides );
 
  223  connect( mSnapToConstructionGuides, &QAction::triggered, 
this, [
this]() { settingsCadSnapToConstructionGuides->
setValue( mSnapToConstructionGuides->isChecked() ); } );
 
  225  constructionSettingsMenu->addSeparator();
 
  227  mClearConstructionGuides = 
new QAction( tr( 
"Clear Construction Guides" ), constructionSettingsMenu );
 
  228  constructionSettingsMenu->addAction( mClearConstructionGuides );
 
  229  connect( mClearConstructionGuides, &QAction::triggered, 
this, [
this]() {
 
  230    resetConstructionGuides();
 
  234  QToolButton *constructionModeToolButton = qobject_cast<QToolButton *>( mToolbar->widgetForAction( mConstructionModeAction ) );
 
  235  constructionModeToolButton->setPopupMode( QToolButton::MenuButtonPopup );
 
  236  constructionModeToolButton->setMenu( constructionSettingsMenu );
 
  237  constructionModeToolButton->setObjectName( QStringLiteral( 
"ConstructionModeButton" ) );
 
  240  QMenu *toolsMenu = 
new QMenu( 
this );
 
  241  connect( toolsMenu, &QMenu::aboutToShow, 
this, [
this, toolsMenu]() {
 
  244    for ( 
const QString &name : toolMetadataNames )
 
  247      QAction *toolAction = 
new QAction( toolMetadata->
icon(), toolMetadata->
visibleName(), toolsMenu );
 
  248      connect( toolAction, &QAction::triggered, 
this, [
this, toolMetadata]() {
 
  251      toolsMenu->addAction( toolAction );
 
  254  qobject_cast<QToolButton *>( mToolbar->widgetForAction( mToolsAction ) )->setPopupMode( QToolButton::InstantPopup );
 
  255  mToolsAction->setMenu( toolsMenu );
 
  257  qobject_cast<QToolButton *>( mToolbar->widgetForAction( mSettingsAction ) )->setPopupMode( QToolButton::InstantPopup );
 
  258  mSettingsAction->setMenu( mCommonAngleActionsMenu );
 
  259  mSettingsAction->setCheckable( 
true );
 
  260  mSettingsAction->setToolTip( 
"<b>" + tr( 
"Snap to common angles" ) + 
"</b><br>(" + tr( 
"press n to cycle through the options" ) + 
")" );
 
  261  mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
 
  262  connect( mCommonAngleActionsMenu, &QMenu::triggered, 
this, &QgsAdvancedDigitizingDockWidget::settingsButtonTriggered );
 
  265  QMenu *constructionMenu = 
new QMenu( 
this );
 
  267  mLineExtensionAction = 
new QAction( tr( 
"Line Extension" ), constructionMenu );
 
  268  mLineExtensionAction->setCheckable( 
true );
 
  269  constructionMenu->addAction( mLineExtensionAction );
 
  270  connect( mLineExtensionAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
 
  272  mXyVertexAction = 
new QAction( tr( 
"X/Y Point" ), constructionMenu );
 
  273  mXyVertexAction->setCheckable( 
true );
 
  274  constructionMenu->addAction( mXyVertexAction );
 
  275  connect( mXyVertexAction, &QAction::triggered, 
this, &QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint );
 
  277  auto constructionToolBar = qobject_cast<QToolButton *>( mToolbar->widgetForAction( mConstructionAction ) );
 
  278  constructionToolBar->setPopupMode( QToolButton::InstantPopup );
 
  279  constructionToolBar->setMenu( constructionMenu );
 
  280  constructionToolBar->setObjectName( QStringLiteral( 
"ConstructionButton" ) );
 
  282  mConstructionAction->setMenu( mCommonAngleActionsMenu );
 
  283  mConstructionAction->setCheckable( 
true );
 
  284  mConstructionAction->setToolTip( tr( 
"Construction Tools" ) );
 
  288  mConstructionModeAction->setToolTip( 
"<b>" + tr( 
"Construction mode" ) + 
"</b><br>(" + tr( 
"press c to toggle on/off" ) + 
")" );
 
  289  mDistanceLineEdit->setToolTip( 
"<b>" + tr( 
"Distance" ) + 
"</b><br>(" + tr( 
"press d for quick access" ) + 
")" );
 
  290  mLockDistanceButton->setToolTip( 
"<b>" + tr( 
"Lock distance" ) + 
"</b><br>(" + tr( 
"press Ctrl + d for quick access" ) + 
")" );
 
  291  mRepeatingLockDistanceButton->setToolTip( 
"<b>" + tr( 
"Continuously lock distance" ) + 
"</b>" );
 
  293  mRelativeAngleButton->setToolTip( 
"<b>" + tr( 
"Toggles relative angle to previous segment" ) + 
"</b><br>(" + tr( 
"press Shift + a for quick access" ) + 
")" );
 
  294  mAngleLineEdit->setToolTip( 
"<b>" + tr( 
"Angle" ) + 
"</b><br>(" + tr( 
"press a for quick access" ) + 
")" );
 
  295  mLockAngleButton->setToolTip( 
"<b>" + tr( 
"Lock angle" ) + 
"</b><br>(" + tr( 
"press Ctrl + a for quick access" ) + 
")" );
 
  296  mRepeatingLockAngleButton->setToolTip( 
"<b>" + tr( 
"Continuously lock angle" ) + 
"</b>" );
 
  298  mRelativeXButton->setToolTip( 
"<b>" + tr( 
"Toggles relative x to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + x for quick access" ) + 
")" );
 
  299  mXLineEdit->setToolTip( 
"<b>" + tr( 
"X coordinate" ) + 
"</b><br>(" + tr( 
"press x for quick access" ) + 
")" );
 
  300  mLockXButton->setToolTip( 
"<b>" + tr( 
"Lock x coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + x for quick access" ) + 
")" );
 
  301  mRepeatingLockXButton->setToolTip( 
"<b>" + tr( 
"Continuously lock x coordinate" ) + 
"</b>" );
 
  303  mRelativeYButton->setToolTip( 
"<b>" + tr( 
"Toggles relative y to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + y for quick access" ) + 
")" );
 
  304  mYLineEdit->setToolTip( 
"<b>" + tr( 
"Y coordinate" ) + 
"</b><br>(" + tr( 
"press y for quick access" ) + 
")" );
 
  305  mLockYButton->setToolTip( 
"<b>" + tr( 
"Lock y coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + y for quick access" ) + 
")" );
 
  306  mRepeatingLockYButton->setToolTip( 
"<b>" + tr( 
"Continuously lock y coordinate" ) + 
"</b>" );
 
  308  mRelativeZButton->setToolTip( 
"<b>" + tr( 
"Toggles relative z to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + z for quick access" ) + 
")" );
 
  309  mZLineEdit->setToolTip( 
"<b>" + tr( 
"Z coordinate" ) + 
"</b><br>(" + tr( 
"press z for quick access" ) + 
")" );
 
  310  mLockZButton->setToolTip( 
"<b>" + tr( 
"Lock z coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + z for quick access" ) + 
")" );
 
  311  mRepeatingLockZButton->setToolTip( 
"<b>" + tr( 
"Continuously lock z coordinate" ) + 
"</b>" );
 
  313  mRelativeMButton->setToolTip( 
"<b>" + tr( 
"Toggles relative m to previous node" ) + 
"</b><br>(" + tr( 
"press Shift + m for quick access" ) + 
")" );
 
  314  mMLineEdit->setToolTip( 
"<b>" + tr( 
"M coordinate" ) + 
"</b><br>(" + tr( 
"press m for quick access" ) + 
")" );
 
  315  mLockMButton->setToolTip( 
"<b>" + tr( 
"Lock m coordinate" ) + 
"</b><br>(" + tr( 
"press Ctrl + m for quick access" ) + 
")" );
 
  316  mRepeatingLockMButton->setToolTip( 
"<b>" + tr( 
"Continuously lock m coordinate" ) + 
"</b>" );
 
  327  mFloaterActionsMenu = 
new QMenu( 
this );
 
  328  qobject_cast<QToolButton *>( mToolbar->widgetForAction( mFloaterAction ) )->setPopupMode( QToolButton::InstantPopup );
 
  329  mFloaterAction->setMenu( mFloaterActionsMenu );
 
  330  mFloaterAction->setCheckable( 
true );
 
  332  mFloaterAction->setChecked( mFloater->
active() );
 
  336    QAction *action = 
new QAction( tr( 
"Show floater" ), mFloaterActionsMenu );
 
  337    action->setCheckable( 
true );
 
  338    action->setChecked( mFloater->
active() );
 
  339    mFloaterActionsMenu->addAction( action );
 
  340    connect( action, &QAction::toggled, 
this, [
this]( 
bool checked ) {
 
  342      mFloaterAction->setChecked( checked );
 
  346  mFloaterActionsMenu->addSeparator();
 
  349    QAction *action = 
new QAction( tr( 
"Show distance" ), mFloaterActionsMenu );
 
  350    action->setCheckable( 
true );
 
  351    mFloaterActionsMenu->addAction( action );
 
  352    connect( action, &QAction::toggled, 
this, [
this]( 
bool checked ) {
 
  355    const bool isDistanceChecked = 
QgsSettings().
value( QStringLiteral( 
"/Cad/DistanceShowInFloater" ), 
true ).toBool();
 
  356    action->setChecked( isDistanceChecked );
 
  362    QAction *action = 
new QAction( tr( 
"Show angle" ), mFloaterActionsMenu );
 
  363    action->setCheckable( 
true );
 
  364    mFloaterActionsMenu->addAction( action );
 
  365    connect( action, &QAction::toggled, 
this, [
this]( 
bool checked ) {
 
  368    const bool isAngleChecked = 
QgsSettings().
value( QStringLiteral( 
"/Cad/AngleShowInFloater" ), 
true ).toBool();
 
  369    action->setChecked( isAngleChecked );
 
  375    QAction *action = 
new QAction( tr( 
"Show XY coordinates" ), mFloaterActionsMenu );
 
  376    action->setCheckable( 
true );
 
  377    mFloaterActionsMenu->addAction( action );
 
  378    connect( action, &QAction::toggled, 
this, [
this]( 
bool checked ) {
 
  383    const bool isXCoordinateChecked = 
QgsSettings().
value( QStringLiteral( 
"/Cad/XCoordinateShowInFloater" ), 
true ).toBool();
 
  384    action->setChecked( isXCoordinateChecked );
 
  392    QAction *action = 
new QAction( tr( 
"Show Z value" ), mFloaterActionsMenu );
 
  393    action->setCheckable( 
true );
 
  394    mFloaterActionsMenu->addAction( action );
 
  395    connect( action, &QAction::toggled, 
this, [
this]( 
bool checked ) {
 
  398    const bool isZCoordinateChecked = 
QgsSettings().
value( QStringLiteral( 
"/Cad/ZCoordinateShowInFloater" ), 
true ).toBool();
 
  399    action->setChecked( isZCoordinateChecked );
 
  406    QAction *action = 
new QAction( tr( 
"Show M value" ), mFloaterActionsMenu );
 
  407    action->setCheckable( 
true );
 
  408    mFloaterActionsMenu->addAction( action );
 
  409    connect( action, &QAction::toggled, 
this, [
this]( 
bool checked ) {
 
  412    const bool isMCoordinateChecked = 
QgsSettings().
value( QStringLiteral( 
"/Cad/MCoordinateShowInFloater" ), 
true ).toBool();
 
  413    action->setChecked( isMCoordinateChecked );
 
  420    QAction *action = 
new QAction( tr( 
"Show bearing/azimuth" ), mFloaterActionsMenu );
 
  421    action->setCheckable( 
true );
 
  422    mFloaterActionsMenu->addAction( action );
 
  423    connect( action, &QAction::toggled, 
this, [
this]( 
bool checked ) {
 
  426    const bool isBearingChecked = 
QgsSettings().
value( QStringLiteral( 
"/Cad/BearingShowInFloater" ), 
false ).toBool();
 
  427    action->setChecked( isBearingChecked );
 
  434    QAction *action = 
new QAction( tr( 
"Show common snapping angle" ), mFloaterActionsMenu );
 
  435    action->setCheckable( 
true );
 
  436    mFloaterActionsMenu->addAction( action );
 
  437    connect( action, &QAction::toggled, 
this, [
this]( 
bool checked ) {
 
  440    const bool isCommonAngleSnappingChecked = 
QgsSettings().
value( QStringLiteral( 
"/Cad/CommonAngleSnappingShowInFloater" ), 
false ).toBool();
 
  441    action->setChecked( isCommonAngleSnappingChecked );
 
  447  updateCapacity( 
true );
 
  451    mConstructionGuidesLayer.reset();
 
 
  462    mCurrentTool->deleteLater();
 
 
  469    return tr( 
"Do Not Snap to Common Angles" );
 
  471    return QString( tr( 
"%1, %2, %3, %4°…" ) ).arg( angle, 0, 
'f', 1 ).arg( angle * 2, 0, 
'f', 1 ).arg( angle * 3, 0, 
'f', 1 ).arg( angle * 4, 0, 
'f', 1 );
 
 
  476  mXLineEdit->setText( value );
 
  479    emit mXLineEdit->returnPressed();
 
  483    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  484    QCoreApplication::postEvent( mXLineEdit, e );
 
  488    emit mXLineEdit->textEdited( value );
 
 
  493  mYLineEdit->setText( value );
 
  496    emit mYLineEdit->returnPressed();
 
  500    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  501    QCoreApplication::postEvent( mYLineEdit, e );
 
  505    emit mYLineEdit->textEdited( value );
 
 
  510  mZLineEdit->setText( value );
 
  513    emit mZLineEdit->returnPressed();
 
  517    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  518    QCoreApplication::postEvent( mZLineEdit, e );
 
  522    emit mZLineEdit->textEdited( value );
 
 
  527  mMLineEdit->setText( value );
 
  530    emit mMLineEdit->returnPressed();
 
  534    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  535    QCoreApplication::postEvent( mMLineEdit, e );
 
  539    emit mMLineEdit->textEdited( value );
 
 
  544  mAngleLineEdit->setText( value );
 
  547    emit mAngleLineEdit->returnPressed();
 
  551    emit mAngleLineEdit->textEdited( value );
 
 
  556  mDistanceLineEdit->setText( value );
 
  559    emit mDistanceLineEdit->returnPressed();
 
  563    QEvent *e = 
new QEvent( QEvent::FocusOut );
 
  564    QCoreApplication::postEvent( mDistanceLineEdit, e );
 
  568    emit mDistanceLineEdit->textEdited( value );
 
 
  573void QgsAdvancedDigitizingDockWidget::setCadEnabled( 
bool enabled )
 
  575  mCadEnabled = enabled;
 
  576  mEnableAction->setChecked( enabled );
 
  577  mConstructionModeAction->setEnabled( enabled );
 
  578  mSettingsAction->setEnabled( enabled );
 
  579  mInputWidgets->setEnabled( enabled );
 
  580  mFloaterAction->setEnabled( enabled );
 
  581  mConstructionAction->setEnabled( enabled );
 
  582  mToolsAction->setEnabled( enabled );
 
  587    mLineExtensionAction->setChecked( 
false );
 
  588    mXyVertexAction->setChecked( 
false );
 
  590    mParallelAction->setEnabled( 
false );
 
  591    mPerpendicularAction->setEnabled( 
false );
 
  594      mCurrentTool->deleteLater();
 
  601  setConstructionMode( 
false );
 
  617  bool enableZ = 
false;
 
  618  bool enableM = 
false;
 
  622    switch ( layer->type() )
 
  635        QgsMeshLayer *mlayer = qobject_cast<QgsMeshLayer *>( layer );
 
  651  mTargetLayerSupportsM = enableM;
 
  652  mTargetLayerSupportsZ = enableZ;
 
 
  660  if ( 
enable && !mTargetLayerSupportsZ )
 
  664  mRelativeZButton->setEnabled( 
enable );
 
  665  mZLabel->setEnabled( 
enable );
 
  666  mZLineEdit->setEnabled( 
enable );
 
  667  if ( mZLineEdit->isEnabled() )
 
  671  mLockZButton->setEnabled( 
enable );
 
 
  677  if ( 
enable && !mTargetLayerSupportsM )
 
  681  mRelativeMButton->setEnabled( 
enable );
 
  682  mMLabel->setEnabled( 
enable );
 
  683  mMLineEdit->setEnabled( 
enable );
 
  684  if ( mMLineEdit->isEnabled() )
 
  688  mLockMButton->setEnabled( 
enable );
 
 
  692void QgsAdvancedDigitizingDockWidget::activateCad( 
bool enabled )
 
  694  enabled &= mCurrentMapToolSupportsCad;
 
  696  mSessionActive = enabled;
 
  698  if ( enabled && !isVisible() )
 
  703  setCadEnabled( enabled );
 
  710    mCurrentTool->deleteLater();
 
  711    mCurrentTool = 
nullptr;
 
  718    if ( QWidget *toolWidget = mCurrentTool->createWidget() )
 
  720      toolWidget->setParent( mUserInputWidget );
 
 
  729  return mCurrentTool.data();
 
 
  732void QgsAdvancedDigitizingDockWidget::betweenLineConstraintClicked( 
bool activated )
 
  738  else if ( sender() == mParallelAction )
 
  742  else if ( sender() == mPerpendicularAction )
 
  748void QgsAdvancedDigitizingDockWidget::setConstraintRelative( 
bool activate )
 
  750  if ( sender() == mRelativeAngleButton )
 
  752    mAngleConstraint->setRelative( activate );
 
  755  else if ( sender() == mRelativeXButton )
 
  757    mXConstraint->setRelative( activate );
 
  760  else if ( sender() == mRelativeYButton )
 
  762    mYConstraint->setRelative( activate );
 
  765  else if ( sender() == mRelativeZButton )
 
  767    mZConstraint->setRelative( activate );
 
  770  else if ( sender() == mRelativeMButton )
 
  772    mMConstraint->setRelative( activate );
 
  777void QgsAdvancedDigitizingDockWidget::setConstraintRepeatingLock( 
bool activate )
 
  779  if ( sender() == mRepeatingLockDistanceButton )
 
  781    mDistanceConstraint->setRepeatingLock( activate );
 
  783  else if ( sender() == mRepeatingLockAngleButton )
 
  785    mAngleConstraint->setRepeatingLock( activate );
 
  787  else if ( sender() == mRepeatingLockXButton )
 
  789    mXConstraint->setRepeatingLock( activate );
 
  791  else if ( sender() == mRepeatingLockYButton )
 
  793    mYConstraint->setRepeatingLock( activate );
 
  795  else if ( sender() == mRepeatingLockZButton )
 
  797    mZConstraint->setRepeatingLock( activate );
 
  799  else if ( sender() == mRepeatingLockMButton )
 
  801    mMConstraint->setRepeatingLock( activate );
 
  805void QgsAdvancedDigitizingDockWidget::setConstructionMode( 
bool enabled )
 
  807  mConstructionMode = enabled;
 
  808  mConstructionModeAction->setChecked( enabled );
 
  812    if ( enabled && mCadPointList.size() > 1 )
 
  814      mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
 
  819void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered( QAction *action )
 
  822  for ( 
auto it = mCommonAngleActions.cbegin(); it != mCommonAngleActions.cend(); ++it )
 
  824    if ( it.value() == action )
 
  826      it.value()->setChecked( 
true );
 
  827      mCommonAngleConstraint = it.key();
 
  829      mSettingsAction->setChecked( mCommonAngleConstraint != 0 );
 
  836QgsMapLayer *QgsAdvancedDigitizingDockWidget::targetLayer()
 const 
  840    return advancedTool->layer();
 
  854  if ( releaseRepeatingLocks )
 
  856    mXyVertexAction->setChecked( 
false );
 
  860    mLineExtensionAction->setChecked( 
false );
 
  867  if ( releaseRepeatingLocks || !mAngleConstraint->isRepeatingLock() )
 
  872  if ( releaseRepeatingLocks || !mDistanceConstraint->isRepeatingLock() )
 
  877  if ( releaseRepeatingLocks || !mXConstraint->isRepeatingLock() )
 
  882  if ( releaseRepeatingLocks || !mYConstraint->isRepeatingLock() )
 
  887  if ( releaseRepeatingLocks || !mZConstraint->isRepeatingLock() )
 
  892  if ( releaseRepeatingLocks || !mMConstraint->isRepeatingLock() )
 
  898  if ( !mCadPointList.empty() )
 
  900    if ( !mXConstraint->isLocked() && !mXConstraint->relative() )
 
  902      mXConstraint->setValue( mCadPointList.constLast().x(), 
true );
 
  904    if ( !mYConstraint->isLocked() && !mYConstraint->relative() )
 
  906      mYConstraint->setValue( mCadPointList.constLast().y(), 
true );
 
  908    if ( !mZConstraint->isLocked() && !mZConstraint->relative() )
 
  910      mZConstraint->setValue( mCadPointList.constLast().z(), 
true );
 
  912    if ( !mMConstraint->isLocked() && !mMConstraint->relative() )
 
  914      mMConstraint->setValue( mCadPointList.constLast().m(), 
true );
 
 
  920void QgsAdvancedDigitizingDockWidget::emit pointChanged()
 
  923  QPoint globalPos = mMapCanvas->cursor().pos();
 
  924  QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
 
  925  QMouseEvent *e = 
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
 
  926  mCurrentMapTool->canvasMoveEvent( e );
 
  932  CadConstraint *constraint = 
nullptr;
 
  933  if ( obj == mAngleLineEdit || obj == mLockAngleButton )
 
  935    constraint = mAngleConstraint.get();
 
  937  else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
 
  939    constraint = mDistanceConstraint.get();
 
  941  else if ( obj == mXLineEdit || obj == mLockXButton )
 
  943    constraint = mXConstraint.get();
 
  945  else if ( obj == mYLineEdit || obj == mLockYButton )
 
  947    constraint = mYConstraint.get();
 
  949  else if ( obj == mZLineEdit || obj == mLockZButton )
 
  951    constraint = mZConstraint.get();
 
  953  else if ( obj == mMLineEdit || obj == mLockMButton )
 
  955    constraint = mMConstraint.get();
 
  957  else if ( obj == mLineExtensionAction )
 
  959    constraint = mLineExtensionConstraint.get();
 
  961  else if ( obj == mXyVertexAction )
 
  963    constraint = mXyVertexConstraint.get();
 
  968double QgsAdvancedDigitizingDockWidget::parseUserInput( 
const QString &inputValue, 
const Qgis::CadConstraintType type, 
bool &ok )
 const 
  979    const QVariant result = expr.evaluate();
 
  980    if ( expr.hasEvalError() )
 
  983      QString inputValueC { inputValue };
 
  986      if ( inputValue.contains( QLocale().groupSeparator() ) )
 
  988        inputValueC.remove( QLocale().groupSeparator() );
 
  990        const QVariant resultC = exprC.evaluate();
 
  991        if ( !exprC.hasEvalError() )
 
  993          value = resultC.toDouble( &ok );
 
  998      if ( !ok && QLocale().decimalPoint() != QChar( 
'.' ) && inputValueC.contains( QLocale().decimalPoint() ) )
 
 1000        QgsExpression exprC( inputValueC.replace( QLocale().decimalPoint(), QChar( 
'.' ) ) );
 
 1001        const QVariant resultC = exprC.evaluate();
 
 1002        if ( !exprC.hasEvalError() )
 
 1004          value = resultC.toDouble( &ok );
 
 1010      value = result.toDouble( &ok );
 
 1025void QgsAdvancedDigitizingDockWidget::updateConstraintValue( CadConstraint *constraint, 
const QString &textValue, 
bool convertExpression )
 
 1027  if ( !constraint || textValue.isEmpty() )
 
 1036  const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
 
 1040  constraint->setValue( value, convertExpression );
 
 1045void QgsAdvancedDigitizingDockWidget::lockConstraint( 
bool activate  )
 
 1047  CadConstraint *constraint = objectToConstraint( sender() );
 
 1055    const QString textValue = constraint->lineEdit()->text();
 
 1056    if ( !textValue.isEmpty() )
 
 1059      const double value = parseUserInput( textValue, constraint->cadConstraintType(), ok );
 
 1062        constraint->setValue( value );
 
 1076  if ( constraint == mXConstraint.get() )
 
 1080  else if ( constraint == mYConstraint.get() )
 
 1084  else if ( constraint == mZConstraint.get() )
 
 1088  else if ( constraint == mMConstraint.get() )
 
 1092  else if ( constraint == mDistanceConstraint.get() )
 
 1096  else if ( constraint == mAngleConstraint.get() )
 
 1104    if ( constraint == mAngleConstraint.get() )
 
 1114void QgsAdvancedDigitizingDockWidget::constraintTextEdited( 
const QString &textValue )
 
 1116  CadConstraint *constraint = objectToConstraint( sender() );
 
 1122  updateConstraintValue( constraint, textValue, 
false );
 
 1125void QgsAdvancedDigitizingDockWidget::constraintFocusOut()
 
 1127  QLineEdit *lineEdit = qobject_cast<QLineEdit *>( sender()->parent() );
 
 1131  CadConstraint *constraint = objectToConstraint( lineEdit );
 
 1137  updateConstraintValue( constraint, lineEdit->text(), 
true );
 
 1142  mBetweenLineConstraint = constraint;
 
 1147void QgsAdvancedDigitizingDockWidget::lockParameterlessConstraint( 
bool activate  )
 
 1149  CadConstraint *constraint = objectToConstraint( sender() );
 
 1157  if ( constraint == mXyVertexConstraint.get() )
 
 1161  else if ( constraint == mLineExtensionConstraint.get() )
 
 1175void QgsAdvancedDigitizingDockWidget::updateCapacity( 
bool updateUIwithoutChange )
 
 1181  if ( mCadPointList.count() > 1 )
 
 1184    if ( !isGeographic )
 
 1190  if ( mCadPointList.count() > 2 )
 
 1192    if ( !isGeographic )
 
 1195  if ( !updateUIwithoutChange && newCapacities == mCapacities )
 
 1205  const bool distance = mCadEnabled && newCapacities.testFlag( 
Distance );
 
 1206  const bool relativeAngle = mCadEnabled && newCapacities.testFlag( 
RelativeAngle );
 
 1207  const bool absoluteAngle = mCadEnabled && newCapacities.testFlag( 
AbsoluteAngle );
 
 1208  const bool relativeCoordinates = mCadEnabled && newCapacities.testFlag( 
RelativeCoordinates );
 
 1210  mPerpendicularAction->setEnabled( distance && snappingEnabled );
 
 1211  mParallelAction->setEnabled( distance && snappingEnabled );
 
 1213  mLineExtensionAction->setEnabled( snappingEnabled );
 
 1214  mXyVertexAction->setEnabled( snappingEnabled );
 
 1218  if ( !snappingEnabled )
 
 1220    mPerpendicularAction->setToolTip( tr( 
"Snapping must be enabled to utilize perpendicular mode." ) );
 
 1221    mParallelAction->setToolTip( tr( 
"Snapping must be enabled to utilize parallel mode." ) );
 
 1222    mLineExtensionAction->setToolTip( tr( 
"Snapping must be enabled to utilize line extension mode." ) );
 
 1223    mXyVertexAction->setToolTip( tr( 
"Snapping must be enabled to utilize xy point mode." ) );
 
 1225  else if ( mCadPointList.count() <= 1 )
 
 1227    mPerpendicularAction->setToolTip( tr( 
"A first vertex should be drawn to utilize perpendicular mode." ) );
 
 1228    mParallelAction->setToolTip( tr( 
"A first vertex should be drawn to utilize parallel mode." ) );
 
 1230  else if ( isGeographic )
 
 1232    mPerpendicularAction->setToolTip( tr( 
"Perpendicular mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 1233    mParallelAction->setToolTip( tr( 
"Parallel mode cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 1237    mPerpendicularAction->setToolTip( 
"<b>" + tr( 
"Perpendicular" ) + 
"</b><br>(" + tr( 
"press p to switch between perpendicular, parallel and normal mode" ) + 
")" );
 
 1238    mParallelAction->setToolTip( 
"<b>" + tr( 
"Parallel" ) + 
"</b><br>(" + tr( 
"press p to switch between perpendicular, parallel and normal mode" ) + 
")" );
 
 1242  if ( !absoluteAngle )
 
 1248  mLockAngleButton->setEnabled( absoluteAngle );
 
 1249  mRelativeAngleButton->setEnabled( relativeAngle );
 
 1250  mAngleLineEdit->setEnabled( absoluteAngle );
 
 1252  if ( !absoluteAngle )
 
 1256  if ( !relativeAngle )
 
 1258    mAngleConstraint->setRelative( 
false );
 
 1261  else if ( relativeAngle && !mCapacities.testFlag( 
RelativeAngle ) )
 
 1264    mAngleConstraint->setRelative( 
true );
 
 1269  mLockDistanceButton->setEnabled( distance && relativeCoordinates );
 
 1270  mDistanceLineEdit->setEnabled( distance && relativeCoordinates );
 
 1272  if ( !( distance && relativeCoordinates ) )
 
 1277  mRelativeXButton->setEnabled( relativeCoordinates );
 
 1278  mRelativeYButton->setEnabled( relativeCoordinates );
 
 1279  mRelativeZButton->setEnabled( relativeCoordinates );
 
 1280  mRelativeMButton->setEnabled( relativeCoordinates );
 
 1283  mCapacities = newCapacities;
 
 1291  constr.
locked = 
c->isLocked();
 
 1293  constr.
value = 
c->value();
 
 1300  if ( !mLineExtensionConstraint->isLocked() && !mXyVertexConstraint->isLocked() )
 
 1306  const int lastIndex = mLockedSnapVertices.length() - 1;
 
 1307  for ( 
int i = lastIndex; i >= 0; --i )
 
 1309    if ( mLockedSnapVertices[i].point() == snapMatch.
point() )
 
 1311      if ( snapMatch.
point() != previouslySnap.
point() )
 
 1313        mLockedSnapVertices.removeAt( i );
 
 1319  if ( snapMatch.
point() != previouslySnap.
point() )
 
 1321    mLockedSnapVertices.enqueue( snapMatch );
 
 1324  if ( mLockedSnapVertices.count() > 3 )
 
 1326    mLockedSnapVertices.dequeue();
 
 1335  context.
xConstraint = _constraint( mXConstraint.get() );
 
 1336  context.
yConstraint = _constraint( mYConstraint.get() );
 
 1337  context.
zConstraint = _constraint( mZConstraint.get() );
 
 1338  context.
mConstraint = _constraint( mMConstraint.get() );
 
 1365  const bool res = output.
valid;
 
 1367  mSnappedSegment.clear();
 
 1372    mSnappedSegment << edgePt0 << edgePt1;
 
 1393    mSnapIndicator->setMatch( output.
snapMatch );
 
 1394    mSnapIndicator->setVisible( 
true );
 
 1398    mSnapIndicator->setVisible( 
false );
 
 1420  if ( mSnapMatch.
layer() )
 
 1436    toggleLockedSnapVertex( mSnapMatch, mLastSnapMatch );
 
 1437    mLastSnapMatch = mSnapMatch;
 
 1447  if ( mLockZButton->isChecked() )
 
 1449    point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
 
 1451  if ( mLockMButton->isChecked() )
 
 1453    point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
 
 1459  updateUnlockedConstraintValues( point );
 
 1467    emit 
pushWarning( tr( 
"Some constraints are incompatible. Resulting point might be incorrect." ) );
 
 
 1474void QgsAdvancedDigitizingDockWidget::updateUnlockedConstraintValues( 
const QgsPoint &point )
 
 1476  bool previousPointExist, penulPointExist;
 
 1481  if ( previousPointExist )
 
 1483    double prevAngle = 0.0;
 
 1485    if ( penulPointExist && mAngleConstraint->relative() )
 
 1488      prevAngle = std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() ) * 180 / M_PI;
 
 1491    const double xAngle { std::atan2( point.
y() - previousPt.
y(), point.
x() - previousPt.
x() ) * 180 / M_PI };
 
 1494    const double angle = std::fmod( xAngle - prevAngle, 360.0 );
 
 1495    if ( !mAngleConstraint->isLocked() )
 
 1497      mAngleConstraint->setValue( angle );
 
 1501    double bearing { std::fmod( xAngle, 360.0 ) };
 
 1502    bearing = bearing <= 90.0 ? 90.0 - bearing : ( bearing > 90 ? 270.0 + 180.0 - bearing : 270.0 - bearing );
 
 1508  if ( !mDistanceConstraint->isLocked() && previousPointExist )
 
 1510    mDistanceConstraint->setValue( std::sqrt( previousPt.
distanceSquared( point ) ) );
 
 1513  if ( !mXConstraint->isLocked() )
 
 1515    if ( previousPointExist && mXConstraint->relative() )
 
 1517      mXConstraint->setValue( point.
x() - previousPt.
x() );
 
 1521      mXConstraint->setValue( point.
x() );
 
 1525  if ( !mYConstraint->isLocked() )
 
 1527    if ( previousPointExist && mYConstraint->relative() )
 
 1529      mYConstraint->setValue( point.
y() - previousPt.
y() );
 
 1533      mYConstraint->setValue( point.
y() );
 
 1537  if ( !mZConstraint->isLocked() )
 
 1539    if ( previousPointExist && mZConstraint->relative() )
 
 1541      mZConstraint->setValue( point.
z() - previousPt.
z() );
 
 1545      mZConstraint->setValue( point.
z() );
 
 1549  if ( !mMConstraint->isLocked() )
 
 1551    if ( previousPointExist && mMConstraint->relative() )
 
 1553      mMConstraint->setValue( point.
m() - previousPt.
m() );
 
 1557      mMConstraint->setValue( point.
m() );
 
 1563QList<QgsPointXY> QgsAdvancedDigitizingDockWidget::snapSegmentToAllLayers( 
const QgsPointXY &originalMapPoint, 
bool *snapped )
 const 
 1576  snappingUtils->
setConfig( localConfig );
 
 1578  match = snappingUtils->
snapToMap( originalMapPoint, 
nullptr, 
true );
 
 1580  snappingUtils->
setConfig( canvasConfig );
 
 1590    *snapped = 
segment.count() == 2;
 
 1600    mCurrentTool->canvasPressEvent( event );
 
 1605    event->setAccepted( 
false );
 
 
 1617    mCurrentTool->canvasMoveEvent( event );
 
 
 1625  if ( event->button() == Qt::RightButton )
 
 1629      mCurrentTool->canvasReleaseEvent( event );
 
 1630      if ( !event->isAccepted() )
 
 1642      event->setAccepted( 
false );
 
 1648      mCurrentTool->canvasReleaseEvent( event );
 
 1649      if ( !event->isAccepted() )
 
 1660        if ( mLockZButton->isChecked() )
 
 1662          point.
setZ( QLocale().toDouble( mZLineEdit->text() ) );
 
 1664        if ( mLockMButton->isChecked() )
 
 1666          point.
setM( QLocale().toDouble( mMLineEdit->text() ) );
 
 1677      event->setAccepted( 
false );
 
 
 1689  bool previousPointExist, penulPointExist, snappedSegmentExist;
 
 1692  mSnappedSegment = snapSegmentToAllLayers( e->
originalMapPoint(), &snappedSegmentExist );
 
 1694  if ( !previousPointExist || !snappedSegmentExist )
 
 1699  double angle = std::atan2( mSnappedSegment[0].y() - mSnappedSegment[1].y(), mSnappedSegment[0].x() - mSnappedSegment[1].x() );
 
 1701  if ( mAngleConstraint->relative() && penulPointExist )
 
 1703    angle -= std::atan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
 
 1711  angle *= 180 / M_PI;
 
 1713  mAngleConstraint->setValue( angle );
 
 1714  mAngleConstraint->setLockMode( lockMode );
 
 
 1732    case Qt::Key_Backspace:
 
 1733    case Qt::Key_Delete:
 
 1739    case Qt::Key_Escape:
 
 
 1758    mCurrentTool->deleteLater();
 
 1761  if ( !mConstructionGuideLine.
isEmpty() )
 
 1763    mConstructionGuideLine.
clear();
 
 
 1779    case Qt::Key_Backspace:
 
 1780    case Qt::Key_Delete:
 
 1786    case Qt::Key_Escape:
 
 1790      if ( mConstructionGuideLine.
numPoints() >= 2 )
 
 1792        mConstructionGuidesLayer->dataProvider()->deleteFeatures( 
QgsFeatureIds() << mConstructionGuideId );
 
 1793        mConstructionGuideLine.
clear();
 
 1798        mCurrentTool->deleteLater();
 
 1805      filterKeyPress( e );
 
 
 1814  const auto constPoints = points;
 
 
 1823  mDistanceConstraint->toggleLocked();
 
 
 1828bool QgsAdvancedDigitizingDockWidget::eventFilter( QObject *obj, QEvent *event )
 
 1832    return QgsDockWidget::eventFilter( obj, event );
 
 1840  if ( event->type() == QEvent::ShortcutOverride || event->type() == QEvent::KeyPress )
 
 1842    if ( QKeyEvent *keyEvent = 
dynamic_cast<QKeyEvent *
>( event ) )
 
 1844      return filterKeyPress( keyEvent );
 
 1847  return QgsDockWidget::eventFilter( obj, event );
 
 1850bool QgsAdvancedDigitizingDockWidget::filterKeyPress( QKeyEvent *e )
 
 1856  const QEvent::Type type = e->type();
 
 1859    case Qt::Key_Escape:
 
 1861      if ( type == QEvent::KeyPress && mCurrentTool )
 
 1863        mCurrentTool->deleteLater();
 
 1865      else if ( type == QEvent::KeyPress && mConstructionMode && mConstructionGuideLine.
numPoints() >= 2 )
 
 1867        mConstructionGuidesLayer->dataProvider()->deleteFeatures( 
QgsFeatureIds() << mConstructionGuideId );
 
 1868        mConstructionGuideLine.
clear();
 
 1870        if ( mCadPointList.size() > 1 )
 
 1872          mConstructionGuideLine.
addVertex( mCadPointList.at( 1 ) );
 
 1887      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1889        mXConstraint->toggleLocked();
 
 1894      else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
 1898          mXConstraint->toggleRelative();
 
 1905      else if ( type == QEvent::KeyPress )
 
 1907        mXLineEdit->setFocus();
 
 1908        mXLineEdit->selectAll();
 
 1917      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1919        mYConstraint->toggleLocked();
 
 1924      else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
 1928          mYConstraint->toggleRelative();
 
 1935      else if ( type == QEvent::KeyPress )
 
 1937        mYLineEdit->setFocus();
 
 1938        mYLineEdit->selectAll();
 
 1947      if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::AltModifier )
 
 1949        mZConstraint->toggleLocked();
 
 1954      else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
 1958          mZConstraint->toggleRelative();
 
 1965      else if ( type == QEvent::KeyPress )
 
 1967        mZLineEdit->setFocus();
 
 1968        mZLineEdit->selectAll();
 
 1977      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 1979        mMConstraint->toggleLocked();
 
 1984      else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
 1988          mMConstraint->toggleRelative();
 
 1995      else if ( type == QEvent::KeyPress )
 
 1997        mMLineEdit->setFocus();
 
 1998        mMLineEdit->selectAll();
 
 2007      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 2011          mAngleConstraint->toggleLocked();
 
 2017      else if ( type == QEvent::ShortcutOverride && e->modifiers() == Qt::ShiftModifier )
 
 2021          mAngleConstraint->toggleRelative();
 
 2028      else if ( type == QEvent::KeyPress )
 
 2030        mAngleLineEdit->setFocus();
 
 2031        mAngleLineEdit->selectAll();
 
 2040      if ( type == QEvent::ShortcutOverride && ( e->modifiers() == Qt::AltModifier || e->modifiers() == Qt::ControlModifier ) )
 
 2049      else if ( type == QEvent::KeyPress )
 
 2051        mDistanceLineEdit->setFocus();
 
 2052        mDistanceLineEdit->selectAll();
 
 2060      if ( type == QEvent::KeyPress )
 
 2062        setConstructionMode( !mConstructionMode );
 
 2069      if ( type == QEvent::KeyPress )
 
 2071        const bool parallel = mParallelAction->isChecked();
 
 2072        const bool perpendicular = mPerpendicularAction->isChecked();
 
 2074        if ( !parallel && !perpendicular )
 
 2078        else if ( perpendicular )
 
 2095      if ( type == QEvent::ShortcutOverride )
 
 2097        const QList<double> constActionKeys { mCommonAngleActions.keys() };
 
 2098        const int currentAngleActionIndex { 
static_cast<int>( constActionKeys.indexOf( mCommonAngleConstraint ) ) };
 
 2099        const QList<QAction *> constActions { mCommonAngleActions.values() };
 
 2100        QAction *nextAngleAction;
 
 2101        if ( e->modifiers() == Qt::ShiftModifier )
 
 2103          nextAngleAction = currentAngleActionIndex == 0 ? constActions.last() : constActions.at( currentAngleActionIndex - 1 );
 
 2107          nextAngleAction = currentAngleActionIndex == constActions.count() - 1 ? constActions.first() : constActions.at( currentAngleActionIndex + 1 );
 
 2109        nextAngleAction->trigger();
 
 2119  return e->isAccepted();
 
 2128    mAngleLineEdit->setToolTip( tr( 
"Angle constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 2129    mDistanceLineEdit->setToolTip( tr( 
"Distance constraint cannot be used on geographic coordinates. Change the coordinates system in the project properties." ) );
 
 2131    mLabelX->setText( tr( 
"Long" ) );
 
 2132    mLabelY->setText( tr( 
"Lat" ) );
 
 2134    mXConstraint->setPrecision( 8 );
 
 2135    mYConstraint->setPrecision( 8 );
 
 2139    mAngleLineEdit->setToolTip( 
"<b>" + tr( 
"Angle" ) + 
"</b><br>(" + tr( 
"press a for quick access" ) + 
")" );
 
 2140    mAngleLineEdit->setToolTip( QString() );
 
 2142    mDistanceLineEdit->setToolTip( 
"<b>" + tr( 
"Distance" ) + 
"</b><br>(" + tr( 
"press d for quick access" ) + 
")" );
 
 2144    mLabelX->setText( tr( 
"x" ) );
 
 2145    mLabelY->setText( tr( 
"y" ) );
 
 2147    mXConstraint->setPrecision( 6 );
 
 2148    mYConstraint->setPrecision( 6 );
 
 2153  mEnableAction->setEnabled( 
true );
 
 2154  mErrorLabel->hide();
 
 2157  mCurrentMapToolSupportsCad = 
true;
 
 2159  if ( mSessionActive && !isVisible() )
 
 2164  setCadEnabled( mSessionActive );
 
 2166  if ( !mConstructionGuidesLayer )
 
 2168    resetConstructionGuides();
 
 2171  if ( mDeferredUpdateConstructionGuidesCrs )
 
 2173    updateConstructionGuidesCrs();
 
 
 2183  mEnableAction->setEnabled( 
false );
 
 2184  mErrorLabel->setText( tr( 
"Advanced digitizing tools are not enabled for the current map tool" ) );
 
 2185  mErrorLabel->show();
 
 2188  mCurrentMapToolSupportsCad = 
false;
 
 2190  mSnapIndicator->setVisible( 
false );
 
 2192  setCadEnabled( 
false );
 
 
 2197  mCadPaintItem->update();
 
 
 2202  if ( !force && ( mLineExtensionConstraint->isLocked() || mXyVertexConstraint->isLocked() ) )
 
 2207  mLockedSnapVertices.clear();
 
 
 2212  QgsPoint pt = pointXYToPoint( point );
 
 2215    mCadPointList << pt;
 
 2219    mCadPointList.insert( 0, pt );
 
 2228      if ( mConstructionGuideLine.
numPoints() == 2 )
 
 2233        mConstructionGuidesLayer->dataProvider()->addFeature( feature );
 
 2234        mConstructionGuideId = feature.
id();
 
 2236      else if ( mConstructionGuideLine.
numPoints() > 2 )
 
 2239        mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
 
 2244      if ( !mConstructionGuideLine.
isEmpty() )
 
 2249        mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { mConstructionGuideId, geom } } );
 
 2250        mConstructionGuideLine.
clear();
 
 
 2265  mCadPointList.removeAt( i );
 
 
 2272  mCadPointList.clear();
 
 2273  mSnappedSegment.clear();
 
 
 2283    mCadPointList << point;
 
 2288    mCadPointList[0] = point;
 
 
 2295  if ( mode == mLockMode )
 
 2300  mLockerButton->setChecked( mode == 
HardLock );
 
 2301  if ( mRepeatingLockButton )
 
 2305      mRepeatingLockButton->setEnabled( 
true );
 
 2309      mRepeatingLockButton->setChecked( 
false );
 
 2310      mRepeatingLockButton->setEnabled( 
false );
 
 
 2322  mRepeatingLock = repeating;
 
 2323  if ( mRepeatingLockButton )
 
 2324    mRepeatingLockButton->setChecked( repeating );
 
 
 2329  mRelative = relative;
 
 2330  if ( mRelativeButton )
 
 2332    mRelativeButton->setChecked( relative );
 
 
 2339  if ( updateWidget && mLineEdit->isEnabled() )
 
 2340    mLineEdit->setText( displayValue() );
 
 
 2345  switch ( mCadConstraintType )
 
 2349      return QLocale().toString( mValue, 
'f', mPrecision ).append( tr( 
" °" ) );
 
 2356        return QLocale().toString( mValue, 
'f', mPrecision ).append( tr( 
" °" ) );
 
 2360        return QLocale().toString( mValue, 
'f', mPrecision );
 
 2377  return QLocale().toString( mValue, 
'f', mPrecision );
 
 
 2382  setLockMode( mLockMode == HardLock ? NoLock : HardLock );
 
 
 2387  setRelative( !mRelative );
 
 
 2393  if ( mLineEdit->isEnabled() )
 
 2394    mLineEdit->setText( displayValue() );
 
 
 2399  return mCadConstraintType;
 
 
 2404  mCadConstraintType = constraintType;
 
 
 2409  mMapCanvas = mapCanvas;
 
 
 2414  QString value { text.trimmed() };
 
 2415  switch ( constraintType )
 
 2421      if ( value.endsWith( distanceUnit ) )
 
 2423        value.chop( distanceUnit.length() );
 
 2430      const QString angleUnit { tr( 
"°" ) };
 
 2431      if ( value.endsWith( angleUnit ) )
 
 2433        value.chop( angleUnit.length() );
 
 2440  return value.trimmed();
 
 
 2448    return mCadPointList.value( 0 );
 
 
 2457    QgsPoint res = mCadPointList.value( 0 );
 
 2459    res.
setX( layerCoordinates.
x() );
 
 2460    res.
setY( layerCoordinates.
y() );
 
 
 2471    return mCadPointList.value( 1 );
 
 
 2481    return mCadPointList.value( 2 );
 
 
 2486QgsPoint QgsAdvancedDigitizingDockWidget::pointXYToPoint( 
const QgsPointXY &point )
 const 
 2493  return mZLineEdit->isEnabled() ? QLocale().toDouble( mZLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
 
 
 2498  return mMLineEdit->isEnabled() ? QLocale().toDouble( mMLineEdit->text() ) : std::numeric_limits<double>::quiet_NaN();
 
 
 2503  return mShowConstructionGuides ? mShowConstructionGuides->isChecked() : 
false;
 
 
 2508  return mSnapToConstructionGuides ? mShowConstructionGuides->isChecked() && mSnapToConstructionGuides->isChecked() : 
false;
 
 
 2513  return mRecordConstructionGuides ? mRecordConstructionGuides->isChecked() : 
false;
 
 
 2516void QgsAdvancedDigitizingDockWidget::updateConstructionGuidesCrs()
 
 2518  if ( !mConstructionGuidesLayer )
 
 2525    mDeferredUpdateConstructionGuidesCrs = 
true;
 
 2536    mConstructionGuidesLayer->dataProvider()->changeGeometryValues( { { feature.
id(), geom } } );
 
 2539  mDeferredUpdateConstructionGuidesCrs = 
false;
 
 2542void QgsAdvancedDigitizingDockWidget::resetConstructionGuides()
 
 2544  if ( mConstructionGuidesLayer )
 
 2546    mConstructionGuidesLayer.reset();
 
 2550  mConstructionGuidesLayer = std::make_unique<QgsVectorLayer>( QStringLiteral( 
"LineString?crs=%1" ).arg( mMapCanvas->
mapSettings().
destinationCrs().
authid() ), QStringLiteral( 
"constructionGuides" ), QStringLiteral( 
"memory" ), options );
 
DistanceUnit
Units of distance.
 
CadConstraintType
Advanced digitizing constraint type.
 
@ Distance
Distance value.
 
@ YCoordinate
Y Coordinate value.
 
@ XCoordinate
X Coordinate value.
 
@ Group
Composite group layer. Added in QGIS 3.24.
 
@ Plugin
Plugin based layer.
 
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
 
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
 
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
 
@ Mesh
Mesh layer. Added in QGIS 3.2.
 
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
 
@ AllLayers
On all vector layers.
 
BetweenLineConstraint
Between line constraints which can be enabled.
 
@ NoConstraint
No additional constraint.
 
@ Perpendicular
Perpendicular.
 
WkbType
The WKB type describes the number of dimensions a geometry has.
 
Draws the graphical elements of the CAD tools (.
 
void updatePosition() override
called on changed extent or resize event to update position of the item
 
A widget that floats next to the mouse pointer, and allows interaction with the AdvancedDigitizing fe...
 
void setItemVisibility(const QgsAdvancedDigitizingFloater::FloaterItem &item, bool visible)
Set whether the floater item should be visible or not.
 
void setActive(bool active)
Set whether the floater should be active or not.
 
bool active()
Whether the floater is active or not.
 
Structure with details of one constraint.
 
bool locked
Whether the constraint is active, i.e. should be considered.
 
double value
Numeric value of the constraint (coordinate/distance in map units or angle in degrees)
 
bool relative
Whether the value is relative to previous value.
 
Defines constraints for the QgsCadUtils::alignMapPoint() method.
 
QgsCadUtils::AlignMapPointConstraint xyVertexConstraint
 
QgsCadUtils::AlignMapPointConstraint yConstraint
Constraint for Y coordinate.
 
QgsCadUtils::AlignMapPointConstraint xConstraint
Constraint for X coordinate.
 
double mapUnitsPerPixel
Map units/pixel ratio from map canvas.
 
void setCadPoints(const QList< QgsPoint > &points)
Sets the list of recent CAD points (in map coordinates).
 
void setLockedSnapVertices(const QQueue< QgsPointLocator::Match > &lockedSnapVertices)
Sets the queue of locked vertices.
 
QgsCadUtils::AlignMapPointConstraint mConstraint
Constraint for M coordinate.
 
QgsCadUtils::AlignMapPointConstraint distanceConstraint
Constraint for distance.
 
bool snappingToFeaturesOverridesCommonAngle
Flag to set snapping to features priority over common angle.
 
QgsCadUtils::AlignMapPointConstraint zConstraint
Constraint for Z coordinate.
 
QgsSnappingUtils * snappingUtils
Snapping utils that will be used to snap point to map. Must not be nullptr.
 
QgsCadUtils::AlignMapPointConstraint commonAngleConstraint
Constraint for soft lock to a common angle.
 
QgsCadUtils::AlignMapPointConstraint lineExtensionConstraint
 
QgsCadUtils::AlignMapPointConstraint angleConstraint
Constraint for angle.
 
Structure returned from alignMapPoint() method.
 
Qgis::LineExtensionSide softLockLineExtension
 
QgsPointXY finalMapPoint
map point aligned according to the constraints
 
bool valid
Whether the combination of constraints is actually valid.
 
QgsPointLocator::Match snapMatch
Snapped point - only valid if actually used for something.
 
double softLockCommonAngle
Angle (in degrees) to which we have soft-locked ourselves (if not set it is -1)
 
static QgsCadUtils::AlignMapPointOutput alignMapPoint(const QgsPointXY &originalMapPoint, const QgsCadUtils::AlignMapPointContext &ctx)
Applies X/Y/angle/distance constraints from the given context to a map point.
 
static QString formatDistance(double distance, int decimals, Qgis::DistanceUnit unit, bool keepBaseUnit=false)
Returns an distance formatted as a friendly string.
 
Handles parsing and evaluation of expressions (formerly called "search strings").
 
Wrapper for iterator of features from vector data provider or vector layer.
 
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
 
Wraps a request for features to a vector layer (or directly its vector data provider).
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
void setGeometry(const QgsGeometry &geometry)
Set the feature's geometry.
 
An event filter for watching for focus events on a parent object.
 
void focusIn()
Emitted when parent object gains focus.
 
void focusOut()
Emitted when parent object loses focus.
 
A geometry is the spatial representation of a feature.
 
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
 
static QgsGui * instance()
Returns a pointer to the singleton instance.
 
static QgsAdvancedDigitizingToolsRegistry * advancedDigitizingToolsRegistry()
Returns the global advanced digitizing tools registry, used for registering advanced digitizing tools...
 
void clear() override
Clears the geometry, ie reset it to a null geometry.
 
bool isEmpty() const override
Returns true if the geometry is empty.
 
int numPoints() const override
Returns the number of points in the curve.
 
void addVertex(const QgsPoint &pt)
Adds a new vertex to the end of the line string.
 
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
 
Map canvas is a class for displaying all GIS data types on a canvas.
 
QgsMapTool * mapTool() const
Returns the currently active tool.
 
QgsSnappingUtils * snappingUtils() const
Returns snapping utility class that is associated with map canvas.
 
void destinationCrsChanged()
Emitted when map CRS has changed.
 
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
 
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
 
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
 
Base class for all map layer types.
 
A mouse event which is the result of a user interaction with a QgsMapCanvas.
 
QgsPointXY originalMapPoint() const
Returns the original, unmodified map point of the mouse cursor.
 
QgsPointXY mapPoint() const
mapPoint returns the point in coordinates
 
void setMapPoint(const QgsPointXY &point)
Set the (snapped) point this event points to in map coordinates.
 
QgsPointXY snapPoint()
snapPoint will snap the points using the map canvas snapping utils configuration
 
Qgis::DistanceUnit mapUnits() const
Returns the units of the map's geographical coordinates - used for scale calculation.
 
QgsPointXY mapToLayerCoordinates(const QgsMapLayer *layer, QgsPointXY point) const
transform point coordinates from output CRS to layer's CRS
 
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
 
Represents a mesh layer supporting display of data on structured or unstructured meshes.
 
bool isEditable() const override
Returns true if the layer can be edited.
 
A context for numeric formats.
 
Point geometry type, with support for z-dimension and m-values.
 
void setY(double y)
Sets the point's y-coordinate.
 
void setX(double x)
Sets the point's x-coordinate.
 
void setM(double m)
Sets the point's m-value.
 
void setZ(double z)
Sets the point's z-coordinate.
 
double distanceSquared(double x, double y) const
Returns the Cartesian 2D squared distance between this point a specified x, y coordinate.
 
const QgsBearingNumericFormat * bearingFormat() const
Returns the project bearing's format, which controls how bearings associated with the project are dis...
 
Qgis::DistanceUnit distanceUnits
 
static QgsProject * instance()
Returns the QgsProject singleton instance.
 
void snappingConfigChanged(const QgsSnappingConfig &config)
Emitted whenever the configuration for snapping has changed.
 
QgsSnappingConfig snappingConfig
 
void cleared()
Emitted when the project is cleared (and additionally when an open project is cleared just before a n...
 
QgsProjectDisplaySettings * displaySettings
 
QgsCoordinateTransformContext transformContext
 
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
 
bool setValue(const T &value, const QString &dynamicKeyPart=QString()) const
Set settings value.
 
A boolean settings entry.
 
static QgsSettingsTreeNode * sTreeDigitizing
 
Stores settings for use within QGIS.
 
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
 
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
 
Shows a snapping marker on map canvas for the current snapping match.
 
Stores configuration of snapping settings for the project.
 
void setTypeFlag(Qgis::SnappingTypes type)
define the type of snapping
 
void setMode(Qgis::SnappingMode mode)
define the mode of snapping
 
Contains configuration of snapping and can return answers to snapping queries.
 
void addExtraSnapLayer(QgsVectorLayer *vl)
Supply an extra snapping layer (typically a memory layer).
 
void removeExtraSnapLayer(QgsVectorLayer *vl)
Removes an extra snapping layer.
 
QgsPointLocator::Match snapToMap(QPoint point, QgsPointLocator::MatchFilter *filter=nullptr, bool relaxed=false)
Snap to map according to the current configuration.
 
void setConfig(const QgsSnappingConfig &snappingConfig)
The snapping configuration controls the behavior of this object.
 
static Q_INVOKABLE double fromUnitToUnitFactor(Qgis::DistanceUnit fromUnit, Qgis::DistanceUnit toUnit)
Returns the conversion factor between the specified distance units.
 
static Q_INVOKABLE QString toAbbreviatedString(Qgis::DistanceUnit unit)
Returns a translated abbreviation representing a distance unit.
 
Represents a vector layer which manages a vector based dataset.
 
Q_INVOKABLE Qgis::WkbType wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
 
static Q_INVOKABLE bool hasZ(Qgis::WkbType type)
Tests whether a WKB type contains the z-dimension.
 
static Q_INVOKABLE bool hasM(Qgis::WkbType type)
Tests whether a WKB type contains m values.
 
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
 
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
 
double qgsPermissiveToDouble(QString string, bool &ok)
Converts a string to a double in a permissive way, e.g., allowing for incorrect numbers of digits bet...
 
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
 
QSet< QgsFeatureId > QgsFeatureIds
 
QLineF segment(int index, QRectF rect, double radius)
 
QgsVectorLayer * layer() const
The vector layer where the snap occurred.
 
QgsPoint interpolatedPoint(const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem()) const
Convenient method to return a point on an edge with linear interpolation of the Z value.
 
QgsPointXY point() const
for vertex / edge match coords depending on what class returns it (geom.cache: layer coords,...
 
bool hasEdge() const
Returns true if the Match is an edge.
 
void edgePoints(QgsPointXY &pt1, QgsPointXY &pt2) const
Only for a valid edge match - obtain endpoints of the edge.
 
bool hasLineEndpoint() const
Returns true if the Match is a line endpoint (start or end vertex).
 
bool hasVertex() const
Returns true if the Match is a vertex.
 
Setting options for loading vector layers.