40 Q_ASSERT( segment.
count() == 2 );
44 const double x1 = segment[0].x() - center.
x();
45 const double y1 = segment[0].y() - center.
y();
46 const double x2 = segment[1].x() - center.
x();
47 const double y2 = segment[1].y() - center.
y();
48 const double dx = x2 - x1;
49 const double dy = y2 - y1;
51 const double dr = sqrt( pow( dx, 2 ) + pow( dy, 2 ) );
52 const double d = x1 * y2 - x2 * y1;
54 const double disc = pow( radius, 2 ) * pow( dr, 2 ) - pow( d, 2 );
64 const int sgnDy = dy < 0 ? -1 : 1;
66 const double ax = center.
x() + ( d * dy + sgnDy * dx * sqrt( pow( radius, 2 ) * pow( dr, 2 ) - pow( d, 2 ) ) ) / ( pow( dr, 2 ) );
67 const double ay = center.
y() + ( -d * dx + qAbs( dy ) * sqrt( pow( radius, 2 ) * pow( dr, 2 ) - pow( d, 2 ) ) ) / ( pow( dr, 2 ) );
70 const double bx = center.
x() + ( d * dy - sgnDy * dx * sqrt( pow( radius, 2 ) * pow( dr, 2 ) - pow( d, 2 ) ) ) / ( pow( dr, 2 ) );
71 const double by = center.
y() + ( -d * dx - qAbs( dy ) * sqrt( pow( radius, 2 ) * pow( dr, 2 ) - pow( d, 2 ) ) ) / ( pow( dr, 2 ) );
78 intersection.
set( p1.
x(), p1.
y() );
82 intersection.
set( p2.
x(), p2.
y() );
91 , mMapCanvas( canvas )
92 , mCurrentMapToolSupportsCad( false )
93 , mCadEnabled( false )
94 , mConstructionMode( false )
96 , mCommonAngleConstraint(
QSettings().value(
"/Cad/CommonAngle", 90 ).toInt() )
97 , mSnappedToVertex( false )
98 , mSessionActive( false )
105 mAngleConstraint =
new CadConstraint( mAngleLineEdit, mLockAngleButton, mRelativeAngleButton );
106 mDistanceConstraint =
new CadConstraint( mDistanceLineEdit, mLockDistanceButton ) ;
107 mXConstraint =
new CadConstraint( mXLineEdit, mLockXButton, mRelativeXButton );
108 mYConstraint =
new CadConstraint( mYLineEdit, mLockYButton, mRelativeYButton ) ;
112 mAngleLineEdit->installEventFilter(
this );
113 mDistanceLineEdit->installEventFilter(
this );
114 mXLineEdit->installEventFilter(
this );
115 mYLineEdit->installEventFilter(
this );
118 mEnableAction =
new QAction(
this );
119 mEnableAction->
setText(
tr(
"Enable advanced digitizing tools" ) );
122 mEnabledButton->addAction( mEnableAction );
123 mEnabledButton->setDefaultAction( mEnableAction );
126 connect( mEnableAction, SIGNAL( triggered(
bool ) ),
this, SLOT( activateCad(
bool ) ) );
127 connect( mConstructionModeButton, SIGNAL( clicked(
bool ) ),
this, SLOT( setConstructionMode(
bool ) ) );
128 connect( mParallelButton, SIGNAL( clicked(
bool ) ),
this, SLOT( addtionalConstraintClicked(
bool ) ) );
129 connect( mPerpendicularButton, SIGNAL( clicked(
bool ) ),
this, SLOT( addtionalConstraintClicked(
bool ) ) );
130 connect( mLockAngleButton, SIGNAL( clicked(
bool ) ),
this, SLOT( lockConstraint(
bool ) ) );
131 connect( mLockDistanceButton, SIGNAL( clicked(
bool ) ),
this, SLOT( lockConstraint(
bool ) ) );
132 connect( mLockXButton, SIGNAL( clicked(
bool ) ),
this, SLOT( lockConstraint(
bool ) ) );
133 connect( mLockYButton, SIGNAL( clicked(
bool ) ),
this, SLOT( lockConstraint(
bool ) ) );
134 connect( mRelativeAngleButton, SIGNAL( clicked(
bool ) ),
this, SLOT( setConstraintRelative(
bool ) ) );
135 connect( mRelativeXButton, SIGNAL( clicked(
bool ) ),
this, SLOT( setConstraintRelative(
bool ) ) );
136 connect( mRelativeYButton, SIGNAL( clicked(
bool ) ),
this, SLOT( setConstraintRelative(
bool ) ) );
137 connect( mAngleLineEdit, SIGNAL( returnPressed() ),
this, SLOT( lockConstraint() ) );
138 connect( mDistanceLineEdit, SIGNAL( returnPressed() ),
this, SLOT( lockConstraint() ) );
139 connect( mXLineEdit, SIGNAL( returnPressed() ),
this, SLOT( lockConstraint() ) );
140 connect( mYLineEdit, SIGNAL( returnPressed() ),
this, SLOT( lockConstraint() ) );
148 commonAngles << QPair<int, QString>( 0,
tr(
"Do not snap to common angles" ) );
156 action->
setChecked( it->first == mCommonAngleConstraint );
159 mCommonAngleActions.
insert( action, it->first );
173 action->
setChecked( it->first == mSnappingMode );
176 mSnappingActions.
insert( action, it->first );
179 mSettingsButton->setMenu( menu );
180 connect( mSettingsButton, SIGNAL( triggered(
QAction* ) ),
this, SLOT( settingsButtonTriggered(
QAction* ) ) );
182 updateCapacity(
true );
189 setCadEnabled(
false );
192 void QgsAdvancedDigitizingDockWidget::setCadEnabled(
bool enabled )
196 mCadButtons->setEnabled( enabled );
197 mInputWidgets->setEnabled( enabled );
201 setConstructionMode(
false );
204 void QgsAdvancedDigitizingDockWidget::activateCad(
bool enabled )
206 enabled &= mCurrentMapToolSupportsCad;
215 setCadEnabled( enabled );
218 void QgsAdvancedDigitizingDockWidget::addtionalConstraintClicked(
bool activated )
224 if (
sender() == mParallelButton )
226 lockAdditionalConstraint(
Parallel );
228 else if (
sender() == mPerpendicularButton )
235 void QgsAdvancedDigitizingDockWidget::setConstraintRelative(
bool activate )
237 if (
sender() == mRelativeAngleButton )
241 else if (
sender() == mRelativeXButton )
245 else if (
sender() == mRelativeYButton )
251 void QgsAdvancedDigitizingDockWidget::setConstructionMode(
bool enabled )
254 mConstructionModeButton->setChecked( enabled );
257 void QgsAdvancedDigitizingDockWidget::settingsButtonTriggered(
QAction* action )
261 if ( isn != mSnappingActions.
end() )
263 isn.
key()->setChecked(
true );
264 mSnappingMode = isn.
value();
271 if ( ica != mCommonAngleActions.
end() )
273 ica.
key()->setChecked(
true );
274 mCommonAngleConstraint = ica.
value();
280 void QgsAdvancedDigitizingDockWidget::releaseLocks()
293 void QgsAdvancedDigitizingDockWidget::emit pointChanged()
296 QPoint globalPos = mMapCanvas->cursor().pos();
297 QPoint pos = mMapCanvas->mapFromGlobal( globalPos );
298 QMouseEvent* e =
new QMouseEvent( QEvent::MouseMove, pos, globalPos, Qt::NoButton, Qt::NoButton, Qt::NoModifier );
299 mCurrentMapTool->canvasMoveEvent( e );
303 void QgsAdvancedDigitizingDockWidget::lockConstraint(
bool activate )
306 CadConstraint* constraint = NULL;
307 if ( obj == mAngleLineEdit || obj == mLockAngleButton )
309 constraint = mAngleConstraint;
311 else if ( obj == mDistanceLineEdit || obj == mLockDistanceButton )
313 constraint = mDistanceConstraint;
315 else if ( obj == mXLineEdit || obj == mLockXButton )
317 constraint = mXConstraint;
319 else if ( obj == mYLineEdit || obj == mLockYButton )
321 constraint = mYConstraint;
330 QString textValue = constraint->lineEdit()->text();
332 double value = textValue.
toDouble( &ok );
337 constraint->setValue( value );
345 if ( expr.hasEvalError() || !ok )
351 constraint->setValue( value );
365 if ( constraint == mAngleConstraint )
375 void QgsAdvancedDigitizingDockWidget::lockAdditionalConstraint( AdditionalConstraint constraint )
377 mAdditionalConstraint = constraint;
378 mPerpendicularButton->setChecked( constraint ==
Perpendicular );
379 mParallelButton->setChecked( constraint ==
Parallel );
382 void QgsAdvancedDigitizingDockWidget::updateCapacity(
bool updateUIwithoutChange )
384 CadCapacities newCapacities = 0;
386 if ( mCadPointList.
count() > 1 )
390 if ( mCadPointList.
count() > 2 )
394 if ( !updateUIwithoutChange && newCapacities == mCapacities )
402 bool relativeAngle = mCadEnabled && newCapacities.testFlag(
RelativeAngle );
403 bool absoluteAngle = mCadEnabled && newCapacities.testFlag(
AbsoluteAngle );
406 mPerpendicularButton->setEnabled( absoluteAngle );
407 mParallelButton->setEnabled( absoluteAngle );
408 if ( !absoluteAngle )
414 mLockAngleButton->setEnabled( absoluteAngle );
415 mRelativeAngleButton->setEnabled( relativeAngle );
416 mAngleLineEdit->setEnabled( absoluteAngle );
417 if ( !absoluteAngle )
419 mAngleConstraint->
setLockMode( CadConstraint::NoLock );
421 if ( !relativeAngle )
425 else if ( relativeAngle && !mCapacities.testFlag(
RelativeAngle ) )
432 mLockDistanceButton->setEnabled( relativeCoordinates );
433 mDistanceLineEdit->setEnabled( relativeCoordinates );
434 if ( !relativeCoordinates )
436 mDistanceConstraint->
setLockMode( CadConstraint::NoLock );
439 mRelativeXButton->setEnabled( relativeCoordinates );
440 mRelativeYButton->setEnabled( relativeCoordinates );
443 mCapacities = newCapacities;
451 QgsDebugMsg(
"Constraints (locked / relative / value" );
461 bool previousPointExist, penulPointExist;
475 point.
setX( previousPt.
x() + mXConstraint->
value() );
480 const double dx = mSnappedSegment[1].x() - mSnappedSegment[0].x();
483 point.
setY( mSnappedSegment[0].
y() );
487 const double dy = mSnappedSegment[1].y() - mSnappedSegment[0].y();
488 point.
setY( mSnappedSegment[0].
y() + ( dy * ( point.
x() - mSnappedSegment[0].x() ) ) / dx );
502 point.
setY( previousPt.
y() + mYConstraint->
value() );
507 const double dy = mSnappedSegment[1].y() - mSnappedSegment[0].y();
510 point.
setX( mSnappedSegment[0].
x() );
514 const double dx = mSnappedSegment[1].x() - mSnappedSegment[0].x();
515 point.
setX( mSnappedSegment[0].
x() + ( dx * ( point.
y() - mSnappedSegment[0].y() ) ) / dy );
525 mAngleConstraint->
setLockMode( CadConstraint::NoLock );
527 if ( !mAngleConstraint->
isLocked() && mCapacities.testFlag(
AbsoluteAngle ) && mCommonAngleConstraint != 0 )
529 double commonAngle = mCommonAngleConstraint *
M_PI / 180;
532 double softAngle = qAtan2( point.
y() - previousPt.
y(),
533 point.
x() - previousPt.
x() );
534 double deltaAngle = 0;
538 deltaAngle = qAtan2( previousPt.
y() - penultimatePt.
y(),
539 previousPt.
x() - penultimatePt.
x() );
540 softAngle -= deltaAngle;
542 int quo = qRound( softAngle / commonAngle );
546 softAngle = quo * commonAngle ;
549 const double dist = qAbs( qCos( softAngle + deltaAngle ) * ( previousPt.
y() - point.
y() )
550 - qSin( softAngle + deltaAngle ) * ( previousPt.
x() - point.
x() ) );
560 double angleValue = mAngleConstraint->
value() *
M_PI / 180;
564 angleValue += qAtan2( previousPt.
y() - penultimatePt.
y(),
565 previousPt.
x() - penultimatePt.
x() );
568 double cosa = qCos( angleValue );
569 double sina = qSin( angleValue );
570 double v = ( point.
x() - previousPt.
x() ) * cosa + ( point.
y() - previousPt.
y() ) * sina ;
575 else if ( mXConstraint->
isLocked() )
583 double x = mXConstraint->
value();
588 point.
setY( previousPt.
y() + x * sina / cosa );
591 else if ( mYConstraint->
isLocked() )
599 double y = mYConstraint->
value();
604 point.
setX( previousPt.
x() + y * cosa / sina );
609 point.
setX( previousPt.
x() + cosa * v );
610 point.
setY( previousPt.
y() + sina * v );
618 const double x1 = previousPt.
x();
619 const double y1 = previousPt.
y();
620 const double x2 = previousPt.
x() + cosa;
621 const double y2 = previousPt.
y() + sina;
623 const double x3 = mSnappedSegment[0].x();
624 const double y3 = mSnappedSegment[0].y();
625 const double x4 = mSnappedSegment[1].x();
626 const double y4 = mSnappedSegment[1].y();
628 const double d = ( x1 - x2 ) * ( y3 - y4 ) - ( y1 - y2 ) * ( x3 - x4 );
632 if ( qAbs( d ) > 0.01 )
634 point.
setX((( x3 - x4 )*( x1*y2 - y1*x2 ) - ( x1 - x2 )*( x3*y4 - y3*x4 ) ) / d );
635 point.
setY((( y3 - y4 )*( x1*y2 - y1*x2 ) - ( y1 - y2 )*( x3*y4 - y3*x4 ) ) / d );
641 if ( mDistanceConstraint->
isLocked() && previousPointExist )
663 const double dist = sqrt( point.
sqrDist( previousPt ) );
668 point.
set( previousPt.
x() + mDistanceConstraint->
value(), previousPt.
y() );
672 const double vP = mDistanceConstraint->
value() / dist;
673 point.
set( previousPt.
x() + ( point.
x() - previousPt.
x() ) * vP,
674 previousPt.
y() + ( point.
y() - previousPt.
y() ) * vP );
689 QgsDebugMsg(
QString(
"penultimate point: %1 %2" ).arg( penultimatePt.
x() ).arg( penultimatePt.
y() ) );
697 updateCurrentPoint( point );
702 if ( !mAngleConstraint->
isLocked() && previousPointExist )
705 if ( penulPointExist && mAngleConstraint->
relative() )
708 angle = qAtan2( previousPt.
y() - penultimatePt.
y(),
709 previousPt.
x() - penultimatePt.
x() );
711 angle = ( qAtan2( point.
y() - previousPt.
y(),
712 point.
x() - previousPt.
x()
713 ) - angle ) * 180 /
M_PI;
715 angle = fmod( angle, 360.0 );
716 mAngleConstraint->
setValue( angle );
719 if ( !mDistanceConstraint->
isLocked() && previousPointExist )
726 if ( previousPointExist && mXConstraint->
relative() )
728 mXConstraint->
setValue( point.
x() - previousPt.
x() );
738 if ( previousPointExist && mYConstraint->
relative() )
740 mYConstraint->
setValue( point.
y() - previousPt.
y() );
752 bool QgsAdvancedDigitizingDockWidget::alignToSegment(
QgsMapMouseEvent* e, CadConstraint::LockMode lockMode )
759 bool previousPointExist, penulPointExist, mSnappedSegmentExist;
764 if ( !previousPointExist || !mSnappedSegmentExist )
769 double angle = qAtan2( mSnappedSegment[0].
y() - mSnappedSegment[1].
y(), mSnappedSegment[0].
x() - mSnappedSegment[1].
x() );
771 if ( mAngleConstraint->
relative() && penulPointExist )
773 angle -= qAtan2( previousPt.
y() - penultimatePt.
y(), previousPt.
x() - penultimatePt.
x() );
783 mAngleConstraint->
setValue( angle );
796 return mCadEnabled && mConstructionMode;
806 if ( e->
button() == Qt::RightButton )
815 if ( alignToSegment( e ) )
829 if ( e->
button() == Qt::LeftButton )
832 if ( !mConstructionMode && !captureSegment )
837 return mConstructionMode;
847 emit
pushWarning(
tr(
"Some constraints are incompatible. Resulting point might be incorrect." ) );
871 case Qt::Key_Backspace:
874 removePreviousPoint();
908 case Qt::Key_Backspace:
911 removePreviousPoint();
928 bool QgsAdvancedDigitizingDockWidget::eventFilter(
QObject* obj,
QEvent* event )
932 if ( event->
type() != QEvent::KeyPress )
941 return filterKeyPress( keyEvent ) ;
944 bool QgsAdvancedDigitizingDockWidget::filterKeyPress(
QKeyEvent* e )
955 else if ( e->
modifiers() == Qt::ShiftModifier )
965 mXLineEdit->setFocus();
966 mXLineEdit->selectAll();
977 else if ( e->
modifiers() == Qt::ShiftModifier )
987 mYLineEdit->setFocus();
988 mYLineEdit->selectAll();
1002 else if ( e->
modifiers() == Qt::ShiftModifier )
1012 mAngleLineEdit->setFocus();
1013 mAngleLineEdit->selectAll();
1029 mDistanceLineEdit->setFocus();
1030 mDistanceLineEdit->selectAll();
1036 setConstructionMode( !mConstructionMode );
1041 bool parallel = mParallelButton->isChecked();
1042 bool perpendicular = mPerpendicularButton->isChecked();
1044 if ( !parallel && !perpendicular )
1048 else if ( perpendicular )
1050 lockAdditionalConstraint(
Parallel );
1070 mErrorLabel->setText(
tr(
"CAD tools can not be used on geographic coordinates. Change the coordinates system in the project properties." ) );
1071 mErrorLabel->show();
1073 setCadEnabled(
false );
1078 mErrorLabel->hide();
1082 mCurrentMapToolSupportsCad =
true;
1088 setCadEnabled( mSessionActive );
1095 mErrorLabel->setText(
tr(
"CAD tools are not enabled for the current map tool" ) );
1096 mErrorLabel->show();
1100 mCurrentMapToolSupportsCad =
false;
1102 setCadEnabled(
false );
1105 void QgsAdvancedDigitizingDockWidget::addPoint(
const QgsPoint& point )
1109 mCadPointList << point;
1113 mCadPointList.
insert( 0, point );
1119 void QgsAdvancedDigitizingDockWidget::removePreviousPoint()
1129 void QgsAdvancedDigitizingDockWidget::clearPoints()
1131 mCadPointList.
clear();
1132 mSnappedSegment.
clear();
1133 mSnappedToVertex =
false;
1138 void QgsAdvancedDigitizingDockWidget::updateCurrentPoint(
const QgsPoint& point )
1142 mCadPointList << point;
1147 mCadPointList[0] = point ;
1165 mRelative = relative;
1166 if ( mRelativeButton )
1168 mRelativeButton->setChecked( relative );
1180 setLockMode( mLockMode == HardLock ? NoLock : HardLock );
1185 setRelative( mRelative ?
false :
true );
1193 return mCadPointList.
value( 0 );
1203 return mCadPointList.
value( 1 );
1213 return mCadPointList.
value( 2 );
void setText(const QString &text)
Class for parsing and evaluation of expressions (formerly called "search strings").
Qt::KeyboardModifiers modifiers() const
QgsPoint mapPoint() const
mapPoint returns the point in coordinates
snap to all rendered layers (tolerance and type from defaultSettings())
bool acceptMatch(const QgsPointLocator::Match &m) override
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
void setIcon(const QIcon &icon)
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
QAction * addAction(QAction *action)
Interface that allows rejection of some matches in intersection queries (e.g.
double toDouble(bool *ok) const
double sqrDist(double x, double y) const
Returns the squared distance between this point and x,y.
QString tr(const char *sourceText, const char *disambiguation, int n)
Map canvas is a class for displaying all GIS data types on a canvas.
void update(const QRectF &rect)
double x() const
Get the x value of the point.
void setValue(const QString &key, const QVariant &value)
QString number(int n, int base)
int count(const T &value) const
snap according to the configuration set in the snapping settings
QString fromUtf8(const char *str, int size)
void installEventFilter(QObject *filterObj)
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
double mapUnitsPerPixel() const
Return the distance in geographical coordinates that equals to one pixel in the map.
void set(double x, double y)
Sets the x and y value of the point.
A class to represent a point.
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
void setX(double x)
Sets the x value of the point.
void setMapPoint(const QgsPoint &point)
Set the (snapped) point this event points to in map coordinates.
void setY(double y)
Sets the y value of the point.
const Key key(const T &value) const
QList< QgsPoint > snapSegment(SnappingMode snappingMode, bool *snapped=0, bool allLayers=false) const
Returns the first snapped segment.
void insert(int i, const T &value)
double y() const
Get the y value of the point.
double toDouble(bool *ok) const
iterator insert(const Key &key, const T &value)
QgsPoint snapPoint(SnappingMode snappingMode)
snapPoint will snap the points using the map canvas snapping utils configuration
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool geographicFlag() const
Get this Geographic? flag.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
iterator find(const Key &key)
The QgsAdvancedDigitizingCanvasItem class draws the graphical elements of the CAD tools (...
const T value(const Key &key) const