#include <algorithm> // for std::sort
#include <plib/puAux.h>
-#include <simgear/sg_inlines.h>
-#include <simgear/route/waypoint.hxx>
#include <simgear/sg_inlines.h>
#include <simgear/misc/strutils.hxx>
#include <simgear/magvar/magvar.hxx>
#include <Airports/runways.hxx>
#include <Main/fg_os.hxx> // fgGetKeyModifiers()
#include <Navaids/routePath.hxx>
+#include <Aircraft/FlightHistory.hxx>
const char* RULER_LEGEND_KEY = "ruler-legend";
///////////////////////////////////////////////////////////////////////////
-const int MAX_ZOOM = 16;
+const int MAX_ZOOM = 12;
const int SHOW_DETAIL_ZOOM = 8;
const int CURSOR_PAN_STEP = 32;
_width = maxX - x;
_height = maxY - y;
_hasPanned = false;
-
+ _orthoAzimuthProject = false;
+
MapData::setFont(legendFont);
MapData::setPalette(colour);
void MapWidget::setProperty(SGPropertyNode_ptr prop)
{
_root = prop;
- int zoom = _root->getBoolValue("zoom", -1);
+ int zoom = _root->getIntValue("zoom", -1);
if (zoom < 0) {
_root->setIntValue("zoom", 6); // default zoom
}
+// expose MAX_ZOOM to the UI
+ _root->setIntValue("max-zoom", MAX_ZOOM);
_root->setBoolValue("centre-on-aircraft", true);
_root->setBoolValue("draw-data", false);
+ _root->setBoolValue("draw-flight-history", false);
_root->setBoolValue("magnetic-headings", true);
}
void MapWidget::zoomIn()
{
- if (zoom() <= 0) {
+ if (zoom() >= MAX_ZOOM) {
return;
}
- _root->setIntValue("zoom", zoom() - 1);
+ _root->setIntValue("zoom", zoom() + 1);
}
void MapWidget::zoomOut()
{
- if (zoom() >= MAX_ZOOM) {
+ if (zoom() <= 0) {
return;
}
- _root->setIntValue("zoom", zoom() + 1);
+ _root->setIntValue("zoom", zoom() - 1);
}
void MapWidget::draw(int dx, int dy)
{
- _aircraft = SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"),
- fgGetDouble("/position/latitude-deg"));
+ _aircraft = globals->get_aircraft_position();
bool mag = _root->getBoolValue("magnetic-headings");
if (mag != _magneticHeadings) {
_upHeading = 0.0;
}
- _cachedZoom = zoom();
+ _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
drawNavRadio(fgGetNode("/instrumentation/nav[0]", false));
drawNavRadio(fgGetNode("/instrumentation/nav[1]", false));
paintAircraftLocation(_aircraft);
+ drawFlightHistory();
paintRoute();
paintRuler();
return;
}
- RoutePath path(_route->waypts());
+ RoutePath path(_route->flightPlan());
// first pass, draw the actual lines
glLineWidth(2.0);
} // of second waypoint iteration
}
+void MapWidget::drawFlightHistory()
+{
+ FGFlightHistory* history = (FGFlightHistory*) globals->get_subsystem("history");
+ if (!history || !_root->getBoolValue("draw-flight-history")) {
+ 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]);
+ glVertex2d(p.x(), p.y());
+ }
+
+ glEnd();
+}
+
/**
* Round a SGGeod to an arbitrary precision.
* For example, passing precision of 0.5 will round to the nearest 0.5 of
{
_heliports = nd->getBoolValue("show-heliports", false);
_hardRunwaysOnly = nd->getBoolValue("hard-surfaced-airports", true);
- _minLengthFt = nd->getDoubleValue("min-runway-length-ft", 2000.0);
+ _minLengthFt = fgGetDouble("/sim/navdb/min-runway-length-ft", 2000);
}
virtual FGPositioned::Type maxType() const {
void MapWidget::drawAirports()
{
MapAirportFilter af(_root);
- FGPositioned::List apts = FGPositioned::findWithinRange(_projectionCenter, _drawRangeNm, &af);
+ bool partial = false;
+ FGPositioned::List apts = FGPositioned::findWithinRangePartial(_projectionCenter, _drawRangeNm, &af, partial);
for (unsigned int i=0; i<apts.size(); ++i) {
drawAirport((FGAirport*) apts[i].get());
}
}
virtual FGPositioned::Type minType() const {
- return _fixes ? FGPositioned::FIX : FGPositioned::VOR;
+ return _fixes ? FGPositioned::FIX : FGPositioned::NDB;
}
virtual FGPositioned::Type maxType() const {
- return _navaids ? FGPositioned::NDB : FGPositioned::FIX;
+ return _navaids ? FGPositioned::VOR : FGPositioned::FIX;
}
private:
// identify the tuned station - unfortunately we don't get lat/lon directly,
// need to do the frequency search again
double mhz = radio->getDoubleValue("frequencies/selected-mhz", 0.0);
- FGNavRecord* nav = globals->get_navlist()->findByFreq(mhz, _aircraft);
+
+ FGNavRecord* nav = FGNavList::findByFreq(mhz, _aircraft,
+ FGNavList::navFilter());
if (!nav || (nav->ident() != radio->getStringValue("nav-id"))) {
// mismatch between navradio selection logic and ours!
return;
void MapWidget::drawTunedLocalizer(SGPropertyNode_ptr radio)
{
double mhz = radio->getDoubleValue("frequencies/selected-mhz", 0.0);
- FGNavRecord* loc = globals->get_loclist()->findByFreq(mhz, _aircraft);
+ FGNavRecord* loc = FGNavList::findByFreq(mhz, _aircraft, FGNavList::locFilter());
if (!loc || (loc->ident() != radio->getStringValue("nav-id"))) {
// mismatch between navradio selection logic and ours!
return;
drawLine(p, project(advance));
}
- if (validDataForKey((void*) model)) {
- setAnchorForKey((void*) model, p);
- return;
- }
// 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 = createDataForKey((void*) model);
+ MapData* d = getOrCreateDataForKey((void*) model);
d->setText(buffer);
d->setLabel(model->getStringValue("callsign", "<>"));
d->setPriority(speedKts > 5 ? 60 : 10); // low priority for parked aircraft
drawLine(p, project(advance));
}
- if (validDataForKey((void*) model)) {
- setAnchorForKey((void*) model, p);
- return;
- }
-
// draw callsign / speed
char buffer[1024];
::snprintf(buffer, 1024, "%s\n%dkts",
model->getStringValue("name", "<>"),
speedKts);
- MapData* d = createDataForKey((void*) model);
+ 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
SGVec2d MapWidget::project(const SGGeod& geod) const
{
- // Sanson-Flamsteed projection, relative to the projection center
+ SGVec2d p;
double r = earth_radius_lat(geod.getLatitudeRad());
- double lonDiff = geod.getLongitudeRad() - _projectionCenter.getLongitudeRad(),
- latDiff = geod.getLatitudeRad() - _projectionCenter.getLatitudeRad();
-
- SGVec2d p = SGVec2d(cos(geod.getLatitudeRad()) * lonDiff, latDiff) * r * currentScale();
+
+ 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();
+
+ } 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),
sint = sin(_upHeading * SG_DEGREES_TO_RADIANS);
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);
+ 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() +
+ 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);
+ }
}
double MapWidget::currentScale() const