]> git.mxchange.org Git - flightgear.git/commitdiff
Crashfix: move spatial, AI queries in map-widget
authorJames Turner <zakalawe@mac.com>
Tue, 14 Jan 2014 13:11:06 +0000 (13:11 +0000)
committerJames Turner <zakalawe@mac.com>
Tue, 14 Jan 2014 13:11:06 +0000 (13:11 +0000)
In threaded OSG drawing, MapWidget::draw runs in the render
thread context, but touches lots of main thread state. Move most of the
work to an update() helper run on the main thread instead, so draw()
mostly makes pure GL calls.

(This is a fix for 3.0, the real solution is to migrate to a
Canvas-based map and GUI)

src/GUI/FGPUIDialog.cxx
src/GUI/MapWidget.cxx
src/GUI/MapWidget.hxx

index a57aeba5e75afb4bfbf2f5ddc373caa8122519b7..a7e2dddbf08198d548298bba3162179faea534de 100644 (file)
@@ -977,6 +977,7 @@ FGPUIDialog::makeObject (SGPropertyNode *props, int parentWidth, int parentHeigh
     } else if (type == "map") {
         MapWidget* mapWidget = new MapWidget(x, y, x + width, y + height);
         setupObject(mapWidget, props);
+        _activeWidgets.push_back(mapWidget);
         return mapWidget;
     } else if (type == "canvas") {
         CanvasWidget* canvasWidget = new CanvasWidget( x, y,
index 3c2cc8ba9b7fc7a01e5f1e3a6c5d9663f17f1049..8a5a0b715e4fe991bf390ffa7c3c1ee62de4f184 100644 (file)
@@ -69,7 +69,7 @@ static bool puBoxIntersect(const puBox& a, const puBox& b)
 
   return (x0 <= x1) && (y0 <= y1);
 }
-
+    
 class MapData;
 typedef std::vector<MapData*> MapDataVec;
 
@@ -380,6 +380,76 @@ int MapData::_fontDescender = 0;
 
 ///////////////////////////////////////////////////////////////////////////
 
+// anonymous namespace
+namespace
+{
+    
+class MapAirportFilter : public FGAirport::AirportFilter
+{
+public:
+    MapAirportFilter(SGPropertyNode_ptr nd)
+    {
+        _heliports = nd->getBoolValue("show-heliports", false);
+        _hardRunwaysOnly = nd->getBoolValue("hard-surfaced-airports", true);
+        _minLengthFt = fgGetDouble("/sim/navdb/min-runway-length-ft", 2000);
+    }
+    
+    virtual FGPositioned::Type maxType() const {
+        return _heliports ? FGPositioned::HELIPORT : FGPositioned::AIRPORT;
+    }
+    
+    virtual bool passAirport(FGAirport* aApt) const {
+        if (_hardRunwaysOnly) {
+            return aApt->hasHardRunwayOfLengthFt(_minLengthFt);
+        }
+        
+        return true;
+    }
+    
+    void showAll()
+    {
+        _hardRunwaysOnly = false;
+    }
+    
+private:
+    bool _heliports;
+    bool _hardRunwaysOnly;
+    double _minLengthFt;
+};
+
+class NavaidFilter : public FGPositioned::Filter
+{
+public:
+    NavaidFilter(bool fixesEnabled, bool navaidsEnabled) :
+    _fixes(fixesEnabled),
+    _navaids(navaidsEnabled)
+    {}
+    
+    virtual bool pass(FGPositioned* aPos) const {
+        if (_fixes && (aPos->type() == FGPositioned::FIX)) {
+            // ignore fixes which end in digits - expirmental
+            if (aPos->ident().length() > 4 && isdigit(aPos->ident()[3]) && isdigit(aPos->ident()[4])) {
+                return false;
+            }
+        }
+        
+        return true;
+    }
+    
+    virtual FGPositioned::Type minType() const {
+        return _fixes ? FGPositioned::FIX : FGPositioned::NDB;
+    }
+    
+    virtual FGPositioned::Type maxType() const {
+        return _navaids ? FGPositioned::VOR : FGPositioned::FIX;
+    }
+    
+private:
+    bool _fixes, _navaids;
+};
+    
+} // of anonymous namespace
+
 const int MAX_ZOOM = 12;
 const int SHOW_DETAIL_ZOOM = 8;
 const int SHOW_DETAIL2_ZOOM = 5;
@@ -544,41 +614,127 @@ void MapWidget::zoomOut()
   _root->setIntValue("zoom", zoom() - 1);
 }
 
