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(const QString &callsign) : m_callsign(callsign) { m_callsign.setTypeHint(CCallsign::Atc); }
29 
30  CAtcStation::CAtcStation(const CCallsign &callsign, const CUser &controller, const CFrequency &frequency,
31  const CCoordinateGeodetic &pos, const CLength &range, bool isOnline,
32  const QDateTime &logoffTimeUtc, const CInformationMessage &atis,
33  const CInformationMessage &metar)
34  : m_callsign(callsign), m_controller(controller), m_frequency(frequency), m_position(pos), m_range(range),
35  m_isOnline(isOnline), m_logoffTimeUtc(logoffTimeUtc), m_atis(atis), m_metar(metar)
36  {
37  // sync callsigns
38  m_callsign.setTypeHint(CCallsign::Atc);
39  if (!m_controller.hasCallsign() && !callsign.isEmpty()) { m_controller.setCallsign(m_callsign); }
40  }
41 
42  bool CAtcStation::hasLogoffTimeUtc() const { return !m_logoffTimeUtc.isNull(); }
43 
44  bool CAtcStation::hasMetar() const { return m_metar.hasMessage(); }
45 
47  {
48  if (!this->isAfvCrossCoupled()) { return this->getCallsignAsString(); }
49  return QStringLiteral("*") % this->getCallsignAsString();
50  }
51 
52  QString CAtcStation::getCallsignSuffix() const { return m_callsign.getSuffix(); }
53 
54  int CAtcStation::getSuffixSortOrder() const { return m_callsign.getSuffixSortOrder(); }
55 
56  void CAtcStation::setCallsign(const CCallsign &callsign)
57  {
58  m_callsign = callsign;
59  m_controller.setCallsign(callsign);
60  m_isAfvCrossCoupled = callsign.getStringAsSet().startsWith('*');
61  }
62 
64  {
65  if (m_callsign.isEmpty()) { return this->getControllerRealName(); }
66  if (!m_controller.hasRealName()) { return m_callsign.asString(); }
67  return m_callsign.asString() % u' ' % this->getControllerRealName();
68  }
69 
70  void CAtcStation::setController(const CUser &controller)
71  {
72  m_controller = controller;
73  m_controller.setCallsign(m_callsign);
74  }
75 
77  {
78  static const QString atcI18n(QCoreApplication::translate("Aviation", "ATC station"));
79  static const QString rangeI18n(QCoreApplication::translate("Aviation", "range"));
80  static const QString fromUtcI18n(QCoreApplication::translate("Aviation", "from(UTC)"));
81  static const QString untilUtcI18n(QCoreApplication::translate("Aviation", "until(UTC)"));
82 
83  const QString s = (i18n ? atcI18n : QStringLiteral("ATC station")) % u' ' % m_callsign.toQString(i18n) % u' ' %
84  m_position.toQString(i18n) % u" online: " % boolToYesNo(m_isOnline) %
85 
86  // controller
87  (m_controller.isNull() ? QString() : u' ' % m_controller.toQString(i18n)) %
88 
89  // frequency
90  u' ' % m_frequency.valueRoundedWithUnit(3, i18n) %
91 
92  // ATIS
93  (!this->hasAtis() ? QString() : u' ' % m_atis.toQString(i18n)) %
94 
95  // METAR
96  (!this->hasMetar() ? QString() : u' ' % m_metar.toQString(i18n)) %
97 
98  // range
99  u' ' % (i18n ? rangeI18n : QStringLiteral("range")) % u' ' % m_range.toQString(i18n) %
100 
101  // distance / bearing
102  u' ' % ICoordinateWithRelativePosition::convertToQString(i18n);
103 
104  return s;
105 
106  // force strings for translation in resource files
107  (void)QT_TRANSLATE_NOOP("Aviation", "ATC station");
108  (void)QT_TRANSLATE_NOOP("Aviation", "online");
109  (void)QT_TRANSLATE_NOOP("Aviation", "offline");
110  (void)QT_TRANSLATE_NOOP("Aviation", "from(UTC)");
111  (void)QT_TRANSLATE_NOOP("Aviation", "until(UTC)");
112  (void)QT_TRANSLATE_NOOP("Aviation", "range");
113  (void)QT_TRANSLATE_NOOP("Aviation", "distance");
114  }
115 
116  void CAtcStation::setFrequency(const CFrequency &frequency)
117  {
118  m_frequency = frequency;
119  m_frequency.setUnit(CFrequencyUnit::MHz());
120  }
121 
123  {
124  if (m_range.isNull() || !hasValidRelativeDistance()) { return false; }
125  return (this->getRelativeDistance() <= m_range);
126  }
127 
128  bool CAtcStation::setOnline(bool online)
129  {
130  if (online == m_isOnline) { return false; }
131  m_isOnline = online;
132  return true;
133  }
134 
136  {
137  return comUnit.isActiveFrequencySameFrequency(this->getFrequency());
138  }
139 
140  bool CAtcStation::isAtcStationFrequency(const CFrequency &frequency) const
141  {
142  return CComSystem::isSameFrequency(frequency, this->getFrequency());
143  }
144 
146  {
147  switch (type)
148  {
149  case CInformationMessage::ATIS: return this->getAtis();
150  case CInformationMessage::METAR: return this->getMetar();
151  default: break;
152  }
154  }
155 
157  {
158  switch (message.getType())
159  {
160  case CInformationMessage::ATIS: this->setAtis(message); return true;
161  case CInformationMessage::METAR: this->setMetar(message); return true;
162  default: break;
163  }
164  return false;
165  }
166 
167  CLatitude CAtcStation::latitude() const { return this->getPosition().latitude(); }
168 
170 
171  const CAltitude &CAtcStation::geodeticHeight() const { return m_position.geodeticHeight(); }
172 
173  QVector3D CAtcStation::normalVector() const { return m_position.normalVector(); }
174 
175  std::array<double, 3> CAtcStation::normalVectorDouble() const { return m_position.normalVectorDouble(); }
176 
178  {
179  if (index.isMyself()) { return QVariant::fromValue(*this); }
180  const auto i = index.frontCasted<ColumnIndex>();
181  switch (i)
182  {
183  case IndexLogoffTime: return QVariant::fromValue(m_logoffTimeUtc);
184  case IndexCallsign: return m_callsign.propertyByIndex(index.copyFrontRemoved());
185  case IndexCallsignString: return this->getCallsignAsString();
186  case IndexCallsignStringCrossCopuled: return this->getCallsignAsStringCrossCoupled();
187  case IndexController: return m_controller.propertyByIndex(index.copyFrontRemoved());
188  case IndexFrequency: return m_frequency.propertyByIndex(index.copyFrontRemoved());
189  case IndexIsOnline: return QVariant::fromValue(m_isOnline);
190  case IndexLatitude: return this->latitude().propertyByIndex(index.copyFrontRemoved());
191  case IndexLongitude: return this->longitude().propertyByIndex(index.copyFrontRemoved());
192  case IndexPosition: return m_position.propertyByIndex(index.copyFrontRemoved());
193  case IndexRange: return m_range.propertyByIndex(index.copyFrontRemoved());
194  case IndexIsInRange: return QVariant::fromValue(isInRange());
195  case IndexAtis: return m_atis.propertyByIndex(index.copyFrontRemoved());
196  case IndexMetar: return m_metar.propertyByIndex(index.copyFrontRemoved());
197  case IndexIsAfvCrossCoupled: return QVariant::fromValue(m_isAfvCrossCoupled);
198  default:
199  return (ICoordinateWithRelativePosition::canHandleIndex(index)) ?
200  ICoordinateWithRelativePosition::propertyByIndex(index) :
202  }
203  }
204 
206  {
207  if (index.isMyself())
208  {
209  (*this) = variant.value<CAtcStation>();
210  return;
211  }
212  const auto i = index.frontCasted<ColumnIndex>();
213  switch (i)
214  {
215  case IndexLogoffTime: this->setLogoffTimeUtc(variant.value<QDateTime>()); break;
216  case IndexCallsign: m_callsign.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
217  case IndexController: m_controller.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
218  case IndexFrequency: m_frequency.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
219  case IndexIsOnline: this->setOnline(variant.value<bool>()); break;
220  case IndexPosition: m_position.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
221  case IndexRange: m_range.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
222  case IndexAtis: m_atis.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
223  case IndexMetar: m_metar.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
224  case IndexIsAfvCrossCoupled: this->setAfvCrossCoupled(variant.value<bool>()); break;
225  case IndexCallsignString:
226  case IndexCallsignStringCrossCopuled:
227  {
228  const QString cs = variant.toString();
229  *this = CAtcStation();
230  this->setAfvCrossCoupled(cs.startsWith('*'));
231  }
232  break;
233  default:
234  if (ICoordinateWithRelativePosition::canHandleIndex(index))
235  {
236  ICoordinateWithRelativePosition::setPropertyByIndex(index, variant);
237  }
238  else { CValueObject::setPropertyByIndex(index, variant); }
239  break;
240  }
241  }
242 
244  {
245  if (index.isMyself())
246  {
248  }
249  const auto i = index.frontCasted<ColumnIndex>();
250  switch (i)
251  {
252  case IndexLogoffTime: return Compare::compare(this->getLogoffTimeUtc(), compareValue.getLogoffTimeUtc());
253  case IndexCallsignString:
254  case IndexCallsignStringCrossCopuled:
255  return m_callsign.comparePropertyByIndex(CPropertyIndexRef::empty(), compareValue.getCallsign());
256  case IndexCallsign:
257  return m_callsign.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getCallsign());
258  case IndexController:
259  return m_controller.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getController());
260  case IndexFrequency:
261  return m_frequency.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getFrequency());
262  case IndexIsOnline: return Compare::compare(this->isOnline(), compareValue.isOnline());
263  case IndexLatitude:
264  return this->latitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.latitude());
265  case IndexLongitude:
266  return this->longitude().comparePropertyByIndex(index.copyFrontRemoved(), compareValue.longitude());
267  case IndexPosition:
268  return m_position.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getPosition());
269  case IndexRange: return m_range.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getRange());
270  case IndexIsInRange: return Compare::compare(this->isInRange(), compareValue.isInRange());
271  case IndexAtis: return m_atis.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getAtis());
272  case IndexMetar: return m_metar.comparePropertyByIndex(index.copyFrontRemoved(), compareValue.getMetar());
273  case IndexIsAfvCrossCoupled:
274  return Compare::compare(this->isAfvCrossCoupled(), compareValue.isAfvCrossCoupled());
275  default:
276  if (ICoordinateWithRelativePosition::canHandleIndex(index))
277  {
278  return ICoordinateWithRelativePosition::comparePropertyByIndex(index, compareValue);
279  }
280  return CValueObject::comparePropertyByIndex(index, *this);
281  }
282  Q_ASSERT_X(false, Q_FUNC_INFO, "Compare failed");
283  return 0;
284  }
285 } // 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:70
geo::CLatitude latitude() const
Latitude.
Definition: atcstation.cpp:167
void setFrequency(const swift::misc::physical_quantities::CFrequency &frequency)
Set frequency.
Definition: atcstation.cpp:116
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
geo::CLongitude longitude() const
Longitude.
Definition: atcstation.cpp:169
bool hasAtis() const
Has ATIS?
Definition: atcstation.h:78
QString getCallsignSuffix() const
Callsign suffix (e.g. TWR)
Definition: atcstation.cpp:52
void setCallsign(const CCallsign &callsign)
Set callsign.
Definition: atcstation.cpp:56
const aviation::CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
Definition: atcstation.cpp:171
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:135
const CInformationMessage & getInformationMessage(CInformationMessage::InformationType type) const
Message per type.
Definition: atcstation.cpp:145
QString getCallsignAsStringCrossCoupled() const
Get callsign.
Definition: atcstation.cpp:46
QString getCallsignAndControllerRealName() const
Callsign and controller's name if available.
Definition: atcstation.cpp:63
std::array< double, 3 > normalVectorDouble() const
Normal vector with double precision.
Definition: atcstation.cpp:175
CAtcStation()=default
Default constructor.
bool setOnline(bool online)
Set online.
Definition: atcstation.cpp:128
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: atcstation.cpp:205
bool isAtcStationFrequency(const physical_quantities::CFrequency &frequency) const
Is passed frequency the frequency of this station.
Definition: atcstation.cpp:140
QString getControllerRealName() const
Get controller name.
Definition: atcstation.h:108
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: atcstation.cpp:177
const CInformationMessage & getAtis() const
Get ATIS.
Definition: atcstation.h:178
bool setMessage(const CInformationMessage &message)
Set given message.
Definition: atcstation.cpp:156
int getSuffixSortOrder() const
Callsign suffix sort order.
Definition: atcstation.cpp:54
const physical_quantities::CFrequency & getFrequency() const
Get frequency.
Definition: atcstation.h:135
bool isAfvCrossCoupled() const
Is AFV cross coupled?
Definition: atcstation.h:162
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:44
QVector3D normalVector() const
Normal vector.
Definition: atcstation.cpp:173
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:122
bool hasLogoffTimeUtc() const
Has expected logoff time?
Definition: atcstation.cpp:42
void setAtis(const CInformationMessage &atis)
Set ATIS.
Definition: atcstation.h:181
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: atcstation.cpp:76
int comparePropertyByIndex(CPropertyIndexRef index, const CAtcStation &compareValue) const
Compare for index.
Definition: atcstation.cpp:243
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:179
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.
const aviation::CAltitude & geodeticHeight() const
Height, ellipsoidal or geodetic height (used in GPS)
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
std::array< double, 3 > normalVectorDouble() const
Normal vector with double precision.
QVector3D normalVector() const
Normal vector.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
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:185
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:158
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:165
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:74
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.
QString translate(const char *context, const char *sourceText, const char *disambiguation, int n)
bool isNull() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QVariant fromValue(T &&value)
QString toString() const const
T value() const &const
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
Definition: valueobject.h:67