QGIS API Documentation  3.13.0-Master (740be229cb)
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  , mAdvancedDigitizingDockWidget( cadDockWidget )
32 {
33 }
34 
35 void QgsAdvancedDigitizingCanvasItem::paint( QPainter *painter )
36 {
37  if ( !mAdvancedDigitizingDockWidget->cadEnabled() )
38  return;
39 
40  // Use visible polygon rather than extent to properly handle rotated maps
41  QPolygonF mapPoly = mMapCanvas->mapSettings().visiblePolygon();
42  double canvasWidth = QLineF( mapPoly[0], mapPoly[1] ).length();
43  double canvasHeight = QLineF( mapPoly[0], mapPoly[3] ).length();
44  QgsRectangle mapRect = QgsRectangle( mapPoly[0],
45  QgsPointXY(
46  mapPoly[0].x() + canvasWidth,
47  mapPoly[0].y() - canvasHeight
48  )
49  );
50  if ( rect() != mapRect )
51  setRect( mapRect );
52 
53  int nPoints = mAdvancedDigitizingDockWidget->pointsCount();
54  if ( !nPoints )
55  return;
56 
57  bool previousPointExist, penulPointExist;
58  const QgsPointXY curPoint = mAdvancedDigitizingDockWidget->currentPoint();
59  const QgsPointXY prevPoint = mAdvancedDigitizingDockWidget->previousPoint( &previousPointExist );
60  const QgsPointXY penulPoint = mAdvancedDigitizingDockWidget->penultimatePoint( &penulPointExist );
61  const bool snappedToVertex = mAdvancedDigitizingDockWidget->snappedToVertex();
62  const QList<QgsPointXY> snappedSegment = mAdvancedDigitizingDockWidget->snappedSegment();
63  const bool hasSnappedSegment = snappedSegment.count() == 2;
64 
65  const bool curPointExist = mapPoly.containsPoint( curPoint.toQPointF(), Qt::OddEvenFill );
66 
67  const double mupp = mMapCanvas->getCoordinateTransform()->mapUnitsPerPixel();
68  if ( mupp == 0 )
69  return;
70 
71  const double canvasRotationRad = mMapCanvas->rotation() * M_PI / 180;
72  const double canvasMaxDimension = std::max( canvasWidth / mupp, canvasHeight / mupp );
73 
74  QPointF curPointPix, prevPointPix, penulPointPix, snapSegmentPix1, snapSegmentPix2;
75 
76  if ( curPointExist )
77  {
78  curPointPix = toCanvasCoordinates( curPoint );
79  }
80  if ( previousPointExist )
81  {
82  prevPointPix = toCanvasCoordinates( prevPoint );
83  }
84  if ( penulPointExist )
85  {
86  penulPointPix = toCanvasCoordinates( penulPoint );
87  }
88  if ( hasSnappedSegment )
89  {
90  snapSegmentPix1 = toCanvasCoordinates( snappedSegment[0] );
91  snapSegmentPix2 = toCanvasCoordinates( snappedSegment[1] );
92  }
93 
94  painter->setRenderHint( QPainter::Antialiasing );
95  painter->setCompositionMode( QPainter::CompositionMode_Difference );
96 
97  // Draw point snap
98  if ( curPointExist && snappedToVertex )
99  {
100  painter->setPen( mSnapPen );
101  painter->drawEllipse( curPointPix, 10, 10 );
102  }
103 
104  // Draw segment snap
105  if ( hasSnappedSegment && !snappedToVertex )
106  {
107  painter->setPen( mSnapPen );
108  painter->drawLine( snapSegmentPix1, snapSegmentPix2 );
109 
110  if ( curPointExist )
111  {
112  painter->setPen( mSnapLinePen );
113  painter->drawLine( snapSegmentPix1, curPointPix );
114  }
115  }
116 
117  // Draw segment par/per input
118  if ( mAdvancedDigitizingDockWidget->additionalConstraint() != QgsAdvancedDigitizingDockWidget::AdditionalConstraint::NoConstraint && hasSnappedSegment )
119  {
120  painter->setPen( mConstruction2Pen );
121  painter->drawLine( snapSegmentPix1, snapSegmentPix2 );
122  }
123 
124  // Draw angle
125  if ( nPoints > 1 )
126  {
127  double a0, a;
128  if ( mAdvancedDigitizingDockWidget->constraintAngle()->relative() && nPoints > 2 )
129  {
130  a0 = std::atan2( -( prevPoint.y() - penulPoint.y() ), prevPoint.x() - penulPoint.x() );
131  }
132  else
133  {
134  a0 = 0;
135  }
136  if ( mAdvancedDigitizingDockWidget->constraintAngle()->isLocked() )
137  {
138  a = a0 - mAdvancedDigitizingDockWidget->constraintAngle()->value() * M_PI / 180;
139  }
140  else
141  {
142  a = std::atan2( -( curPoint.y() - prevPoint.y() ), curPoint.x() - prevPoint.x() );
143  }
144 
145  a0 += canvasRotationRad;
146  a += canvasRotationRad;
147 
148  painter->setPen( mConstruction2Pen );
149  painter->drawArc( QRectF( prevPointPix.x() - 20,
150  prevPointPix.y() - 20,
151  40, 40 ),
152  static_cast<int>( 16 * -a0 * 180 / M_PI ),
153  static_cast<int>( 16 * ( a0 - a ) * 180 / M_PI ) );
154  painter->drawLine( prevPointPix,
155  prevPointPix + 60 * QPointF( std::cos( a0 ), std::sin( a0 ) ) );
156 
157 
158  if ( mAdvancedDigitizingDockWidget->constraintAngle()->isLocked() )
159  {
160  painter->setPen( mLockedPen );
161  painter->drawLine( prevPointPix - canvasMaxDimension * QPointF( std::cos( a ), std::sin( a ) ),
162  prevPointPix + canvasMaxDimension * QPointF( std::cos( a ), std::sin( a ) ) );
163  }
164  }
165 
166  // Draw distance
167  if ( nPoints > 1 && mAdvancedDigitizingDockWidget->constraintDistance()->isLocked() )
168  {
169  painter->setPen( mLockedPen );
170  double r = mAdvancedDigitizingDockWidget->constraintDistance()->value() / mupp;
171  painter->drawEllipse( prevPointPix, r, r );
172  }
173 
174  // Draw x
175  if ( mAdvancedDigitizingDockWidget->constraintX()->isLocked() )
176  {
177  double x = 0.0;
178  bool draw = true;
179  painter->setPen( mLockedPen );
180  if ( mAdvancedDigitizingDockWidget->constraintX()->relative() )
181  {
182  if ( nPoints > 1 )
183  {
184  x = mAdvancedDigitizingDockWidget->constraintX()->value() + prevPoint.x();
185  }
186  else
187  {
188  draw = false;
189  }
190  }
191  else
192  {
193  x = mAdvancedDigitizingDockWidget->constraintX()->value();
194  }
195  if ( draw )
196  {
197  painter->drawLine( toCanvasCoordinates( QgsPointXY( x, mapPoly[0].y() ) ) - canvasMaxDimension * QPointF( std::sin( -canvasRotationRad ), std::cos( -canvasRotationRad ) ),
198  toCanvasCoordinates( QgsPointXY( x, mapPoly[0].y() ) ) + canvasMaxDimension * QPointF( std::sin( -canvasRotationRad ), std::cos( -canvasRotationRad ) ) );
199  }
200  }
201 
202  // Draw y
203  if ( mAdvancedDigitizingDockWidget->constraintY()->isLocked() )
204  {
205  double y = 0.0;
206  bool draw = true;
207  painter->setPen( mLockedPen );
208  if ( mAdvancedDigitizingDockWidget->constraintY()->relative() )
209  {
210  if ( nPoints > 1 )
211  {
212  y = mAdvancedDigitizingDockWidget->constraintY()->value() + prevPoint.y();
213  }
214  else
215  {
216  draw = false;
217  }
218  }
219  else
220  {
221  y = mAdvancedDigitizingDockWidget->constraintY()->value();
222  }
223  if ( draw )
224  {
225  painter->drawLine( toCanvasCoordinates( QgsPointXY( mapPoly[0].x(), y ) ) - canvasMaxDimension * QPointF( std::cos( -canvasRotationRad ), -std::sin( -canvasRotationRad ) ),
226  toCanvasCoordinates( QgsPointXY( mapPoly[0].x(), y ) ) + canvasMaxDimension * QPointF( std::cos( -canvasRotationRad ), -std::sin( -canvasRotationRad ) ) );
227 
228  }
229  }
230 
231  // Draw constr
233  {
234  if ( curPointExist && previousPointExist )
235  {
236  painter->setPen( mConstruction2Pen );
237  painter->drawLine( prevPointPix, curPointPix );
238  }
239 
240  if ( previousPointExist && penulPointExist )
241  {
242  painter->setPen( mConstruction1Pen );
243  painter->drawLine( penulPointPix, prevPointPix );
244  }
245  }
246 
247  if ( curPointExist )
248  {
249  painter->setPen( mCursorPen );
250  painter->drawLine( curPointPix + QPointF( -5, -5 ),
251  curPointPix + QPointF( +5, +5 ) );
252  painter->drawLine( curPointPix + QPointF( -5, +5 ),
253  curPointPix + QPointF( +5, -5 ) );
254  }
255 }
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"
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
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
double rotation() const
Gets the current map canvas rotation in clockwise degrees.
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:78
QList< QgsPointXY > snappedSegment() const
Snapped to a segment.
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:154
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.
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 QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
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.
const QgsMapToPixel * getCoordinateTransform()
Gets the current coordinate transform.
QPolygonF visiblePolygon() const
Returns the visible area as a polygon (may be rotated)
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...