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  CInterpolationAndRenderingSetupBase::CInterpolationAndRenderingSetupBase()
23  {
24  // Experimental
25  // m_fixSceneryOffset = CBuildConfig::isLocalDeveloperDebugBuild();
26  }
27 
28  bool CInterpolationAndRenderingSetupBase::setSendingGndFlagToSimulator(bool sendFLag)
29  {
30  if (sendFLag == m_sendGndToSim) { return false; }
31  m_sendGndToSim = sendFLag;
32  return true;
33  }
34 
35  bool CInterpolationAndRenderingSetupBase::setPitchOnGround(const CAngle &pitchOnGround)
36  {
37  if (pitchOnGround == m_pitchOnGround) { return false; }
38  m_pitchOnGround = pitchOnGround;
39  return true;
40  }
41 
42  void CInterpolationAndRenderingSetupBase::consolidateWithClient(const CClient &client)
43  {
44  m_enabledAircraftParts &= client.hasAircraftPartsCapability();
45  }
46 
47  bool
48  CInterpolationAndRenderingSetupBase::setInterpolatorMode(CInterpolationAndRenderingSetupBase::InterpolatorMode mode)
49  {
50  const int m = static_cast<int>(mode);
51  if (m_interpolatorMode == m) { return false; }
52  m_interpolatorMode = m;
53  return true;
54  }
55 
56  bool CInterpolationAndRenderingSetupBase::setInterpolatorMode(const QString &mode)
57  {
58  if (mode.contains("spline", Qt::CaseInsensitive)) { return this->setInterpolatorMode(Spline); }
59  if (mode.contains("linear", Qt::CaseInsensitive)) { return this->setInterpolatorMode(Linear); }
60  return false;
61  }
62 
63  const QString &CInterpolationAndRenderingSetupBase::modeToString(InterpolatorMode mode)
64  {
65  static const QString l("linear");
66  static const QString s("spline");
67 
68  switch (mode)
69  {
70  case Linear: return l;
71  case Spline: return s;
72  default: return s;
73  }
74  }
75 
76  bool CInterpolationAndRenderingSetupBase::setLogInterpolation(bool log)
77  {
78  if (m_logInterpolation == log) { return false; }
79  m_logInterpolation = log;
80  return true;
81  }
82 
83  bool CInterpolationAndRenderingSetupBase::setEnabledAircraftParts(bool enabled)
84  {
85  if (m_enabledAircraftParts == enabled) { return false; }
86  m_enabledAircraftParts = enabled;
87  return true;
88  }
89 
90  bool CInterpolationAndRenderingSetupBase::maskEnabledAircraftParts(bool mask)
91  {
92  const bool masked = mask && m_enabledAircraftParts;
93  return this->setEnabledAircraftParts(masked);
94  }
95 
96  QVariant CInterpolationAndRenderingSetupBase::propertyByIndex(CPropertyIndexRef index) const
97  {
98  const ColumnIndex i = index.frontCasted<ColumnIndex>();
99  switch (i)
100  {
101  case IndexLogInterpolation: return QVariant::fromValue(m_logInterpolation);
102  case IndexSimulatorDebugMessages: return QVariant::fromValue(m_simulatorDebugMessages);
103  case IndexForceFullInterpolation: return QVariant::fromValue(m_forceFullInterpolation);
104  case IndexEnabledAircraftParts: return QVariant::fromValue(m_enabledAircraftParts);
105  case IndexSendGndFlagToSimulator: return QVariant::fromValue(m_sendGndToSim);
106  case IndexInterpolatorMode: return QVariant::fromValue(m_interpolatorMode);
107  case IndexInterpolatorModeAsString: return QVariant::fromValue(this->getInterpolatorModeAsString());
108  case IndexFixSceneryOffset: return QVariant::fromValue(m_fixSceneryOffset);
109  case IndexPitchOnGround: return QVariant::fromValue(m_pitchOnGround);
110  default: break;
111  }
112  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Cannot handle index");
113  return QStringLiteral("Wrong index for %1").arg(i);
114  }
115 
116  void CInterpolationAndRenderingSetupBase::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
117  {
118  const ColumnIndex i = index.frontCasted<ColumnIndex>();
119  switch (i)
120  {
121  case IndexLogInterpolation: m_logInterpolation = variant.toBool(); return;
122  case IndexSimulatorDebugMessages: m_simulatorDebugMessages = variant.toBool(); return;
123  case IndexForceFullInterpolation: m_forceFullInterpolation = variant.toBool(); return;
124  case IndexEnabledAircraftParts: m_enabledAircraftParts = variant.toBool(); return;
125  case IndexSendGndFlagToSimulator: m_sendGndToSim = variant.toBool(); return;
126  case IndexInterpolatorMode: m_interpolatorMode = variant.toInt(); return;
127  case IndexInterpolatorModeAsString: this->setInterpolatorMode(variant.toString()); return;
128  case IndexFixSceneryOffset: m_fixSceneryOffset = variant.toBool(); return;
129  case IndexPitchOnGround: m_pitchOnGround.setPropertyByIndex(index.copyFrontRemoved(), variant); return;
130  default: break;
131  }
132  SWIFT_VERIFY_X(false, Q_FUNC_INFO, "Cannot handle index");
133  }
134 
135  QString CInterpolationAndRenderingSetupBase::convertToQString(bool i18n) const
136  {
137  Q_UNUSED(i18n)
138  return QStringLiteral("Interpolator: ") % this->getInterpolatorModeAsString() %
139  QStringLiteral(" | Dbg.sim.msgs: ") % boolToYesNo(m_simulatorDebugMessages) %
140  QStringLiteral(" | log interpolation: ") % boolToYesNo(m_logInterpolation) %
141  QStringLiteral(" | force VTOL interpolation: ") % boolToYesNo(m_forceFullInterpolation) %
142  QStringLiteral(" | enable parts: ") % boolToYesNo(m_enabledAircraftParts) %
143  QStringLiteral(" | send gnd: ") % boolToYesNo(m_sendGndToSim) %
144  QStringLiteral(" | fix.scenery offset: ") % boolToYesNo(m_fixSceneryOffset) %
145  QStringLiteral(" | pitch on gnd.: ") % m_pitchOnGround.valueRoundedWithUnit(CAngleUnit::deg(), 1, true);
146  }
147 
148  bool CInterpolationAndRenderingSetupBase::canHandleIndex(int index)
149  {
150  return index >= CInterpolationAndRenderingSetupBase::IndexLogInterpolation &&
151  index <= CInterpolationAndRenderingSetupBase::IndexFixSceneryOffset;
152  }
153 
154  CInterpolationAndRenderingSetupGlobal::CInterpolationAndRenderingSetupGlobal() {}
155 
156  int CInterpolationAndRenderingSetupGlobal::InfiniteAircraft() { return 100; }
157 
158  bool CInterpolationAndRenderingSetupGlobal::isRenderingEnabled() const
159  {
160  if (m_maxRenderedAircraft < 1) { return false; }
161  if (!isMaxDistanceRestricted()) { return true; }
162  return m_maxRenderedDistance.isPositiveWithEpsilonConsidered();
163  }
164 
165  bool CInterpolationAndRenderingSetupGlobal::isRenderingRestricted() const
166  {
167  return isRenderingEnabled() && (isMaxAircraftRestricted() || isMaxDistanceRestricted());
168  }
169 
170  int CInterpolationAndRenderingSetupGlobal::getMaxRenderedAircraft() const
171  {
172  return (m_maxRenderedAircraft <= InfiniteAircraft()) ? m_maxRenderedAircraft : InfiniteAircraft();
173  }
174 
175  bool CInterpolationAndRenderingSetupGlobal::setMaxRenderedAircraft(int maxRenderedAircraft)
176  {
177  if (maxRenderedAircraft == m_maxRenderedAircraft) { return false; }
178  if (maxRenderedAircraft < 1)
179  {
180  // disable, we set both values to 0
181  this->disableRendering();
182  }
183  else if (maxRenderedAircraft >= InfiniteAircraft()) { m_maxRenderedAircraft = InfiniteAircraft(); }
184  else { m_maxRenderedAircraft = maxRenderedAircraft; }
185  return true;
186  }
187 
188  bool CInterpolationAndRenderingSetupGlobal::setMaxRenderedDistance(const CLength &distance)
189  {
190 
191  if (distance == m_maxRenderedDistance) { return false; }
192  if (distance.isNull() || distance.isNegativeWithEpsilonConsidered())
193  {
194  m_maxRenderedDistance = CLength(0.0, nullptr);
195  }
196  else if (distance.isZeroEpsilonConsidered())
197  {
198  // zero means disabled, we disable max aircraft too
199  this->disableRendering();
200  }
201  else
202  {
203  Q_ASSERT(!distance.isNegativeWithEpsilonConsidered());
204  m_maxRenderedDistance = distance;
205  }
206  return true;
207  }
208 
209  void CInterpolationAndRenderingSetupGlobal::clearMaxRenderedDistance()
210  {
211  this->setMaxRenderedDistance(CLength(0.0, nullptr));
212  }
213 
214  bool CInterpolationAndRenderingSetupGlobal::isMaxAircraftRestricted() const
215  {
216  return m_maxRenderedAircraft < InfiniteAircraft();
217  }
218 
219  void CInterpolationAndRenderingSetupGlobal::clearAllRenderingRestrictions()
220  {
221  m_maxRenderedDistance = CLength(0, nullptr);
222  m_maxRenderedAircraft = InfiniteAircraft();
223  }
224 
225  void CInterpolationAndRenderingSetupGlobal::disableRendering()
226  {
227  m_maxRenderedAircraft = 0;
228  m_maxRenderedDistance = CLength(0, CLengthUnit::NM()); // zero distance
229  }
230 
231  bool CInterpolationAndRenderingSetupGlobal::isMaxDistanceRestricted() const
232  {
233  return !m_maxRenderedDistance.isNull();
234  }
235 
236  QString CInterpolationAndRenderingSetupGlobal::getRenderRestrictionText() const
237  {
238  if (!this->isRenderingRestricted()) { return "none"; }
239  QString rt;
240  if (this->isMaxAircraftRestricted())
241  {
242  rt.append(QString::number(this->getMaxRenderedAircraft())).append(" A/C");
243  }
244  if (this->isMaxDistanceRestricted())
245  {
246  if (!rt.isEmpty()) { rt.append(" "); }
247  rt.append(this->getMaxRenderedDistance().valueRoundedWithUnit(CLengthUnit::NM(), 0));
248  }
249  return rt;
250  }
251 
252  void CInterpolationAndRenderingSetupGlobal::setBaseValues(const CInterpolationAndRenderingSetupBase &baseValues)
253  {
254  m_logInterpolation = baseValues.logInterpolation();
255  m_simulatorDebugMessages = baseValues.showSimulatorDebugMessages();
256  m_forceFullInterpolation = baseValues.isForcingFullInterpolation();
257  m_enabledAircraftParts = baseValues.isAircraftPartsEnabled();
258  m_sendGndToSim = baseValues.isSendingGndFlagToSimulator();
259  m_fixSceneryOffset = baseValues.isFixingSceneryOffset();
260  m_interpolatorMode = baseValues.getInterpolatorMode();
261  m_pitchOnGround = baseValues.getPitchOnGround();
262  }
263 
264  QString CInterpolationAndRenderingSetupGlobal::convertToQString(bool i18n) const
265  {
266  Q_UNUSED(i18n)
267  return CInterpolationAndRenderingSetupBase::convertToQString(i18n) % QStringLiteral(" max.aircraft:") %
268  QString::number(m_maxRenderedAircraft) % QStringLiteral(" max.distance:") %
269  m_maxRenderedDistance.valueRoundedWithUnit(CLengthUnit::NM(), 2);
270  }
271 
272  QVariant CInterpolationAndRenderingSetupGlobal::propertyByIndex(CPropertyIndexRef index) const
273  {
274  if (index.isMyself()) { return QVariant::fromValue(*this); }
275  const ColumnIndex i = index.frontCasted<ColumnIndex>();
276  switch (i)
277  {
278  case IndexMaxRenderedAircraft: return QVariant::fromValue(m_maxRenderedAircraft);
279  case IndexMaxRenderedDistance: return QVariant::fromValue(m_maxRenderedDistance);
280  default: break;
281  }
282  if (CInterpolationAndRenderingSetupBase::canHandleIndex(i))
283  {
284  return CInterpolationAndRenderingSetupBase::propertyByIndex(index);
285  }
286  return CValueObject::propertyByIndex(index);
287  }
288 
289  void CInterpolationAndRenderingSetupGlobal::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
290  {
291  if (index.isMyself())
292  {
293  *this = variant.value<CInterpolationAndRenderingSetupGlobal>();
294  return;
295  }
296  const ColumnIndex i = index.frontCasted<ColumnIndex>();
297  switch (i)
298  {
299  case IndexMaxRenderedAircraft: m_maxRenderedAircraft = variant.toInt(); return;
300  case IndexMaxRenderedDistance: m_maxRenderedDistance = variant.value<CLength>(); return;
301  default: break;
302  }
303  if (CInterpolationAndRenderingSetupBase::canHandleIndex(i))
304  {
305  CInterpolationAndRenderingSetupBase::setPropertyByIndex(index, variant);
306  return;
307  }
308  CValueObject::setPropertyByIndex(index, variant);
309  }
310 
311  CInterpolationAndRenderingSetupPerCallsign::CInterpolationAndRenderingSetupPerCallsign() {}
312 
313  CInterpolationAndRenderingSetupPerCallsign::CInterpolationAndRenderingSetupPerCallsign(
314  const CCallsign &callsign, const CInterpolationAndRenderingSetupGlobal &globalSetup)
315  : CInterpolationAndRenderingSetupBase(globalSetup), m_callsign(callsign)
316  {}
317 
319  const CInterpolationAndRenderingSetupGlobal &globalSetup) const
320  {
321  CPropertyIndexList diff;
322  if (this->logInterpolation() != globalSetup.logInterpolation()) { diff.push_back(IndexLogInterpolation); }
323  if (this->showSimulatorDebugMessages() != globalSetup.showSimulatorDebugMessages())
324  {
325  diff.push_back(IndexSimulatorDebugMessages);
326  }
327  if (this->isForcingFullInterpolation() != globalSetup.isForcingFullInterpolation())
328  {
329  diff.push_back(IndexForceFullInterpolation);
330  }
331  if (this->isAircraftPartsEnabled() != globalSetup.isAircraftPartsEnabled())
332  {
333  diff.push_back(IndexEnabledAircraftParts);
334  }
335  if (this->isSendingGndFlagToSimulator() != globalSetup.isSendingGndFlagToSimulator())
336  {
337  diff.push_back(IndexSendGndFlagToSimulator);
338  }
339  if (this->isFixingSceneryOffset() != globalSetup.isFixingSceneryOffset())
340  {
341  diff.push_back(IndexFixSceneryOffset);
342  }
343  if (this->getPitchOnGround() != globalSetup.getPitchOnGround()) { diff.push_back(IndexPitchOnGround); }
344  return diff;
345  }
346 
348  const CInterpolationAndRenderingSetupGlobal &globalSetup) const
349  {
350  const CPropertyIndexList il = this->unequalToGlobal(globalSetup);
351  const bool equal = il.isEmpty();
352  return equal;
353  }
354 
356  {
357  if (index.isMyself()) { return QVariant::fromValue(*this); }
358  const ColumnIndex i = index.frontCasted<ColumnIndex>();
359  switch (i)
360  {
361  case IndexCallsign: return m_callsign.propertyByIndex(index.copyFrontRemoved());
362  default: break;
363  }
365  }
366 
368  const QVariant &variant)
369  {
370  if (index.isMyself())
371  {
372  *this = variant.value<CInterpolationAndRenderingSetupPerCallsign>();
373  return;
374  }
375  const ColumnIndex i = index.frontCasted<ColumnIndex>();
376  switch (i)
377  {
378  case IndexCallsign: m_callsign.setPropertyByIndex(index.copyFrontRemoved(), variant); return;
379  default: break;
380  }
382  }
383 
385  {
387  return null;
388  }
389 } // 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.
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".
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.
#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