swift
coordinateform.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2017 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "coordinateform.h"
5 
6 #include <QIntValidator>
7 
8 #include "ui_coordinateform.h"
9 
12 #include "core/webdataservices.h"
13 #include "gui/guiapplication.h"
14 #include "misc/aviation/airport.h"
15 
16 using namespace swift::gui;
17 using namespace swift::misc;
18 using namespace swift::misc::geo;
19 using namespace swift::misc::aviation;
20 using namespace swift::misc::physical_quantities;
21 
22 namespace swift::gui::editors
23 {
24  CCoordinateForm::CCoordinateForm(QWidget *parent) : CForm(parent), ui(new Ui::CCoordinateForm)
25  {
26  ui->setupUi(this);
27 
28  ui->lblp_LatCheck->setToolTips("ok", "wrong format");
29  ui->lblp_LngCheck->setToolTips("ok", "wrong format");
30  ui->lblp_ElvCheck->setToolTips("ok", "wrong format");
31 
32  ui->le_LatDeg->setValidator(new QIntValidator(-90, 90, ui->le_LatDeg));
33  ui->le_LatMin->setValidator(new QIntValidator(0, 60, ui->le_LatMin));
34  ui->le_LatSec->setValidator(new QIntValidator(0, 60, ui->le_LatSec));
35  ui->le_LatSecFrag->setValidator(new QIntValidator(0, 10E7, ui->le_LatSecFrag));
36 
37  ui->le_LngDeg->setValidator(new QIntValidator(-180, 180, ui->le_LngDeg));
38  ui->le_LngMin->setValidator(new QIntValidator(0, 60, ui->le_LngMin));
39  ui->le_LngSec->setValidator(new QIntValidator(0, 60, ui->le_LngSec));
40  ui->le_LngSecFrag->setValidator(new QIntValidator(0, 10E7, ui->le_LngSecFrag));
41 
42  connect(ui->le_Latitude, &QLineEdit::editingFinished, this, &CCoordinateForm::latEntered);
43  connect(ui->le_Longitude, &QLineEdit::editingFinished, this, &CCoordinateForm::lngEntered);
44  connect(ui->le_Elevation, &QLineEdit::editingFinished, this, &CCoordinateForm::elvEntered);
45 
46  connect(ui->le_LatDeg, &QLineEdit::editingFinished, this, &CCoordinateForm::latCombinedEntered);
47  connect(ui->le_LatMin, &QLineEdit::editingFinished, this, &CCoordinateForm::latCombinedEntered);
48  connect(ui->le_LatSec, &QLineEdit::editingFinished, this, &CCoordinateForm::latCombinedEntered);
49  connect(ui->le_LatSecFrag, &QLineEdit::editingFinished, this, &CCoordinateForm::latCombinedEntered);
50 
51  connect(ui->le_LngDeg, &QLineEdit::editingFinished, this, &CCoordinateForm::lngCombinedEntered);
52  connect(ui->le_LngMin, &QLineEdit::editingFinished, this, &CCoordinateForm::lngCombinedEntered);
53  connect(ui->le_LngSec, &QLineEdit::editingFinished, this, &CCoordinateForm::lngCombinedEntered);
54  connect(ui->le_LngSecFrag, &QLineEdit::editingFinished, this, &CCoordinateForm::lngCombinedEntered);
55 
56  connect(ui->le_Location, &QLineEdit::returnPressed, this, &CCoordinateForm::locationEntered);
57 
58  connect(ui->pb_Set, &QPushButton::pressed, this, &CCoordinateForm::changedCoordinate);
59  connect(ui->pb_OwnAircraft, &QPushButton::pressed, this, &CCoordinateForm::presetOwnAircraftPosition);
60 
61  const CCoordinateGeodetic c;
62  this->setCoordinate(c);
63  }
64 
66 
68  {
69  if (coordinate == m_coordinate) { return false; }
70  m_coordinate = coordinate;
71 
72  const CLatitude lat = coordinate.latitude();
73  const QString latWgs = lat.toWgs84();
74  ui->le_Latitude->setText(latWgs);
75  ui->le_Latitude->setToolTip(QString::number(lat.value(CAngleUnit::deg())));
76  ui->lblp_LatCheck->setTicked(!lat.isNull());
77  if (latWgs.contains('S')) { ui->rb_S->setChecked(true); }
78  else { ui->rb_N->setChecked(true); }
79 
80  const CLongitude lng = coordinate.longitude();
81  const QString lngWgs = lng.toWgs84();
82  ui->le_Longitude->setText(lngWgs);
83  ui->le_Longitude->setToolTip(QString::number(lng.value(CAngleUnit::deg())));
84  ui->lblp_LngCheck->setTicked(!lng.isNull());
85  if (lngWgs.contains('W')) { ui->rb_W->setChecked(true); }
86  else { ui->rb_E->setChecked(true); }
87 
88  const CLatitude::DegMinSecFractionalSec latParts = lat.asSexagesimalDegMinSec(true);
89  ui->le_LatDeg->setText(latParts.degAsString());
90  ui->le_LatMin->setText(latParts.minAsString());
91  ui->le_LatSec->setText(latParts.secAsString());
92  ui->le_LatSecFrag->setText(latParts.fractionalSecAsString(6));
93 
94  const CLongitude::DegMinSecFractionalSec lngParts = lng.asSexagesimalDegMinSec(true);
95  ui->le_LngDeg->setText(lngParts.degAsString());
96  ui->le_LngMin->setText(lngParts.minAsString());
97  ui->le_LngSec->setText(lngParts.secAsString());
98  ui->le_LngSecFrag->setText(lngParts.fractionalSecAsString(6));
99 
100  const QString elvString = coordinate.geodeticHeightAsString();
101  ui->le_Elevation->setText(elvString);
102  ui->lblp_ElvCheck->setTicked(!elvString.isEmpty());
103 
104  std::array<double, 3> v = coordinate.normalVectorDouble();
105  ui->le_X->setText(QString::number(v[0]));
106  ui->le_Y->setText(QString::number(v[1]));
107  ui->le_Z->setText(QString::number(v[2]));
108  ui->le_X->home(false);
109  ui->le_Y->home(false);
110  ui->le_Z->home(false);
111 
112  return true;
113  }
114 
115  void CCoordinateForm::setReadOnly(bool readonly)
116  {
117  ui->le_Elevation->setReadOnly(readonly);
118  ui->le_LatDeg->setReadOnly(readonly);
119  ui->le_Latitude->setReadOnly(readonly);
120  ui->le_LatMin->setReadOnly(readonly);
121  ui->le_LatSec->setReadOnly(readonly);
122  ui->le_LatSecFrag->setReadOnly(readonly);
123  ui->le_LngDeg->setReadOnly(readonly);
124  ui->le_LngMin->setReadOnly(readonly);
125  ui->le_LngSec->setReadOnly(readonly);
126  ui->le_LngSecFrag->setReadOnly(readonly);
127  ui->le_Longitude->setReadOnly(readonly);
128 
129  ui->rb_E->setEnabled(!readonly);
130  ui->rb_N->setEnabled(!readonly);
131  ui->rb_S->setEnabled(!readonly);
132  ui->rb_W->setEnabled(!readonly);
133 
134  ui->le_Location->setReadOnly(readonly);
135  ui->le_Location->setVisible(!readonly); // does not make sense to show it in ro, no reverse lookup
136  ui->lbl_Location->setVisible(!readonly);
137 
138  this->forceStyleSheetUpdate();
139  }
140 
142  {
143  // not implemented
144  Q_UNUSED(nested);
146  return ml;
147  }
148 
149  void CCoordinateForm::showSetButton(bool visible) { ui->pb_Set->setVisible(visible); }
150 
152  {
153  ui->le_Elevation->setVisible(show);
154  ui->lbl_Elevation->setVisible(show);
155  ui->lblp_ElvCheck->setVisible(show);
156  m_coordinate.setGeodeticHeightToNull();
157  }
158 
159  void CCoordinateForm::locationEntered()
160  {
161  const QString l = ui->le_Location->text().trimmed().simplified().toUpper();
162 
163  // location based on swift data
164  if (sApp && sApp->hasWebDataServices())
165  {
166  CAirport airport;
167 
168  // airport ICAO
169  if (l.length() == 4 && sApp->getWebDataServices()->getAirportsCount() > 0)
170  {
172  if (airport.hasValidDbKey())
173  {
174  this->setCoordinate(airport);
175  return;
176  }
177  }
178 
180  if (airport.hasValidDbKey())
181  {
182  this->setCoordinate(airport);
183  return;
184  }
185  }
186  // 33°59′42″S 150°57′06″E
187  if (l.contains(' '))
188  {
189  QString lat, lng;
190  const QStringList parts = l.split(' ');
191  for (const QString &p : parts)
192  {
193  if (p.contains('S') || p.contains('N')) { lat = p; }
194  else if (p.contains('E') || p.contains('W')) { lng = p; }
195  }
196  if (!lat.isEmpty() && !lng.isEmpty())
197  {
198  CCoordinateGeodetic c = m_coordinate;
199  c.setLatLongFromWgs84(lat, lng);
200  this->setCoordinate(c);
201  }
202  }
203  }
204 
205  void CCoordinateForm::latEntered()
206  {
207  const QString ls = ui->le_Latitude->text();
208  const CLatitude l = CLatitude::fromWgs84(ls);
209  ui->lblp_LatCheck->setTicked(!l.isNull());
210  CCoordinateGeodetic c = m_coordinate;
211  c.setLatitude(l);
212  this->setCoordinate(c);
213  }
214 
215  void CCoordinateForm::latCombinedEntered()
216  {
217  bool ok;
218  int deg = ui->le_LatDeg->text().trimmed().toInt(&ok);
219  if (!ok) return;
220 
221  int min = ui->le_LatMin->text().trimmed().toInt(&ok);
222  if (!ok) return;
223 
224  const QString secStr = ui->le_LatSec->text().trimmed() + "." + ui->le_LatSecFrag->text().trimmed();
225  double sec = secStr.toDouble(&ok);
226  if (!ok) return;
227 
228  CAngle::unifySign(deg, min, sec);
229  const CAngle a(deg, min, sec);
230  CLatitude lat(a);
231  lat.roundToEpsilon();
232  CCoordinateGeodetic c = m_coordinate;
233  c.setLatitude(lat);
234  this->setCoordinate(c);
235  }
236 
237  void CCoordinateForm::lngEntered()
238  {
239  const QString ls = ui->le_Longitude->text();
240  const CLongitude l = CLongitude::fromWgs84(ls);
241  ui->lblp_LatCheck->setTicked(!l.isNull());
242  CCoordinateGeodetic c = m_coordinate;
243  c.setLongitude(l);
244  this->setCoordinate(c);
245  }
246 
247  void CCoordinateForm::lngCombinedEntered()
248  {
249  bool ok;
250  int deg = ui->le_LngDeg->text().trimmed().toInt(&ok);
251  if (!ok) return;
252 
253  int min = ui->le_LngMin->text().trimmed().toInt(&ok);
254  if (!ok) return;
255 
256  const QString secStr = ui->le_LngSec->text().trimmed() + "." + ui->le_LngSecFrag->text().trimmed();
257  double sec = secStr.toDouble(&ok);
258  if (!ok) return;
259 
260  CAngle::unifySign(deg, min, sec);
261  const CAngle a(deg, min, sec);
262  CLongitude lng(a);
263  lng.roundToEpsilon();
264  CCoordinateGeodetic c = m_coordinate;
265  c.setLongitude(lng);
266  this->setCoordinate(c);
267  }
268 
269  void CCoordinateForm::elvEntered()
270  {
271  const QString e = ui->le_Elevation->text().trimmed();
272  CAltitude a;
273  a.parseFromString(e, CPqString::SeparatorBestGuess);
274  ui->lblp_ElvCheck->setTicked(!e.isNull());
275  CCoordinateGeodetic c = m_coordinate;
276  c.setGeodeticHeight(a);
277  this->setCoordinate(c);
278  }
279 
280  void CCoordinateForm::presetOwnAircraftPosition()
281  {
282  if (!sGui || sGui->isShuttingDown()) { return; }
283  if (!sGui->getIContextOwnAircraft()) { return; }
285  this->setCoordinate(coordinate);
286  }
287 } // namespace swift::gui::editors
SWIFT_CORE_EXPORT swift::core::CApplication * sApp
Single instance of application object.
Definition: application.cpp:71
const context::IContextOwnAircraft * getIContextOwnAircraft() const
Direct access to contexts if a CCoreFacade has been initialized.
bool hasWebDataServices() const
Web data services available?
bool isShuttingDown() const
Is application shutting down?
CWebDataServices * getWebDataServices() const
Get the web data services.
swift::misc::aviation::CAirport getAirportForIcaoDesignator(const QString &icao) const
Get airport for ICAO designator.
int getAirportsCount() const
Get airports count.
swift::misc::aviation::CAirport getAirportForNameOrLocation(const QString &nameOrLocation) const
Get airport for name of location.
virtual swift::misc::simulation::CSimulatedAircraft getOwnAircraft() const =0
Get own aircraft.
Select / enter a geo position.
void showElevation(bool show)
Show elevation.
virtual swift::misc::CStatusMessageList validate(bool nested=false) const
Validate, empty list means OK.
void showSetButton(bool visible)
Set button visible.
virtual void setReadOnly(bool readonly)
Set editable.
void changedCoordinate()
Change coordinate.
bool setCoordinate(const swift::misc::geo::ICoordinateGeodetic &coordinate)
Set the coordinate.
Form base class.
Definition: form.h:27
void forceStyleSheetUpdate()
Forces a stylesheet update.
Definition: form.cpp:47
Status messages, e.g. from Core -> GUI.
Value object encapsulating information about an airpot.
Definition: airport.h:36
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
void parseFromString(const QString &value)
Parse value from string.
Definition: altitude.cpp:140
bool hasValidDbKey() const
Has valid DB key.
Definition: datastore.h:102
void setLatLongFromWgs84(const QString &latitude, const QString &longitude)
Set latitude and longitude.
void setLatitude(const CLatitude &latitude)
Set latitude.
void setGeodeticHeightToNull()
Set height to NULL.
void setGeodeticHeight(const aviation::CAltitude &height)
Set height (ellipsoidal or geodetic height)
void setLongitude(const CLongitude &longitude)
Set longitude.
QString toWgs84(int fractionalDigits=3) const
To WGS84 string.
Definition: latitude.h:32
QString toWgs84(int withFragmentSecDigits=3) const
To WGS84 string.
Definition: longitude.h:32
Geodetic coordinate, a position in 3D space relative to the reference geoid.
virtual CLongitude longitude() const =0
Longitude.
virtual std::array< double, 3 > normalVectorDouble() const =0
Normal vector with double precision.
QString geodeticHeightAsString() const
Height as string.
virtual CLatitude latitude() const =0
Latitude.
Physical unit angle (radians, degrees)
Definition: angle.h:23
DegMinSecFractionalSec asSexagesimalDegMinSec(bool range180Degrees=false) const
As individual values.
Definition: angle.cpp:44
double value(MU unit) const
Value in given unit.
const aviation::CAircraftSituation & getSituation() const
Get situation.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
GUI related classes.
Free functions in swift::misc.