GeoDesk  0.1.3
 All Classes Namespaces Files Functions Typedefs Pages
mainboard.cpp
Go to the documentation of this file.
1 /**
2  * \file mainboard.cpp
3  * \brief Implementation of application main board.
4  * \author Le Bars, Yoann
5  * \version 1.0
6  * \date 2013/06/20
7  * \date 2013/06/21
8  * \date 2013/06/24
9  * \date 2013/06/25
10  * \date 2013/06/26
11  * \date 2013/06/27
12  * \date 2013/06/28
13  * \date 2013/07/01
14  * \date 2013/07/02
15  * \date 2013/07/03
16  * \date 2013/07/04
17  * \date 2013/07/05
18  * \date 2013/07/09
19  * \date 2013/07/12
20  * \date 2013/07/16
21  * \date 2013/07/29
22  * \date 2013/07/30
23  * \date 2013/09/24
24  * \date 2013/10/15
25  * \date 2013/10/18
26  * \date 2013/10/21
27  * \date 2013/10/31
28  * \date 2013/11/05
29  * \date 2013/11/06
30  * \date 2013/11/12
31  * \date 2013/11/22
32  * \date 2013/11/26
33  */
34 
35 #include <QFileDialog>
36 #include <QPixmap>
37 #include <QImage>
38 #include <QMessageBox>
39 #include <cstddef>
40 #include <algorithm>
41 #include <QInputDialog>
42 #include <QMessageBox>
43 #include <QFileInfo>
44 #include <QDir>
45 #include <QFile>
46 #include <QTextStream>
47 #include <QMessageBox>
48 #include <boost/units/systems/si/io.hpp>
49 // #include <gdal_priv.h>
50 
51 #include "mainboard.hpp"
52 
53 /* -- Open an image. ------------------------------------------------------ */
55  ui.statusbar->showMessage(tr("Opening image."));
56 
57  /* Filter for standard images. */
58  const QString standard =
59  tr("Standard images (*.bmp *.gif *.jpg *.jpeg *.png *.pbm *.pgm *.ppm "
60  "*.tiff *.tif *.xbm *.xpm)");
61  /* Filter for geo-referenced images. */
62  const QString georeferenced =
63  tr("Geo-referenced images (*.tiff *.tif *.jp2 *.j2k *.jpf *.jpx *.jpm "
64  "*.mj2)");
65  /* Filter for all files. */
66  const QString all = tr("All files (*)");
67  /* List of filters. */
68  const QString filtersList = standard + ";;" + georeferenced + ";;" + all;
69  /* Filter selected by user. */
70  QString selectedFilter;
71  /* Name of the file to be opened. */
72  const QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"),
73  QDir::currentPath(),
74  filtersList,
75  &selectedFilter);
76 
77  if (!fileName.isEmpty()) {
78  if (selectedFilter == georeferenced) {
79 // GDALAllRegister();
80 //
81 // /* Pointer to the image */
82 // GDALDataset* poDataset =
83 // static_cast<GDALDataset*>(GDALOpen(fileName.toStdString().c_str(),
84 // GA_ReadOnly));
85 // if (poDataset == nullptr) {
86 // QMessageBox::information(this, tr("GeoDesk"),
87 // tr("Cannot load %1.").arg(fileName));
88 // }
89  }
90  else {
91  const QImage image (fileName);
92  if (image.isNull()) {
93  QMessageBox::information(this, tr("GeoDesk"),
94  tr("Cannot load %1.").arg(fileName));
95  return;
96  }
97 
98  imageLabel->setPixmap(QPixmap::fromImage(image));
99  scaleFactor = 1.0;
100 
101  imageLabel->adjustSize();
102 
103  ui.actionZoomIn->setEnabled(true);
104  ui.actionZoomOut->setEnabled(true);
105  ui.actionNormalSize->setEnabled(true);
106  ui.actionSetData->setEnabled(false);
107  ui.actionSampleIsobath->setEnabled(false);
108  ui.actionSetData->setChecked(false);
109  ui.actionSampleIsobath->setChecked(false);
110 
111  /* Information about the image file. */
112  const QFileInfo imageFile (fileName);
113  /* Extension of the image file. */
114  const QString imageExtension = imageFile.suffix();
115  /* Extension for the world file. */
116  const QString worldExtension = '.' + imageExtension.at(0)
117  + imageExtension.at(imageExtension.size() - 1) + 'w';
118  /* Name of the world file. */
119  worldFileName =
120  imageFile.canonicalPath() + QDir::separator()
121  + imageFile.completeBaseName() + worldExtension;
122  worldExists = false;
123  ui.statusbar->showMessage(geoNotOk);
124  if (QFile::exists(worldFileName)) {
125  loadWorldFile(worldFileName);
126  }
127 
128  ui.actionSaveWorldFile->setEnabled(false);
129  ui.actionSaveReferencePoints->setEnabled(false);
130  ui.actionSaveReferencePointsAs->setEnabled(false);
131  data.clear();
132  dataFileName.clear();
133  referencePointFileName.clear();
134  referencing = false;
135  setting = false;
136  sampling = false;
137  ui.actionGeoreferenceImage->setEnabled(true);
138  ui.actionSaveDataFile->setEnabled(false);
139  ui.actionSaveDataFileAs->setEnabled(false);
140  }
141  }
142  else {
143  ui.statusbar->showMessage(noFile);
144  }
145 }
146 
147 /* -- Load a world file. -------------------------------------------------- */
149  ui.statusbar->showMessage(tr("Loading world file."));
150 
151  /* Name of the file to be opened. */
152  const QString fileName = QFileDialog::getOpenFileName(this, tr("Open file"),
153  QDir::currentPath(),
154  tr("World files (*.bpw *.gfw "
155  "*.jgw *.pgw *.pmw "
156  "*.tfw *.twfx *.xmw);;"
157  "All files (*)"));
158 
159  if (!fileName.isEmpty()) {
160  loadWorldFile(fileName);
161  setting = false;
162  ui.statusbar->showMessage(done);
163  }
164  else {
165  ui.statusbar->showMessage(noFile);
166  }
167 }
168 
169 /* -- Load reference points. ---------------------------------------------- */
171  ui.statusbar->showMessage(tr("Loading reference points."));
172 
173  referencePointList.clear();
174  referencePointFileName = QFileDialog::getOpenFileName(this, openFile,
175  QDir::currentPath(),
176  textOrAny);
177 
178  if (!referencePointFileName.isEmpty()) {
179  /* The file itself. */
180  QFile file (referencePointFileName);
181  if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
182  /* Stream on the file. */
183  QTextStream referencePointFileStream (&file);
184 
185  while (!referencePointFileStream.atEnd()) {
186  /* Point coordinates in image referential. */
187  Point2D image;
188  /* Point coordinates in geographical referential. */
189  Point2D geographic;
190  referencePointFileStream >> image.x() >> image.y()
191  >> geographic.x() >> geographic.y();
192  /* New reference point. */
193  const ReferencePointType referencePoint =
194  std::make_pair(image, geographic);
195  referencePointList.push_back(referencePoint);
196  }
197  }
198  else {
199  QMessageBox::critical(this, tr("Error"),
200  tr("File named \"%1\" cannot "
201  "be opened.").arg(referencePointFileName));
202  }
203  ui.statusbar->showMessage(done);
204  }
205  else {
206  ui.statusbar->showMessage(noFile);
207  }
208 }
209 
210 /* -- Load a data file. --------------------------------------------------- */
212  ui.statusbar->showMessage(tr("Loading data file."));
213 
214  data.clear();
215  /* Name of the file to be opened. */
216  dataFileName = QFileDialog::getOpenFileName(this, openFile,
217  QDir::currentPath(), textOrAny);
218 
219  if (!dataFileName.isEmpty()) {
220  /* The file itself. */
221  QFile file (dataFileName);
222  if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
223  data = file.readAll();
224  file.close();
225  }
226  else {
227  QMessageBox::critical(this, tr("Error"),
228  tr("File named \"%1\" cannot "
229  "be opened.").arg(dataFileName));
230  }
231  ui.statusbar->showMessage(done);
232  }
233  else {
234  ui.statusbar->showMessage(noFile);
235  }
236 }
237 
238 /* -- Zoom into image. ---------------------------------------------------- */
240  ui.statusbar->showMessage(tr("Zooming in."));
241  scaleImage(1.25);
242  ui.statusbar->showMessage(done);
243 }
244 
245 /* -- Zoom out an image. -------------------------------------------------- */
247  ui.statusbar->showMessage(tr("Zooming out."));
248  scaleImage(0.8);
249  ui.statusbar->showMessage(done);
250 }
251 
252 /* -- Set image to its normal size. --------------------------------------- */
254  ui.statusbar->showMessage(tr("Back to normal size."));
255  imageLabel->adjustSize();
256  scaleFactor = 1.0;
257  ui.actionZoomIn->setEnabled(true);
258  ui.actionZoomOut->setEnabled(true);
259  ui.statusbar->showMessage(done);
260 }
261 
262 /* -- Save reference points used for image geo-referencing. --------------- */
264  ui.statusbar->showMessage(tr("Saving reference points."));
265 
266  if (referencePointFileName.isEmpty()) {
267  on_actionSaveReferencePointsAs_triggered();;
268  }
269  else {
270  saveReferencePointFile();
271  }
272 }
273 
274 /* -- Save reference points in a new file. -------------------------------- */
276  ui.statusbar->showMessage(tr("Saving reference points in a new file."));
277 
278  referencePointFileName = QFileDialog::getSaveFileName(this,
279  tr("Save reference "
280  "points in a new "
281  "file"),
282  QDir::currentPath(),
283  tr("Text files "
284  "(*.txt);;"
285  "All files (*)"));
286  saveReferencePointFile();
287 }
288 
289 /* -- Save world file associated to opened image. ------------------------- */
291  ui.statusbar->showMessage(tr("Saving world file."));
292 
293  if (QFile::exists(worldFileName)) {
294  /* User's decision whether or not overwrite world file. */
295  const int choice =
296  QMessageBox::question(this, tr("Overwrite"),
297  tr("World file already exists, overwrite it?"),
298  QMessageBox::Yes | QMessageBox::No);
299  if (choice == QMessageBox::No) {
300  ui.statusbar->showMessage(aborted);
301  return;
302  }
303  }
304 
305  /* World file itself. */
306  QFile worldFile (worldFileName);
307  worldFile.open(QIODevice::WriteOnly | QIODevice::Text
308  | QIODevice::Truncate);
309  /* Stream on the world file. */
310  QTextStream worldFileStream (&worldFile);
311 
312  worldFileStream << change(0, 0) << '\n'
313  << change(1, 0) << '\n'
314  << change(0, 1) << '\n'
315  << change(1, 1) << '\n'
316  << change(0, 2) << '\n'
317  << change(1, 2) << '\n';
318 
319  worldFile.close();
320 
321  ui.actionSaveWorldFile->setEnabled(false);
322 
323  ui.statusbar->showMessage(tr("Saved world file: %1").arg(worldFileName));
324  setting = false;
325 }
326 
327 /* -- Save data which have been set by the user. -------------------------- */
329  ui.statusbar->showMessage(tr("Saving data file."));
330 
331  if (dataFileName.isEmpty()) {
332  on_actionSaveDataFileAs_triggered();
333  }
334  else {
335  saveDataFile();
336  }
337 }
338 
339 /* -- Save data in a new file. -------------------------------------------- */
341  ui.statusbar->showMessage(tr("Saving data in a new file."));
342 
343  dataFileName = QFileDialog::getSaveFileName(this, tr("Save data file as"),
344  QDir::currentPath(),
345  tr("Text files (*.txt);;"
346  "All files (*)"));
347  saveDataFile();
348 }
349 
350 /* -- Give reference point for image geo-reference. ----------------------- */
352  ui.statusbar->showMessage(
353  tr("Referencing: point 1 / %1").arg(requiredReference));
354 
355  worldExists = false;
356  referencing = true;
357  setting = false;
358  sampling = false;
359  numberReferencePoints = 0;
360 }
361 
362 /* -- Enable setting geo-referenced data. --------------------------------- */
364  if (setting) {
365  setting = false;
366  ui.actionSampleIsobath->setEnabled(true);
367  ui.statusbar->showMessage(tr("Stop setting geo-referenced data."));
368  }
369  else {
370  setting = true;
371  ui.actionSampleIsobath->setEnabled(false);
372  ui.statusbar->showMessage(tr("Setting geo-referenced data."));
373  }
374 }
375 
376 /* -- Sampling an isobath. ------------------------------------------------ */
378  if (sampling) {
379  sampling = false;
380  ui.actionSetData->setEnabled(true);
381  ui.statusbar->showMessage(tr("Stop sampling isobath."));
382  }
383  else {
384  /* Did the user push the "OK" button? */
385  bool ok;
386  /* Isobath value. */
387 // const quantity<length> isobath
388 // (QInputDialog::getDouble(this, tr("Isobath value"),
389 // tr("Enter isobath value in meter"), 0., 0.,
390 // 15000., 2, &ok) * meter);
391  const double isobath =
392  QInputDialog::getDouble(this, tr("Isobath value"),
393  tr("Enter isobath value in meter"), 0., 0.,
394  15000., 2, &ok);
395  if (ok) {
396  sampling = true;
397  value = isobath;
398  ui.actionSetData->setEnabled(false);
399  ui.statusbar->showMessage(tr("Sampling isobath"));
400  }
401  else {
402  ui.actionSampleIsobath->setChecked(false);
403  }
404  }
405 }
406 
407 /* -- When mouse is left-clicked. ----------------------------------------- */
408 void GUI::MainBoard::mousePressEvent (QMouseEvent* event) {
409  /* Degree character. */
410  const QChar degree = 0x00B0;
411 
412  QWidget::mousePressEvent(event);
413  if (!imageLabel->pixmap()) return;
414  if (event->button() != Qt::LeftButton) return;
415 
416  /* Coordinate of the point being clicked. */
417  const Point2D pos = getMousePosition(event->pos());
418 
419  if (referencing) {
420  /* Reference points in image coordinates. */
421  static std::vector<Point2D> r1 (requiredReference);
422 
423  /* \brief Reference points in geographical coordinates. */
424  static std::vector<Point2D> r2 (requiredReference);
425 
426  r1[numberReferencePoints] = pos;
427  /* Did the user push "OK" button? */
428  bool ok;
429  r2[numberReferencePoints].x() =
430  QInputDialog::getDouble(this, tr("Longitude"),
431  tr("Longitude in decimal degrees east"),
432  0., -180., 180., 4, &ok);
433  if (!ok) return;
434  r2[numberReferencePoints].y() =
435  QInputDialog::getDouble(this, tr("Latitude"),
436  tr("Latitude in decimal degrees north"),
437  0., -90., 90., 4, &ok);
438  if (ok) {
439  referencePointList.push_back(std::make_pair(pos,
440  r2[numberReferencePoints]));
441  ui.actionSaveReferencePoints->setEnabled(true);
442  ui.actionSaveReferencePointsAs->setEnabled(true);
443  ++numberReferencePoints;
444  }
445  ui.statusbar->showMessage(
446  tr("Referencing: point %1 / %2").arg(numberReferencePoints
447  + 1).arg(requiredReference));
448 
449  if (numberReferencePoints == requiredReference) {
450  change = computeCoefficients(r1, r2).transpose();
451  ui.actionSaveWorldFile->setEnabled(true);
452  ui.actionSetData->setEnabled(true);
453  worldExists = true;
454  referencing = false;
455  ui.statusbar->showMessage(geoOk);
456  }
457  }
458  else if (setting) {
459  /* Vector for referential change. */
460  const Eigen::Vector3d x (pos.x(), pos.y(), 1.);
461  /* Coordinates in geographical referential. */
462  const Eigen::Vector2d b = change * x;
463  /* Message to be outputted. */
464  const QString message = QString::number(b(0)) + degree + tr(" E, ")
465  + QString::number(b(1)) + degree + tr(" N");
466  /* Did the user push "OK" button? */
467  bool ok;
468  /* Value associated to the clicked localisation. */
469  const quantity<length> value
470  (QInputDialog::getDouble(this, tr("Enter value"),
471  message, 0., 0., 15000., 2, &ok) * meter);
472  if (ok) {
473  /* Stream on the QString which contains data. */
474  QTextStream dataStream (&data);
475  dataStream << pos.x() << ' ' << pos.y() << ' ' << b(0) << ' ' << b(1)
476  << ' ' << value.value() << '\n';
477  ui.actionSaveDataFile->setEnabled(true);
478  ui.actionSaveDataFileAs->setEnabled(true);
479  }
480  }
481  else if (sampling) {
482  /* Vector for referential change. */
483  const Eigen::Vector3d x (pos.x(), pos.y(), 1.);
484  /* Coordinates in geographical referential. */
485  const Eigen::Vector2d b = change * x;
486  /* Stream on the QString which contains data. */
487  QTextStream dataStream (&data);
488  dataStream << pos.x() << ' ' << pos.y() << ' ' << b(0) << ' ' << b(1)
489  << ' ' << value << '\n';
490  ui.statusbar->showMessage(tr("Isobath ") + value + tr(" m, ")
491  + QString::number(b(0)) + degree + tr(" E,")
492  + QString::number(b(1)) + degree + tr(" N"));
493  ui.actionSaveDataFile->setEnabled(true);
494  ui.actionSaveDataFileAs->setEnabled(true);
495  }
496 }
void on_actionSaveReferencePoints_triggered()
Save reference points, used for image geo-referencing.
Definition: mainboard.cpp:263
void on_actionLoadDataFile_triggered()
Load a data file.
Definition: mainboard.cpp:211
void on_actionLoadWorldFile_triggered()
Load a world file.
Definition: mainboard.cpp:148
void on_actionSaveReferencePointsAs_triggered()
Save reference points in a new file.
Definition: mainboard.cpp:275
void on_actionSaveDataFileAs_triggered()
Save data in a new file.
Definition: mainboard.cpp:340
void on_actionZoomOut_triggered()
Zooms out an image.
Definition: mainboard.cpp:246
void on_actionOpen_triggered()
Get the name of the file to be opened.
Definition: mainboard.cpp:54
Class for 2D points.
Definition: projection.hpp:23
void on_actionSampleIsobath_triggered()
Sampling an isobath.
Definition: mainboard.cpp:377
void on_actionSetData_triggered()
Enable setting of geo-referenced data.
Definition: mainboard.cpp:363
Coefficients computeCoefficients(const std::vector< Point2D > &r1, const std::vector< Point2D > &r2)
Compute the projection coefficients.
Definition: projection.hpp:84
void on_actionZoomIn_triggered()
Zooms in an image.
Definition: mainboard.cpp:239
Definitions to create program main board.
double y() const
Access to ordinate, modification is not possible.
Definition: projection.hpp:48
void on_actionSaveWorldFile_triggered()
Save a world file associated to an image.
Definition: mainboard.cpp:290
void on_actionLoadReferencePoints_triggered()
Load reference points.
Definition: mainboard.cpp:170
virtual void mousePressEvent(QMouseEvent *event)
What to do when mouse is clicked.
Definition: mainboard.cpp:408
void on_actionGeoreferenceImage_triggered()
Give reference points for image geo-reference.
Definition: mainboard.cpp:351
void on_actionNormalSize_triggered()
Gets the image back to its normal size.
Definition: mainboard.cpp:253
double x() const
Access to abscissa, modification is not possible.
Definition: projection.hpp:42
void on_actionSaveDataFile_triggered()
Save data which have been set by user.
Definition: mainboard.cpp:328