swift
situationform.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 "situationform.h"
5 
6 #include <QDoubleValidator>
7 
8 #include "ui_situationform.h"
9 
11 #include "gui/guiapplication.h"
12 #include "misc/logmessage.h"
13 #include "misc/pq/angle.h"
14 #include "misc/pq/pressure.h"
15 #include "misc/stringutils.h"
16 
17 using namespace swift::misc;
18 using namespace swift::misc::aviation;
19 using namespace swift::misc::geo;
20 using namespace swift::misc::physical_quantities;
21 
22 namespace swift::gui::editors
23 {
24  CSituationForm::CSituationForm(QWidget *parent) : CForm(parent), ui(new Ui::CSituationForm)
25  {
26  ui->setupUi(this);
27 
28  ui->le_Bank->setValidator(new QDoubleValidator(-180.0 + CAngleUnit::deg().getEpsilon(), 180.0, 3, ui->le_Bank));
29  ui->le_Pitch->setValidator(
30  new QDoubleValidator(-180.0 + CAngleUnit::deg().getEpsilon(), 180.0, 3, ui->le_Pitch));
31  ui->le_Pressure->setValidator(new QDoubleValidator(980.0, 1046.0, 2, ui->le_Pressure));
32 
33  connect(ui->hs_Bank, &QSlider::valueChanged, this, &CSituationForm::bankSliderChanged);
34  connect(ui->hs_Pitch, &QSlider::valueChanged, this, &CSituationForm::pitchSliderChanged);
35  connect(ui->hs_Heading, &QSlider::valueChanged, this, &CSituationForm::headingSliderChanged);
36  connect(ui->hs_Pressure, &QSlider::valueChanged, this, &CSituationForm::pressureSliderChanged);
37  connect(ui->le_Bank, &QLineEdit::editingFinished, this, &CSituationForm::bankEntered);
38  connect(ui->le_Pitch, &QLineEdit::editingFinished, this, &CSituationForm::pitchEntered);
39  connect(ui->le_Pressure, &QLineEdit::editingFinished, this, &CSituationForm::pressureEntered);
40  connect(ui->le_Heading, &QLineEdit::editingFinished, this, &CSituationForm::headingEntered);
41 
42  connect(ui->tb_ResetBank, &QToolButton::clicked, this, &CSituationForm::resetBank);
43  connect(ui->tb_ResetPitch, &QToolButton::clicked, this, &CSituationForm::resetPitch);
44  connect(ui->tb_ResetHeading, &QToolButton::clicked, this, &CSituationForm::resetHeading);
45  connect(ui->tb_ResetPressure, &QToolButton::clicked, this, &CSituationForm::resetPressure);
46  connect(ui->pb_SetOwnAircraft, &QPushButton::released, this, &CSituationForm::changeAircraftSituation);
47  connect(ui->pb_SetEnvironment, &QPushButton::released, this, &CSituationForm::changeAircraftSituation);
48  connect(ui->pb_PresetOwnAircraft, &QPushButton::released, this, &CSituationForm::presetOwnAircraftSituation);
49  connect(ui->comp_Coordinate, &CCoordinateForm::changedCoordinate, this, &CSituationForm::onCoordinateChanged);
50  }
51 
53 
55  {
56  ui->comp_Coordinate->setCoordinate(situation);
57  this->bankSliderChanged(situation.getBank().valueInteger(CAngleUnit::deg()));
58  this->pitchSliderChanged(situation.getPitch().valueInteger(CAngleUnit::deg()));
59  this->headingSliderChanged(situation.getHeading().valueInteger(CAngleUnit::deg()));
60  }
61 
63  {
64  const CCoordinateGeodetic position = ui->comp_Coordinate->getCoordinate();
65  const CAltitude pressureAltitude(
66  position.geodeticHeight().toPressureAltitude(this->getBarometricPressureMsl()));
67 
68  CAircraftSituation s(position);
69  s.setBank(this->getBankAngle());
70  s.setPitch(this->getPitchAngle());
71  s.setHeading(CHeading(this->getHeadingAngle(), CHeading::True));
72  s.setGroundSpeed(this->getGroundSpeed());
73 
74  if (!pressureAltitude.isNull() && pressureAltitude.getAltitudeType() == CAltitude::PressureAltitude)
75  {
76  s.setPressureAltitude(pressureAltitude);
77  }
78  return s;
79  }
80 
81  CAngle CSituationForm::getBankAngle() const { return CAngle(getBankAngleDegrees(), CAngleUnit::deg()); }
82 
83  double CSituationForm::getBankAngleDegrees() const
84  {
85  const QString v(ui->le_Bank->text().replace(',', '.'));
86  bool ok;
87  double vd = v.toDouble(&ok);
88  if (!ok) { vd = 0.0; }
89  return CAngle::normalizeDegrees180(vd, RoundDigits);
90  }
91 
92  CAngle CSituationForm::getPitchAngle() const { return CAngle(getPitchAngleDegrees(), CAngleUnit::deg()); }
93 
94  double CSituationForm::getPitchAngleDegrees() const
95  {
96  const QString v(ui->le_Pitch->text().replace(',', '.'));
97  bool ok;
98  double vd = v.toDouble(&ok);
99  if (!ok) { vd = 0.0; }
100  return CAngle::normalizeDegrees180(vd, RoundDigits);
101  }
102 
103  CAngle CSituationForm::getHeadingAngle() const { return CAngle(getHeadingAngleDegrees(), CAngleUnit::deg()); }
104 
105  double CSituationForm::getHeadingAngleDegrees() const
106  {
107  const QString v(ui->le_Heading->text().replace(',', '.'));
108  bool ok;
109  double vd = v.toDouble(&ok);
110  if (!ok) { vd = 0.0; }
111  return CAngle::normalizeDegrees180(vd, RoundDigits);
112  }
113 
114  double CSituationForm::getBarometricPressureMslMillibar() const
115  {
116  const QString v(ui->le_Pressure->text().replace(',', '.'));
117  bool ok;
118  double vd = v.toDouble(&ok);
119  if (!ok) { vd = CAltitude::standardISASeaLevelPressure().value(CPressureUnit::mbar()); }
120  return vd;
121  }
122 
123  CPressure CSituationForm::getBarometricPressureMsl() const
124  {
125  return CPressure(this->getBarometricPressureMslMillibar(), CPressureUnit::mbar());
126  }
127 
128  CSpeed CSituationForm::getGroundSpeed() const
129  {
130  const int gsKts = ui->sb_GsKts->value();
131  return CSpeed(gsKts, CSpeedUnit::kts());
132  }
133 
134  void CSituationForm::setReadOnly(bool readonly)
135  {
136  ui->comp_Coordinate->setReadOnly(readonly);
137 
138  ui->le_Bank->setReadOnly(readonly);
139  ui->le_Heading->setReadOnly(readonly);
140  ui->le_Pitch->setReadOnly(readonly);
141  ui->le_Pressure->setReadOnly(readonly);
142 
143  ui->hs_Bank->setEnabled(!readonly);
144  ui->hs_Heading->setEnabled(!readonly);
145  ui->hs_Pitch->setEnabled(!readonly);
146  ui->hs_Pressure->setEnabled(!readonly);
147 
148  this->forceStyleSheetUpdate();
149  }
150 
152 
154  {
156  if (nested) { ml.push_back(ui->comp_Coordinate->validate(nested)); }
157  return ml;
158  }
159 
160  void CSituationForm::showSetButton(bool visible) { ui->pb_SetOwnAircraft->setVisible(visible); }
161 
162  int clampAngle(int in) { return qBound(-179, in, 180); }
163 
164  void CSituationForm::bankSliderChanged(int value)
165  {
166  const int angle = clampAngle(qRound(this->getBankAngleDegrees()));
167  if (value == angle) { return; } // avoid roundtrips
168  ui->le_Bank->setText(QString::number(value));
169  }
170 
171  void CSituationForm::pitchSliderChanged(int value)
172  {
173  const int angle = clampAngle(qRound(this->getPitchAngleDegrees()));
174  if (value == angle) { return; } // avoid roundtrips
175  ui->le_Pitch->setText(QString::number(value));
176  }
177 
178  void CSituationForm::headingSliderChanged(int value)
179  {
180  const int angle = clampAngle(qRound(this->getHeadingAngleDegrees()));
181  if (value == angle) { return; } // avoid roundtrips
182  ui->le_Heading->setText(QString::number(value));
183  }
184 
185  void CSituationForm::pressureSliderChanged(int value)
186  {
187  const int pressure = qRound(this->getBarometricPressureMslMillibar());
188  if (value == pressure) { return; } // avoid roundtrips
189  ui->le_Pressure->setText(QString::number(value));
190  }
191 
192  void CSituationForm::bankEntered()
193  {
194  const double ad = this->getBankAngleDegrees();
195  QString n = QString::number(ad, 'g', 3 + RoundDigits);
196  if (ui->le_Pitch->validator()) { dotToLocaleDecimalPoint(n); }
197  ui->le_Bank->setText(n);
198  const int angle = clampAngle(qRound(ad));
199  if (angle == ui->hs_Bank->value()) { return; } // avoid roundtrips
200  ui->hs_Bank->setValue(angle);
201  }
202 
203  void CSituationForm::resetBank()
204  {
205  ui->le_Bank->setText("0");
206  ui->hs_Bank->setValue(0);
207  }
208 
209  void CSituationForm::pitchEntered()
210  {
211  const double ad = this->getPitchAngleDegrees();
212  QString n = QString::number(ad, 'g', 3 + RoundDigits);
213  if (ui->le_Pitch->validator()) { dotToLocaleDecimalPoint(n); }
214  ui->le_Pitch->setText(n);
215  const int angle = clampAngle(qRound(ad));
216  if (angle == ui->hs_Pitch->value()) { return; } // avoid roundtrips
217  ui->hs_Pitch->setValue(angle);
218  }
219 
220  void CSituationForm::resetPitch()
221  {
222  ui->le_Pitch->setText("0");
223  ui->hs_Pitch->setValue(0);
224  }
225 
226  void CSituationForm::headingEntered()
227  {
228  const double ad = this->getHeadingAngleDegrees();
229  QString n = QString::number(ad, 'g', 3 + RoundDigits);
230  if (ui->le_Heading->validator()) { dotToLocaleDecimalPoint(n); }
231  ui->le_Heading->setText(n);
232  const int angle = clampAngle(qRound(ad));
233  if (angle == ui->hs_Heading->value()) { return; } // avoid roundtrips
234  ui->hs_Heading->setValue(angle);
235  }
236 
237  void CSituationForm::resetHeading()
238  {
239  ui->le_Heading->setText("0");
240  ui->hs_Heading->setValue(0);
241  }
242 
243  void CSituationForm::pressureEntered()
244  {
245  const double pd = this->getBarometricPressureMslMillibar();
246  QString n = QString::number(pd, 'g', 4 + RoundDigits);
247  if (ui->le_Pressure->validator()) { dotToLocaleDecimalPoint(n); }
248  ui->le_Pressure->setText(n);
249  const int pi = qRound(pd);
250  if (pi == ui->hs_Pressure->value()) { return; } // avoid roundtrips
251  ui->hs_Pressure->setValue(pi);
252  }
253 
254  void CSituationForm::resetPressure()
255  {
256  static const int v = CAltitude::standardISASeaLevelPressure().valueInteger(CPressureUnit::mbar());
257  static const QString vs(dotToLocaleDecimalPoint(
258  QString::number(CAltitude::standardISASeaLevelPressure().valueRounded(CPressureUnit::mbar(), 2))));
259  ui->le_Pressure->setText(vs);
260  ui->hs_Pressure->setValue(v);
261  }
262 
263  void CSituationForm::presetOwnAircraftSituation()
264  {
265  if (!sGui || sGui->isShuttingDown() || !sGui->getIContextOwnAircraft()) { return; }
267  this->setSituation(s);
268  }
269 
270  void CSituationForm::onCoordinateChanged() { emit this->changeAircraftSituation(); }
271 } // namespace swift::gui::editors
const context::IContextOwnAircraft * getIContextOwnAircraft() const
Direct access to contexts if a CCoreFacade has been initialized.
bool isShuttingDown() const
Is application shutting down?
virtual swift::misc::aviation::CAircraftSituation getOwnAircraftSituation() const =0
Get own aircraft.
void changedCoordinate()
Change coordinate.
Form base class.
Definition: form.h:27
void forceStyleSheetUpdate()
Forces a stylesheet update.
Definition: form.cpp:47
virtual ~CSituationForm()
Destructor.
swift::misc::aviation::CAircraftSituation getSituation() const
Get the situation.
void changeAircraftSituation()
Aircraft situation to be changed.
void showSetButton(bool visible)
Set button visible.
virtual void setReadOnly(bool readonly)
Set editable.
void setSituation(const swift::misc::aviation::CAircraftSituation &situation)
Set the situation.
virtual swift::misc::CStatusMessageList validate(bool nested=false) const
Validate, empty list means OK.
virtual void setSelectOnly()
Read only, but entity can be selected (normally used in mapping). Use setReadOnly to reset this very ...
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
Status messages, e.g. from Core -> GUI.
Value object encapsulating information of an aircraft's situation.
void setPressureAltitude(const CAltitude &altitude)
Set pressure altitude.
void setGroundSpeed(const physical_quantities::CSpeed &groundspeed)
Set ground speed.
const CHeading & getHeading() const
Get heading.
void setBank(const physical_quantities::CAngle &bank)
Set bank (angle)
void setHeading(const CHeading &heading)
Set heading.
void setPitch(const physical_quantities::CAngle &pitch)
Set pitch.
const physical_quantities::CAngle & getBank() const
Get bank (angle)
const physical_quantities::CAngle & getPitch() const
Get pitch.
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
AltitudeType getAltitudeType() const
Current altitude type.
Definition: altitude.h:157
CAltitude toPressureAltitude(const physical_quantities::CPressure &seaLevelPressure) const
Returns the altitude converted to pressure altitude. Requires the current barometric pressure at MSL.
Definition: altitude.cpp:131
Heading as used in aviation, can be true or magnetic heading.
Definition: heading.h:41
virtual const aviation::CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
Physical unit angle (radians, degrees)
Definition: angle.h:23
int valueInteger(MU unit) const
As integer value.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
Free functions in swift::misc.
SWIFT_MISC_EXPORT QString dotToLocaleDecimalPoint(QString &input)
Replace dot '.' by locale decimal point.