From e356e691b2ff391875448560a921e80e79261e63 Mon Sep 17 00:00:00 2001 From: James Turner Date: Tue, 17 Nov 2015 07:36:54 +0000 Subject: [PATCH] Cap number of airports displayed in diagrams - restrict heliports / seaports by aircraft type - prioritise by runway length - clean up airport label names --- src/GUI/AircraftModel.cxx | 27 +++++- src/GUI/AircraftModel.hxx | 5 +- src/GUI/BaseDiagram.cxx | 194 ++++++++++++++++++++++++------------- src/GUI/BaseDiagram.hxx | 10 ++ src/GUI/LocationWidget.cxx | 54 +++++++++-- src/GUI/LocationWidget.hxx | 7 +- src/GUI/QtLauncher.cxx | 10 +- src/GUI/QtLauncher_fwd.hxx | 15 +++ 8 files changed, 238 insertions(+), 84 deletions(-) create mode 100644 src/GUI/QtLauncher_fwd.hxx diff --git a/src/GUI/AircraftModel.cxx b/src/GUI/AircraftModel.cxx index bc0bdadca..9febfc703 100644 --- a/src/GUI/AircraftModel.cxx +++ b/src/GUI/AircraftModel.cxx @@ -47,14 +47,18 @@ const int STANDARD_THUMBNAIL_WIDTH = 172; using namespace simgear::pkg; AircraftItem::AircraftItem() : - excluded(false) + excluded(false), + usesHeliports(false), + usesSeaports(false) { // oh for C++11 initialisers for (int i=0; i<4; ++i) ratings[i] = 0; } AircraftItem::AircraftItem(QDir dir, QString filePath) : - excluded(false) + excluded(false), + usesHeliports(false), + usesSeaports(false) { for (int i=0; i<4; ++i) ratings[i] = 0; @@ -89,6 +93,21 @@ AircraftItem::AircraftItem(QDir dir, QString filePath) : if (sim->hasChild("variant-of")) { variantOf = sim->getStringValue("variant-of"); } + + if (sim->hasChild("tags")) { + SGPropertyNode_ptr tagsNode = sim->getChild("tags"); + int nChildren = tagsNode->nChildren(); + for (int i = 0; i < nChildren; i++) { + const SGPropertyNode* c = tagsNode->getChild(i); + if (strcmp(c->getName(), "tag") == 0) { + const char* tagName = c->getStringValue(); + usesHeliports |= (strcmp(tagName, "helicopter") == 0); + // could also consider vtol tag? + usesSeaports |= (strcmp(tagName, "seaplane") == 0); + usesSeaports |= (strcmp(tagName, "floats") == 0); + } + } // of tags iteration + } // of set-xml has tags } QString AircraftItem::baseName() const @@ -574,6 +593,10 @@ QVariant AircraftItemModel::dataFromItem(AircraftItemPtr item, quint32 variantIn "I'm just a poor boy, I need no sympathy because I'm easy come, easy go." "Litte high, little low. Anywhere the wind blows."; #endif + } else if (role == AircraftIsHelicopterRole) { + return item->usesHeliports; + } else if (role == AircraftIsSeaplaneRole) { + return item->usesSeaports; } return QVariant(); diff --git a/src/GUI/AircraftModel.hxx b/src/GUI/AircraftModel.hxx index c6a85e836..b49527ed8 100644 --- a/src/GUI/AircraftModel.hxx +++ b/src/GUI/AircraftModel.hxx @@ -46,6 +46,8 @@ const int AircraftPackageSizeRole = Qt::UserRole + 12; const int AircraftInstallDownloadedSizeRole = Qt::UserRole + 13; const int AircraftURIRole = Qt::UserRole + 14; const int AircraftThumbnailSizeRole = Qt::UserRole + 15; +const int AircraftIsHelicopterRole = Qt::UserRole + 16; +const int AircraftIsSeaplaneRole = Qt::UserRole + 17; const int AircraftRatingRole = Qt::UserRole + 100; const int AircraftVariantDescriptionRole = Qt::UserRole + 200; @@ -79,8 +81,9 @@ struct AircraftItem int ratings[4]; QString variantOf; QDateTime pathModTime; - QList variants; + bool usesHeliports; + bool usesSeaports; private: mutable QPixmap m_thumbnail; }; diff --git a/src/GUI/BaseDiagram.cxx b/src/GUI/BaseDiagram.cxx index 0db4a88c1..e268e4cd4 100644 --- a/src/GUI/BaseDiagram.cxx +++ b/src/GUI/BaseDiagram.cxx @@ -31,6 +31,8 @@ #include #include +#include "QtLauncher_fwd.hxx" + /* equatorial and polar earth radius */ const float rec = 6378137; // earth radius, equator (?) const float rpol = 6356752.314f; // earth radius, polar (?) @@ -133,30 +135,61 @@ void BaseDiagram::paintAirplaneIcon(QPainter* painter, const SGGeod& geod, int h class MapFilter : public FGPositioned::TypeFilter { public: - MapFilter() + + MapFilter(LauncherAircraftType aircraft) { // addType(FGPositioned::FIX); - addType(FGPositioned::AIRPORT); - addType(FGPositioned::HELIPORT); - addType(FGPositioned::SEAPORT); addType(FGPositioned::NDB); addType(FGPositioned::VOR); + + if (aircraft == Helicopter) { + addType(FGPositioned::HELIPAD); + } + + if (aircraft == Seaplane) { + addType(FGPositioned::SEAPORT); + } else { + addType(FGPositioned::AIRPORT); + } } virtual bool pass(FGPositioned* aPos) const { bool ok = TypeFilter::pass(aPos); + // fix-filtering code disabled since fixed are entirely disabled +#if 0 if (ok && (aPos->type() == FGPositioned::FIX)) { // ignore fixes which end in digits if (aPos->ident().length() > 4 && isdigit(aPos->ident()[3]) && isdigit(aPos->ident()[4])) { return false; } } - +#endif return ok; } }; +void BaseDiagram::splitItems(const FGPositionedList& in, FGPositionedList& navaids, + FGPositionedList& ports) +{ + FGPositionedList::const_iterator it = in.begin(); + for (; it != in.end(); ++it) { + if (FGAirport::isAirportType(it->ptr())) { + ports.push_back(*it); + } else { + navaids.push_back(*it); + } + } +} + +bool orderAirportsByRunwayLength(const FGPositionedRef& a, + const FGPositionedRef& b) +{ + FGAirport* aptA = static_cast(a.ptr()); + FGAirport* aptB = static_cast(b.ptr()); + + return aptA->longestRunway()->lengthFt() > aptB->longestRunway()->lengthFt(); +} void BaseDiagram::paintNavaids(QPainter* painter) { @@ -169,85 +202,104 @@ void BaseDiagram::paintNavaids(QPainter* painter) SGGeod viewCenter = unproject(invT.map(rect().center()), m_projectionCenter); SGGeod bottomRight = unproject(invT.map(rect().bottomRight()), m_projectionCenter); - double minRunwayLengthFt = (16 / m_scale) * SG_METER_TO_FEET; - double drawRangeNm = std::max(SGGeodesy::distanceNm(viewCenter, topLeft), SGGeodesy::distanceNm(viewCenter, bottomRight)); - MapFilter f; + MapFilter f(m_aircraftType); FGPositionedList items = FGPositioned::findWithinRange(viewCenter, drawRangeNm, &f); + FGPositionedList navaids, ports; + splitItems(items, navaids, ports); + + if (ports.size() >= 40) { + FGPositionedList::iterator middle = ports.begin() + 40; + std::partial_sort(ports.begin(), middle, ports.end(), + orderAirportsByRunwayLength); + ports.resize(40); + } + m_labelRects.clear(); m_labelRects.reserve(items.size()); FGPositionedList::const_iterator it; - for (it = items.begin(); it != items.end(); ++it) { - FGPositionedRef pos(*it); - bool drawAsIcon = true; - if (isNavaidIgnored(pos)) - continue; - - FGPositioned::Type ty(pos->type()); - if (ty == FGPositioned::AIRPORT) { - FGAirport* apt = static_cast(pos.ptr()); - if (apt->hasHardRunwayOfLengthFt(minRunwayLengthFt)) { - - drawAsIcon = false; - painter->setTransform(xf); - QVector lines = projectAirportRuwaysWithCenter(apt, m_projectionCenter); - - QPen pen(QColor(0x03, 0x83, 0xbf), 8); - pen.setCosmetic(true); - painter->setPen(pen); - painter->drawLines(lines); - - QPen linePen(Qt::white, 2); - linePen.setCosmetic(true); - painter->setPen(linePen); - painter->drawLines(lines); - - painter->resetTransform(); - } - } + for (it = ports.begin(); it != ports.end(); ++it) { + paintNavaid(painter, xf, *it); + } - if (drawAsIcon) { - QPixmap pm = iconForPositioned(pos); - QPointF loc = xf.map(project(pos->geod())); - QRect iconRect = pm.rect(); - iconRect.moveCenter(loc.toPoint()); - painter->drawPixmap(iconRect, pm); - bool isNDB = (ty == FGPositioned::NDB); - - // compute label text so we can measure it - QString label; - if (FGAirport::isAirportType(pos.ptr())) { - label = QString::fromStdString((*it)->name()); - } else { - label = QString::fromStdString((*it)->ident()); - } + for (it = navaids.begin(); it != navaids.end(); ++it) { + paintNavaid(painter, xf, *it); + } - if (ty == FGPositioned::NDB) { - FGNavRecord* nav = static_cast(pos.ptr()); - label.append("\n").append(QString::number(nav->get_freq() / 100)); - } else if (ty == FGPositioned::VOR) { - FGNavRecord* nav = static_cast(pos.ptr()); - label.append("\n").append(QString::number(nav->get_freq() / 100.0, 'f', 1)); - } - QRect textBounds = painter->boundingRect(QRect(0, 0, 100, 100), - Qt::TextWordWrap, label); - int textFlags; - textBounds = rectAndFlagsForLabel(pos->guid(), iconRect, - textBounds.size(), - textFlags); + // restore transform + painter->setTransform(xf); +} + +void BaseDiagram::paintNavaid(QPainter* painter, const QTransform& t, const FGPositionedRef &pos) +{ + bool drawAsIcon = true; + if (isNavaidIgnored(pos)) + return; + + const double minRunwayLengthFt = (16 / m_scale) * SG_METER_TO_FEET; + FGPositioned::Type ty(pos->type()); + if (ty == FGPositioned::AIRPORT) { + FGAirport* apt = static_cast(pos.ptr()); + if (apt->hasHardRunwayOfLengthFt(minRunwayLengthFt)) { + + drawAsIcon = false; + painter->setTransform(t); + QVector lines = projectAirportRuwaysWithCenter(apt, m_projectionCenter); + + QPen pen(QColor(0x03, 0x83, 0xbf), 8); + pen.setCosmetic(true); + painter->setPen(pen); + painter->drawLines(lines); + + QPen linePen(Qt::white, 2); + linePen.setCosmetic(true); + painter->setPen(linePen); + painter->drawLines(lines); - painter->setPen(isNDB ? QColor(0x9b, 0x5d, 0xa2) : QColor(0x03, 0x83, 0xbf)); - painter->drawText(textBounds, textFlags, label); + painter->resetTransform(); } } - // restore transform - painter->setTransform(xf); + if (drawAsIcon) { + QPixmap pm = iconForPositioned(pos); + QPointF loc = t.map(project(pos->geod())); + QRect iconRect = pm.rect(); + iconRect.moveCenter(loc.toPoint()); + painter->drawPixmap(iconRect, pm); + bool isNDB = (ty == FGPositioned::NDB); + + // compute label text so we can measure it + QString label; + if (FGAirport::isAirportType(pos.ptr())) { + label = QString::fromStdString(pos->name()); + label = fixNavaidName(label); + } else { + label = QString::fromStdString(pos->ident()); + } + + if (ty == FGPositioned::NDB) { + FGNavRecord* nav = static_cast(pos.ptr()); + label.append("\n").append(QString::number(nav->get_freq() / 100)); + } else if (ty == FGPositioned::VOR) { + FGNavRecord* nav = static_cast(pos.ptr()); + label.append("\n").append(QString::number(nav->get_freq() / 100.0, 'f', 1)); + } + + QRect textBounds = painter->boundingRect(QRect(0, 0, 100, 100), + Qt::TextWordWrap, label); + int textFlags; + textBounds = rectAndFlagsForLabel(pos->guid(), iconRect, + textBounds.size(), + textFlags); + + painter->setPen(isNDB ? QColor(0x9b, 0x5d, 0xa2) : QColor(0x03, 0x83, 0xbf)); + painter->drawText(textBounds, textFlags, label); + } } bool BaseDiagram::isNavaidIgnored(const FGPositionedRef &pos) const @@ -626,6 +678,12 @@ QVector BaseDiagram::projectAirportRuwaysWithCenter(FGAirportRef apt, co return r; } +void BaseDiagram::setAircraftType(LauncherAircraftType type) +{ + m_aircraftType = type; + update(); +} + QVector BaseDiagram::projectAirportRuwaysIntoRect(FGAirportRef apt, const QRectF &bounds) { QVector r = projectAirportRuwaysWithCenter(apt, apt->geod()); diff --git a/src/GUI/BaseDiagram.hxx b/src/GUI/BaseDiagram.hxx index ce7291a60..9cbb81102 100644 --- a/src/GUI/BaseDiagram.hxx +++ b/src/GUI/BaseDiagram.hxx @@ -30,6 +30,8 @@ #include #include +#include "QtLauncher_fwd.hxx" + class BaseDiagram : public QWidget { Q_OBJECT @@ -50,6 +52,8 @@ public: static QVector projectAirportRuwaysIntoRect(FGAirportRef apt, const QRectF& bounds); static QVector projectAirportRuwaysWithCenter(FGAirportRef apt, const SGGeod &c); + + void setAircraftType(LauncherAircraftType type); protected: virtual void paintEvent(QPaintEvent* pe); @@ -80,6 +84,7 @@ protected: QPointF m_panOffset, m_lastMousePos; int m_wheelAngleDeltaAccumulator; bool m_didPan; + LauncherAircraftType m_aircraftType; static void extendRect(QRectF& r, const QPointF& p); @@ -118,6 +123,11 @@ private: mutable QVector m_labelRects; static int textFlagsForLabelPosition(LabelPosition pos); + + void splitItems(const FGPositionedList &in, FGPositionedList &navaids, FGPositionedList &ports); + void paintNavaid(QPainter *painter, + const QTransform& t, + const FGPositionedRef &pos); }; Q_DECLARE_OPERATORS_FOR_FLAGS(BaseDiagram::IconOptions) diff --git a/src/GUI/LocationWidget.cxx b/src/GUI/LocationWidget.cxx index 2f4dfc2ba..533c76623 100644 --- a/src/GUI/LocationWidget.cxx +++ b/src/GUI/LocationWidget.cxx @@ -59,11 +59,21 @@ QString fixNavaidName(QString s) continue; } - if (up == "MUNI") { + if (up == "CO") { + changedWords.append("County"); + continue; + } + + if ((up == "MUNI") || (up == "MUN")) { changedWords.append("Municipal"); continue; } + if (up == "MEM") { + changedWords.append("Memorial"); + continue; + } + if (up == "RGNL") { changedWords.append("Regional"); continue; @@ -85,11 +95,19 @@ QString fixNavaidName(QString s) continue; } - if ((up == "VOR") || (up == "NDB") || (up == "VOR-DME") || (up == "VORTAC") || (up == "NDB-DME")) { + if ((up == "VOR") || (up == "NDB") + || (up == "VOR-DME") || (up == "VORTAC") + || (up == "NDB-DME") + || (up == "AFB") || (up == "RAF")) + { changedWords.append(w); continue; } + if ((up =="[X]") || (up == "[H]") || (up == "[S]")) { + continue; // consume + } + QChar firstChar = w.at(0).toUpper(); w = w.mid(1).toLower(); w.prepend(firstChar); @@ -171,14 +189,21 @@ FGPositionedList loadPositionedList(QVariant v) class IdentSearchFilter : public FGPositioned::TypeFilter { public: - IdentSearchFilter() + IdentSearchFilter(LauncherAircraftType aircraft) { - addType(FGPositioned::AIRPORT); - addType(FGPositioned::SEAPORT); - addType(FGPositioned::HELIPAD); addType(FGPositioned::VOR); addType(FGPositioned::FIX); addType(FGPositioned::NDB); + + if (aircraft == Helicopter) { + addType(FGPositioned::HELIPAD); + } + + if (aircraft == Seaplane) { + addType(FGPositioned::SEAPORT); + } else { + addType(FGPositioned::AIRPORT); + } } }; @@ -191,7 +216,7 @@ public: { } - void setSearch(QString t) + void setSearch(QString t, LauncherAircraftType aircraft) { beginResetModel(); @@ -200,7 +225,7 @@ public: std::string term(t.toUpper().toStdString()); - IdentSearchFilter filter; + IdentSearchFilter filter(aircraft); FGPositionedList exactMatches = NavDataCache::instance()->findAllWithIdent(term, &filter, true); for (unsigned int i=0; isetupUi(this); @@ -596,7 +622,7 @@ void LocationWidget::onSearch() return; } - m_searchModel->setSearch(search); + m_searchModel->setSearch(search, m_aircraftType); if (m_searchModel->isSearchActive()) { m_ui->searchStatusText->setText(QString("Searching for '%1'").arg(search)); @@ -868,6 +894,14 @@ void LocationWidget::setBaseLocation(FGPositionedRef ref) updateDescription(); } +void LocationWidget::setAircraftType(LauncherAircraftType ty) +{ + m_aircraftType = ty; + // nothing happens until next search + m_ui->navaidDiagram->setAircraftType(ty); + m_ui->airportDiagram->setAircraftType(ty); +} + void LocationWidget::onOffsetDataChanged() { m_ui->navaidDiagram->setOffsetEnabled(m_ui->offsetGroup->isChecked()); diff --git a/src/GUI/LocationWidget.hxx b/src/GUI/LocationWidget.hxx index 5df4d62a2..5dd0eb65e 100644 --- a/src/GUI/LocationWidget.hxx +++ b/src/GUI/LocationWidget.hxx @@ -28,6 +28,8 @@ #include #include +#include "QtLauncher_fwd.hxx" + namespace Ui { class LocationWidget; } @@ -49,6 +51,8 @@ public: void setBaseLocation(FGPositionedRef ref); + void setAircraftType(LauncherAircraftType ty); + bool shouldStartPaused() const; void setLocationOptions(); @@ -87,8 +91,7 @@ private: QToolButton* m_backButton; FGPositionedList m_recentLocations; - - + LauncherAircraftType m_aircraftType; }; #endif // LOCATIONWIDGET_H diff --git a/src/GUI/QtLauncher.cxx b/src/GUI/QtLauncher.cxx index 842a36966..e3b9e6f07 100644 --- a/src/GUI/QtLauncher.cxx +++ b/src/GUI/QtLauncher.cxx @@ -864,7 +864,6 @@ void QtLauncher::onAircraftInstallFailed(QModelIndex index, QString errorMessage void QtLauncher::onAircraftSelected(const QModelIndex& index) { m_selectedAircraft = index.data(AircraftURIRole).toUrl(); - qDebug() << "selected aircraft is now" << m_selectedAircraft; updateSelectedAircraft(); } @@ -910,6 +909,15 @@ void QtLauncher::updateSelectedAircraft() int status = index.data(AircraftPackageStatusRole).toInt(); bool canRun = (status == PackageInstalled); m_ui->runButton->setEnabled(canRun); + + LauncherAircraftType aircraftType = Airplane; + if (index.data(AircraftIsHelicopterRole).toBool()) { + aircraftType = Helicopter; + } else if (index.data(AircraftIsSeaplaneRole).toBool()) { + aircraftType = Seaplane; + } + + m_ui->location->setAircraftType(aircraftType); } else { m_ui->thumbnail->setPixmap(QPixmap()); m_ui->aircraftDescription->setText(""); diff --git a/src/GUI/QtLauncher_fwd.hxx b/src/GUI/QtLauncher_fwd.hxx new file mode 100644 index 000000000..cb80f480e --- /dev/null +++ b/src/GUI/QtLauncher_fwd.hxx @@ -0,0 +1,15 @@ +#ifndef QTGUI_FWD_H +#define QTGUI_FWD_H + +enum LauncherAircraftType +{ + Airplane = 0, + Seaplane, + Helicopter, + Airship +}; + +extern QString fixNavaidName(QString s); + +#endif // QTGUI_FWD_H + -- 2.39.5