-void MapWidget::draw(int dx, int dy)
+void MapWidget::update()
 {
-  _aircraft = globals->get_aircraft_position();
+    _aircraft = globals->get_aircraft_position();
     
-  bool mag = _root->getBoolValue("magnetic-headings");
-  if (mag != _magneticHeadings) {
-    clearData(); // flush cached data text, since it often includes heading
-    _magneticHeadings =  mag;
-  }
-  
-  if (_hasPanned) {
-      _root->setBoolValue("centre-on-aircraft", false);
-      _hasPanned = false;
-  }
-  else if (_root->getBoolValue("centre-on-aircraft")) {
-    _projectionCenter = _aircraft;
-  }
+    bool mag = _root->getBoolValue("magnetic-headings");
+    if (mag != _magneticHeadings) {
+        clearData(); // flush cached data text, since it often includes heading
+        _magneticHeadings =  mag;
+    }
+    
+    if (_hasPanned) {
+        _root->setBoolValue("centre-on-aircraft", false);
+        _hasPanned = false;
+    }
+    else if (_root->getBoolValue("centre-on-aircraft")) {
+        _projectionCenter = _aircraft;
+    }
+    
+    double julianDate = globals->get_time_params()->getJD();
+    _magVar->update(_projectionCenter, julianDate);
+    
+    _aircraftUp = _root->getBoolValue("aircraft-heading-up");
+    if (_aircraftUp) {
+        _upHeading = fgGetDouble("/orientation/heading-deg");
+    } else {
+        _upHeading = 0.0;
+    }
+    
+    if (_magneticHeadings) {
+        _displayHeading = (int) fgGetDouble("/orientation/heading-magnetic-deg");
+    } else {
+        _displayHeading = (int) _upHeading;
+    }
+    
+    _cachedZoom = MAX_ZOOM - zoom();
+    SGGeod topLeft = unproject(SGVec2d(_width/2, _height/2));
+    // compute draw range, including a fudge factor for ILSs and other 'long'
+    // symbols
+    _drawRangeNm = SGGeodesy::distanceNm(_projectionCenter, topLeft) + 10.0;
+    
+    
+    FGFlightHistory* history = (FGFlightHistory*) globals->get_subsystem("history");
+    if (history && _root->getBoolValue("draw-flight-history")) {
+        _flightHistoryPath = history->pathForHistory();
+    } else {
+        _flightHistoryPath.clear();
+    }
+
+// make spatial queries. This can trigger loading of XML files, etc, so we do
+// not want to do it in draw(), which can be called from an arbitrary OSG
+// rendering thread.
+    
+    MapAirportFilter af(_root);
+    if (_cachedZoom <= SHOW_DETAIL2_ZOOM) {
+        // show all airports when zoomed in sufficently
+        af.showAll();
+    }
+    
+    bool partial = false;
+    FGPositionedList newItemsToDraw =
+        FGPositioned::findWithinRangePartial(_projectionCenter, _drawRangeNm, &af, partial);
+    
+    bool fixes = _root->getBoolValue("draw-fixes");
+    NavaidFilter f(fixes, _root->getBoolValue("draw-navaids"));
+    if (f.minType() <= f.maxType()) {
+        FGPositionedList navs = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
+        newItemsToDraw.insert(newItemsToDraw.end(), navs.begin(), navs.end());
+    }
 
-  double julianDate = globals->get_time_params()->getJD();
-  _magVar->update(_projectionCenter, julianDate);
+    FGPositioned::TypeFilter tf(FGPositioned::COUNTRY);
+    if (_cachedZoom <= SHOW_DETAIL_ZOOM) {
+        tf.addType(FGPositioned::CITY);
+    }
+    
+    if (_cachedZoom <= SHOW_DETAIL2_ZOOM) {
+        tf.addType(FGPositioned::TOWN);
+    }
+    
+    FGPositionedList poi = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &tf);
+    newItemsToDraw.insert(newItemsToDraw.end(), poi.begin(), poi.end());
+    
+    _itemsToDraw.swap(newItemsToDraw);
+    
+    updateAIObjects();
+}
 
