swift
atcstation.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include <QCoreApplication>
7 #include <QStringBuilder>
8 #include <QtGlobal>
9 
11 #include "misc/comparefunctions.h"
14 #include "misc/pq/units.h"
15 #include "misc/propertyindexref.h"
16 #include "misc/propertyindexvariantmap.h" // needed for mixin::Index::apply
17 #include "misc/stringutils.h"
18 
19 using namespace swift::misc;
20 using namespace swift::misc::physical_quantities;
21 using namespace swift::misc::geo;
22 using namespace swift::misc::network;
23 
24 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::aviation, CAtcStation)
25 
26 namespace swift::misc::aviation
27 {
28  CAtcStation::CAtcStation() {}
29 
30  CAtcStation::CAtcStation(const QString &callsign) : m_callsign(callsign) { m_callsign.setTypeHint(CCallsign::Atc); }
31 
32  CAtcStation::CAtcStation(const CCallsign &callsign, const CUser &controller, const CFrequency &frequency,
33  const CCoordinateGeodetic &pos, const CLength &range, bool isOnline,
34  const QDateTime &logoffTimeUtc, const CInformationMessage &atis,
35  const CInformationMessage &metar)
36  : m_callsign(callsign), m_controller(controller), m_frequency(frequency), m_position(pos), m_range(range),
37  m_isOnline(isOnline), m_logoffTimeUtc(logoffTimeUtc), m_atis(atis), m_metar(metar)
38  {
39  // sync callsigns
40  m_callsign.setTypeHint(CCallsign::Atc);
41  if (!m_controller.hasCallsign() && !callsign.isEmpty()) { m_controller.setCallsign(m_callsign); }
42  }
43 
44  bool CAtcStation::hasLogoffTimeUtc() const { return !m_logoffTimeUtc.isNull(); }
45 
46  bool CAtcStation::hasMetar() const { return m_metar.hasMessage(); }
47 
49  {
50  if (!this->isAfvCrossCoupled()) { return this->getCallsignAsString(); }
51  return QStringLiteral("*") % this->getCallsignAsString();
52  }
53 
54  QString CAtcStation::getCallsignSuffix() const { return m_callsign.getSuffix(); }
55 
56  int CAtcStation::getSuffixSortOrder() const { return m_callsign.getSuffixSortOrder(); }
57 
58  void CAtcStation::setCallsign(const CCallsign &callsign)
59  {
60  m_callsign = callsign;
61  m_controller.setCallsign(callsign);
62  m_isAfvCrossCoupled = callsign.getStringAsSet().startsWith('*');
63  }
64 
66  {
67  if (m_callsign.isEmpty()) { return this->getControllerRealName(); }
68  if (!m_controller.hasRealName()) { return m_callsign.asString(); }
69  return m_callsign.asString() % u' ' % this->getControllerRealName();
70  }
71 
72  void CAtcStation::setController(const CUser &controller)
73  {
74  m_controller = controller;
75  m_controller.setCallsign(m_callsign);
76  }
77 
78  QString CAtcStation::convertToQString(bool i18n) const
79  {
80  static const QString atcI18n(QCoreApplication::translate("Aviation", "ATC station"));
81  static const QString rangeI18n(QCoreApplication::translate("Aviation", "range"));
82  static const QString fromUtcI18n(QCoreApplication::translate("Aviation", "from(UTC)"));
83  static const QString untilUtcI18n(QCoreApplication::translate("Aviation", "until(UTC)"));
84 
85  const QString s = (i18n ? atcI18n : QStringLiteral("ATC station")) % u' ' % m_callsign.toQString(i18n) % u' ' %
86  m_position.toQString(i18n) % u" online: " % boolToYesNo(m_isOnline) %
87 
88  // controller
89  (m_controller.isNull() ? QString() : u' ' % m_controller.toQString(i18n)) %
90 
91  // frequency
92  u' ' % m_frequency.valueRoundedWithUnit(3, i18n) %
93 
94  // ATIS
95  (!this->hasAtis() ? QString() : u' ' % m_atis.toQString(i18n)) %
96 
97  // METAR
98  (!this->hasMetar() ? QString() : u' ' % m_metar.toQString(i18n)) %
99 
100  // range
101  u' ' % (i18n ? rangeI18n : QStringLiteral("range")) % u' ' % m_range.toQString(i18n) %
102 
103  // distance / bearing
104  u' ' % ICoordinateWithRelativePosition::convertToQString(i18n);
105 
106  return s;
107 
108  // force strings for translation in resource files
109  (void)QT_TRANSLATE_NOOP("Aviation", "ATC station");
110  (void)QT_TRANSLATE_NOOP("Aviation", "online");
111  (void)QT_TRANSLATE_NOOP("Aviation", "offline");
112  (void)QT_TRANSLATE_NOOP("Aviation", "from(UTC)");
113  (void)QT_TRANSLATE_NOOP("Aviation", "until(UTC)");
114  (void)QT_TRANSLATE_NOOP("Aviation", "range");
115  (void)QT_TRANSLATE_NOOP("Aviation", "distance");
116  }
117 
118  void CAtcStation::setFrequency(const CFrequency &frequency)
119  {
120  m_frequency = frequency;
121  m_frequency.setUnit(CFrequencyUnit::MHz());
122  }
123 
125  {
126  if (m_range.isNull() || !hasValidRelativeDistance()) { return false; }
127  return (this->getRelativeDistance() <= m_range);
128  }
129 
130  bool CAtcStation::setOnline(bool online)
131  {
132  if (online == m_isOnline) { return false; }
133  m_isOnline = online;
134  return true;
135  }
136 
138  {
139  return comUnit.isActiveFrequencySameFrequency(this->getFrequency());
140  }
141 
142  bool CAtcStation::isAtcStationFrequency(const CFrequency &frequency) const
143  {
144  return CComSystem::isSameFrequency(frequency, this->getFrequency());
145  }
146 
148  {
149  switch (type)
150  {
151  case CInformationMessage::ATIS: return this->getAtis();
152  case CInformationMessage::METAR: return this->getMetar();
153  default: break;
154  }
156  }
157 
159  {
160  switch (message.getType())
161  {
162  case CInformationMessage::ATIS: this->setAtis(message); return true;
163  case CInformationMessage::METAR: this->setMetar(message); return true;
164  default: break;
165  }
166  return false;
167  }
168 
169  CLatitude CAtcStation::latitude() const { return this->getPosition().latitude(); }
170 
172 
173  const CAltitude &CAtcStation::geodeticHeight() const { return m_position.geodeticHeight(); }
174 
175  QVector3D CAtcStation::normalVector() const { return m_position.normalVector(); }
176 
177  std::array<double, 3> CAtcStation::normalVectorDouble() const { return m_position.normalVectorDouble(); }
178 
180  {
181  if (index.isMyself()) { return QVariant::fromValue(*this); }
182  const ColumnIndex i = index.frontCasted<ColumnIndex>();
183  switch (i)
184  {
185  case IndexLogoffTime: return QVariant::fromValue(m_logoffTimeUtc);
186  case IndexCallsign: return m_callsign.propertyByIndex(index.copyFrontRemoved());
187  case IndexCallsignString: return this->getCallsignAsString();
188  case IndexCallsignStringCrossCopuled: return this->getCallsignAsStringCrossCoupled();
189  case IndexController: return m_controller.propertyByIndex(index.copyFrontRemoved());
190  case IndexFrequency: return m_frequency.propertyByIndex(index.copyFrontRemoved());
191  case IndexIsOnline: return QVariant::fromValue(m_isOnline);
192  case IndexLatitude: return this->latitude().propertyByIndex(index.copyFrontRemoved());
193  case IndexLongitude: return this->longitude().propertyByIndex(index.copyFrontRemoved());
194  case IndexPosition: return m_position.propertyByIndex(index.copyFrontRemoved());
195  case IndexRange: return m_range.propertyByIndex(index.copyFrontRemoved());
196  case IndexIsInRange: return QVariant::fromValue(isInRange());
197  case IndexAtis: return m_atis.propertyByIndex(index.copyFrontRemoved());
198  case IndexMetar: return m_metar.propertyByIndex(index.copyFrontRemoved());
199  case IndexIsAfvCrossCoupled: return QVariant::fromValue(m_isAfvCrossCoupled);
200  default:
201  return (ICoordinateWithRelativePosition::canHandleIndex(index)) ?
202  ICoordinateWithRelativePosition::propertyByIndex(index) :
204  }
205  }
206 
207  void CAtcStation::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
208  {
209  if (index.isMyself())
210  {
211  (*this) = variant.value<CAtcStation>();
212  return;
213  }
214  const ColumnIndex i = index.frontCasted<ColumnIndex>();
215  switch (i)
216  {
217  case IndexLogoffTime: this->setLogoffTimeUtc(variant.value<QDateTime>()); break;
218  case IndexCallsign: m_callsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
219  case IndexController: m_controller.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
220  case IndexFrequency: m_frequency.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
221  case IndexIsOnline: this->setOnline(variant.value<bool>()); break;
222  case IndexPosition: m_position.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
223  case IndexRange: m_range.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
224  case IndexAtis: m_atis.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
225  case IndexMetar: m_metar.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
226  case IndexIsAfvCrossCoupled: this->setAfvCrossCoupled(variant.value<bool>()); break;
227  case IndexCallsignString:
228  case IndexCallsignStringCrossCopuled:
229  {
230  const QString cs = variant.toString();
231  *this = CAtcStation();
232  this->setAfvCrossCoupled(cs.startsWith('*'));
233  }
234  break;
235  default:
236  if (ICoordinateWithRelativePosition::canHandleIndex(index))
237  {
238  ICoordinateWithRelativePosition::setPropertyByIndex(index, variant);
239  }
240  else { CValueObject::setPropertyByIndex(index, variant); }
241  break;
242  }
243  }
244 
246  {
247  if (index.isMyself())
248  {
250  }
251  const ColumnIndex i = index.frontCasted<ColumnIndex>();
252  switch (i)
253  {
254  case IndexLogoffTime: return Compare::compare(this->getLogoffTimeUtc(), compareValue.getLogoffTimeUtc());
255  case IndexCallsignString:
256  case IndexCallsignStringCrossCopuled:
257  return m_callsign.comparePropertyByIndex(CPropertyIndexRef::empty(), compareValue.getCallsign());
258  case IndexCallsign:
259  return m_callsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCallsign());
260  case IndexController:
261  return m_controller.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getController());
262  case IndexFrequency:
263  return m_frequency.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getFrequency());
264  case IndexIsOnline: return Compare::compare(this->isOnline(), compareValue.isOnline());
265  case IndexLatitude:
266  return this->latitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.latitude());
267  case IndexLongitude:
268  return this->longitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.longitude());
269  case IndexPosition:
270  return m_position.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getPosition());
271  case IndexRange: return m_range.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getRange());
272  case IndexIsInRange: return Compare::compare(this->isInRange(), compareValue.isInRange());
273  case IndexAtis: return m_atis.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getAtis());
274  case IndexMetar: return m_metar.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getMetar());
275  case IndexIsAfvCrossCoupled:
276  return Compare::compare(this->isAfvCrossCoupled(), compareValue.isAfvCrossCoupled());
277  default:
278  if (ICoordinateWithRelativePosition::canHandleIndex(index))
279  {
280  return ICoordinateWithRelativePosition::comparePropertyByIndex(index, compareValue);
281  }
282  return CValueObject::comparePropertyByIndex(index, *this);
283  }
284  Q_ASSERT_X(false, Q_FUNC_INFO, "Compare failed");
285  return 0;
286  }
287 } // namespace swift::misc::aviation
Non-owning reference to a CPropertyIndex with a subset of its features.
Q_REQUIRED_RESULT CPropertyIndexRef copyFrontRemoved() const
Copy with first element removed.
static CPropertyIndexRef empty()
an empty property index
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
Altitude as used in aviation, can be AGL or MSL altitude.
Definition: altitude.h:52
Value object encapsulating information about an ATC station.
Definition: atcstation.h:38
void setController(const network::CUser &controller)
Set controller.
Definition: atcstation.cpp:72
virtual geo::CLatitude latitude() const
Latitude.
Definition: atcstation.cpp:169
void setFrequency(const swift::misc::physical_quantities::CFrequency &frequency)
Set frequency.
Definition: atcstation.cpp:118
void setAfvCrossCoupled(bool coupled)
Set AFV cross coupled.
Definition: atcstation.h:165
ColumnIndex
Properties by index.
Definition: atcstation.h:42
bool isOnline() const
Is station online?
Definition: atcstation.h:156
const CCallsign & getCallsign() const
Get callsign.
Definition: atcstation.h:84
void setMetar(const CInformationMessage &metar)
Set METAR.
Definition: atcstation.h:193
virtual geo::CLongitude longitude() const
Longitude.
Definition: atcstation.cpp:171
bool hasAtis() const
Has ATIS?
Definition: atcstation.h:78
QString getCallsignSuffix() const
Callsign suffix (e.g. TWR)
Definition: atcstation.cpp:54
void setCallsign(const CCallsign &callsign)
Set callsign.
Definition: atcstation.cpp:58
const aviation::CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
Definition: atcstation.cpp:173
const geo::CCoordinateGeodetic & getPosition() const
Get the position of the center of the controller's area of visibility.
Definition: atcstation.h:141
const CInformationMessage & getMetar() const
Get METAR.
Definition: atcstation.h:187
QString getCallsignAsString() const
Get callsign as string.
Definition: atcstation.h:90
bool isComUnitTunedToFrequency(const aviation::CComSystem &comUnit) const
Is Com unit tuned to this stations frequency.
Definition: atcstation.cpp:137
const CInformationMessage & getInformationMessage(CInformationMessage::InformationType type) const
Message per type.
Definition: atcstation.cpp:147
QString getCallsignAsStringCrossCoupled() const
Get callsign.
Definition: atcstation.cpp:48
QString getCallsignAndControllerRealName() const
Callsign and controller's name if available.
Definition: atcstation.cpp:65
virtual std::array< double, 3 > normalVectorDouble() const
Normal vector with double precision.
Definition: atcstation.cpp:177
bool setOnline(bool online)
Set online.
Definition: atcstation.cpp:130
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: atcstation.cpp:207
bool isAtcStationFrequency(const physical_quantities::CFrequency &frequency) const
Is passed frequency the frequency of this station.
Definition: atcstation.cpp:142
QString getControllerRealName() const
Get controller name.
Definition: atcstation.h:108
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: atcstation.cpp:179
const CInformationMessage & getAtis() const
Get ATIS.
Definition: atcstation.h:178
bool setMessage(const CInformationMessage &message)
Set given message.
Definition: atcstation.cpp:158
int getSuffixSortOrder() const
Callsign suffix sort order.
Definition: atcstation.cpp:56
const physical_quantities::CFrequency & getFrequency() const
Get frequency.
Definition: atcstation.h:135
bool isAfvCrossCoupled() const
Is AFV cross coupled?
Definition: atcstation.h:162
CAtcStation()
Default constructor.
Definition: atcstation.cpp:28
const swift::misc::network::CUser & getController() const
Get controller.
Definition: atcstation.h:105
const QDateTime & getLogoffTimeUtc() const
Return the expected logoff time (UTC). This data comes from the controller through its ATIS line.
Definition: atcstation.h:169
bool hasMetar() const
Has METAR?
Definition: atcstation.cpp:46
virtual QVector3D normalVector() const
Normal vector.
Definition: atcstation.cpp:175
const physical_quantities::CLength & getRange() const
Get the radius of the controller's area of visibility.
Definition: atcstation.h:147
bool isInRange() const
In range? If range and distance to own aircraft are not available false.
Definition: atcstation.cpp:124
bool hasLogoffTimeUtc() const
Has expected logoff time?
Definition: atcstation.cpp:44
void setAtis(const CInformationMessage &atis)
Set ATIS.
Definition: atcstation.h:181
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: atcstation.cpp:78
int comparePropertyByIndex(CPropertyIndexRef index, const CAtcStation &compareValue) const
Compare for index.
Definition: atcstation.cpp:245
void setLogoffTimeUtc(const QDateTime &logoffTimeUtc)
Set expected logoff time (UTC)
Definition: atcstation.h:202
Value object encapsulating information of a callsign.
Definition: callsign.h:30
int getSuffixSortOrder() const
Sort order by suffix.
Definition: callsign.cpp:302
int comparePropertyByIndex(CPropertyIndexRef index, const CCallsign &compareValue) const
Compare for index.
Definition: callsign.cpp:341
const QString & asString() const
Get callsign (normalized)
Definition: callsign.h:96
QString getSuffix() const
Get the callsign suffix ("TWR", "ATIS" ...) if any ("_" is removed)
Definition: callsign.cpp:212
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: callsign.cpp:310
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: callsign.cpp:324
bool isEmpty() const
Is empty?
Definition: callsign.h:63
void setTypeHint(TypeHint hint)
Type hint.
Definition: callsign.h:114
const QString & getStringAsSet() const
Get callsign.
Definition: callsign.h:99
COM system (aka "radio")
Definition: comsystem.h:37
static bool isSameFrequency(const physical_quantities::CFrequency &freq1, const physical_quantities::CFrequency &freq2)
Compare frequencies under consideration that on VATSIM frequencies .x20/.x25 and ....
Definition: comsystem.cpp:181
bool isActiveFrequencySameFrequency(const physical_quantities::CFrequency &comFrequency) const
Is active frequency the same frequency.
Definition: comsystem.cpp:53
Value object encapsulating information message (ATIS, METAR, TAF)
int comparePropertyByIndex(CPropertyIndexRef index, const CInformationMessage &compareValue) const
Compare for index.
bool hasMessage() const
Is a message available.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
static const CInformationMessage & unspecified()
Unspecified object.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
int comparePropertyByIndex(CPropertyIndexRef index, const CCoordinateGeodetic &compareValue) const
Set property by index.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
virtual CLatitude latitude() const
Latitude.
virtual std::array< double, 3 > normalVectorDouble() const
Normal vector with double precision.
virtual const aviation::CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
virtual QVector3D normalVector() const
Normal vector.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
virtual CLongitude longitude() const
Longitude.
const physical_quantities::CLength & getRelativeDistance() const
Get the distance.
int comparePropertyByIndex(CPropertyIndexRef index, const Derived &compareValue) const
Compare for index.
Definition: mixinindex.h:187
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:160
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:167
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
Value object encapsulating information of a user.
Definition: user.h:28
bool hasRealName() const
Valid real name?
Definition: user.h:80
int comparePropertyByIndex(CPropertyIndexRef index, const CUser &compareValue) const
Compare for index.
Definition: user.cpp:281
bool isNull() const
Null?
Definition: user.h:74
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: user.cpp:241
bool setCallsign(const aviation::CCallsign &callsign)
Set associated callsign.
Definition: user.cpp:62
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: user.cpp:259
bool hasCallsign() const
Has associated callsign?
Definition: user.h:89
Physical unit length (length)
Definition: length.h:18
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
int comparePropertyByIndex(CPropertyIndexRef index, const PQ &pq) const
Compare for index.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
void setUnit(const MU &unit)
Simply set unit, do no calclulate conversion.
QString valueRoundedWithUnit(const MU &unit, int digits=-1, bool withGroupSeparator=false, bool i18n=false) const
Value to QString with the given unit, e.g. "5.00m".
Free functions in swift::misc.
SWIFT_MISC_EXPORT const QString & boolToYesNo(bool v)
Bool to yes/no.
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
Definition: valueobject.h:67