QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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 
45  const int nPoints = mAdvancedDigitizingDockWidget->pointsCount();
46  if ( !nPoints )
47  return;
48 
49  bool previousPointExist, penulPointExist;
50  const QgsPointXY curPoint = mAdvancedDigitizingDockWidget->currentPointV2();
51  const QgsPointXY prevPoint = mAdvancedDigitizingDockWidget->previousPointV2( &previousPointExist );
52  const QgsPointXY penulPoint = mAdvancedDigitizingDockWidget->penultimatePointV2( &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 = mapPoly.containsPoint( curPoint.toQPointF(), Qt::OddEvenFill );
58 
59  const double mupp = mMapCanvas->getCoordinateTransform()->mapUnitsPerPixel();
60  if ( mupp == 0 )
61  return;
62 
63  const double canvasRotationRad = mMapCanvas->rotation() * M_PI / 180;
64  const double canvasDiagonalDimension = ( canvasWidth + canvasHeight ) / mupp ;
65 
66  QPointF curPointPix, prevPointPix, penulPointPix, snapSegmentPix1, snapSegmentPix2;
67 
68  if ( curPointExist )
69  {
70  curPointPix = toCanvasCoordinates( curPoint );
71  }
72  if ( previousPointExist )
73  {
74  prevPointPix = toCanvasCoordinates( prevPoint );
75  }
76  if ( penulPointExist )
77  {
78  penulPointPix = toCanvasCoordinates( penulPoint );
79  }
80  if ( hasSnappedSegment )
81  {
82  snapSegmentPix1 = toCanvasCoordinates( snappedSegment[0] );
83  snapSegmentPix2 = toCanvasCoordinates( snappedSegment[1] );
84  }
85 
86  painter->setRenderHint( QPainter::Antialiasing );
87  painter->setCompositionMode( QPainter::CompositionMode_Difference );
88 
89  // Draw point snap
90  if ( curPointExist && snappedToVertex )
91  {
92  painter->setPen( mSnapPen );
93  painter->drawEllipse( curPointPix, 10, 10 );
94  }
95 
96  // Draw segment snap
97  if ( hasSnappedSegment && !snappedToVertex )
98  {
99  painter->setPen( mSnapPen );
100  painter->drawLine( snapSegmentPix1, snapSegmentPix2 );
101 
102  if ( curPointExist )
103  {
104  painter->setPen( mSnapLinePen );
105  painter->drawLine( snapSegmentPix1, curPointPix );
106  }
107  }
108 
109  // Draw segment par/per input
110  if ( mAdvancedDigitizingDockWidget->additionalConstraint() != QgsAdvancedDigitizingDockWidget::AdditionalConstraint::NoConstraint && hasSnappedSegment )
111  {
112  painter->setPen( mConstruction2Pen );
113  painter->drawLine( snapSegmentPix1, snapSegmentPix2 );
114  }
115 
116  // Draw angle
117  if ( nPoints > 1 )
118  {
119  double a0, a;
120  if ( mAdvancedDigitizingDockWidget->constraintAngle()->relative() && nPoints > 2 )
121  {
122  a0 = std::atan2( -( prevPoint.y() - penulPoint.y() ), prevPoint.x() - penulPoint.x() );
123  }
124  else
125  {
126  a0 = 0;
127  }
128  if ( mAdvancedDigitizingDockWidget->constraintAngle()->isLocked() )
129  {
130  a = a0 - mAdvancedDigitizingDockWidget->constraintAngle()->value() * M_PI / 180;
131  }
132  else
133  {
134  a = std::atan2( -( curPoint.y() - prevPoint.y() ), curPoint.x() - prevPoint.x() );
135  }
136 
137  a0 += canvasRotationRad;
138  a += canvasRotationRad;
139 
140  painter->setPen( mConstruction2Pen );
141  painter->drawArc( QRectF( prevPointPix.x() - 20,
142  prevPointPix.y() - 20,
143  40, 40 ),
144  static_cast<int>( 16 * -a0 * 180 / M_PI ),
145  static_cast<int>( 16 * ( a0 - a ) * 180 / M_PI ) );
146  painter->drawLine( prevPointPix,
147  prevPointPix + 60 * QPointF( std::cos( a0 ), std::sin( a0 ) ) );
148 
149 
150  if ( mAdvancedDigitizingDockWidget->constraintAngle()->isLocked() )
151  {
152  painter->setPen( mLockedPen );
153  const double canvasPadding = QLineF( prevPointPix, curPointPix ).length();
154  painter->drawLine( prevPointPix + ( canvasPadding - canvasDiagonalDimension ) * QPointF( std::cos( a ), std::sin( a ) ),
155  prevPointPix + ( canvasPadding + canvasDiagonalDimension ) * QPointF( std::cos( a ), std::sin( a ) ) );
156  }
157  }
158 
159  // Draw distance
160  if ( nPoints > 1 && mAdvancedDigitizingDockWidget->constraintDistance()->isLocked() )
161  {
162  painter->setPen( mLockedPen );
163  const double r = mAdvancedDigitizingDockWidget->constraintDistance()->value() / mupp;
164  painter->drawEllipse( prevPointPix, r, r );
165  }
166 
167  // Draw x
168  if ( mAdvancedDigitizingDockWidget->constraintX()->isLocked() )
169  {
170  double x = 0.0;
171  bool draw = true;
172  painter->setPen( mLockedPen );
173  if ( mAdvancedDigitizingDockWidget->constraintX()->relative() )
174  {
175  if ( nPoints > 1 )
176  {
177  x = mAdvancedDigitizingDockWidget->constraintX()->value() + prevPoint.x();
178  }
179  else
180  {
181  draw = false;
182  }
183  }
184  else
185  {
186  x = mAdvancedDigitizingDockWidget->constraintX()->value();
187  }
188  if ( draw )
189  {
190  painter->drawLine( toCanvasCoordinates( QgsPointXY( x, mapPoly[0].y() ) ) - canvasDiagonalDimension * QPointF( std::sin( -canvasRotationRad ), std::cos( -canvasRotationRad ) ),
191  toCanvasCoordinates( QgsPointXY( x, mapPoly[0].y() ) ) + canvasDiagonalDimension * QPointF( std::sin( -canvasRotationRad ), std::cos( -canvasRotationRad ) ) );
192  }
193  }
194 
195  // Draw y
196  if ( mAdvancedDigitizingDockWidget->constraintY()->isLocked() )
197  {
198  double y = 0.0;
199  bool draw = true;
200  painter->setPen( mLockedPen );
201  if ( mAdvancedDigitizingDockWidget->constraintY()->relative() )
202  {
203  if ( nPoints > 1 )
204  {
205  y = mAdvancedDigitizingDockWidget->constraintY()->value() + prevPoint.y();
206  }
207  else
208  {
209  draw = false;
210  }
211  }
212  else
213  {
214  y = mAdvancedDigitizingDockWidget->constraintY()->value();
215  }
216  if ( draw )
217  {
218  painter->drawLine( toCanvasCoordinates( QgsPointXY( mapPoly[0].x(), y ) ) - canvasDiagonalDimension * QPointF( std::cos( -canvasRotationRad ), -std::sin( -canvasRotationRad ) ),
219  toCanvasCoordinates( QgsPointXY( mapPoly[0].x(), y ) ) + canvasDiagonalDimension * QPointF( std::cos( -canvasRotationRad ), -std::sin( -canvasRotationRad ) ) );
220 
221  }
222  }
223 
224  // Draw constr
226  {
227  if ( curPointExist && previousPointExist )
228  {
229  painter->setPen( mConstruction2Pen );
230  painter->drawLine( prevPointPix, curPointPix );
231  }
232 
233  if ( previousPointExist && penulPointExist )
234  {
235  painter->setPen( mConstruction1Pen );
236  painter->drawLine( penulPointPix, prevPointPix );
237  }
238  }
239 
240  if ( curPointExist )
241  {
242  painter->setPen( mCursorPen );
243  painter->drawLine( curPointPix + QPointF( -5, -5 ),
244  curPointPix + QPointF( +5, +5 ) );
245  painter->drawLine( curPointPix + QPointF( -5, +5 ),
246  curPointPix + QPointF( +5, -5 ) );
247  }
248 }
249 
251 {
252  // Use visible polygon rather than extent to properly handle rotated maps
253  QPolygonF mapPoly = mMapCanvas->mapSettings().visiblePolygon();
254  const double canvasWidth = QLineF( mapPoly[0], mapPoly[1] ).length();
255  const double canvasHeight = QLineF( mapPoly[0], mapPoly[3] ).length();
256  const QgsRectangle mapRect = QgsRectangle( mapPoly[0],
257  QgsPointXY(
258  mapPoly[0].x() + canvasWidth,
259  mapPoly[0].y() - canvasHeight
260  )
261  );
262  if ( rect() != mapRect )
263  setRect( mapRect );
264 }
void paint(QPainter *painter) override
function to be implemented by derived classes
void updatePosition() override
called on changed extent or resize event to update position of the item
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:90
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