1 /***************************************************************************
2 qgsadvanceddigitizingcanvasitem.cpp - map canvas item for CAD tools
3 ----------------------
4 begin : October 2014
5 copyright : (C) Denis Rouzaud
6 email : denis.rouzaud@gmail.com
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
18 #include "qgsadvanceddigitizingdockwidget.h"
19 #include "qgsadvanceddigitizingcanvasitem.h"
20 #include "qgsmapcanvas.h"
21
22
QgsAdvancedDigitizingCanvasItem(QgsMapCanvas * canvas,QgsAdvancedDigitizingDockWidget * cadDockWidget)23 QgsAdvancedDigitizingCanvasItem::QgsAdvancedDigitizingCanvasItem( QgsMapCanvas *canvas, QgsAdvancedDigitizingDockWidget *cadDockWidget )
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
paint(QPainter * painter)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
232 if ( mAdvancedDigitizingDockWidget->additionalConstraint() == QgsAdvancedDigitizingDockWidget::AdditionalConstraint::NoConstraint )
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 }
256