6 #include <QStringBuilder>
9 #include "ui_radarcomponent.h"
18 using namespace swift::misc::aviation;
19 using namespace swift::misc::simulation;
20 using namespace swift::misc::geo;
21 using namespace swift::misc::physical_quantities;
26 CRadarComponent::CRadarComponent(QWidget *parent)
27 : QFrame(parent), ui(new Ui::
CRadarComponent), m_tagFont(QApplication::font())
31 ui->gv_RadarView->setScene(&m_scene);
33 ui->cb_RadarRange->addItem(QString::number(0.5) % u
" nm", 0.5);
34 for (
int r = 1; r <= 9; ++r) { ui->cb_RadarRange->addItem(QString::number(r) % u
" nm", r); }
35 for (
int r = 10; r <= 90; r += 10) { ui->cb_RadarRange->addItem(QString::number(r) % u
" nm", r); }
37 ui->cb_RadarRange->setCurrentText(QString::number(m_rangeNM) % u
" nm");
38 ui->sb_FontSize->setRange(1, 100);
39 ui->sb_FontSize->setValue(QApplication::font().pointSize());
41 connect(ui->gv_RadarView, &CRadarView::radarViewResized,
this, &CRadarComponent::fitInView);
42 connect(ui->gv_RadarView, &CRadarView::zoomEvent,
this, &CRadarComponent::changeRangeInSteps);
43 connect(&m_updateTimer, &QTimer::timeout,
this, &CRadarComponent::refreshTargets);
44 connect(&m_headingTimer, &QTimer::timeout,
this, &CRadarComponent::rotateView);
46 connect(ui->cb_RadarRange, qOverload<int>(&QComboBox::currentIndexChanged),
this,
47 &CRadarComponent::changeRangeFromUserSelection);
48 connect(ui->sb_FontSize, qOverload<int>(&QSpinBox::valueChanged),
this, &CRadarComponent::updateFont);
49 connect(ui->cb_Callsign, &QCheckBox::toggled,
this, &CRadarComponent::refreshTargets);
50 connect(ui->cb_Heading, &QCheckBox::toggled,
this, &CRadarComponent::refreshTargets);
51 connect(ui->cb_Altitude, &QCheckBox::toggled,
this, &CRadarComponent::refreshTargets);
52 connect(ui->cb_GroundSpeed, &QCheckBox::toggled,
this, &CRadarComponent::refreshTargets);
53 connect(ui->cb_Grid, &QCheckBox::toggled,
this, &CRadarComponent::toggleGrid);
57 m_updateTimer.start(5000);
58 m_headingTimer.start(50);
67 &CRadarComponent::onInfoAreaTabBarChanged);
68 Q_ASSERT_X(c, Q_FUNC_INFO,
"failed connect");
69 Q_ASSERT_X(parentDockableWidget, Q_FUNC_INFO,
"missing parent");
70 return c && parentDockableWidget;
73 void CRadarComponent::prepareScene()
75 m_scene.addItem(&m_center);
76 m_scene.addItem(&m_macroGraticule);
77 m_scene.addItem(&m_microGraticule);
78 m_scene.addItem(&m_radials);
79 m_scene.addItem(&m_radarTargets);
80 m_radarTargetPen.setCosmetic(
true);
86 void CRadarComponent::addCenter()
88 QPen pen(Qt::white, 1);
89 pen.setCosmetic(
true);
90 QGraphicsLineItem *lix =
new QGraphicsLineItem { QLineF(-5.0, 0.0, 5.0, 0.0), &m_center };
91 lix->setFlags(QGraphicsItem::ItemIgnoresTransformations);
94 QGraphicsLineItem *liy =
new QGraphicsLineItem(QLineF(0.0, -5.0, 0.0, 5.0), &m_center);
95 liy->setFlags(QGraphicsItem::ItemIgnoresTransformations);
99 void CRadarComponent::addGraticules()
101 QPen pen(Qt::white, 1);
102 pen.setCosmetic(
true);
105 for (
int range = 10; range <= 100; range += 10)
107 QGraphicsEllipseItem *circle =
108 new QGraphicsEllipseItem(-range, -range, 2.0 * range, 2.0 * range, &m_macroGraticule);
111 pen = QPen(Qt::gray, 1, Qt::DashLine);
112 pen.setCosmetic(
true);
115 for (qreal range = 1; range <= 3; ++range)
117 QGraphicsEllipseItem *circle =
118 new QGraphicsEllipseItem(-range * 2.5, -range * 2.5, 5.0 * range, 5.0 * range, &m_microGraticule);
123 void CRadarComponent::addRadials()
125 QPen pen(Qt::gray, 1, Qt::DashDotDotLine);
126 pen.setCosmetic(
true);
128 for (
int angle = 0; angle < 360; angle += 30)
130 const QLineF line({ 0.0, 0.0 }, polarPoint(1000.0, qDegreesToRadians(
static_cast<qreal
>(angle))));
131 QGraphicsLineItem *li =
new QGraphicsLineItem(line, &m_radials);
132 li->setFlags(QGraphicsItem::ItemIgnoresTransformations);
137 void CRadarComponent::refreshTargets()
141 qDeleteAll(m_radarTargets.childItems());
150 const double distanceNM = sa.getRelativeDistance().value(CLengthUnit::NM());
151 const double bearingRad = sa.getRelativeBearing().value(CAngleUnit::rad());
152 const int groundSpeedKts = sa.getGroundSpeed().valueInteger(CSpeedUnit::kts());
154 QPointF position(polarPoint(distanceNM, bearingRad));
156 QGraphicsEllipseItem *dot =
new QGraphicsEllipseItem(-2.0, -2.0, 4.0, 4.0, &m_radarTargets);
157 dot->setPos(position);
158 dot->setPen(m_radarTargetPen);
159 dot->setBrush(m_radarTargetPen.color());
160 dot->setFlags(QGraphicsItem::ItemIgnoresTransformations);
162 QGraphicsTextItem *tag =
new QGraphicsTextItem(&m_radarTargets);
164 if (ui->cb_Callsign->isChecked()) { tagText += sa.getCallsignAsString() % u
"\n"; }
165 if (ui->cb_Altitude->isChecked())
167 int flightLeveL = sa.getAltitude().valueInteger(CLengthUnit::ft()) / 100;
168 tagText += u
"FL" % QStringLiteral(
"%1").arg(flightLeveL, 3, 10, QChar(
'0'));
170 if (ui->cb_GroundSpeed->isChecked())
172 if (!tagText.isEmpty()) tagText += QStringLiteral(
" ");
173 tagText += QString::number(groundSpeedKts) % u
" kt";
176 tag->setPlainText(tagText);
177 tag->setFont(m_tagFont);
178 tag->setPos(position);
179 tag->setDefaultTextColor(Qt::green);
180 tag->setFlags(QGraphicsItem::ItemIgnoresTransformations);
182 if (ui->cb_Heading->isChecked() && groundSpeedKts > 3.0)
184 const double headingRad = sa.getHeading().value(CAngleUnit::rad());
185 QPen pen(Qt::green, 1);
186 pen.setCosmetic(
true);
187 QGraphicsLineItem *li =
188 new QGraphicsLineItem(QLineF({ 0.0, 0.0 }, polarPoint(5.0, headingRad)), &m_radarTargets);
189 li->setPos(position);
197 void CRadarComponent::rotateView()
203 int headingDegree = 0;
204 if (!ui->cb_LockNorth->isChecked())
210 if (m_rotatenAngle != headingDegree)
214 ui->gv_RadarView->rotate(m_rotatenAngle);
215 ui->gv_RadarView->rotate(-headingDegree);
216 m_rotatenAngle = headingDegree;
222 void CRadarComponent::toggleGrid(
bool checked)
224 m_macroGraticule.setVisible(checked);
225 m_microGraticule.setVisible(checked);
226 m_radials.setVisible(checked);
229 void CRadarComponent::fitInView()
231 ui->gv_RadarView->fitInView(-m_rangeNM, -m_rangeNM, 2.0 * m_rangeNM, 2.0 * m_rangeNM, Qt::KeepAspectRatio);
234 void CRadarComponent::changeRangeInSteps(
bool zoomIn)
236 qreal direction = zoomIn ? 1.0 : -1.0;
237 double factor = 10.0;
238 if (m_rangeNM < 10.0 || (qFuzzyCompare(m_rangeNM, 10.0) && zoomIn)) { factor = 1.0; }
240 if (m_rangeNM < 1.0 || (qFuzzyCompare(m_rangeNM, 1.0) && zoomIn)) { factor = 0.5; }
242 m_rangeNM = m_rangeNM - direction * factor;
243 m_rangeNM = qMin(90.0, qMax(0.5, m_rangeNM));
244 ui->cb_RadarRange->setCurrentText(QString::number(m_rangeNM) % u
" nm");
248 void CRadarComponent::changeRangeFromUserSelection(
int index)
250 double range = ui->cb_RadarRange->itemData(index).toDouble();
251 if (!qFuzzyCompare(m_rangeNM, range))
258 void CRadarComponent::updateFont(
int pointSize)
260 m_tagFont.setPointSize(pointSize);
261 this->refreshTargets();
264 void CRadarComponent::onInfoAreaTabBarChanged(
int index)
274 QPointer<CRadarComponent> myself(
this);
276 if (!myself) {
return; }
277 myself->refreshTargets();
281 QPointF CRadarComponent::polarPoint(
double distance,
double angleRadians)
283 angleRadians = -angleRadians;
286 QPointF p(distance * qCos(angleRadians), distance * qSin(angleRadians));
const context::IContextOwnAircraft * getIContextOwnAircraft() const
Direct access to contexts if a CCoreFacade has been initialized.
const context::IContextNetwork * getIContextNetwork() const
Direct access to contexts if a CCoreFacade has been initialized.
bool isShuttingDown() const
Is application shutting down?
virtual swift::misc::simulation::CSimulatedAircraftList getAircraftInRange() const =0
Aircraft list.
virtual bool isConnected() const =0
Network connected?
virtual swift::misc::aviation::CAircraftSituation getOwnAircraftSituation() const =0
Get own aircraft.
void changedInfoAreaTabBarIndex(int index)
Tab bar changed.
GUI displaying a radar like view with aircrafts nearby.
virtual ~CRadarComponent()
Destructor.
virtual bool setParentDockWidgetInfoArea(swift::gui::CDockWidgetInfoArea *parentDockableWidget)
Corresponding dockable widget in info area.
const CHeading & getHeading() const
Get heading.
int valueInteger(MU unit) const
As integer value.
Comprehensive information of an aircraft.
Value object encapsulating a list of aircraft.
SWIFT_GUI_EXPORT swift::gui::CGuiApplication * sGui
Single instance of GUI application object.
High level reusable GUI components.
Views, mainly QTableView.
Free functions in swift::misc.
void swap(Optional< T > &a, Optional< T > &b) noexcept(std::is_nothrow_swappable_v< T >)
Efficient swap for two Optional objects.
auto singleShot(int msec, QObject *target, F &&task)
Starts a single-shot timer which will call a task in the thread of the given object when it times out...