1 /***************************************************************************
2    qgsmaptoolrectangle3points.cpp  -  map tool for adding rectangle
3    from 3 points
4    ---------------------
5    begin                : September 2017
6    copyright            : (C) 2017 by Loïc Bartoletti
7    email                : lbartoletti at tuxfamily dot org
8 ***************************************************************************
9 *                                                                         *
10 *   This program is free software; you can redistribute it and/or modify  *
11 *   it under the terms of the GNU General Public License as published by  *
12 *   the Free Software Foundation; either version 3 of the License, or     *
13 *   (at your option) any later version.                                   *
14 *                                                                         *
15 ***************************************************************************/
16 
17 #include "qgsmaptoolrectangle3points.h"
18 #include "qgsgeometryrubberband.h"
19 #include "qgsgeometryutils.h"
20 #include "qgslinestring.h"
21 #include "qgsmapcanvas.h"
22 #include "qgspoint.h"
23 #include "qgsmapmouseevent.h"
24 #include <memory>
25 #include "qgssnapindicator.h"
26 
QgsMapToolRectangle3Points(QgsMapToolCapture * parentTool,QgsMapCanvas * canvas,CreateMode createMode,CaptureMode mode)27 QgsMapToolRectangle3Points::QgsMapToolRectangle3Points( QgsMapToolCapture *parentTool,
28     QgsMapCanvas *canvas, CreateMode createMode, CaptureMode mode )
29   : QgsMapToolAddRectangle( parentTool, canvas, mode ),
30     mCreateMode( createMode )
31 {
32   mToolName = tr( "Add rectangle from 3 points" );
33 }
34 
cadCanvasReleaseEvent(QgsMapMouseEvent * e)35 void QgsMapToolRectangle3Points::cadCanvasReleaseEvent( QgsMapMouseEvent *e )
36 {
37   QgsPoint point = mapPoint( *e );
38 
39   if ( !currentVectorLayer() )
40   {
41     notifyNotVectorLayer();
42     clean();
43     stopCapturing();
44     e->ignore();
45     return;
46   }
47 
48   if ( e->button() == Qt::LeftButton )
49   {
50     bool is3D = false;
51     QgsVectorLayer *currentLayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
52     if ( currentLayer )
53       is3D = QgsWkbTypes::hasZ( currentLayer->wkbType() );
54 
55     if ( is3D && !point.is3D() )
56       point.addZValue( defaultZValue() );
57 
58     if ( mPoints.size() < 2 )
59     {
60       mPoints.append( point );
61     }
62 
63     if ( !mPoints.isEmpty() && !mTempRubberBand )
64     {
65       mTempRubberBand = createGeometryRubberBand( mLayerType, true );
66       mTempRubberBand->show();
67     }
68     if ( mPoints.size() == 3 )
69     {
70       delete mTempRubberBand;
71       mTempRubberBand = createGeometryRubberBand( mLayerType, true ); // recreate rubberband for polygon
72     }
73   }
74   else if ( e->button() == Qt::RightButton )
75   {
76     release( e );
77   }
78 }
79 
cadCanvasMoveEvent(QgsMapMouseEvent * e)80 void QgsMapToolRectangle3Points::cadCanvasMoveEvent( QgsMapMouseEvent *e )
81 {
82   QgsPoint point = mapPoint( *e );
83 
84   mSnapIndicator->setMatch( e->mapPointMatch() );
85 
86   if ( mTempRubberBand )
87   {
88     switch ( mPoints.size() )
89     {
90       case 1:
91       {
92         std::unique_ptr<QgsLineString> line( new QgsLineString() );
93         line->addVertex( mPoints.at( 0 ) );
94         line->addVertex( point );
95         mTempRubberBand->setGeometry( line.release() );
96       }
97       break;
98       case 2:
99       {
100         bool is3D = false;
101         QgsVectorLayer *currentLayer = qobject_cast<QgsVectorLayer *>( mCanvas->currentLayer() );
102         if ( currentLayer )
103           is3D = QgsWkbTypes::hasZ( currentLayer->wkbType() );
104 
105         if ( is3D && !point.is3D() )
106           point.addZValue( defaultZValue() );
107 
108         switch ( mCreateMode )
109         {
110           case DistanceMode:
111             mRectangle = QgsQuadrilateral::rectangleFrom3Points( mPoints.at( 0 ), mPoints.at( 1 ), point, QgsQuadrilateral::Distance );
112             break;
113           case ProjectedMode:
114             mRectangle = QgsQuadrilateral::rectangleFrom3Points( mPoints.at( 0 ), mPoints.at( 1 ), point, QgsQuadrilateral::Projected );
115             break;
116         }
117         mTempRubberBand->setGeometry( mRectangle.toPolygon( ) );
118       }
119       break;
120       default:
121         break;
122     }
123   }
124 }
125