QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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  const double canvasWidth = QLineF( mapPoly[0], mapPoly[1] ).length();
43  const double canvasHeight = QLineF( mapPoly[0], mapPoly[3] ).length();
44  const 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  const int nPoints = mAdvancedDigitizingDockWidget->pointsCount();
54  if ( !nPoints )
55  return;
56 
57  bool previousPointExist, penulPointExist;
58  const QgsPointXY curPoint = mAdvancedDigitizingDockWidget->currentPointV2();
59  const QgsPointXY prevPoint = mAdvancedDigitizingDockWidget->previousPointV2( &previousPointExist );
60  const QgsPointXY penulPoint = mAdvancedDigitizingDockWidget->penultimatePointV2( &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  const 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 }
void paint(QPainter *painter) override
function to be implemented by derived classes
QgsAdvancedDigitizingCanvasItem(QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget)
bool isLocked() const
Is any kind of lock mode enabled.
double value() const
The value of the constraint.
bool relative() const
Is the constraint in relative mode.
The QgsAdvancedDigitizingDockWidget class is a dockable widget used to handle the CAD tools on top of...
const CadConstraint * constraintDistance() const
Returns the CadConstraint on the distance.
bool cadEnabled() const
determines if CAD tools are enabled or if map tools behaves "nomally"
int pointsCount() const
The number of points in the CAD point helper list.
bool snappedToVertex() const
Is it snapped to a vertex.
AdditionalConstraint additionalConstraint() const
Returns the additional constraints which are used to place perpendicular/parallel segments to snapped...
QgsPoint previousPointV2(bool *exists=nullptr) const
The previous point.
const CadConstraint * constraintX() const
Returns the CadConstraint on the X coordinate.
QgsPoint penultimatePointV2(bool *exists=nullptr) const
The penultimate point.
const CadConstraint * constraintAngle() const
Returns the CadConstraint on the angle.
const CadConstraint * constraintY() const
Returns the CadConstraint on the Y coordinate.
QgsPoint currentPointV2(bool *exists=nullptr) const
The last point.
QList< QgsPointXY > snappedSegment() const
Snapped to a segment.
An abstract class for items that can be placed on the map canvas.
QgsRectangle rect() const
returns canvas item rectangle in map units
QPointF toCanvasCoordinates(const QgsPointXY &point) const
transformation from map coordinates to screen coordinates
QgsMapCanvas * mMapCanvas
pointer to map canvas
void setRect(const QgsRectangle &r, bool resetRotation=true)
sets canvas item rectangle in map units
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
double rotation() const
Gets the current map canvas rotation in clockwise degrees.
const QgsMapToPixel * getCoordinateTransform()
Gets the current coordinate transform.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QPolygonF visiblePolygon() const
Returns the visible area as a polygon (may be rotated)
double mapUnitsPerPixel() const
Returns the current map units per pixel.
A class to represent a 2D point.
Definition: qgspointxy.h:59
double y
Definition: qgspointxy.h:63
Q_GADGET double x
Definition: qgspointxy.h:62
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspointxy.h:169
A rectangle specified with double values.
Definition: qgsrectangle.h:42