]> git.mxchange.org Git - flightgear.git/blobdiff - src/GUI/MapWidget.cxx
Support for multiple data dirs.
[flightgear.git] / src / GUI / MapWidget.cxx
index c0d1c0376810e0c51ef9f474b6db09008344d2d2..7edb0c93e5dc72c4fdf9794270ed6f3c35c4021a 100644 (file)
@@ -26,6 +26,8 @@
 #include <Main/fg_os.hxx>      // fgGetKeyModifiers()
 #include <Navaids/routePath.hxx>
 #include <Aircraft/FlightHistory.hxx>
+#include <AIModel/AIAircraft.hxx>
+#include <AIModel/AIFlightPlan.hxx>
 
 const char* RULER_LEGEND_KEY = "ruler-legend";
 
@@ -387,7 +389,8 @@ MapWidget::MapWidget(int x, int y, int maxX, int maxY) :
   _width = maxX - x;
   _height = maxY - y;
   _hasPanned = false;
-  _orthoAzimuthProject = false;
+  _projection = PROJECTION_SAMSON_FLAMSTEED;
+  _magneticHeadings = false;
   
   MapData::setFont(legendFont);
   MapData::setPalette(colour);
@@ -938,7 +941,7 @@ void MapWidget::drawAirports()
 {
   MapAirportFilter af(_root);
   bool partial = false;
-  FGPositioned::List apts = FGPositioned::findWithinRangePartial(_projectionCenter, _drawRangeNm, &af, partial);
+  FGPositionedList apts = FGPositioned::findWithinRangePartial(_projectionCenter, _drawRangeNm, &af, partial);
   for (unsigned int i=0; i<apts.size(); ++i) {
     drawAirport((FGAirport*) apts[i].get());
   }
@@ -981,7 +984,7 @@ void MapWidget::drawNavaids()
   NavaidFilter f(fixes, _root->getBoolValue("draw-navaids"));
 
   if (f.minType() <= f.maxType()) {
-    FGPositioned::List navs = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
+    FGPositionedList navs = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
 
     glLineWidth(1.0);
     for (unsigned int i=0; i<navs.size(); ++i) {
@@ -1002,7 +1005,7 @@ void MapWidget::drawPOIs()
   FGPositioned::TypeFilter f(FGPositioned::COUNTRY);
   f.addType(FGPositioned::CITY);
   f.addType(FGPositioned::TOWN);
-  FGPositioned::List poi = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
+  FGPositionedList poi = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &f);
 
     glLineWidth(1.0);
     for (unsigned int i=0; i<poi.size(); ++i) {
@@ -1060,7 +1063,11 @@ void MapWidget::drawVOR(bool tuned, FGNavRecord* vor)
     glColor3f(0.0, 0.0, 1.0);
   }
 
-  circleAt(pos, 6, 8);
+  circleAt(pos, 6, 9);
+  circleAt(pos, 8, 1);
+
+  if (vor->hasDME())
+  squareAt(pos, 9);
 
   if (validDataForKey(vor)) {
     setAnchorForKey(vor, pos);
@@ -1556,22 +1563,38 @@ void MapWidget::drawAIAircraft(const SGPropertyNode* model, const SGGeod& pos, d
 
     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()) {
+            originICAO = p->GetFlightPlan()->departureAirport()->ident();
+            destinationICAO = p->GetFlightPlan()->arrivalAirport()->ident();
+        }
+    }
 
   // draw callsign / altitude / speed
-  char buffer[1024];
-       ::snprintf(buffer, 1024, "%s\n%d'\n%dkts",
-               model->getStringValue("callsign", "<>"),
-               static_cast<int>(pos.getElevationFt() / 50.0) * 50,
-    speedKts);
-
-  MapData* d = getOrCreateDataForKey((void*) model);
-  d->setText(buffer);
-  d->setLabel(model->getStringValue("callsign", "<>"));
-  d->setPriority(speedKts > 5 ? 60 : 10); // low priority for parked aircraft
-  d->setOffset(MapData::VALIGN_CENTER | MapData::HALIGN_LEFT, 10);
-  d->setAnchor(p);
-
+    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
+    d->setOffset(MapData::VALIGN_CENTER | MapData::HALIGN_LEFT, 10);
+    d->setAnchor(p);
 }
 
 void MapWidget::drawAIShip(const SGPropertyNode* model, const SGGeod& pos, double hdg)
@@ -1616,26 +1639,45 @@ SGVec2d MapWidget::project(const SGGeod& geod) const
   SGVec2d p;
   double r = earth_radius_lat(geod.getLatitudeRad());
   
-  if (_orthoAzimuthProject) {
-    // http://mathworld.wolfram.com/OrthographicProjection.html
-    double cosTheta = cos(geod.getLatitudeRad());
-    double sinDLambda = sin(geod.getLongitudeRad() - _projectionCenter.getLongitudeRad());
-    double cosDLambda = cos(geod.getLongitudeRad() - _projectionCenter.getLongitudeRad());
-    double sinTheta1 = sin(_projectionCenter.getLatitudeRad());
-    double sinTheta = sin(geod.getLatitudeRad());
-    double cosTheta1 = cos(_projectionCenter.getLatitudeRad());
-    
-    p = SGVec2d(cosTheta * sinDLambda,
-                (cosTheta1 * sinTheta) - (sinTheta1 * cosTheta * cosDLambda)) * r * currentScale();
+    switch (_projection) {
+    case PROJECTION_SAMSON_FLAMSTEED:
+    {
+        // Sanson-Flamsteed projection, relative to the projection center
+        double lonDiff = geod.getLongitudeRad() - _projectionCenter.getLongitudeRad(),
+        latDiff = geod.getLatitudeRad() - _projectionCenter.getLatitudeRad();
+        
+        p = SGVec2d(cos(geod.getLatitudeRad()) * lonDiff, latDiff) * r * currentScale();
+        break;
+    }
+            
+    case PROJECTION_ORTHO_AZIMUTH:
+    {
+        // http://mathworld.wolfram.com/OrthographicProjection.html
+        double cosTheta = cos(geod.getLatitudeRad());
+        double sinDLambda = sin(geod.getLongitudeRad() - _projectionCenter.getLongitudeRad());
+        double cosDLambda = cos(geod.getLongitudeRad() - _projectionCenter.getLongitudeRad());
+        double sinTheta1 = sin(_projectionCenter.getLatitudeRad());
+        double sinTheta = sin(geod.getLatitudeRad());
+        double cosTheta1 = cos(_projectionCenter.getLatitudeRad());
+        
+        p = SGVec2d(cosTheta * sinDLambda,
+                    (cosTheta1 * sinTheta) - (sinTheta1 * cosTheta * cosDLambda)) * r * currentScale();
+        break;
+    }
+            
+    case PROJECTION_SPHERICAL:
+    {
+        SGVec3d cartCenter = SGVec3d::fromGeod(_projectionCenter);
+        SGVec3d cartPt = SGVec3d::fromGeod(geod) - cartCenter;
+        
+        // rotate relative to projection center
+        SGQuatd orient = SGQuatd::fromLonLat(_projectionCenter);
+        cartPt = orient.rotateBack(cartPt);
+        return SGVec2d(cartPt.y(), cartPt.x()) * currentScale();
+        break;
+    }
+    } // of projection mode switch
     
-  } else {
-    // Sanson-Flamsteed projection, relative to the projection center
-    double lonDiff = geod.getLongitudeRad() - _projectionCenter.getLongitudeRad(),
-      latDiff = geod.getLatitudeRad() - _projectionCenter.getLatitudeRad();
-
-    p = SGVec2d(cos(geod.getLatitudeRad()) * lonDiff, latDiff) * r * currentScale();
-      
-  }
   
 // rotate as necessary
   double cost = cos(_upHeading * SG_DEGREES_TO_RADIANS),
@@ -1653,24 +1695,43 @@ SGGeod MapWidget::unproject(const SGVec2d& p) const
   SGVec2d ur(cost * p.x() - sint * p.y(),
              sint * p.x() + cost * p.y());
 
-  double r = earth_radius_lat(_projectionCenter.getLatitudeRad());
-  SGVec2d unscaled = ur * (1.0 / (currentScale() * r));
-
-  if (_orthoAzimuthProject) {
-      double phi = length(p);
-      double c = asin(phi);
-      double sinTheta1 = sin(_projectionCenter.getLatitudeRad());
-      double cosTheta1 = cos(_projectionCenter.getLatitudeRad());
-      
-      double lat = asin(cos(c) * sinTheta1 + ((unscaled.y() * sin(c) * cosTheta1) / phi));
-      double lon = _projectionCenter.getLongitudeRad() + 
+  
+
+    switch (_projection) {
+    case PROJECTION_SAMSON_FLAMSTEED:
+    {
+        double r = earth_radius_lat(_projectionCenter.getLatitudeRad());
+        SGVec2d unscaled = ur * (1.0 / (currentScale() * r));
+        double lat = unscaled.y() + _projectionCenter.getLatitudeRad();
+        double lon = (unscaled.x() / cos(lat)) + _projectionCenter.getLongitudeRad();
+        return SGGeod::fromRad(lon, lat);
+    }
+        
+    case PROJECTION_ORTHO_AZIMUTH:
+    {
+        double r = earth_radius_lat(_projectionCenter.getLatitudeRad());
+        SGVec2d unscaled = ur * (1.0 / (currentScale() * r));
+        
+        double phi = length(p);
+        double c = asin(phi);
+        double sinTheta1 = sin(_projectionCenter.getLatitudeRad());
+        double cosTheta1 = cos(_projectionCenter.getLatitudeRad());
+        
+        double lat = asin(cos(c) * sinTheta1 + ((unscaled.y() * sin(c) * cosTheta1) / phi));
+        double lon = _projectionCenter.getLongitudeRad() +
         atan((unscaled.x()* sin(c)) / (phi  * cosTheta1 * cos(c) - unscaled.y() * sinTheta1 * sin(c)));
-      return SGGeod::fromRad(lon, lat);
-  } else {
-      double lat = unscaled.y() + _projectionCenter.getLatitudeRad();
-      double lon = (unscaled.x() / cos(lat)) + _projectionCenter.getLongitudeRad();
-      return SGGeod::fromRad(lon, lat);
-  }
+        return SGGeod::fromRad(lon, lat);
+    }
+        
+    case PROJECTION_SPHERICAL:
+    {
+        SGVec2d unscaled = ur * (1.0 / currentScale());
+        SGQuatd orient = SGQuatd::fromLonLat(_projectionCenter);
+        SGVec3d cartCenter = SGVec3d::fromGeod(_projectionCenter);
+        SGVec3d cartPt = orient.rotate(SGVec3d(unscaled.x(), unscaled.y(), 0.0));
+        return SGGeod::fromCart(cartPt + cartCenter);
+    }
+    } // of projection mode switch
 }
 
 double MapWidget::currentScale() const
@@ -1682,15 +1743,25 @@ void MapWidget::circleAt(const SGVec2d& center, int nSides, double r)
 {
   glBegin(GL_LINE_LOOP);
   double advance = (SGD_PI * 2) / nSides;
-  glVertex2d(center.x(), center.y() + r);
+  glVertex2d(center.x() +r, center.y());
   double t=advance;
   for (int i=1; i<nSides; ++i) {
-    glVertex2d(center.x() + (sin(t) * r), center.y() + (cos(t) * r));
+    glVertex2d(center.x() + (cos(t) * r), center.y() + (sin(t) * r));
     t += advance;
   }
   glEnd();
 }
 
+void MapWidget::squareAt(const SGVec2d& center, double r)
+{
+  glBegin(GL_LINE_LOOP);
+  glVertex2d(center.x() + r, center.y() + r);
+  glVertex2d(center.x() + r, center.y() - r);
+  glVertex2d(center.x() - r, center.y() - r);
+  glVertex2d(center.x() - r, center.y() + r);
+  glEnd();
+}
+
 void MapWidget::circleAtAlt(const SGVec2d& center, int nSides, double r, double r2)
 {
   glBegin(GL_LINE_LOOP);