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