swift
interpolationrenderingsetup.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2016 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #include "config/buildconfig.h"
7 #include "misc/network/client.h"
8 #include "misc/propertyindexvariantmap.h" // needed for mixin::Index::apply
9 #include "misc/stringutils.h"
10 #include "misc/verify.h"
11 
12 using namespace swift::config;
13 using namespace swift::misc::aviation;
14 using namespace swift::misc::physical_quantities;
15 using namespace swift::misc::network;
16 
17 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::simulation, CInterpolationAndRenderingSetupGlobal)
18 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::simulation, CInterpolationAndRenderingSetupPerCallsign)
19 
20 namespace swift::misc::simulation
21 {
22  bool CInterpolationAndRenderingSetupBase::setSendingGndFlagToSimulator(bool sendFLag)
23  {
24  if (sendFLag == m_sendGndToSim) { return false; }
25  m_sendGndToSim = sendFLag;
26  return true;
27  }
28 
29  bool CInterpolationAndRenderingSetupBase::setPitchOnGround(const CAngle &pitchOnGround)
30  {
31  if (pitchOnGround == m_pitchOnGround) { return false; }
32  m_pitchOnGround = pitchOnGround;
33  return true;
34  }
35 
36  void CInterpolationAndRenderingSetupBase::consolidateWithClient(const CClient &client)
37  {
38  m_enabledAircraftParts &= client.hasAircraftPartsCapability();
39  }
40 
41  bool
42  CInterpolationAndRenderingSetupBase::setInterpolatorMode(CInterpolationAndRenderingSetupBase::InterpolatorMode mode)
43  {
44  const int m = static_cast<int>(mode);
45  if (m_interpolatorMode == m) { return false; }
46  m_interpolatorMode = m;
47  return true;
48  }
49 
50  bool CInterpolationAndRenderingSetupBase::setInterpolatorMode(const QString &mode)
51  {
52  if (mode.contains("spline", Qt::CaseInsensitive)) { return this->setInterpolatorMode(Spline); }
53  if (mode.contains("linear", Qt::CaseInsensitive)) { return this->setInterpolatorMode(Linear); }
54  return false;
55  }
56 
57  const QString &CInterpolationAndRenderingSetupBase::modeToString(InterpolatorMode mode)
58  {
59  static const QString l("linear");
60  static const QString s("spline");
61 
62  switch (mode)
63  {
64  case Linear: return l;
65  case Spline: return s;
66  default: return s;
67  }
68  }
69 
70  bool CInterpolationAndRenderingSetupBase::setLogInterpolation(bool log)
71  {
72  if (m_logInterpolation == log) { return false; }
73  m_logInterpolation = log;
74  return true;
75  }
76 
77  bool CInterpolationAndRenderingSetupBase::setEnabledAircraftParts(bool enabled)
78  {
79  if (m_enabledAircraftParts == enabled) { return false; }
80  m_enabledAircraftParts = enabled;
81  return true;
82  }
83 
84  bool CInterpolationAndRenderingSetupBase::maskEnabledAircraftParts(bool mask)
85  {
86  const bool masked = mask && m_enabledAircraftParts;
87  return this->setEnabledAircraftParts(masked);
88  }
89 
90  QVariant CInterpolationAndRenderingSetupBase::propertyByIndex(CPropertyIndexRef index) const
91  {
92  const auto i = index.frontCasted<ColumnIndex>();
93  switch (i)
94  {
95  case IndexLogInterpolation: return QVariant::fromValue(m_logInterpolation);
96  case IndexSimulatorDebugMessages: return QVariant::fromValue(m_simulatorDebugMessages);
97  case IndexForceFullInterpolation: return QVariant::fromValue(m_forceFullInterpolation);
98  case IndexEnabledAircraftParts: return QVariant::fromValue(m_enabledAircraftParts);
99  case IndexSendGndFlagToSimulator: return QVariant::fromValue(m_sendGndToSim);
100  case IndexInterpolatorMode: return QVariant::fromValue(m_interpolatorMode);
101  case IndexInterpolatorModeAsString: return QVariant::fromValue(this->getInterpolatorModeAsString());
102  case IndexFixSceneryOffset: return QVariant::fromValue(m_fixSceneryOffset);
103  case IndexPitchOnGround: return QVariant::fromValue(m_pitchOnGround);
104  default: break;
105  }
106  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Cannot handle index");
107  return QStringLiteral("Wrong index for %1").arg(i);
108  }
109 
110  void CInterpolationAndRenderingSetupBase::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
111  {
112  const auto i = index.frontCasted<ColumnIndex>();
113  switch (i)
114  {
115  case IndexLogInterpolation: m_logInterpolation = variant.toBool(); return;
116  case IndexSimulatorDebugMessages: m_simulatorDebugMessages = variant.toBool(); return;
117  case IndexForceFullInterpolation: m_forceFullInterpolation = variant.toBool(); return;
118  case IndexEnabledAircraftParts: m_enabledAircraftParts = variant.toBool(); return;
119  case IndexSendGndFlagToSimulator: m_sendGndToSim = variant.toBool(); return;
120  case IndexInterpolatorMode: m_interpolatorMode = variant.toInt(); return;
121  case IndexInterpolatorModeAsString: this->setInterpolatorMode(variant.toString()); return;
122  case IndexFixSceneryOffset: m_fixSceneryOffset = variant.toBool(); return;
123  case IndexPitchOnGround: m_pitchOnGround.setPropertyByIndex(index.copyFrontRemoved(), variant); return;
124  default: break;
125  }
126  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Cannot handle index");
127  }
128 
129  QString CInterpolationAndRenderingSetupBase::convertToQString(bool i18n) const
130  {
131  Q_UNUSED(i18n)
132  return QStringLiteral("Interpolator: ") % this->getInterpolatorModeAsString() %
133  QStringLiteral(" | Dbg.sim.msgs: ") % boolToYesNo(m_simulatorDebugMessages) %
134  QStringLiteral(" | log interpolation: ") % boolToYesNo(m_logInterpolation) %
135  QStringLiteral(" | force VTOL interpolation: ") % boolToYesNo(m_forceFullInterpolation) %
136  QStringLiteral(" | enable parts: ") % boolToYesNo(m_enabledAircraftParts) %
137  QStringLiteral(" | send gnd: ") % boolToYesNo(m_sendGndToSim) %
138  QStringLiteral(" | fix.scenery offset: ") % boolToYesNo(m_fixSceneryOffset) %
139  QStringLiteral(" | pitch on gnd.: ") % m_pitchOnGround.valueRoundedWithUnit(CAngleUnit::deg(), 1, true);
140  }
141 
142  bool CInterpolationAndRenderingSetupBase::canHandleIndex(int index)
143  {
144  return index >= CInterpolationAndRenderingSetupBase::IndexLogInterpolation &&
145  index <= CInterpolationAndRenderingSetupBase::IndexFixSceneryOffset;
146  }
147 
148  int CInterpolationAndRenderingSetupGlobal::InfiniteAircraft() { return 100; }
149 
150  bool CInterpolationAndRenderingSetupGlobal::isRenderingEnabled() const
151  {
152  if (m_maxRenderedAircraft < 1) { return false; }
153  if (!isMaxDistanceRestricted()) { return true; }
154  return m_maxRenderedDistance.isPositiveWithEpsilonConsidered();
155  }
156 
157  bool CInterpolationAndRenderingSetupGlobal::isRenderingRestricted() const
158  {
159  return isRenderingEnabled() && (isMaxAircraftRestricted() || isMaxDistanceRestricted());
160  }
161 
162  int CInterpolationAndRenderingSetupGlobal::getMaxRenderedAircraft() const
163  {
164  return (m_maxRenderedAircraft <= InfiniteAircraft()) ? m_maxRenderedAircraft : InfiniteAircraft();
165  }
166 
167  bool CInterpolationAndRenderingSetupGlobal::setMaxRenderedAircraft(int maxRenderedAircraft)
168  {
169  if (maxRenderedAircraft == m_maxRenderedAircraft) { return false; }
170  if (maxRenderedAircraft < 1)
171  {
172  // disable, we set both values to 0
173  this->disableRendering();
174  }
175  else if (maxRenderedAircraft >= InfiniteAircraft()) { m_maxRenderedAircraft = InfiniteAircraft(); }
176  else { m_maxRenderedAircraft = maxRenderedAircraft; }
177  return true;
178  }
179 
180  bool CInterpolationAndRenderingSetupGlobal::setMaxRenderedDistance(const CLength &distance)
181  {
182 
183  if (distance == m_maxRenderedDistance) { return false; }
184  if (distance.isNull() || distance.isNegativeWithEpsilonConsidered())
185  {
186  m_maxRenderedDistance = CLength(0.0, nullptr);
187  }
188  else if (distance.isZeroEpsilonConsidered())
189  {
190  // zero means disabled, we disable max aircraft too
191  this->disableRendering();
192  }
193  else
194  {
195  Q_ASSERT(!distance.isNegativeWithEpsilonConsidered());
196  m_maxRenderedDistance = distance;
197  }
198  return true;
199  }
200 
201  void CInterpolationAndRenderingSetupGlobal::clearMaxRenderedDistance()
202  {
203  this->setMaxRenderedDistance(CLength(0.0, nullptr));
204  }
205 
206  bool CInterpolationAndRenderingSetupGlobal::isMaxAircraftRestricted() const
207  {
208  return m_maxRenderedAircraft < InfiniteAircraft();
209  }
210 
211  void CInterpolationAndRenderingSetupGlobal::clearAllRenderingRestrictions()
212  {
213  m_maxRenderedDistance = CLength(0, nullptr);
214  m_maxRenderedAircraft = InfiniteAircraft();
215  }
216 
217  void CInterpolationAndRenderingSetupGlobal::disableRendering()
218  {
219  m_maxRenderedAircraft = 0;
220  m_maxRenderedDistance = CLength(0, CLengthUnit::NM()); // zero distance
221  }
222 
223  bool CInterpolationAndRenderingSetupGlobal::isMaxDistanceRestricted() const
224  {
225  return !m_maxRenderedDistance.isNull();
226  }
227 
228  QString CInterpolationAndRenderingSetupGlobal::getRenderRestrictionText() const
229  {
230  if (!this->isRenderingRestricted()) { return "none"; }
231  QString rt;
232  if (this->isMaxAircraftRestricted())
233  {
234  rt.append(QString::number(this->getMaxRenderedAircraft())).append(" A/C");
235  }
236  if (this->isMaxDistanceRestricted())
237  {
238  if (!rt.isEmpty()) { rt.append(" "); }
239  rt.append(this->getMaxRenderedDistance().valueRoundedWithUnit(CLengthUnit::NM(), 0));
240  }
241  return rt;
242  }
243 
244  void CInterpolationAndRenderingSetupGlobal::setBaseValues(const CInterpolationAndRenderingSetupBase &baseValues)
245  {
246  m_logInterpolation = baseValues.logInterpolation();
247  m_simulatorDebugMessages = baseValues.showSimulatorDebugMessages();
248  m_forceFullInterpolation = baseValues.isForcingFullInterpolation();
249  m_enabledAircraftParts = baseValues.isAircraftPartsEnabled();
250  m_sendGndToSim = baseValues.isSendingGndFlagToSimulator();
251  m_fixSceneryOffset = baseValues.isFixingSceneryOffset();
252  m_interpolatorMode = baseValues.getInterpolatorMode();
253  m_pitchOnGround = baseValues.getPitchOnGround();
254  }
255 
256  QString CInterpolationAndRenderingSetupGlobal::convertToQString(bool i18n) const
257  {
258  Q_UNUSED(i18n)
259  return CInterpolationAndRenderingSetupBase::convertToQString(i18n) % QStringLiteral(" max.aircraft:") %
260  QString::number(m_maxRenderedAircraft) % QStringLiteral(" max.distance:") %
261  m_maxRenderedDistance.valueRoundedWithUnit(CLengthUnit::NM(), 2);
262  }
263 
264  QVariant CInterpolationAndRenderingSetupGlobal::propertyByIndex(CPropertyIndexRef index) const
265  {
266  if (index.isMyself()) { return QVariant::fromValue(*this); }
267  const auto i = index.frontCasted<ColumnIndex>();
268  switch (i)
269  {
270  case IndexMaxRenderedAircraft: return QVariant::fromValue(m_maxRenderedAircraft);
271  case IndexMaxRenderedDistance: return QVariant::fromValue(m_maxRenderedDistance);
272  default: break;
273  }
274  if (CInterpolationAndRenderingSetupBase::canHandleIndex(i))
275  {
276  return CInterpolationAndRenderingSetupBase::propertyByIndex(index);
277  }
278  return CValueObject::propertyByIndex(index);
279  }
280 
281  void CInterpolationAndRenderingSetupGlobal::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
282  {
283  if (index.isMyself())
284  {
285  *this = variant.value<CInterpolationAndRenderingSetupGlobal>();
286  return;
287  }
288  const auto i = index.frontCasted<ColumnIndex>();
289  switch (i)
290  {
291  case IndexMaxRenderedAircraft: m_maxRenderedAircraft = variant.toInt(); return;
292  case IndexMaxRenderedDistance: m_maxRenderedDistance = variant.value<CLength>(); return;
293  default: break;
294  }
295  if (CInterpolationAndRenderingSetupBase::canHandleIndex(i))
296  {
297  CInterpolationAndRenderingSetupBase::setPropertyByIndex(index, variant);
298  return;
299  }
300  CValueObject::setPropertyByIndex(index, variant);
301  }
302 
303  CInterpolationAndRenderingSetupPerCallsign::CInterpolationAndRenderingSetupPerCallsign(
304  const CCallsign &callsign, const CInterpolationAndRenderingSetupGlobal &globalSetup)
305  : CInterpolationAndRenderingSetupBase(globalSetup), m_callsign(callsign)
306  {}
307 
309  const CInterpolationAndRenderingSetupGlobal &globalSetup) const
310  {
311  CPropertyIndexList diff;
312  if (this->logInterpolation() != globalSetup.logInterpolation()) { diff.push_back(IndexLogInterpolation); }
313  if (this->showSimulatorDebugMessages() != globalSetup.showSimulatorDebugMessages())
314  {
315  diff.push_back(IndexSimulatorDebugMessages);
316  }
317  if (this->isForcingFullInterpolation() != globalSetup.isForcingFullInterpolation())
318  {
319  diff.push_back(IndexForceFullInterpolation);
320  }
321  if (this->isAircraftPartsEnabled() != globalSetup.isAircraftPartsEnabled())
322  {
323  diff.push_back(IndexEnabledAircraftParts);
324  }
325  if (this->isSendingGndFlagToSimulator() != globalSetup.isSendingGndFlagToSimulator())
326  {
327  diff.push_back(IndexSendGndFlagToSimulator);
328  }
329  if (this->isFixingSceneryOffset() != globalSetup.isFixingSceneryOffset())
330  {
331  diff.push_back(IndexFixSceneryOffset);
332  }
333  if (this->getPitchOnGround() != globalSetup.getPitchOnGround()) { diff.push_back(IndexPitchOnGround); }
334  return diff;
335  }
336 
338  const CInterpolationAndRenderingSetupGlobal &globalSetup) const
339  {
340  const CPropertyIndexList il = this->unequalToGlobal(globalSetup);
341  const bool equal = il.isEmpty();
342  return equal;
343  }
344 
346  {
347  if (index.isMyself()) { return QVariant::fromValue(*this); }
348  const auto i = index.frontCasted<ColumnIndex>();
349  switch (i)
350  {
351  case IndexCallsign: return m_callsign.propertyByIndex(index.copyFrontRemoved());
352  default: break;
353  }
355  }
356 
358  const QVariant &variant)
359  {
360  if (index.isMyself())
361  {
363  return;
364  }
365  const auto i = index.frontCasted<ColumnIndex>();
366  switch (i)
367  {
368  case IndexCallsign: m_callsign.setPropertyByIndex(index.copyFrontRemoved(), variant); return;
369  default: break;
370  }
372  }
373 
375  {
377  return null;
378  }
379 } // namespace swift::misc::simulation
Value object encapsulating a list of property indexes.
Non-owning reference to a CPropertyIndex with a subset of its features.
Q_REQUIRED_RESULT CPropertyIndexRef copyFrontRemoved() const
Copy with first element removed.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Value object encapsulating information of a callsign.
Definition: callsign.h:30
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
ColumnIndex
Base class enums.
Definition: mixinindex.h:44
Another client software.
Definition: client.h:27
bool hasAircraftPartsCapability() const
Supports aircraft parts?
Definition: client.cpp:66
Physical unit angle (radians, degrees)
Definition: angle.h:23
Physical unit length (length)
Definition: length.h:18
bool isNegativeWithEpsilonConsidered() const
Value <= 0 epsilon considered.
bool isZeroEpsilonConsidered() const
Quantity value <= epsilon.
Value object for interpolator and rendering base class.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
bool isFixingSceneryOffset() const
Fix scenery offset if it has been detected.
bool isAircraftPartsEnabled() const
Aircraft parts enabled (still requires the other aircraft to send parts)
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
const physical_quantities::CAngle & getPitchOnGround() const
Force a given pitch on ground.
bool showSimulatorDebugMessages() const
Debugging messages for simulation.
bool isForcingFullInterpolation() const
Full interpolation (skip optimizations like checking if aircraft moves etc.)
Value object for interpolator and rendering per callsign.
bool isEqualToGlobal(const CInterpolationAndRenderingSetupGlobal &globalSetup) const
Equal to global setup?
static const CInterpolationAndRenderingSetupPerCallsign & null()
NULL object.
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
CPropertyIndexList unequalToGlobal(const CInterpolationAndRenderingSetupGlobal &globalSetup) const
Properties unequal to global setup.
QString & append(QChar ch)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
CaseInsensitive
QVariant fromValue(T &&value)
bool toBool() const const
int toInt(bool *ok) const const
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
#define SWIFT_VERIFY_X(COND, WHERE, WHAT)
A weaker kind of assert.
Definition: verify.h:26