InputCoordinateDialog.cpp
Go to the documentation of this file.
2 
3 #include "ui_InputCoordinateForm.h"
4 
5 // TerraLib
6 #include "../../../geometry/Coord2D.h"
7 #include "../Exception.h"
8 
9 #include "../canvas/MapDisplay.h"
10 
11 // STL
12 #include <iostream>
13 
14 #include <QDoubleValidator>
15 #include <QPushButton>
16 #include <QRegularExpression>
17 
18 // ------------------------------
19 // Utilities functions section
20 // ------------------------------
21 
22 /*!
23  * \brief Extracts the degree, minute and second portions of the \a match object.
24  *
25  * \param match Qt structure that has a regular expression.
26  *
27  * \param[out] d Degrees.
28  *
29  * \param[out] m Minutes.
30  *
31  * \param[out] s Seconds.
32  */
33 void ParseDMS(const QRegularExpressionMatch& match, int& d, int& m, int& s)
34 {
35  d = 999;
36  m = 999;
37  s = 999;
38 
39  QStringList texts = match.capturedTexts();
40  bool ok;
41  bool negative = false;
42 
43  for(int i = 1; i < texts.size(); i++)
44  {
45  int v = texts.at(i).toInt(&ok);
46 
47  if(ok)
48  {
49  switch(i)
50  {
51  case 2:
52  d = v * ((negative) ? -1 : 1);
53  break;
54 
55  case 3:
56  m = v;
57  break;
58 
59  case 4:
60  s = v;
61  break;
62 
63  default:
64  break;
65  }
66  }
67  else
68  {
69  if(texts.at(i).compare("-") == 0)
70  negative = true;
71  }
72  }
73 }
74 
75 /*!
76  * \brief Returns the status of the \a dms construction.
77  *
78  * \param dms The degree-minute-second value.
79  *
80  * \param[out] d Degrees.
81  *
82  * \param[out] m Minutes.
83  *
84  * \param[out] s Seconds.
85  *
86  * \return Three possible states: accepted, intermediate, invalid.
87  */
88 QValidator::State IsAValidDMSValue(const QString& dms, int& d, int& m, int& s)
89 {
90  QString aux("^(-)?(\\d{1,3})?");
91 
92  aux += QString(QChar(0260)) += " *(\\d{1,2})?' *(\\d{1,2})?''$";
93 
94  QRegularExpression r(aux);
95 
96  QString dmsS = dms;
97 
98  QRegularExpressionMatch match = r.match(dmsS.remove(" "));
99 
100  if(!match.hasMatch())
101  return QValidator::Invalid;
102 
103  ParseDMS(match, d, m, s);
104 
105  // If some information is missed, the input can be used.
106  if((d == 999) || (m == 999) || (s == 999))
107  return QValidator::Intermediate;
108 
109  //Checking degrees
110  if(!((d >= -180) && (d <= 180)))
111  return QValidator::Invalid;
112 
113  //Checking minutes
114  if(!((m >= 0) && (m <= 60)))
115  return QValidator::Invalid;
116 
117  //Checking second
118  if(!((s >= 0) && (s <= 60)))
119  return QValidator::Invalid;
120 
121  return QValidator::Acceptable;
122 }
123 
124 /*!
125  * \overload QValidator::State IsAValidDMSValue(const QString& dms)
126  */
127 QValidator::State IsAValidDMSValue(const QString& dms)
128 {
129  int d,
130  m,
131  s;
132 
133  return IsAValidDMSValue(dms, d, m, s);
134 }
135 
136 /*!
137  * \brief Returns the value as a formatted string.
138  *
139  * \param d Degrees.
140  *
141  * \param m Minutes.
142  *
143  * \param s Seconds.
144  *
145  * \return A string formatted as a degrees-minutes-seconds value.
146  */
147 QString GetDMSAsString(const int& d, const int& m, const int& s)
148 {
149  QString dS,
150  mS,
151  sS;
152 
153  // Checking degrees.
154  if(d == 999)
155  dS = " 0";
156  else
157  {
158  dS = QString::number(d);
159  int diff = 4 - dS.size();
160 
161  for(int i = 0; i < diff; i++)
162  dS = " " + dS;
163  }
164 
165  // Checking minutes
166  if(m == 999)
167  mS = " 0";
168  else
169  {
170  mS = QString::number(m);
171  int diff = 2 - mS.size();
172 
173  for(int i = 0; i < diff; i++)
174  mS = " " + mS;
175  }
176 
177  // Checking seconds
178  if(s == 999)
179  sS = " 0";
180  else
181  {
182  sS = QString::number(s);
183  int diff = 2 - sS.size();
184 
185  for(int i = 0; i < diff; i++)
186  sS = " " + sS;
187  }
188 
189  return dS + QString(QChar(0260)) + " " + mS + "' " + sS + "''";
190 }
191 
192 /*!
193  * \brief Returns the mask to be used by lineEdit objects.
194  *
195  * \param decimalDegree Flag telling what kind of validators we will use.
196  *
197  * \return The mask for lineEdits acoording to \a decimalDegree.
198  */
199 QString GetLineEditMask(const bool& decimalDegree)
200 {
201  QString res;
202 
203  if(decimalDegree)
204  res = QString("###9" + QString(QChar(0260)) + " 00\' 00\'\'");
205 
206  return res;
207 }
208 
209 /*!
210  * \brief Transforms a degree-minute-second value into a decimal-degree value.
211  *
212  * \param d Degrees.
213  *
214  * \param m Minutes.
215  *
216  * \param s Seconds.
217  *
218  * \return The decimal-degree value.
219  */
220 double DMS2DD(const int& d, const int& m, const int& s)
221 {
222  bool negativeValue = false;
223  double dd = 0;
224 
225  if (d < 0)
226  {
227  negativeValue = true;
228  dd = d * (-1);
229  }
230  else
231  dd = d;
232 
233  double coord = dd + (m / 60.0) + (s / 3600.0);
234 
235  coord *= (negativeValue) ? -1 : 1;
236 
237  return coord;
238 }
239 
240 /*!
241  * \brief Transforms a decimal-degree value in a degree-minute-second formatted string.
242  *
243  * \param value Value in decimal-degrees.
244  *
245  * \return The degree-minute-second representing the given \a value.
246  */
247 QString DD2DMS(const double& value)
248 {
249  int degree;
250  int minute;
251  double second;
252  double ll;
253 
254  degree = static_cast<int>(value);
255  ll = value - degree;
256  minute = static_cast<int>(ll * 60);
257  ll = (ll * 60.) - minute;
258  second = ll * 60.;
259 
260  return GetDMSAsString(degree, minute, static_cast<int>(std::ceil(second)));
261 }
262 
263 /*!
264  * \brief Returns a centralized box maintaining the aspect ratio of the older one.
265  *
266  * \param world The bounding rect of the current visible area.
267  *
268  * \param center Point where to centralize.
269  *
270  * \return The new envelope.
271  */
273 {
274  double w = world.getWidth(),
275  h = world.getHeight(),
276  llx = center.getX() - w/2,
277  lly = center.getY() - h/2,
278  urx = center.getX() + w/2,
279  ury = center.getY() + h/2;
280 
281  return te::gm::Envelope(llx, lly, urx, ury);
282 }
283 
284 /*!
285  * \class DMSValidator
286  *
287  * \brief Class used to evaluate the coordinates given as degree-minute-second values.
288  */
289 class DMSValidator : public QValidator
290 {
291 public:
292 
293  /*!
294  * \brief Constructor.
295  *
296  * \param parent Used by Qt to manage the pointers.
297  */
298  DMSValidator(QWidget* parent = nullptr) :
299  QValidator(parent)
300  {
301  }
302 
303  /*!
304  * \brief Destructor.
305  */
306  ~DMSValidator() override = default;
307 
308  /*!
309  * \brief Verifies if the value is a degree-minute-second valid value.
310  *
311  * \param value The formatted value.
312  *
313  * \return Three possible values: accepted, intermediate, invalid.
314  */
315  State validate(QString& value, int&) const override
316  {
317  return IsAValidDMSValue(value);
318  }
319 
320  /*!
321  * \brief Used to try to fix some errors on \a value.
322  *
323  * \param value The string to be fixed.
324  */
325  void fixup(QString& value) const override
326  {
327  int d,
328  m,
329  s;
330 
331  QValidator::State state = IsAValidDMSValue(value, d, m, s);
332 
333  if(state == QValidator::Intermediate)
334  value = GetDMSAsString(d, m, s);
335  }
336 };
337 
338 // ------------------------------
339 // End utilities functions section
340 // ------------------------------
341 
343  QDialog(display),
344  m_ui(new Ui::InputCoordinateForm),
345  m_validator(nullptr),
346  m_display(display)
347 {
348  m_ui->setupUi(this);
349 
350  updateValidator(true);
351 
352  m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
353 
354  connect(m_ui->m_Latitude_lineEdit, SIGNAL(editingFinished()), SLOT(validatorStateChanged()));
355  connect(m_ui->m_Longitude_lineEdit, SIGNAL(editingFinished()), SLOT(validatorStateChanged()));
356 }
357 
359 {
360  delete m_ui;
361 }
362 
364 {
365  if(!m_ui->m_DMS_checkButton->isChecked())
366  return;
367 
368  double lat,
369  lon;
370 
371  bool ok;
372 
373  QString latS,
374  longS;
375 
376  lat = m_ui->m_Latitude_lineEdit->text().toDouble(&ok);
377 
378  if(!ok)
379  return;
380 
381  lon = m_ui->m_Longitude_lineEdit->text().toDouble(&ok);
382 
383  if(!ok)
384  return;
385 
386  updateValidator(true);
387 
388  m_ui->m_Latitude_lineEdit->setText(DD2DMS(lat));
389  m_ui->m_Longitude_lineEdit->setText(DD2DMS(lon));
390 }
391 
393 {
394  if(!m_ui->m_DD_checkButton->isChecked())
395  return;
396 
397  int d,
398  m,
399  s;
400 
401  double lat = 0,
402  lon = 0;
403 
404  QValidator::State state = IsAValidDMSValue(m_ui->m_Latitude_lineEdit->text(), d, m, s);
405 
406  if(state != QValidator::Invalid)
407  lat = DMS2DD(d, m, s);
408 
409  state = IsAValidDMSValue(m_ui->m_Longitude_lineEdit->text(), d, m, s);
410 
411  if(state != QValidator::Invalid)
412  lon = DMS2DD(d, m, s);
413 
414  updateValidator(false);
415 
416  m_ui->m_Latitude_lineEdit->setText(QString::number(lat));
417  m_ui->m_Longitude_lineEdit->setText(QString::number(lon));
418 }
419 
421 {
422  std::unique_ptr<te::gm::Coord2D> coord(getCoordinate());
423 
424  int srid = 4326,
425  displaySrid = m_display->getSRID();
426 
428 
429  if(srid != displaySrid)
430  env.transform(displaySrid, srid);
431 
432  env = GetCenteredBox(env, *coord.get());
433 
434  if(srid != displaySrid)
435  env.transform(srid, displaySrid);
436 
437  m_display->setExtent(env, true);
438 }
439 
441 {
442  reject();
443 }
444 
446 {
447  if(m_ui->m_Latitude_lineEdit->text().isEmpty() || m_ui->m_Longitude_lineEdit->text().isEmpty())
448  m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
449  else
450  m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
451 
452  if(m_ui->m_Latitude_lineEdit->hasAcceptableInput() && m_ui->m_Latitude_lineEdit->hasAcceptableInput())
453  m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
454  else
455  m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
456 }
457 
459 {
460  QString mask = GetLineEditMask(isDMS);
461 
462  delete m_validator;
463 
464  if(isDMS)
465  m_validator = new DMSValidator(this);
466  else
467  m_validator = new QDoubleValidator(this);
468 
469  m_ui->m_Latitude_lineEdit->setInputMask(mask);
470  m_ui->m_Latitude_lineEdit->setValidator(m_validator);
471 
472  m_ui->m_Longitude_lineEdit->setInputMask(mask);
473  m_ui->m_Longitude_lineEdit->setValidator(m_validator);
474 }
475 
477 {
478  te::gm::Coord2D* coord = nullptr;
479 
480  if(m_ui->m_DMS_checkButton->isChecked())
481  {
482  int d,
483  m,
484  s;
485  double x,
486  y;
487 
488  QValidator::State state = IsAValidDMSValue(m_ui->m_Latitude_lineEdit->text(), d, m, s);
489 
490  if(state != QValidator::Invalid)
491  {
492  x = DMS2DD(d, m, s);
493 
494  state = IsAValidDMSValue(m_ui->m_Longitude_lineEdit->text(), d, m, s);
495 
496  if(state != QValidator::Invalid)
497  {
498  y = DMS2DD(d, m, s);
499 
500  coord = new te::gm::Coord2D(x, y);
501  }
502 
503  }
504  }
505  else
506  {
507  double x,
508  y;
509  bool ok;
510 
511  x = m_ui->m_Latitude_lineEdit->text().toDouble(&ok);
512 
513  if(ok)
514  {
515  y = m_ui->m_Longitude_lineEdit->text().toDouble(&ok);
516 
517  if(ok)
518  coord = new te::gm::Coord2D(x, y);
519  }
520  }
521 
522  return coord;
523 }
Ui::InputCoordinateForm * m_ui
Pointer for Qt structure.
Class used to evaluate the coordinates given as degree-minute-second values.
QString DD2DMS(const double &value)
Transforms a decimal-degree value in a degree-minute-second formatted string.
DMSValidator(QWidget *parent=nullptr)
Constructor.
QValidator::State IsAValidDMSValue(const QString &dms, int &d, int &m, int &s)
Returns the status of the dms construction.
MapDisplay * m_display
Map display to show the result.
double getWidth() const
It returns the envelope width.
void DD_triggered()
Called when the decimal-degree button was selected.
A widget to control the display of a set of layers.
An utility struct for representing 2D coordinates.
Definition: Coord2D.h:40
double getY() const
It returns the y-coordinate.
Definition: Coord2D.h:108
~DMSValidator() override=default
Destructor.
InputCoordinateDialog(MapDisplay *display)
Constructor.
QString GetLineEditMask(const bool &decimalDegree)
Returns the mask to be used by lineEdit objects.
te::gm::Coord2D * getCoordinate()
Returns the coordinate of the input.
An Envelope defines a 2D rectangular region.
virtual int getSRID() const
It return the Spatial Reference System used by the Map Display.
void DMS_triggered()
Called when the degree-minute-second button was selected.
static te::dt::DateTime d(2010, 8, 9, 15, 58, 39)
virtual const te::gm::Envelope & getExtent() const
It returns the world extent showned by the MapDisplay.
void validatorStateChanged()
Called when the line-edits changed its valid state.
void ParseDMS(const QRegularExpressionMatch &match, int &d, int &m, int &s)
Extracts the degree, minute and second portions of the match object.
te::gm::Envelope GetCenteredBox(const te::gm::Envelope &world, const te::gm::Coord2D &center)
Returns a centralized box maintaining the aspect ratio of the older one.
double DMS2DD(const int &d, const int &m, const int &s)
Transforms a degree-minute-second value into a decimal-degree value.
void ok_triggered()
Called when the Ok button was pressed.
void fixup(QString &value) const override
Used to try to fix some errors on value.
double getX() const
It returns the x-coordinate.
Definition: Coord2D.h:102
QValidator * m_validator
Validator being used.
void transform(int oldsrid, int newsrid)
It will transform the coordinates of the Envelope from the old SRS to the new one.
virtual void setExtent(te::gm::Envelope &e, bool doRefresh=true)
It sets the world visible area and refreshes the contents in the map display.
QString GetDMSAsString(const int &d, const int &m, const int &s)
Returns the value as a formatted string.
double getHeight() const
It returns the envelope height.
void updateValidator(const bool &isDMS)
Updates the validator and the mask being used on coordinate line edit.
void cancel_triggered()
Called when the Cancel button was pressed.
Implements a dialog used to centralize the area of visualization in some coordinate.
State validate(QString &value, int &) const override
Verifies if the value is a degree-minute-second valid value.