1 /***************************************************************************
2  *   Copyright (C) 2003 by Tim Sutton                                      *
3  *   tim@linfiniti.com                                                     *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  ***************************************************************************/
10 
11 #ifndef QGSGEOREFMAINWINDOW_H
12 #define QGSGEOREFMAINWINDOW_H
13 
14 #include "ui_qgsgeorefpluginguibase.h"
15 #include "qgsgeoreftransform.h"
16 
17 #include "qgsgcplist.h"
18 #include "qgsmapcoordsdialog.h"
19 #include "qgsimagewarper.h"
20 #include "qgscoordinatereferencesystem.h"
21 
22 #include <memory>
23 
24 #include <QPointer>
25 
26 class QAction;
27 class QActionGroup;
28 class QIcon;
29 class QPlainTextEdit;
30 class QLabel;
31 
32 class QgisInterface;
33 class QgsDoubleSpinBox;
34 class QgsGeorefDataPoint;
35 class QgsGCPListWidget;
36 class QgsMapTool;
37 class QgsMapCanvas;
38 class QgsMapCoordsDialog;
39 class QgsPointXY;
40 class QgsRasterLayer;
41 class QgsRectangle;
42 class QgsMessageBar;
43 class QgsGeorefToolAddPoint;
44 class QgsGeorefToolDeletePoint;
45 class QgsGeorefToolMovePoint;
46 class QgsGeorefToolMovePoint;
47 class QgsGCPCanvasItem;
48 
49 class QgsGeorefDockWidget : public QgsDockWidget
50 {
51     Q_OBJECT
52   public:
53     QgsGeorefDockWidget( const QString &title, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags() );
54 };
55 
56 class QgsGeoreferencerMainWindow : public QMainWindow, private Ui::QgsGeorefPluginGuiBase
57 {
58     Q_OBJECT
59 
60   public:
61     QgsGeoreferencerMainWindow( QWidget *parent = nullptr, Qt::WindowFlags fl = Qt::WindowFlags() );
62     ~QgsGeoreferencerMainWindow() override;
63 
64   protected:
65     void closeEvent( QCloseEvent * ) override;
66     void dropEvent( QDropEvent *event ) override;
67     void dragEnterEvent( QDragEnterEvent *event ) override;
68 
69   private slots:
70     // file
71     void reset();
72     void openRaster( const QString &fileName = QString() );
73     void doGeoreference();
74     void generateGDALScript();
75     bool getTransformSettings();
76 
77     // edit
78     void setAddPointTool();
79     void setDeletePointTool();
80     void setMovePointTool();
81 
82     // view
83     void setZoomInTool();
84     void setZoomOutTool();
85     void zoomToLayerTool();
86     void zoomToLast();
87     void zoomToNext();
88     void setPanTool();
89     void linkGeorefToQgis( bool link );
90     void linkQGisToGeoref( bool link );
91 
92     // gcps
93     void addPoint( const QgsPointXY &pixelCoords, const QgsPointXY &mapCoords,
94                    const QgsCoordinateReferenceSystem &crs, bool enable = true, bool finalize = true );
95     void deleteDataPoint( QPoint pixelCoords );
96     void deleteDataPoint( int index );
97     void showCoordDialog( const QgsPointXY &pixelCoords );
98 
99     void selectPoint( QPoint );
100     void movePoint( QPoint );
101     void releasePoint( QPoint );
102 
103     void loadGCPsDialog();
104     void saveGCPsDialog();
105 
106     // settings
107     void showRasterPropertiesDialog();
108     void showGeorefConfigDialog();
109 
110     // comfort
111     void jumpToGCP( uint theGCPIndex );
112     void extentsChangedGeorefCanvas();
113     void extentsChangedQGisCanvas();
114     void updateCanvasRotation();
115 
116     // canvas info
117     void showMouseCoords( const QgsPointXY &pt );
118     void updateMouseCoordinatePrecision();
119 
120     // Histogram stretch
121     void localHistogramStretch();
122     void fullHistogramStretch();
123 
124     bool updateGeorefTransform();
125     void invalidateCanvasCoords();
126 
127   private:
128     enum SaveGCPs
129     {
130       GCPSAVE,
131       GCPSILENTSAVE,
132       GCPDISCARD,
133       GCPCANCEL
134     };
135 
136     // gui
137     void createActions();
138     void createActionGroups();
139     void createMapCanvas();
140     void createMenus();
141     void createDockWidgets();
142     QLabel *createBaseLabelStatus();
143     void createStatusBar();
144     void setupConnections();
145     void removeOldLayer();
146 
147     // Mapcanvas Plugin
148     void addRaster( const QString &file );
149 
150     // settings
151     void readSettings();
152     void writeSettings();
153 
154     // gcp points
155     bool loadGCPs( /*bool verbose = true*/ );
156     void saveGCPs();
157     QgsGeoreferencerMainWindow::SaveGCPs checkNeedGCPSave();
158 
159     // georeference
160     bool georeference();
161     bool writeWorldFile( const QgsPointXY &origin, double pixelXSize, double pixelYSize, double rotation );
162     bool writePDFReportFile( const QString &fileName, const QgsGeorefTransform &transform );
163     bool writePDFMapFile( const QString &fileName, const QgsGeorefTransform &transform );
164     void updateTransformParamLabel();
165 
166     // gdal script
167     void showGDALScript( const QStringList &commands );
168     QString generateGDALtranslateCommand( bool generateTFW = true );
169 
170     /**
171      * Generate command-line for gdalwarp based on current GCPs and given parameters.
172      * For values in the range 1 to 3, the parameter "order" prescribes the degree of the interpolating polynomials to use,
173      * a value of -1 indicates that thin plate spline interpolation should be used for warping.
174     */
175     QString generateGDALwarpCommand( const QString &resampling, const QString &compress, bool useZeroForTrans, int order,
176                                      double targetResX, double targetResY );
177 
178     // utils
179     bool checkReadyGeoref();
180     QgsRectangle transformViewportBoundingBox( const QgsRectangle &canvasExtent, QgsGeorefTransform &t,
181         bool rasterToWorld = true, uint numSamples = 4 );
182     QString convertResamplingEnumToString( QgsImageWarper::ResamplingMethod resampling );
183     int polynomialOrder( QgsGeorefTransform::TransformMethod transform );
184     QString guessWorldFileName( const QString &rasterFileName );
185     bool checkFileExisting( const QString &fileName, const QString &title, const QString &question );
186     bool equalGCPlists( const QgsGCPList &list1, const QgsGCPList &list2 );
187     void logTransformOptions();
188     void logRequaredGCPs();
189     void clearGCPData();
190 
191     /**
192      * Calculates root mean squared error for the currently active
193      * ground control points and transform method.
194      * Note that the RMSE measure is adjusted for the degrees of freedom of the
195      * used polynomial transform.
196      * \param error out: the mean error
197      * \returns TRUE in case of success
198      */
199     bool calculateMeanError( double &error ) const;
200 
201     //! Docks / undocks this window
202     void dockThisWindow( bool dock );
203 
204     QGridLayout *mCentralLayout = nullptr;
205 
206     QgsMessageBar *mMessageBar = nullptr;
207     QMenu *mPanelMenu = nullptr;
208     QMenu *mToolbarMenu = nullptr;
209 
210     QgsGCPListWidget *mGCPListWidget = nullptr;
211     QLineEdit *mScaleEdit = nullptr;
212     QLabel *mScaleLabel = nullptr;
213     QLabel *mCoordsLabel = nullptr;
214     QLabel *mTransformParamLabel = nullptr;
215     QLabel *mEPSG = nullptr;
216     QLabel *mRotationLabel = nullptr;
217     QgsDoubleSpinBox *mRotationEdit = nullptr;
218     unsigned int mMousePrecisionDecimalPlaces = 0;
219 
220     QString mRasterFileName;
221     QString mModifiedRasterFileName;
222     QString mWorldFileName;
223     QString mTranslatedRasterFileName;
224     QString mGCPpointsFileName;
225     QgsCoordinateReferenceSystem mProjection;
226     QgsCoordinateReferenceSystem mLastGCPProjection;
227     QString mPdfOutputFile;
228     QString mPdfOutputMapFile;
229     QString mSaveGcp;
230     double  mUserResX, mUserResY;  // User specified target scale
231 
232     QgsGcpTransformerInterface::TransformMethod mTransformParam = QgsGcpTransformerInterface::TransformMethod::InvalidTransform;
233     QgsImageWarper::ResamplingMethod mResamplingMethod;
234     QgsGeorefTransform mGeorefTransform;
235     QString mCompressionMethod;
236 
237     QgsGCPList mPoints;
238     QgsGCPList mInitialPoints;
239     QgsMapCanvas *mCanvas = nullptr;
240     std::unique_ptr< QgsRasterLayer > mLayer;
241 
242     QgsMapTool *mToolZoomIn = nullptr;
243     QgsMapTool *mToolZoomOut = nullptr;
244     QgsMapTool *mToolPan = nullptr;
245     QgsMapTool *mPrevQgisMapTool = nullptr;
246     QgsGeorefToolAddPoint *mToolAddPoint = nullptr;
247     QgsGeorefToolDeletePoint *mToolDeletePoint = nullptr;
248     QgsGeorefToolMovePoint *mToolMovePoint = nullptr;
249     QgsGeorefToolMovePoint *mToolMovePointQgis = nullptr;
250 
251     QgsGCPCanvasItem *mNewlyAddedPointItem = nullptr;
252 
253     QgsGeorefDataPoint *mMovingPoint = nullptr;
254     QgsGeorefDataPoint *mMovingPointQgis = nullptr;
255     QPointer<QgsMapCoordsDialog> mMapCoordsDialog;
256 
257     bool mUseZeroForTrans = false;
258     bool mExtentsChangedRecursionGuard;
259     bool mGCPsDirty;
260     bool mLoadInQgis = false;
261 
262 
263     QgsDockWidget *mDock = nullptr;
264 };
265 
266 #endif
267