]> git.mxchange.org Git - flightgear.git/blobdiff - src/GUI/BaseDiagram.cxx
Launcher: Maintain aircraft selection better
[flightgear.git] / src / GUI / BaseDiagram.cxx
index 0db4a88c1f63918be42b5f3dfe12ef57a76ac202..fa593f8b7cdcc5353bdfea0d233173b5914ece1a 100644 (file)
 #include <Navaids/navrecord.hxx>
 #include <Navaids/positioned.hxx>
 #include <Airports/airport.hxx>
+#include <Navaids/PolyLine.hxx>
+
+#include "QtLauncher_fwd.hxx"
 
 /* equatorial and polar earth radius */
 const float rec  = 6378137;          // earth radius, equator (?)
 const float rpol = 6356752.314f;      // earth radius, polar   (?)
 
+const double MINIMUM_SCALE = 0.002;
+
 //Returns Earth radius at a given latitude (Ellipsoide equation with two equal axis)
 static float earth_radius_lat( float lat )
 {
@@ -110,6 +115,8 @@ void BaseDiagram::paintEvent(QPaintEvent* pe)
     QTransform t(transform());
     p.setTransform(t);
 
+    paintPolygonData(&p);
+
     paintNavaids(&p);
 
     paintContents(&p);
@@ -130,33 +137,139 @@ void BaseDiagram::paintAirplaneIcon(QPainter* painter, const SGGeod& geod, int h
     painter->drawPixmap(airplaneIconRect, pix);
 }
 
+void BaseDiagram::paintPolygonData(QPainter* painter)
+{
+    QTransform xf = painter->transform();
+    QTransform invT = xf.inverted();
+
+    SGGeod topLeft = unproject(invT.map(rect().topLeft()), m_projectionCenter);
+    SGGeod viewCenter = unproject(invT.map(rect().center()), m_projectionCenter);
+    SGGeod bottomRight = unproject(invT.map(rect().bottomRight()), m_projectionCenter);
+
+    double drawRangeNm = std::max(SGGeodesy::distanceNm(viewCenter, topLeft),
+                                  SGGeodesy::distanceNm(viewCenter, bottomRight));
+
+    flightgear::PolyLineList lines(flightgear::PolyLine::linesNearPos(viewCenter, drawRangeNm,
+                                                                      flightgear::PolyLine::COASTLINE));
+
+    QPen waterPen(QColor(64, 64, 255), 1);
+    waterPen.setCosmetic(true);
+    painter->setPen(waterPen);
+    flightgear::PolyLineList::const_iterator it;
+    for (it=lines.begin(); it != lines.end(); ++it) {
+        paintGeodVec(painter, (*it)->points());
+    }
+
+    lines = flightgear::PolyLine::linesNearPos(viewCenter, drawRangeNm,
+                                              flightgear::PolyLine::URBAN);
+    for (it=lines.begin(); it != lines.end(); ++it) {
+        fillClosedGeodVec(painter, QColor(192, 192, 96), (*it)->points());
+    }
+
+    lines = flightgear::PolyLine::linesNearPos(viewCenter, drawRangeNm,
+                                              flightgear::PolyLine::RIVER);
+
+    painter->setPen(waterPen);
+    for (it=lines.begin(); it != lines.end(); ++it) {
+        paintGeodVec(painter, (*it)->points());
+    }
+
+
+    lines = flightgear::PolyLine::linesNearPos(viewCenter, drawRangeNm,
+                                              flightgear::PolyLine::LAKE);
+
+    for (it=lines.begin(); it != lines.end(); ++it) {
+        fillClosedGeodVec(painter, QColor(128, 128, 255),
+                          (*it)->points());
+    }
+
+
+}
+
+void BaseDiagram::paintGeodVec(QPainter* painter, const flightgear::SGGeodVec& vec)
+{
+    QVector<QPointF> projected;
+    projected.reserve(vec.size());
+    flightgear::SGGeodVec::const_iterator it;
+    for (it=vec.begin(); it != vec.end(); ++it) {
+        projected.append(project(*it));
+    }
+
+    painter->drawPolyline(projected.data(), projected.size());
+}
+
+void BaseDiagram::fillClosedGeodVec(QPainter* painter, const QColor& color, const flightgear::SGGeodVec& vec)
+{
+    QVector<QPointF> projected;
+    projected.reserve(vec.size());
+    flightgear::SGGeodVec::const_iterator it;
+    for (it=vec.begin(); it != vec.end(); ++it) {
+        projected.append(project(*it));
+    }
+
+    painter->setPen(Qt::NoPen);
+    painter->setBrush(color);
+    painter->drawPolygon(projected.data(), projected.size());
+}
+
 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<FGAirport*>(a.ptr());
+    FGAirport* aptB = static_cast<FGAirport*>(b.ptr());
+
+    return aptA->longestRunway()->lengthFt() > aptB->longestRunway()->lengthFt();
+}
 
 void BaseDiagram::paintNavaids(QPainter* painter)
 {
@@ -169,85 +282,118 @@ 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<FGAirport*>(pos.ptr());
-            if (apt->hasHardRunwayOfLengthFt(minRunwayLengthFt)) {
-
-                drawAsIcon = false;
-                painter->setTransform(xf);
-                QVector<QLineF> 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<FGNavRecord*>(pos.ptr());
-                label.append("\n").append(QString::number(nav->get_freq() / 100));
-            } else if (ty == FGPositioned::VOR) {
-                FGNavRecord* nav = static_cast<FGNavRecord*>(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);
+}
 
-            painter->setPen(isNDB ? QColor(0x9b, 0x5d, 0xa2) : QColor(0x03, 0x83, 0xbf));
-            painter->drawText(textBounds, textFlags, label);
+QRect boundsOfLines(const QVector<QLineF>& lines)
+{
+    QRect r;
+    Q_FOREACH(const QLineF& l, lines) {
+        r = r.united(QRectF(l.p1(), l.p2()).toRect());
+    }
+
+    return r;
+}
+
+void BaseDiagram::paintNavaid(QPainter* painter, const QTransform& t, const FGPositionedRef &pos)
+{
+    if (isNavaidIgnored(pos))
+        return;
+
+    bool drawAsIcon = true;
+    const double minRunwayLengthFt = (16 / m_scale) * SG_METER_TO_FEET;
+    const FGPositioned::Type ty(pos->type());
+    const bool isNDB = (ty == FGPositioned::NDB);
+    QRect iconRect;
+
+    if (ty == FGPositioned::AIRPORT) {
+        FGAirport* apt = static_cast<FGAirport*>(pos.ptr());
+        if (apt->hasHardRunwayOfLengthFt(minRunwayLengthFt)) {
+
+            drawAsIcon = false;
+            painter->setTransform(t);
+            QVector<QLineF> 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();
+
+            iconRect = t.mapRect(boundsOfLines(lines));
         }
     }
 
-    // restore transform
-    painter->setTransform(xf);
+    if (drawAsIcon) {
+        QPixmap pm = iconForPositioned(pos);
+        QPointF loc = t.map(project(pos->geod()));
+        iconRect = pm.rect();
+        iconRect.moveCenter(loc.toPoint());
+        painter->drawPixmap(iconRect, pm);
+    }
+
+   // 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<FGNavRecord*>(pos.ptr());
+        label.append("\n").append(QString::number(nav->get_freq() / 100));
+    } else if (ty == FGPositioned::VOR) {
+        FGNavRecord* nav = static_cast<FGNavRecord*>(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
@@ -403,12 +549,16 @@ void BaseDiagram::wheelEvent(QWheelEvent *we)
     m_wheelAngleDeltaAccumulator += delta;
     if (m_wheelAngleDeltaAccumulator > 120) {
         m_wheelAngleDeltaAccumulator = 0;
-        m_scale *= 2.0;
+
+        m_scale *= 1.5;
+
     } else if (m_wheelAngleDeltaAccumulator < -120) {
         m_wheelAngleDeltaAccumulator = 0;
-        m_scale *= 0.5;
+
+        m_scale *= 0.75;
     }
 
+    SG_CLAMP_RANGE(m_scale, MINIMUM_SCALE, 1.0);
     update();
 }
 
@@ -626,6 +776,12 @@ QVector<QLineF> BaseDiagram::projectAirportRuwaysWithCenter(FGAirportRef apt, co
     return r;
 }
 
+void BaseDiagram::setAircraftType(LauncherAircraftType type)
+{
+    m_aircraftType = type;
+    update();
+}
+
 QVector<QLineF> BaseDiagram::projectAirportRuwaysIntoRect(FGAirportRef apt, const QRectF &bounds)
 {
     QVector<QLineF> r = projectAirportRuwaysWithCenter(apt, apt->geod());