-  bool aircraftUp = _root->getBoolValue("aircraft-heading-up");
-  if (aircraftUp) {
-    _upHeading = fgGetDouble("/orientation/heading-deg");
-  } else {
-    _upHeading = 0.0;
-  }
+void MapWidget::updateAIObjects()
+{
+    if (!_root->getBoolValue("draw-traffic") || (_cachedZoom > SHOW_DETAIL_ZOOM)) {
+        _aiDrawVec.clear();
+        return;
+    }
+    
+    AIDrawVec newDrawVec;
+    
+    const SGPropertyNode* ai = fgGetNode("/ai/models", true);
+    for (int i = 0; i < ai->nChildren(); ++i) {
+        const SGPropertyNode *model = ai->getChild(i);
+        // skip bad or dead entries
+        if (!model || model->getIntValue("id", -1) == -1) {
+            continue;
+        }
+        
+        SGGeod pos = SGGeod::fromDegFt(
+                                       model->getDoubleValue("position/longitude-deg"),
+                                       model->getDoubleValue("position/latitude-deg"),
+                                       model->getDoubleValue("position/altitude-ft"));
+        
+        double dist = SGGeodesy::distanceNm(_projectionCenter, pos);
+        if (dist > _drawRangeNm) {
+            continue;
+        }
+    
+        newDrawVec.push_back(DrawAIObject((SGPropertyNode*) model, pos));
+    } // of ai/models iteration
 
-  _cachedZoom = MAX_ZOOM - zoom();
-  SGGeod topLeft = unproject(SGVec2d(_width/2, _height/2));
-  // compute draw range, including a fudge factor for ILSs and other 'long'
-  // symbols
-  _drawRangeNm = SGGeodesy::distanceNm(_projectionCenter, topLeft) + 10.0;
+    _aiDrawVec.swap(newDrawVec);
+}
 
