QGIS API Documentation  3.6.0-Noosa (5873452)
qgsadvanceddigitizingcanvasitem.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsadvanceddigitizingcanvasitem.cpp - map canvas item for CAD tools
3  ----------------------
4  begin : October 2014
5  copyright : (C) Denis Rouzaud
6  email : [email protected]
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QPainter>
17 
20 #include "qgsmapcanvas.h"
21 
22 
24  : QgsMapCanvasItem( canvas )
25  , mLockedPen( QPen( QColor( 0, 127, 0, 255 ), 1, Qt::DashLine ) )
26  , mConstruction1Pen( QPen( QColor( 127, 127, 127, 150 ), 1, Qt::DashLine ) )
27  , mConstruction2Pen( QPen( QColor( 127, 127, 127, 255 ), 1, Qt::DashLine ) )
28  , mSnapPen( QPen( QColor( 127, 0, 0, 150 ), 1 ) )
29  , mSnapLinePen( QPen( QColor( 127, 0, 0, 150 ), 1, Qt::DashLine ) )
30  , mCursorPen( QPen( QColor( 127, 127, 127, 255 ), 1 ) )
31  , mSnapIndicator( qgis::make_unique< QgsSnapIndicator>( canvas ) )
32  , mAdvancedDigitizingDockWidget( cadDockWidget )
33 {
34 }
35 
36 void QgsAdvancedDigitizingCanvasItem::paint( QPainter *painter )
37 {
38  if ( !mAdvancedDigitizingDockWidget->cadEnabled() )
39  return;
40 
41  QgsRectangle mapRect = mMapCanvas->extent();
42  if ( rect() != mapRect )
43  setRect( mapRect );
44 
45  int nPoints = mAdvancedDigitizingDockWidget->pointsCount();
46  if ( !nPoints )
47  return;
48 
49  bool previousPointExist, penulPointExist;
50  const QgsPointXY curPoint = mAdvancedDigitizingDockWidget->currentPoint();
51  const QgsPointXY prevPoint = mAdvancedDigitizingDockWidget->previousPoint( &previousPointExist );
52  const QgsPointXY penulPoint = mAdvancedDigitizingDockWidget->penultimatePoint( &penulPointExist );
53  const bool snappedToVertex = mAdvancedDigitizingDockWidget->snappedToVertex();
54  const QList<QgsPointXY> snappedSegment = mAdvancedDigitizingDockWidget->snappedSegment();
55  const bool hasSnappedSegment = snappedSegment.count() == 2;
56 
57  const bool curPointExist = mapRect.contains( curPoint );
58 
59  const double mupp = mMapCanvas->getCoordinateTransform()->mapUnitsPerPixel();
60  if ( mupp == 0 )
61  return;
62 
63  QPointF curPointPix, prevPointPix, penulPointPix, snapSegmentPix1, snapSegmentPix2;
64 
65  if ( curPointExist )
66  {
67  curPointPix = toCanvasCoordinates( curPoint );
68  }
69  if ( previousPointExist )
70  {
71  prevPointPix = toCanvasCoordinates( prevPoint );
72  }
73  if ( penulPointExist )
74  {
75  penulPointPix = toCanvasCoordinates( penulPoint );
76  }
77  if ( hasSnappedSegment )
78  {
79  snapSegmentPix1 = toCanvasCoordinates( snappedSegment[0] );
80  snapSegmentPix2 = toCanvasCoordinates( snappedSegment[1] );
81  }
82 
83  painter->setRenderHint( QPainter::Antialiasing );
84  painter->setCompositionMode( QPainter::CompositionMode_Difference );
85 
86  // Draw point snap
87  if ( curPointExist && snappedToVertex )
88  {
89  painter->setPen( mSnapPen );
90  painter->drawEllipse( curPointPix, 10, 10 );
91  }
92 
93  // Draw segment snap
94  if ( hasSnappedSegment && !snappedToVertex )
95  {
96  painter->setPen( mSnapPen );
97  painter->drawLine( snapSegmentPix1, snapSegmentPix2 );
98 
99  if ( curPointExist )
100  {
101  painter->setPen( mSnapLinePen );
102  painter->drawLine( snapSegmentPix1, curPointPix );
103  }
104  }
105 
106  // Draw segment par/per input
107  if ( mAdvancedDigitizingDockWidget->additionalConstraint() != QgsAdvancedDigitizingDockWidget::NoConstraint && hasSnappedSegment )
108  {
109  painter->setPen( mConstruction2Pen );
110  painter->drawLine( snapSegmentPix1, snapSegmentPix2 );
111  }
112 
113  // Draw angle
114  if ( nPoints > 1 )
115  {
116  double a0, a;
117  if ( mAdvancedDigitizingDockWidget->constraintAngle()->relative() && nPoints > 2 )
118  {
119  a0 = std::atan2( -( prevPoint.y() - penulPoint.y() ), prevPoint.x() - penulPoint.x() );
120  }
121  else
122  {
123  a0 = 0;
124  }
125  if ( mAdvancedDigitizingDockWidget->constraintAngle()->isLocked() )
126  {
127  a = a0 - mAdvancedDigitizingDockWidget->constraintAngle()->value() * M_PI / 180;
128  }
129  else
130  {
131  a = std::atan2( -( curPoint.y() - prevPoint.y() ), curPoint.x() - prevPoint.x() );
132  }
133  painter->setPen( mConstruction2Pen );
134  painter->drawArc( QRectF( prevPointPix.x() - 20,
135  prevPointPix.y() - 20,
136  40, 40 ),
137  static_cast<int>( 16 * -a0 * 180 / M_PI ),
138  static_cast<int>( 16 * ( a0 - a ) * 180 / M_PI ) );
139  painter->drawLine( prevPointPix,
140  prevPointPix + 60 * QPointF( std::cos( a0 ), std::sin( a0 ) ) );
141 
142 
143  if ( mAdvancedDigitizingDockWidget->constraintAngle()->isLocked() )
144  {
145  painter->setPen( mLockedPen );
146  double d = std::max( boundingRect().width(), boundingRect().height() );
147  painter->drawLine( prevPointPix - d * QPointF( std::cos( a ), std::sin( a ) ),
148  prevPointPix + d * QPointF( std::cos( a ), std::sin( a ) ) );
149  }
150  }
151 
152  // Draw distance
153  if ( nPoints > 1 && mAdvancedDigitizingDockWidget->constraintDistance()->isLocked() )
154  {
155  painter->setPen( mLockedPen );
156  double r = mAdvancedDigitizingDockWidget->constraintDistance()->value() / mupp;
157  painter->drawEllipse( prevPointPix, r, r );
158  }
159 
160  // Draw x
161  if ( mAdvancedDigitizingDockWidget->constraintX()->isLocked() )
162  {
163  double x = 0.0;
164  bool draw = true;
165  painter->setPen( mLockedPen );
166  if ( mAdvancedDigitizingDockWidget->constraintX()->relative() )
167  {
168  if ( nPoints > 1 )
169  {
170  x = mAdvancedDigitizingDockWidget->constraintX()->value() / mupp + prevPointPix.x();
171  }
172  else
173  {
174  draw = false;
175  }
176  }
177  else
178  {
179  x = toCanvasCoordinates( QgsPointXY( mAdvancedDigitizingDockWidget->constraintX()->value(), 0 ) ).x();
180  }
181  if ( draw )
182  {
183  painter->drawLine( QPointF( x, 0 ),
184  QPointF( x, boundingRect().height() ) );
185  }
186  }
187 
188  // Draw y
189  if ( mAdvancedDigitizingDockWidget->constraintY()->isLocked() )
190  {
191  double y = 0.0;
192  bool draw = true;
193  painter->setPen( mLockedPen );
194  if ( mAdvancedDigitizingDockWidget->constraintY()->relative() )
195  {
196  if ( nPoints > 1 )
197  {
198  // y is reversed!
199  y = -mAdvancedDigitizingDockWidget->constraintY()->value() / mupp + prevPointPix.y();
200  }
201  else
202  {
203  draw = false;
204  }
205  }
206  else
207  {
208  y = toCanvasCoordinates( QgsPointXY( 0, mAdvancedDigitizingDockWidget->constraintY()->value() ) ).y();
209  }
210  if ( draw )
211  {
212  painter->drawLine( QPointF( 0, y ),
213  QPointF( boundingRect().width(), y ) );
214  }
215  }
216 
217  // Draw constr
218  if ( mAdvancedDigitizingDockWidget->additionalConstraint() == QgsAdvancedDigitizingDockWidget::NoConstraint )
219  {
220  if ( curPointExist && previousPointExist )
221  {
222  painter->setPen( mConstruction2Pen );
223  painter->drawLine( prevPointPix, curPointPix );
224  }
225 
226  if ( previousPointExist && penulPointExist )
227  {
228  painter->setPen( mConstruction1Pen );
229  painter->drawLine( penulPointPix, prevPointPix );
230  }
231  }
232 
233  if ( curPointExist )
234  {
235  painter->setPen( mCursorPen );
236  painter->drawLine( curPointPix + QPointF( -5, -5 ),
237  curPointPix + QPointF( +5, +5 ) );
238  painter->drawLine( curPointPix + QPointF( -5, +5 ),
239  curPointPix + QPointF( +5, -5 ) );
240  }
241 
242 
243  QgsPointLocator::Match match = mAdvancedDigitizingDockWidget->mapPointMatch();
244  if ( match.isValid() )
245  {
246  mSnapIndicator->setMatch( match );
247  mSnapIndicator->setVisible( true );
248  }
249  else
250  mSnapIndicator->setVisible( false );
251 
252 }
int pointsCount() const
The number of points in the CAD point helper list.
bool cadEnabled() const
determines if CAD tools are enabled or if map tools behaves "nomally"
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
Definition: qgsrectangle.h:342
A rectangle specified with double values.
Definition: qgsrectangle.h:41
const CadConstraint * constraintY() const
Returns the CadConstraint on the Y coordinate.
QgsRectangle rect() const
returns canvas item rectangle in map units
QgsPointLocator::Match mapPointMatch() const
Returns the point locator match.
QgsPointXY previousPoint(bool *exists=nullptr) const
The previous point.
const CadConstraint * constraintAngle() const
Returns the CadConstraint on the angle.
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
An abstract class for items that can be placed on the map canvas.
void paint(QPainter *painter) override
function to be implemented by derived classes
QgsPointXY currentPoint(bool *exists=nullptr) const
The last point.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:73
QList< QgsPointXY > snappedSegment() const
Snapped to a segment.
QRectF boundingRect() const override
double value() const
The value of the constraint.
QgsPointXY penultimatePoint(bool *exists=nullptr) const
The penultimate point.
bool isLocked() const
Is any kind of lock mode enabled.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
void setRect(const QgsRectangle &r, bool resetRotation=true)
sets canvas item rectangle in map units
const CadConstraint * constraintX() const
Returns the CadConstraint on the X coordinate.
AdditionalConstraint additionalConstraint() const
Returns the additional constraints which are used to place perpendicular/parallel segments to snapped...
double mapUnitsPerPixel() const
Returns current map units per pixel.
double x
Definition: qgspointxy.h:47
const CadConstraint * constraintDistance() const
Returns the CadConstraint on the distance.
bool relative() const
Is the constraint in relative mode.
QgsAdvancedDigitizingCanvasItem(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)
QgsMapCanvas * mMapCanvas
pointer to map canvas
bool snappedToVertex() const
Is it snapped to a vertex.
Class that shows snapping marker on map canvas for the current snapping match.
const QgsMapToPixel * getCoordinateTransform()
Gets the current coordinate transform.
std::unique_ptr< QgsSnapIndicator > mSnapIndicator
Snapping indicators.
QPointF toCanvasCoordinates(const QgsPointXY &point) const
transformation from map coordinates to screen coordinates
The QgsAdvancedDigitizingDockWidget class is a dockable widget used to handle the CAD tools on top of...