-// drawing operations
+void MapWidget::draw(int dx, int dy)
+{
   GLint sx = (int) abox.min[0],
     sy = (int) abox.min[1];
   glScissor(dx + sx, dy + sy, _width, _height);
@@ -592,7 +748,7 @@ void MapWidget::draw(int dx, int dy)
 
   drawLatLonGrid();
 
-  if (aircraftUp) {
+  if (_aircraftUp) {
     int textHeight = legendFont.getStringHeight() + 5;
 
     // draw heading line
@@ -600,23 +756,14 @@ void MapWidget::draw(int dx, int dy)
     glColor3f(1.0, 1.0, 1.0);
     drawLine(loc, SGVec2d(loc.x(), (_height / 2) - textHeight));
 
-    int displayHdg;
-    if (_magneticHeadings) {
-      displayHdg = (int) fgGetDouble("/orientation/heading-magnetic-deg");
-    } else {
-      displayHdg = (int) _upHeading;
-    }
-
     double y = (_height / 2) - textHeight;
     char buf[16];
-    ::snprintf(buf, 16, "%d", displayHdg);
+    ::snprintf(buf, 16, "%d", _displayHeading);
     int sw = legendFont.getStringWidth(buf);
     legendFont.drawString(buf, loc.x() - sw/2, y);
   }
 
-  drawAirports();
-  drawNavaids();
-  drawPOIs();
+  drawPositioned();
   drawTraffic();
   drawGPSData();
   drawNavRadio(fgGetNode("/instrumentation/nav[0]", false));
@@ -657,8 +804,6 @@ void MapWidget::paintRuler()
   d->setAnchor(clickPos);
   d->setOffset(MapData::VALIGN_TOP | MapData::HALIGN_CENTER, 15);
   d->setPriority(20000);
-
-
 }
 
 void MapWidget::paintAircraftLocation(const SGGeod& aircraftPos)
@@ -762,20 +907,17 @@ void MapWidget::paintRoute()
 
 void MapWidget::drawFlightHistory()
 {
-  FGFlightHistory* history = (FGFlightHistory*) globals->get_subsystem("history");
-  if (!history || !_root->getBoolValue("draw-flight-history")) {
+  if (_flightHistoryPath.empty())
     return;
-  }
-  
+    
   // first pass, draw the actual lines
   glLineWidth(2.0);
   
-  SGGeodVec gv(history->pathForHistory());
   glColor4f(0.0, 0.0, 1.0, 0.7);
 
   glBegin(GL_LINE_STRIP);
-  for (unsigned int i=0; i<gv.size(); ++i) {
-    SGVec2d p = project(gv[i]);
+  for (unsigned int i=0; i<_flightHistoryPath.size(); ++i) {
+    SGVec2d p = project(_flightHistoryPath[i]);
     glVertex2d(p.x(), p.y());
   }
   
@@ -914,125 +1056,33 @@ void MapWidget::drawGPSData()
   }
 }
 
-class MapAirportFilter : public FGAirport::AirportFilter
-{
-public:
-  MapAirportFilter(SGPropertyNode_ptr nd)
-  {
-    _heliports = nd->getBoolValue("show-heliports", false);
-    _hardRunwaysOnly = nd->getBoolValue("hard-surfaced-airports", true);
-    _minLengthFt = fgGetDouble("/sim/navdb/min-runway-length-ft", 2000);
-  }
-
-  virtual FGPositioned::Type maxType() const {
-    return _heliports ? FGPositioned::HELIPORT : FGPositioned::AIRPORT;
-  }
-
-  virtual bool passAirport(FGAirport* aApt) const {
-    if (_hardRunwaysOnly) {
-      return aApt->hasHardRunwayOfLengthFt(_minLengthFt);
-    }
-
-    return true;
-  }
-    
-    void showAll()
-    {
-        _hardRunwaysOnly = false;
-    }
-
-private:
-  bool _heliports;
-  bool _hardRunwaysOnly;
-  double _minLengthFt;
-};
-
-void MapWidget::drawAirports()
-{
-  MapAirportFilter af(_root);
-    if (_cachedZoom <= SHOW_DETAIL2_ZOOM) {
-        // show all airports when zoomed in sufficently
-        af.showAll();
-    }
-    
-  bool partial = false;
-  FGPositionedList apts = FGPositioned::findWithinRangePartial(_projectionCenter, _drawRangeNm, &af, partial);
-  for (unsigned int i=0; i<apts.size(); ++i) {
-    drawAirport((FGAirport*) apts[i].get());
-  }
-}
-
-class NavaidFilter : public FGPositioned::Filter
-{
-public:
-  NavaidFilter(bool fixesEnabled, bool navaidsEnabled) :
-    _fixes(fixesEnabled),
-    _navaids(navaidsEnabled)
-  {}
-
-  virtual bool pass(FGPositioned* aPos) const {
-    if (_fixes && (aPos->type() == FGPositioned::FIX)) {
-      // ignore fixes which end in digits - expirmental
-      if (aPos->ident().length() > 4 && isdigit(aPos->ident()[3]) && isdigit(aPos->ident()[4])) {
-        return false;
-      }
-    }
-
-    return true;
-  }
-
-  virtual FGPositioned::Type minType() const {
-    return _fixes ? FGPositioned::FIX : FGPositioned::NDB;
-  }
-
-  virtual FGPositioned::Type maxType() const {
-    return _navaids ? FGPositioned::VOR : FGPositioned::FIX;
-  }
-
-private:
-  bool _fixes, _navaids;
-};
-
-void MapWidget::drawNavaids()
-{
-  bool fixes = _root->getBoolValue("draw-fixes");
-  NavaidFilter f(fixes, _root->getBoolValue("draw-navaids"));
-
-  if (f.minType() <= f.maxType()) {
-    FGPositionedList navs = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
-
-    glLineWidth(1.0);
-    for (unsigned int i=0; i<navs.size(); ++i) {
-      FGPositioned::Type ty = navs[i]->type();
-      if (ty == FGPositioned::NDB) {
-        drawNDB(false, (FGNavRecord*) navs[i].get());
-      } else if (ty == FGPositioned::VOR) {
-        drawVOR(false, (FGNavRecord*) navs[i].get());
-      } else if (ty == FGPositioned::FIX) {
-        drawFix((FGFix*) navs[i].get());
-      }
-    } // of navaid iteration
-  } // of navaids || fixes are drawn test
-}
-
-void MapWidget::drawPOIs()
+void MapWidget::drawPositioned()
 {
-  FGPositioned::TypeFilter f(FGPositioned::COUNTRY);
-  f.addType(FGPositioned::CITY);
-  f.addType(FGPositioned::TOWN);
-  FGPositionedList poi = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
-
-    glLineWidth(1.0);
-    for (unsigned int i=0; i<poi.size(); ++i) {
-      FGPositioned::Type ty = poi[i]->type();
-      if (ty == FGPositioned::COUNTRY) {
-        drawCountries((FGNavRecord*) poi[i].get());
-      } else if (ty == FGPositioned::CITY) {
-        drawCities((FGNavRecord*) poi[i].get());
-      } else if (ty == FGPositioned::TOWN) {
-        drawTowns((FGNavRecord*) poi[i].get());
-      }
-    } // of navaid iteration
+  for (unsigned int i=0; i<_itemsToDraw.size(); ++i) {
+      FGPositionedRef p = _itemsToDraw[i];
+      switch (p->type()) {
+          case FGPositioned::AIRPORT:
+              drawAirport((FGAirport*) p.get());
+              break;
+          case FGPositioned::NDB:
+              drawNDB(false, (FGNavRecord*) p.get());
+              break;
+          case FGPositioned::VOR:
+              drawVOR(false, (FGNavRecord*) p.get());
+              break;
+          case FGPositioned::FIX:
+              drawFix((FGFix*) p.get());
+              break;
+         case FGPositioned::TOWN:
+          case FGPositioned::CITY:
+          case FGPositioned::COUNTRY:
+              drawPOI(p);
+              break;
+              
+          default:
+              SG_LOG(SG_GENERAL, SG_WARN, "unhandled type in MapWidget::drawPositioned");
+      } // of positioned type switch
+  } // of items to draw iteration
 }
 
 void MapWidget::drawNDB(bool tuned, FGNavRecord* ndb)
@@ -1193,91 +1243,38 @@ void MapWidget::drawTunedLocalizer(SGPropertyNode_ptr radio)
   }
 }
 
-void MapWidget::drawCountries(FGNavRecord* rec)
+void MapWidget::drawPOI(FGPositioned* poi)
 {
-  if (_cachedZoom < 9) {
-    return; // hide labels beyond a certain zoom level
-  }
-
-  SGVec2d pos = project(rec->geod());
+  SGVec2d pos = project(poi->geod());
   glColor3f(1.0, 1.0, 0.0);
+  glLineWidth(1.0);
 
-  circleAt(pos, 4, 10);
+    int radius = 10;
+    if (poi->type() == FGPositioned::CITY) {
+        radius = 8;
+        glColor3f(0.0, 1.0, 0.0);
+    } else if (poi->type() == FGPositioned::TOWN) {
+        radius =  5;
+        glColor3f(0.2, 1.0, 0.0);
+    }
+    
+  circleAt(pos, 4, radius);
 
-  if (validDataForKey(rec)) {
-    setAnchorForKey(rec, pos);
+  if (validDataForKey(poi)) {
+    setAnchorForKey(poi, pos);
     return;
   }
 
   char buffer[1024];
         ::snprintf(buffer, 1024, "%s",
-                rec->name().c_str());
+                poi->name().c_str());
 
-  MapData* d = createDataForKey(rec);
+  MapData* d = createDataForKey(poi);
   d->setPriority(200);
-  d->setLabel(rec->ident());
-  d->setText(buffer);
-  d->setOffset(MapData::HALIGN_CENTER | MapData::VALIGN_BOTTOM, 10);
-  d->setAnchor(pos);
-
-}
-
-void MapWidget::drawCities(FGNavRecord* rec)
-{
-  if (_cachedZoom > SHOW_DETAIL_ZOOM) {
-    return; // hide labels beyond a certain zoom level
-  }
-
-  SGVec2d pos = project(rec->geod());
-  glColor3f(0.0, 1.0, 0.0);
-
-  circleAt(pos, 4, 8);
-
-  if (validDataForKey(rec)) {
-    setAnchorForKey(rec, pos);
-    return;
-  }
-
-  char buffer[1024];
-        ::snprintf(buffer, 1024, "%s",
-                rec->name().c_str());
-
-  MapData* d = createDataForKey(rec);
-  d->setPriority(40);
-  d->setLabel(rec->ident());
-  d->setText(buffer);
-  d->setOffset(MapData::HALIGN_CENTER | MapData::VALIGN_BOTTOM, 10);
-  d->setAnchor(pos);
-
-}
-
-void MapWidget::drawTowns(FGNavRecord* rec)
-{
-  if (_cachedZoom > SHOW_DETAIL2_ZOOM) {
-    return; // hide labels beyond a certain zoom level
-  }
-
-  SGVec2d pos = project(rec->geod());
-  glColor3f(0.2, 1.0, 0.0);
-
-  circleAt(pos, 4, 5);
-
-  if (validDataForKey(rec)) {
-    setAnchorForKey(rec, pos);
-    return;
-  }
-
-  char buffer[1024];
-        ::snprintf(buffer, 1024, "%s",
-                rec->name().c_str());
-
-  MapData* d = createDataForKey(rec);
-  d->setPriority(40);
-  d->setLabel(rec->ident());
+  d->setLabel(poi->ident());
   d->setText(buffer);
   d->setOffset(MapData::HALIGN_CENTER | MapData::VALIGN_BOTTOM, 10);
   d->setAnchor(pos);
-
 }
 
 /*
@@ -1491,42 +1488,10 @@ void MapWidget::drawILS(bool tuned, FGRunway* rwy)
 
 void MapWidget::drawTraffic()
 {
-  if (!_root->getBoolValue("draw-traffic")) {
-    return;
-  }
-
-  if (_cachedZoom > SHOW_DETAIL_ZOOM) {
-    return;
-  }
-
-  const SGPropertyNode* ai = fgGetNode("/ai/models", true);
-
-  for (int i = 0; i < ai->nChildren(); ++i) {
-    const SGPropertyNode *model = ai->getChild(i);
-    // skip bad or dead entries
-    if (!model || model->getIntValue("id", -1) == -1) {
-      continue;
-    }
-
-    const std::string& name(model->getName());
-    SGGeod pos = SGGeod::fromDegFt(
-      model->getDoubleValue("position/longitude-deg"),
-      model->getDoubleValue("position/latitude-deg"),
-      model->getDoubleValue("position/altitude-ft"));
-
-    double dist = SGGeodesy::distanceNm(_projectionCenter, pos);
-    if (dist > _drawRangeNm) {
-      continue;
-    }
-
-    double heading = model->getDoubleValue("orientation/true-heading-deg");
-    if ((name == "aircraft") || (name == "multiplayer") ||
-        (name == "wingman") || (name == "tanker")) {
-      drawAIAircraft(model, pos, heading);
-    } else if ((name == "ship") || (name == "carrier") || (name == "escort")) {
-      drawAIShip(model, pos, heading);
+    AIDrawVec::const_iterator it;
+    for (it = _aiDrawVec.begin(); it != _aiDrawVec.end(); ++it) {
+        drawAI(*it);
     }
-  } // of ai/models iteration
 }
 
 void MapWidget::drawHelipad(FGHelipad* hp)
@@ -1555,105 +1520,36 @@ void MapWidget::drawHelipad(FGHelipad* hp)
   d->setAnchor(pos);
 }
 
-void MapWidget::drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, double hdg)
+void MapWidget::drawAI(const DrawAIObject& dai)
 {
+  SGVec2d p = project(dai.pos);
 
-  SGVec2d p = project(pos);
+    if (dai.boat) {
+        glColor3f(0.0, 0.0, 0.5);
 
-  glColor3f(0.0, 0.0, 0.0);
+    } else {
+        glColor3f(0.0, 0.0, 0.0);
+    }
   glLineWidth(2.0);
   circleAt(p, 4, 6.0); // black diamond
 
 // draw heading vector
-  int speedKts = static_cast<int>(model->getDoubleValue("velocities/true-airspeed-kt"));
-  if (speedKts > 1) {
+  if (dai.speedKts > 1) {
     glLineWidth(1.0);
-
     const double dt = 15.0 / (3600.0); // 15 seconds look-ahead
-    double distanceM = speedKts * SG_NM_TO_METER * dt;
-
-    SGGeod advance;
-    double az2;
-    SGGeodesy::direct(pos, hdg, distanceM, advance, az2);
-
+    double distanceM = dai.speedKts * SG_NM_TO_METER * dt;
+    SGGeod advance = SGGeodesy::direct(dai.pos, dai.heading, distanceM);
     drawLine(p, project(advance));
   }
    
-    // try to access the flight-plan of the aircraft. There are several layers
-    // of potential NULL-ness here, so we have to be defensive at each stage.
-    std::string originICAO, destinationICAO;
-    FGAIManager* aiManager = static_cast<FGAIManager*>(globals->get_subsystem("ai-model"));
-    FGAIBasePtr aircraft = aiManager ? aiManager->getObjectFromProperty(model) : NULL;
-    if (aircraft) {
-        FGAIAircraft* p = static_cast<FGAIAircraft*>(aircraft.get());
-        if (p->GetFlightPlan()) {
-            if (p->GetFlightPlan()->departureAirport()) {
-                originICAO = p->GetFlightPlan()->departureAirport()->ident();
-            }
-            
-            if (p->GetFlightPlan()->arrivalAirport()) {
-                destinationICAO = p->GetFlightPlan()->arrivalAirport()->ident();
-            }
-        } // of flight-plan exists
-    } // of check for AIBase-derived instance
-
-  // draw callsign / altitude / speed
-    int altFt50 = static_cast<int>(pos.getElevationFt() / 50.0) * 50;
-    std::ostringstream ss;
-    ss << model->getStringValue("callsign", "<>");
-    if (speedKts > 1) {
-        ss << "\n" << altFt50 << "' " << speedKts << "kts";
-    }
-    
-    if (!originICAO.empty() || ! destinationICAO.empty()) {
-        ss << "\n" << originICAO << " -> " << destinationICAO;
-    }
-    
-    MapData* d = getOrCreateDataForKey((void*) model);
-    d->setText(ss.str().c_str());
-    d->setLabel(model->getStringValue("callsign", "<>"));
-    d->setPriority(speedKts > 5 ? 60 : 10); // low priority for parked aircraft
+    MapData* d = getOrCreateDataForKey((void*) dai.model);
+    d->setText(dai.legend);
+    d->setLabel(dai.label);
+    d->setPriority(dai.speedKts > 5 ? 60 : 10); // low priority for parked aircraft
     d->setOffset(MapData::VALIGN_CENTER | MapData::HALIGN_LEFT, 10);
     d->setAnchor(p);
 }
 
-void MapWidget::drawAIShip(const SGPropertyNode* model, const SGGeod& pos, double hdg)
-{
-  SGVec2d p = project(pos);
-
-  glColor3f(0.0, 0.0, 0.5);
-  glLineWidth(2.0);
-  circleAt(p, 4, 6.0); // blue diamond (to differentiate from aircraft.
-
-// draw heading vector
-  int speedKts = static_cast<int>(model->getDoubleValue("velocities/speed-kts"));
-  if (speedKts > 1) {
-    glLineWidth(1.0);
-
-    const double dt = 15.0 / (3600.0); // 15 seconds look-ahead
-    double distanceM = speedKts * SG_NM_TO_METER * dt;
-
-    SGGeod advance;
-    double az2;
-    SGGeodesy::direct(pos, hdg, distanceM, advance, az2);
-
-    drawLine(p, project(advance));
-  }
-
-  // draw callsign / speed
-  char buffer[1024];
-       ::snprintf(buffer, 1024, "%s\n%dkts",
-               model->getStringValue("name", "<>"),
-    speedKts);
-
-  MapData* d = getOrCreateDataForKey((void*) model);
-  d->setText(buffer);
-  d->setLabel(model->getStringValue("name", "<>"));
-  d->setPriority(speedKts > 2 ? 30 : 10); // low priority for slow moving ships
-  d->setOffset(MapData::VALIGN_CENTER | MapData::HALIGN_LEFT, 10);
-  d->setAnchor(p);
-}
-
 SGVec2d MapWidget::project(const SGGeod& geod) const
 {
   SGVec2d p;
@@ -1979,3 +1875,63 @@ int MapWidget::displayHeading(double h) const
   SG_NORMALIZE_RANGE(h, 0.0, 360.0);
   return SGMiscd::roundToInt(h);
 }
+
+MapWidget::DrawAIObject::DrawAIObject(SGPropertyNode* m, const SGGeod& g) :
+    model(m),
+    boat(false),
+    pos(g),
+    speedKts(0)
+{
+    std::string name(model->getNameString());
+    heading = model->getDoubleValue("orientation/true-heading-deg");
+    
+    if ((name == "aircraft") || (name == "multiplayer") ||
+        (name == "wingman") || (name == "tanker"))
+    {
+        speedKts = static_cast<int>(model->getDoubleValue("velocities/true-airspeed-kt"));
+        label = model->getStringValue("callsign", "<>");
+    
+        // try to access the flight-plan of the aircraft. There are several layers
+        // of potential NULL-ness here, so we have to be defensive at each stage.
+        std::string originICAO, destinationICAO;
+        FGAIManager* aiManager = static_cast<FGAIManager*>(globals->get_subsystem("ai-model"));
+        FGAIBasePtr aircraft = aiManager ? aiManager->getObjectFromProperty(model) : NULL;
+        if (aircraft) {
+            FGAIAircraft* p = static_cast<FGAIAircraft*>(aircraft.get());
+            if (p->GetFlightPlan()) {
+                if (p->GetFlightPlan()->departureAirport()) {
+                    originICAO = p->GetFlightPlan()->departureAirport()->ident();
+                }
+                
+                if (p->GetFlightPlan()->arrivalAirport()) {
+                    destinationICAO = p->GetFlightPlan()->arrivalAirport()->ident();
+                }
+            } // of flight-plan exists
+        } // of check for AIBase-derived instance
+        
+        // draw callsign / altitude / speed
+        int altFt50 = static_cast<int>(pos.getElevationFt() / 50.0) * 50;
+        std::ostringstream ss;
+        ss << model->getStringValue("callsign", "<>");
+        if (speedKts > 1) {
+            ss << "\n" << altFt50 << "' " << speedKts << "kts";
+        }
+        
+        if (!originICAO.empty() || ! destinationICAO.empty()) {
+            ss << "\n" << originICAO << " -> " << destinationICAO;
+        }
+
+        legend = ss.str();
+    } else if ((name == "ship") || (name == "carrier") || (name == "escort")) {
+        boat = true;
+        speedKts = static_cast<int>(model->getDoubleValue("velocities/speed-kts"));
+        label = model->getStringValue("name", "<>");
+        
+        char buffer[1024];
+        ::snprintf(buffer, 1024, "%s\n%dkts",
+                   model->getStringValue("name", "<>"),
+                   speedKts);
+        legend = buffer;
+    }
+}
+
index 0a826f761b61884c79c0db3b2a2460ef0d173e55..1ad5aa15a2214ac8a84d5d17ecfc04952431e3c5 100644 (file)
@@ -6,9 +6,10 @@
 #include <simgear/math/SGMath.hxx>
 #include <simgear/props/props.hxx>
 
+#include <Navaids/positioned.hxx>
 #include <plib/pu.h>
 
-#include "dialog.hxx" // for GUI_ID
+#include "FGPUIDialog.hxx"
 
 // forward decls
 class FGRouteMgr;
@@ -20,18 +21,25 @@ class FGFix;
 class MapData;
 class SGMagVar;
 
-class MapWidget : public puObject
+typedef std::vector<SGGeod> SGGeodVec;
+
+class MapWidget : public puObject, public FGPUIDialog::ActiveWidget
 {
 public:
   MapWidget(int x, int y, int width, int height);
   virtual ~MapWidget();
   
+    // puObject over-rides
   virtual void setSize(int width, int height);
   virtual void doHit( int button, int updown, int x, int y ) ;
   virtual void draw( int dx, int dy ) ;
   virtual int checkKey(int key, int updown);
     
   void setProperty(SGPropertyNode_ptr prop);
+    
+    // PUIDialog::ActiveWidget over-rides
+    virtual void update();
+    
 private:
     enum Projection {
         PROJECTION_SAMSON_FLAMSTEED,
@@ -60,7 +68,6 @@ private:
   SGVec2d gridPoint(int ix, int iy);
   bool drawLineClipped(const SGVec2d& a, const SGVec2d& b);
   
-  void drawAirports();
   void drawAirport(FGAirport* apt);
   int scoreAirportRunways(FGAirport* apt);
   void drawRunwayPre(FGRunway* rwy);
@@ -68,19 +75,34 @@ private:
   void drawHelipad(FGHelipad* hp);
   void drawILS(bool tuned, FGRunway* rwy);
   
-  void drawNavaids();
-  void drawPOIs();
+  void drawPositioned();
   void drawNDB(bool tuned, FGNavRecord* nav);
   void drawVOR(bool tuned, FGNavRecord* nav);
   void drawFix(FGFix* fix);
 
-  void drawCountries(FGNavRecord* rec);
-  void drawCities(FGNavRecord* rec);
-  void drawTowns(FGNavRecord* rec);
-  
+  void drawPOI(FGPositioned* rec);
+    
   void drawTraffic();
-  void drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, double hdg);
-  void drawAIShip(const SGPropertyNode* model, const SGGeod& pos, double hdg);
+    
+    class DrawAIObject
+    {
+    public:
+        DrawAIObject(SGPropertyNode* model, const SGGeod& g);
+        
+        SGPropertyNode* model;
+        bool boat;
+        SGGeod pos;
+        double heading;
+        int speedKts;
+        std::string label;
+        std::string legend;
+    };
+    
+    typedef std::vector<DrawAIObject> AIDrawVec;
+    AIDrawVec _aiDrawVec;
+    
+    void updateAIObjects();
+    void drawAI(const DrawAIObject& dai);
   
   void drawData();
   bool validDataForKey(void* key);
@@ -107,7 +129,9 @@ private:
   double _upHeading; // true heading corresponding to +ve y-axis
   bool _magneticHeadings;
   bool _hasPanned;
-  
+  bool _aircraftUp;
+  int _displayHeading;
+    
   SGGeod _projectionCenter;
   Projection _projection;
   SGGeod _aircraft;
@@ -116,7 +140,10 @@ private:
   FGRouteMgr* _route;
   SGPropertyNode_ptr _root;
   SGPropertyNode_ptr _gps;
-  
+  SGGeodVec _flightHistoryPath;
+    
+  FGPositionedList _itemsToDraw;
+    
   typedef std::map<void*, MapData*> KeyDataMap;
   KeyDataMap _mapData;
   std::vector<MapData*> _dataQueue;