#include <Main/viewer.hxx>
#include <Scenery/scenery.hxx>
#include <Scenery/tilemgr.hxx>
+#include <Airports/dynamics.hxx>
#include <string>
#include <math.h>
#include <Traffic/SchedFlight.hxx>
#include <Traffic/Schedule.hxx>
+#include <ATC/trafficcontrol.hxx>
#include <string>
using std::string;
# include <config.h>
#endif
+#include <iostream>
+
#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/route/waypoint.hxx>
#include <Main/fg_init.hxx>
#include <Airports/simple.hxx>
#include <Airports/runways.hxx>
-
+#include <Airports/groundnetwork.hxx>
#include <Environment/environment_mgr.hxx>
#include <Environment/environment.hxx>
#include "AIFlightPlan.hxx"
+using std::cerr;
+
FGAIFlightPlan::FGAIFlightPlan(const string& filename)
{
using std::vector;
using std::string;
+class FGTaxiRoute;
class FGAIFlightPlan {
#include "AIFlightPlan.hxx"
#include <simgear/math/sg_geodesy.hxx>
#include <Airports/runways.hxx>
+#include <Airports/dynamics.hxx>
#include <Environment/environment_mgr.hxx>
#include <Environment/environment.hxx>
}
string rwyClass = getRunwayClassFromTrafficType(fltType);
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway);
- if (!(globals->get_runways()->search(apt->getId(),
- activeRunway,
- &rwy)))
- {
- SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " <<
- activeRunway <<
- " at airport " << apt->getId() << " of class " << rwyClass << " (1)");
- exit(1);
- }
-
+ rwy = apt->getRunwayByIdent(activeRunway);
+
// Determine the beginning of he runway
heading = rwy._heading;
double azimuth = heading + 180.0;
//string name;
string rwyClass = getRunwayClassFromTrafficType(fltType);
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway);
- if (!(globals->get_runways()->search(apt->getId(),
- activeRunway,
- &rwy)))
- {
- SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " <<
- activeRunway <<
- " at airport " << apt->getId()<< " of class " << rwyClass << " (2)");
- exit(1);
- }
+ rwy = apt->getRunwayByIdent(activeRunway);
}
// Acceleration point, 105 meters into the runway,
heading = rwy._heading;
//string name;
string rwyClass = getRunwayClassFromTrafficType(fltType);
apt->getDynamics()->getActiveRunway(rwyClass, 1, activeRunway);
- if (!(globals->get_runways()->search(apt->getId(),
- activeRunway,
- &rwy)))
- {
- SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " <<
- activeRunway <<
- " at airport " << apt->getId()<< " of class " << rwyClass << " (3)");
- exit(1);
- }
+ rwy = apt->getRunwayByIdent(activeRunway);
}
// allow "mil" and "gen" as well
string rwyClass = getRunwayClassFromTrafficType(fltType);
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway);
- if (!(globals->get_runways()->search(apt->getId(),
- activeRunway,
- &rwy)))
- {
- SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " <<
- activeRunway <<
- " at airport " << apt->getId()<< " of class " << rwyClass << " (4)");
- exit(1);
- }
-
+ rwy = apt->getRunwayByIdent(activeRunway);
+
heading = rwy._heading;
azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
#include <Navaids/awynet.hxx>
#include <Airports/runways.hxx>
+#include <Airports/dynamics.hxx>
#include <Environment/environment_mgr.hxx>
#include <Environment/environment.hxx>
string rwyClass = getRunwayClassFromTrafficType(fltType);
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway);
- if (!(globals->get_runways()->search(arr->getId(),
- activeRunway,
- &rwy)))
- {
- SG_LOG(SG_INPUT, SG_ALERT, "Failed to find runway " <<
- activeRunway <<
- " at airport " << arr->getId()<< " of class " << rwyClass << " (5)");
- exit(1);
- }
+ rwy = arr->getRunwayByIdent(activeRunway);
+
heading = rwy._heading;
azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
#include "AIFlightPlan.hxx"
#include <simgear/math/sg_geodesy.hxx>
#include <Airports/runways.hxx>
+#include <Airports/dynamics.hxx>
#include <Environment/environment_mgr.hxx>
#include <Environment/environment.hxx>
#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include <Traffic/TrafficMgr.hxx>
-
+#include <Airports/groundnetwork.hxx>
+#include <Airports/dynamics.hxx>
/***************************************************************************
* FGTrafficRecord
// Now we need to get the threshold position and rwy heading
- FGRunway runway;
- bool rwyGood = globals->get_runways()->search(id, rwy.rwyID, &runway);
- if(rwyGood) {
- double hdg = runway._heading;
- double other_way = hdg - 180.0;
- while(other_way <= 0.0) {
- other_way += 360.0;
- }
+ const FGAirport* apt = fgFindAirportID(id);
+ assert(apt);
+ FGRunway runway(apt->getRunwayByIdent(rwy.rwyID));
+ double hdg = runway._heading;
+ double other_way = hdg - 180.0;
+ while(other_way <= 0.0) {
+ other_way += 360.0;
+ }
+
// move to the +l end/center of the runway
//cout << "Runway center is at " << runway._lon << ", " << runway._lat << '\n';
Point3D origin = Point3D(runway._lon, runway._lat, aptElev);
ortho.Init(rwy.threshold_pos, rwy.hdg);
rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
- } else {
- SG_LOG(SG_ATC, SG_ALERT, "Help - can't get good runway at airport " << id << " in FGAILocalTraffic!!");
- }
}
# include <config.h>
#endif
+#include <iostream>
+
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <simgear/misc/sg_path.hxx>
#include "ATCDialog.hxx"
#include <Airports/runways.hxx>
+#include <Airports/simple.hxx>
+
#include <simgear/constants.h>
#include <simgear/math/polar3d.hxx>
#include <simgear/misc/sg_path.hxx>
void FGApproach::get_active_runway() {
//cout << "Entering FGApproach::get_active_runway()\n";
- FGEnvironment stationweather =
- ((FGEnvironmentMgr *)globals->get_subsystem("environment"))
- ->getEnvironment(lat, lon, elev);
-
- double hdg = stationweather.get_wind_from_heading_deg();
-
- FGRunway runway;
- if ( globals->get_runways()->search( ident, int(hdg), &runway) ) {
- active_runway = runway._rwy_no;
- active_rw_hdg = runway._heading;
- active_rw_lon = runway._lon;
- active_rw_lat = runway._lat;
- active_rw_len = runway._length;
- //cout << "Active runway is: " << active_runway << " heading = "
- // << active_rw_hdg
- // << " lon = " << active_rw_lon
- // << " lat = " << active_rw_lat <<endl;
- }
- else cout << "FGRunways search failed\n";
+ const FGAirport* apt = fgFindAirportID(ident);
+ assert(apt);
+ FGRunway runway = apt->getActiveRunwayForUsage();
+ active_runway = runway._rwy_no;
+ active_rw_hdg = runway._heading;
+ active_rw_lon = runway._lon;
+ active_rw_lat = runway._lat;
+ active_rw_len = runway._length;
}
// ========================================================================
+ ConvertNumToSpokenDigits(tempstr2) + " degrees";
}
- string rwy_no = globals->get_runways()->search(ident, int(hdg));
- if(rwy_no != "NN") {
+ const FGAirport* apt = fgFindAirportID(ident);
+ assert(apt);
+ string rwy_no = apt->getActiveRunwayForUsage()._rwy_no;
+ if(rwy_no != "NN") {
transmission += " / Landing_and_departing_runway ";
transmission += ConvertRwyNumToSpokenString(atoi(rwy_no.c_str()));
//cout << "in atis.cxx, r.rwy_no = " << rwy_no << " r.id = " << r->id << " r.heading = " << r->heading << endl;
# include <config.h>
#endif
+#include <iostream>
+
#include <simgear/misc/sg_path.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/debug/logstream.hxx>
// will be initialised before ground so we can't do that.
void FGGround::DoRwyDetails() {
//cout << "GetRwyDetails called" << endl;
-
- // Based on the airport-id and wind get the active runway
-
- //wind
- double hdg = wind_from_hdg->getDoubleValue();
- double speed = wind_speed_knots->getDoubleValue();
- hdg = (speed == 0.0 ? 270.0 : hdg);
- //cout << "Heading = " << hdg << '\n';
-
- FGRunway runway;
- bool rwyGood = globals->get_runways()->search(ident, int(hdg), &runway);
- if(rwyGood) {
- activeRwy = runway._rwy_no;
- rwy.rwyID = runway._rwy_no;
- SG_LOG(SG_ATC, SG_INFO, "In FGGround, active runway for airport " << ident << " is " << activeRwy);
- // Get the threshold position
- double other_way = runway._heading - 180.0;
- while(other_way <= 0.0) {
- other_way += 360.0;
- }
- // move to the +l end/center of the runway
- //cout << "Runway center is at " << runway._lon << ", " << runway._lat << '\n';
- Point3D origin = Point3D(runway._lon, runway._lat, aptElev);
- Point3D ref = origin;
- double tshlon, tshlat, tshr;
- double tolon, tolat, tor;
- rwy.length = runway._length * SG_FEET_TO_METER;
- geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way,
- rwy.length / 2.0 - 25.0, &tshlat, &tshlon, &tshr );
- geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), runway._heading,
- rwy.length / 2.0 - 25.0, &tolat, &tolon, &tor );
- // Note - 25 meters in from the runway end is a bit of a hack to put the plane ahead of the user.
- // now copy what we need out of runway into rwy
- rwy.threshold_pos = Point3D(tshlon, tshlat, aptElev);
- Point3D takeoff_end = Point3D(tolon, tolat, aptElev);
- //cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
- //cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
- rwy.hdg = runway._heading;
- // Set the projection for the local area based on this active runway
- ortho.Init(rwy.threshold_pos, rwy.hdg);
- rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
- rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
- } else {
- SG_LOG(SG_ATC, SG_ALERT, "Help - can't get good runway in FGTower!!");
- activeRwy = "NN";
- }
+ const FGAirport* apt = fgFindAirportID(ident);
+ assert(apt);
+ FGRunway runway = apt->getActiveRunwayForUsage();
+
+ activeRwy = runway._rwy_no;
+ rwy.rwyID = runway._rwy_no;
+ SG_LOG(SG_ATC, SG_INFO, "In FGGround, active runway for airport " << ident << " is " << activeRwy);
+
+ // Get the threshold position
+ double other_way = runway._heading - 180.0;
+ while(other_way <= 0.0) {
+ other_way += 360.0;
+ }
+ // move to the +l end/center of the runway
+ //cout << "Runway center is at " << runway._lon << ", " << runway._lat << '\n';
+ Point3D origin = Point3D(runway._lon, runway._lat, aptElev);
+ Point3D ref = origin;
+ double tshlon, tshlat, tshr;
+ double tolon, tolat, tor;
+ rwy.length = runway._length * SG_FEET_TO_METER;
+ geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way,
+ rwy.length / 2.0 - 25.0, &tshlat, &tshlon, &tshr );
+ geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), runway._heading,
+ rwy.length / 2.0 - 25.0, &tolat, &tolon, &tor );
+ // Note - 25 meters in from the runway end is a bit of a hack to put the plane ahead of the user.
+ // now copy what we need out of runway into rwy
+ rwy.threshold_pos = Point3D(tshlon, tshlat, aptElev);
+ Point3D takeoff_end = Point3D(tolon, tolat, aptElev);
+ //cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
+ //cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
+ rwy.hdg = runway._heading;
+ // Set the projection for the local area based on this active runway
+ ortho.Init(rwy.threshold_pos, rwy.hdg);
+ rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
+ rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
}
// Return a random gate ID of an unused gate.
#include <sstream>
#include <iomanip>
+#include <iostream>
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
// Based on the airport-id and wind get the active runway
- //wind
- double hdg = wind_from_hdg->getDoubleValue();
- double speed = wind_speed_knots->getDoubleValue();
- hdg = (speed == 0.0 ? 270.0 : hdg);
- //cout << "Heading = " << hdg << '\n';
-
- FGRunway runway;
- bool rwyGood = globals->get_runways()->search(ident, int(hdg), &runway);
- if(rwyGood) {
- //cout << "RUNWAY GOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOD\n";
- activeRwy = runway._rwy_no;
- rwy.rwyID = runway._rwy_no;
- SG_LOG(SG_ATC, SG_INFO, "Active runway for airport " << ident << " is " << activeRwy);
-
- // Get the threshold position
- double other_way = runway._heading - 180.0;
- while(other_way <= 0.0) {
- other_way += 360.0;
- }
- // move to the +l end/center of the runway
- //cout << "Runway center is at " << runway._lon << ", " << runway._lat << '\n';
- Point3D origin = Point3D(runway._lon, runway._lat, aptElev);
- Point3D ref = origin;
- double tshlon, tshlat, tshr;
- double tolon, tolat, tor;
- rwy.length = runway._length * SG_FEET_TO_METER;
- rwy.width = runway._width * SG_FEET_TO_METER;
- geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way,
- rwy.length / 2.0 - 25.0, &tshlat, &tshlon, &tshr );
- geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), runway._heading,
- rwy.length / 2.0 - 25.0, &tolat, &tolon, &tor );
- // Note - 25 meters in from the runway end is a bit of a hack to put the plane ahead of the user.
- // now copy what we need out of runway into rwy
- rwy.threshold_pos = Point3D(tshlon, tshlat, aptElev);
- Point3D takeoff_end = Point3D(tolon, tolat, aptElev);
- //cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
- //cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
- rwy.hdg = runway._heading;
- // Set the projection for the local area based on this active runway
- ortho.Init(rwy.threshold_pos, rwy.hdg);
- rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
- rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
-
- // Set the pattern direction
- // TODO - we'll check for a facilities file with this in eventually - for now assume left traffic except
- // for certain circumstances (RH parallel rwy).
- rwy.patternDirection = -1; // Left
- if(rwy.rwyID.size() == 3) {
- rwy.patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
- }
- //cout << "Doing details, rwy.patterDirection is " << rwy.patternDirection << '\n';
- } else {
- SG_LOG(SG_ATC, SG_ALERT, "Help - can't get good runway in FGTower!!");
- activeRwy = "NN";
- }
+ const FGAirport* apt = fgFindAirportID(ident);
+ assert(apt);
+ FGRunway runway = apt->getActiveRunwayForUsage();
+
+ //cout << "RUNWAY GOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOD\n";
+
+ activeRwy = runway._rwy_no;
+ rwy.rwyID = runway._rwy_no;
+ SG_LOG(SG_ATC, SG_INFO, "Active runway for airport " << ident << " is " << activeRwy);
+
+ // Get the threshold position
+ double other_way = runway._heading - 180.0;
+ while(other_way <= 0.0) {
+ other_way += 360.0;
+ }
+ // move to the +l end/center of the runway
+ //cout << "Runway center is at " << runway._lon << ", " << runway._lat << '\n';
+ Point3D origin = Point3D(runway._lon, runway._lat, aptElev);
+ Point3D ref = origin;
+ double tshlon, tshlat, tshr;
+ double tolon, tolat, tor;
+ rwy.length = runway._length * SG_FEET_TO_METER;
+ rwy.width = runway._width * SG_FEET_TO_METER;
+ geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), other_way,
+ rwy.length / 2.0 - 25.0, &tshlat, &tshlon, &tshr );
+ geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), runway._heading,
+ rwy.length / 2.0 - 25.0, &tolat, &tolon, &tor );
+ // Note - 25 meters in from the runway end is a bit of a hack to put the plane ahead of the user.
+ // now copy what we need out of runway into rwy
+ rwy.threshold_pos = Point3D(tshlon, tshlat, aptElev);
+ Point3D takeoff_end = Point3D(tolon, tolat, aptElev);
+ //cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
+ //cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
+ rwy.hdg = runway._heading;
+ // Set the projection for the local area based on this active runway
+ ortho.Init(rwy.threshold_pos, rwy.hdg);
+ rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
+ rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
+
+ // Set the pattern direction
+ // TODO - we'll check for a facilities file with this in eventually - for now assume left traffic except
+ // for certain circumstances (RH parallel rwy).
+ rwy.patternDirection = -1; // Left
+ if(rwy.rwyID.size() == 3) {
+ rwy.patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
+ }
+ //cout << "Doing details, rwy.patterDirection is " << rwy.patternDirection << '\n';
}
}
// Based on the airport-id, go through all the runways and check for a point in them
-
- // TODO - do we actually need to search for the airport - surely we already know our ident and
- // can just search runways of our airport???
- //cout << "Airport ident is " << ad.ident << '\n';
- FGRunway runway;
- bool rwyGood = globals->get_runways()->search(ad.ident, &runway);
- if(!rwyGood) {
- SG_LOG(SG_ATC, SG_WARN, "Unable to find any runways for airport ID " << ad.ident << " in FGTower");
- }
- bool on = false;
- while(runway._id == ad.ident) {
- on = OnRunway(pt, runway);
- //cout << "Runway " << runway._rwy_no << ": On = " << (on ? "true\n" : "false\n");
- if(on) {
- if(onGround == false)
- return(true);
- if(runway._rwy_no != "xx")
- return(true);
- }
- globals->get_runways()->next(&runway);
- }
- return(on);
+
+ const FGAirport* apt = fgFindAirportID(ad.ident);
+ assert(apt);
+
+ for (unsigned int i=0; i<apt->numRunways(); ++i) {
+ if (OnRunway(pt, apt->getRunwayByIndex(i))) {
+ return true;
+ }
+ }
+
+ // if onGround is true, we only match real runways, so we're done
+ if (onGround) return false;
+
+ // try taxiways as well
+ for (unsigned int i=0; i<apt->numTaxiways(); ++i) {
+ if (OnRunway(pt, apt->getTaxiwayByIndex(i))) {
+ return true;
+ }
+ }
+
+ return false;
}
#include "apt_loader.hxx"
-static void addAirport(FGAirportList *airports, const string& apt_id, const string& apt_name,
+FGAirport* addAirport(FGAirportList *airports, const string& apt_id, const string& apt_name,
int rwy_count, double rwy_lat_accum, double rwy_lon_accum, double last_rwy_heading,
double apt_elev, SGGeod& tower, bool got_tower, int type)
{
if (apt_id.empty())
- return;
+ return NULL;
if (!rwy_count) {
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR: No runways for " << apt_id
<< ", skipping." );
- return;
+ return NULL;
}
double lat = rwy_lat_accum / (double)rwy_count;
tower = SGGeod::fromDegFt(lon + fudge_lon, lat + fudge_lat, apt_elev + tower_height);
}
- airports->add(apt_id, SGGeod::fromDegFt(lon, lat, apt_elev), tower, apt_name, false,
+ return airports->add(apt_id, SGGeod::fromDegFt(lon, lat, apt_elev), tower, apt_name, false,
type == 1/*airport*/, type == 16/*seaport*/, type == 17/*heliport*/);
}
// Load the airport data base from the specified aptdb file. The
// metar file is used to mark the airports as having metar available
// or not.
-bool fgAirportDBLoad( FGAirportList *airports, FGRunwayList *runways,
+bool fgAirportDBLoad( FGAirportList *airports,
const string &aptdb_file, const string &metar_file )
{
//
string line;
char tmp[2049];
tmp[2048] = 0;
-
+ vector<FGRunway> runways;
+
unsigned int line_id = 0;
unsigned int line_num = 0;
double rwy_lon_accum = 0.0;
SG_LOG( SG_GENERAL, SG_BULK, "Next airport = " << id << " "
<< elev );
- addAirport(airports, last_apt_id, last_apt_name, rwy_count, rwy_lat_accum, rwy_lon_accum,
+ FGAirport* apt = addAirport(airports, last_apt_id, last_apt_name, rwy_count, rwy_lat_accum, rwy_lon_accum,
last_rwy_heading, last_apt_elev, last_tower, got_tower, last_apt_type);
+ for (unsigned int r=0; r< runways.size(); ++r) {
+ apt->addRunway(runways[r]);
+ }
+
+ runways.clear();
+
last_apt_id = id;
last_apt_elev = elev;
last_apt_name = "";
double smoothness = atof( token[13].c_str() );
bool dist_remaining = (atoi( token[14].c_str() ) == 1 );
- runways->add( last_apt_id, rwy_no, lon, lat, heading, length,
+ FGRunway rwy(last_apt_id, rwy_no, lon, lat, heading, length,
width, displ_thresh1, displ_thresh2,
stopway1, stopway2, lighting_flags, surface_code,
shoulder_code, marking_code, smoothness,
- dist_remaining );
+ dist_remaining);
+ runways.push_back(rwy);
} else if ( line_id == 18 ) {
// beacon entry (ignore)
} else if ( line_id == 14 ) {
#ifndef _FG_APT_LOADER_HXX
#define _FG_APT_LOADER_HXX
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include <simgear/compiler.h>
#include <string>
-using std::string;
-
#include "simple.hxx"
-#include "runways.hxx"
// Load the airport data base from the specified aptdb file. The
// metar file is used to mark the airports as having metar available
// or not.
-bool fgAirportDBLoad( FGAirportList *airports, FGRunwayList *runways,
- const string &aptdb_file, const string &metar_file );
+bool fgAirportDBLoad( FGAirportList *airports, const string &aptdb_file, const std::string &metar_file );
#endif // _FG_APT_LOADER_HXX
currentlyActive = &ulActive;
}
//
- currRunwayGroup->setActive(_ap->getId(),
+ currRunwayGroup->setActive(_ap,
windSpeed,
windHeading,
maxTail,
string FGAirportDynamics::chooseRunwayFallback()
{
- FGEnvironment
- stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
- ->getEnvironment(getLatitude(),
- getLongitude(),
- getElevation());
-
- double windSpeed = stationweather.get_wind_speed_kt();
- double windHeading = stationweather.get_wind_from_heading_deg();
- if (windSpeed == 0) {
- windHeading = 270; // This forces West-facing rwys to be used in no-wind situations
- //which is consistent with Flightgear's initial setup.
- }
-
- return globals->get_runways()->search(_ap->getId(), int(windHeading));
+ FGRunway rwy = _ap->getActiveRunwayForUsage();
+ return rwy._rwy_no;
}
void FGAirportDynamics::addParking(FGParking& park) {
//#include <Main/fg_props.hxx>
//#include <Airports/runways.hxx>
+#include <Airports/dynamics.hxx>
+
#include <AIModel/AIFlightPlan.hxx>
//#include <string>
return *this;
}
-void RunwayGroup::setActive(const string &aptId,
+void RunwayGroup::setActive(const FGAirport* airport,
double windSpeed,
double windHeading,
double maxTail,
//
validSelection = true;
for (int j = 0; j < activeRwys; j++)
- {
-
- name = rwyList[j].getRwyList(i);
- //cerr << "Name of Runway: " << name;
- if (globals->get_runways()->search( aptId,
- name,
- &rwy))
- {
- //cerr << "Succes" << endl;
+ {
+ rwy = airport->getRunwayByIdent(rwyList[j].getRwyList(i));
+
+ //cerr << "Succes" << endl;
hdgDiff = fabs(windHeading - rwy._heading);
//cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
//cerr << "Wind Speed : " << windSpeed << endl;
{
//cerr << ". [Valid] ";
}
- }else {
- SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
- exit(1);
- }
- //cerr << endl;
- }
+ //cerr << endl;
+ } // of active runways iteration
+
if (validSelection)
{
//cerr << "Valid selection : " << i << endl;;
bool validSelection = true;
for (int j = 0; j < 2; j++)
{
- //cerr << "I J " << i << " " << j << endl;
- name = rwyList[choice[j]].getRwyList(i);
- //cerr << "Name of Runway: " << name << endl;
- if (globals->get_runways()->search( aptId,
- name,
- &rwy))
- {
+ name = rwyList[choice[j]].getRwyList(i);
+ rwy = airport->getRunwayByIdent(name);
+
//cerr << "Succes" << endl;
hdgDiff = fabs(windHeading - rwy._heading);
if (hdgDiff > 180)
tailWind = -windSpeed * cos(hdgDiff);
if ((tailWind > maxTail) || (crossWind > maxCross))
validSelection = false;
- }else {
- SG_LOG( SG_GENERAL, SG_INFO, "Failed to find runway " << name << " at " << aptId );
- exit(1);
- }
+
}
if (validSelection)
void setName(const string& nm) { name = nm; };
void add(const RunwayList& list) { rwyList.push_back(list);};
- void setActive(const string& aptId, double windSpeed, double windHeading, double maxTail, double maxCross, stringVec *curr);
+ void setActive(const FGAirport* airport, double windSpeed, double windHeading, double maxTail, double maxCross, stringVec *curr);
int getNrActiveRunways() { return nrActive;};
void getActive(int i, string& name, string& type);
using std::istream;
using std::multimap;
+using std::string;
+FGRunway::FGRunway()
+{
+}
-// add an entry to the list
-void FGRunwayList::add( const string& id, const string& rwy_no,
+FGRunway::FGRunway( const string& id, const string& rwy_no,
const double longitude, const double latitude,
const double heading, const double length,
const double width,
const string& shoulder_code, const int marking_code,
const double smoothness, const bool dist_remaining )
{
- FGRunway rwy;
-
- rwy._id = id;
- rwy._rwy_no = rwy_no;
- // strip trailing "x" if it exists in runway number
- string tmp = rwy._rwy_no.substr(2, 1);
- if ( tmp == "x" ) {
- rwy._rwy_no = rwy._rwy_no.substr(0, 2);
+ _rwy_no = rwy_no;
+ if (rwy_no[0] == 'x') {
+ _type = "taxiway";
+ } else {
+ _type = "runway";
+
+ // canonicalise runway ident
+ if ((rwy_no.size() == 1) || !isdigit(rwy_no[1])) {
+ _rwy_no = "0" + rwy_no;
}
- rwy._lon = longitude;
- rwy._lat = latitude;
- rwy._heading = heading;
- rwy._length = length;
- rwy._width = width;
- rwy._displ_thresh1 = displ_thresh1;
- rwy._displ_thresh2 = displ_thresh2;
- rwy._stopway1 = stopway1;
- rwy._stopway2 = stopway2;
-
- rwy._lighting_flags = lighting_flags;
- rwy._surface_code = surface_code;
- rwy._shoulder_code = shoulder_code;
- rwy._marking_code = marking_code;
- rwy._smoothness = smoothness;
- rwy._dist_remaining = dist_remaining;
-
- if ( rwy_no[0] == 'x' ) {
- rwy._type = "taxiway";
- } else {
- rwy._type = "runway";
+ if ((_rwy_no.size() > 2) && (_rwy_no[2] == 'x')) {
+ _rwy_no = _rwy_no.substr(0, 2);
}
- runways.insert(pair<const string, FGRunway>(rwy._id, rwy));
+ }
+
+ _id = id;
+ _lon = longitude;
+ _lat = latitude;
+ _heading = heading;
+ _length = length;
+ _width = width;
+ _displ_thresh1 = displ_thresh1;
+ _displ_thresh2 = displ_thresh2;
+ _stopway1 = stopway1;
+ _stopway2 = stopway2;
+
+ _lighting_flags = lighting_flags;
+ _surface_code = surface_code;
+ _shoulder_code = shoulder_code;
+ _marking_code = marking_code;
+ _smoothness = smoothness;
+ _dist_remaining = dist_remaining;
}
+string FGRunway::reverseIdent(const string& aRunwayIdent)
+{
+ // Helipads don't have a seperate number per end
+ if (aRunwayIdent.size() && (aRunwayIdent[0] == 'H' || aRunwayIdent[0] == 'h' || aRunwayIdent[0] == 'x')) {
+ return aRunwayIdent;
+ }
-// Return reverse rwy number
-// eg 01 -> 19
-// 03L -> 21R
-static string GetReverseRunwayNo(string& rwyno) {
- // cout << "Original rwyno = " << rwyNo << '\n';
+ std::string ident(aRunwayIdent);
- // Helipads don't have a seperate number per end
- if(rwyno.size() && (rwyno[0] == 'H' || rwyno[0] == 'h' || rwyno[0] == 'x')) {
- return rwyno;
- }
-
- // standardize input number
- string tmp = rwyno.substr(1, 1);
- if (( tmp == "L" || tmp == "R" || tmp == "C" ) || (rwyno.size() == 1)) {
- tmp = rwyno;
- rwyno = "0" + tmp;
- SG_LOG( SG_GENERAL, SG_INFO,
- "Standardising rwy number from " << tmp << " to " << rwyno );
- }
-
- char buf[4];
- int rn = atoi(rwyno.substr(0,2).c_str());
- rn += 18;
- while(rn > 36) {
- rn -= 36;
- }
- sprintf(buf, "%02i", rn);
- if(rwyno.size() == 3) {
- if(rwyno.substr(2,1) == "L") {
- buf[2] = 'R';
- buf[3] = '\0';
- } else if (rwyno.substr(2,1) == "R") {
- buf[2] = 'L';
- buf[3] = '\0';
- } else if (rwyno.substr(2,1) == "C") {
- buf[2] = 'C';
- buf[3] = '\0';
- } else if (rwyno.substr(2,1) == "T") {
- buf[2] = 'T';
- buf[3] = '\0';
- } else {
- SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code "
- << rwyno << " passed to GetReverseRunwayNo(...)");
- }
- }
- return(buf);
-}
-
-
-// search for the specified apt id (wierd!)
-bool FGRunwayList::search( const string& aptid, FGRunway* r ) {
- runway_map_iterator pos;
-
- pos = runways.lower_bound(aptid);
- if ( pos != runways.end() ) {
- current = pos;
- *r = pos->second;
- return true;
+ char buf[4];
+ int rn = atoi(ident.substr(0,2).c_str());
+ rn += 18;
+ while(rn > 36) {
+ rn -= 36;
+ }
+
+ sprintf(buf, "%02i", rn);
+ if(ident.size() == 3) {
+ if(ident.substr(2,1) == "L") {
+ buf[2] = 'R';
+ buf[3] = '\0';
+ } else if (ident.substr(2,1) == "R") {
+ buf[2] = 'L';
+ buf[3] = '\0';
+ } else if (ident.substr(2,1) == "C") {
+ buf[2] = 'C';
+ buf[3] = '\0';
+ } else if (ident.substr(2,1) == "T") {
+ buf[2] = 'T';
+ buf[3] = '\0';
} else {
- return false;
+ SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code "
+ << aRunwayIdent << " passed to FGRunway::reverseIdent");
}
+ }
+
+ return buf;
}
-
-// search for the specified apt id and runway no
-bool FGRunwayList::search( const string& aptid, const string& rwyno,
- FGRunway *r )
+double FGRunway::score(double aLengthWt, double aWidthWt, double aSurfaceWt) const
{
- string revrwyno = "";
- string runwayno = rwyno;
- if ( runwayno.length() ) {
- // standardize input number
- string tmp = runwayno.substr(1, 1);
- if (( tmp == "L" || tmp == "R" || tmp == "C" )
- || (runwayno.size() == 1))
- {
- tmp = runwayno;
- runwayno = "0" + tmp;
- SG_LOG( SG_GENERAL, SG_INFO, "Standardising rwy number from "
- << tmp << " to " << runwayno );
- }
- revrwyno = GetReverseRunwayNo(runwayno);
- }
- runway_map_iterator pos;
- for ( pos = runways.lower_bound( aptid );
- pos != runways.upper_bound( aptid ); ++pos)
- {
- if ( pos->second._rwy_no == runwayno ) {
- current = pos;
- *r = pos->second;
- return true;
- } else if ( pos->second._rwy_no == revrwyno ) {
- // Search again with the other-end runway number.
- // Remember we have to munge the heading and rwy_no
- // results if this one matches
- current = pos;
- *r = pos->second;
- // NOTE - matching revrwyno implies that runwayno was
- // actually correct.
- r->_rwy_no = runwayno;
- r->_heading += 180.0;
- return true;
- }
- }
-
- return false;
-}
-
-
-// (wierd!)
-FGRunway FGRunwayList::search( const string& aptid ) {
- FGRunway a;
- search( aptid, &a );
- return a;
+ int surface = 1;
+ if (_surface_code == 12 || _surface_code == 5) // dry lakebed & gravel
+ surface = 2;
+ else if (_surface_code == 1 || _surface_code == 2) // asphalt & concrete
+ surface = 3;
+
+ return _length * aLengthWt + _width * aWidthWt + surface * aSurfaceWt + 1e-20;
}
-
-// Return the runway closest to a given heading
-bool FGRunwayList::search( const string& aptid, const int tgt_hdg,
- FGRunway *runway )
+bool FGRunway::isTaxiway() const
{
- string rwyNo = search(aptid, tgt_hdg);
- return(rwyNo == "NN" ? false : search(aptid, rwyNo, runway));
-}
-
-
-// Return the runway number of the runway closest to a given heading
-string FGRunwayList::search( const string& aptid, const int hdg ) {
- //SG_LOG(SG_GENERAL, SG_ALERT, "searching runway for " << aptid
- // << " with target heading " << hdg);
-
- FGRunway r;
- if (!search(aptid, &r)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "Failed to find "
- << aptid << " in database.");
- return "NN";
- }
-
- SGPropertyNode *param = fgGetNode("/sim/airport/runways/search", true);
- double lenwgt = param->getDoubleValue("length-weight", 0.01);
- double widwgt = param->getDoubleValue("width-weight", 0.01);
- double surfwgt = param->getDoubleValue("surface-weight", 10);
- double devwgt = param->getDoubleValue("deviation-weight", 1);
-
- FGRunway best;
- double max = 0.0;
- bool reversed = false;
-
- do {
- if (r._id != aptid)
- break;
- if (r._type != "runway")
- continue;
-
- int surface = 1;
- if (r._surface_code == 12 || r._surface_code == 5) // dry lakebed & gravel
- surface = 2;
- else if (r._surface_code == 1 || r._surface_code == 2) // asphalt & concrete
- surface = 3;
-
- double quality, bad, diff;
- double good = lenwgt * r._length + widwgt * r._width + surfwgt * surface + 1e-20;
-
- // this side
- diff = hdg - r._heading;
- while (diff < -180)
- diff += 360;
- while (diff >= 180)
- diff -= 360;
- bad = fabs(devwgt * diff) + 1e-20;
-
- quality = good / bad;
- //SG_LOG(SG_GENERAL, SG_ALERT, " runway " << r._rwy_no << " -> " << quality);
- if (quality > max) {
- max = quality;
- best = r;
- reversed = false;
- }
-
- // other side
- diff = hdg - r._heading - 180;
- while (diff < -180)
- diff += 360;
- while (diff >= 180)
- diff -= 360;
- bad = fabs(devwgt * diff) + 1e-20;
-
- quality = good / bad;
- //SG_LOG(SG_GENERAL, SG_ALERT, " runway " << GetReverseRunwayNo(r._rwy_no)
- // << " -> " << quality);
- if (quality > max) {
- max = quality;
- best = r;
- reversed = true;
- }
-
- } while (next(&r));
-
- return reversed ? GetReverseRunwayNo(best._rwy_no) : best._rwy_no;
-}
-
-
-bool FGRunwayList::next( FGRunway* runway ) {
- ++current;
- if ( current != runways.end() ) {
- *runway = current->second;
- return true;
- } else {
- return false;
- }
-}
-
-
-FGRunway FGRunwayList::next() {
- FGRunway result;
-
- ++current;
- if ( current != runways.end() ) {
- result = current->second;
- }
-
- return result;
-}
-
-
-// Destructor
-FGRunwayList::~FGRunwayList( void ) {
+ return (_rwy_no[0] == 'x');
}
#ifndef _FG_RUNWAYS_HXX
#define _FG_RUNWAYS_HXX
-
-#ifndef __cplusplus
-# error This library requires C++
-#endif
-
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#include <simgear/compiler.h>
#include <string>
-#include <map>
+#include <vector>
-using std::string;
-using std::multimap;
-
-
-struct ltstr {
- bool operator()(const string& s1, const string& s2) const {
- return s1 < s2;
- }
-};
-
-
-struct FGRunway {
-
- string _id;
- string _rwy_no;
- string _type; // runway / taxiway
+class FGRunway
+{
+public:
+ FGRunway();
+
+ FGRunway(const std::string& id, const std::string& rwy_no,
+ const double longitude, const double latitude,
+ const double heading, const double length,
+ const double width,
+ const double displ_thresh1, const double displ_thresh2,
+ const double stopway1, const double stopway2,
+ const std::string& lighting_flags, const int surface_code,
+ const std::string& shoulder_code, const int marking_code,
+ const double smoothness, const bool dist_remaining);
+
+ /**
+ * given a runway identifier (06, 18L, 31R) compute the identifier for the
+ * opposite heading runway (24, 36R, 13L) string.
+ */
+ static std::string reverseIdent(const std::string& aRunayIdent);
+
+ /**
+ * score this runway according to the specified weights. Used by
+ * FGAirport::findBestRunwayForHeading
+ */
+ double score(double aLengthWt, double aWidthWt, double aSurfaceWt) const;
+
+ bool isTaxiway() const;
+
+ std::string _id;
+ std::string _rwy_no;
+ std::string _type; // runway / taxiway
double _lon;
double _lat;
double _stopway1;
double _stopway2;
- string _lighting_flags;
+ std::string _lighting_flags;
int _surface_code;
- string _shoulder_code;
+ std::string _shoulder_code;
int _marking_code;
double _smoothness;
bool _dist_remaining;
};
-typedef multimap < string, FGRunway, ltstr > runway_map;
-typedef runway_map::iterator runway_map_iterator;
-typedef runway_map::const_iterator const_runway_map_iterator;
-
-class FGRunwayList {
-
-private:
-
- runway_map runways;
- runway_map_iterator current;
-
-public:
-
- // Constructor (new)
- FGRunwayList() {}
-
- // Destructor
- ~FGRunwayList();
-
- // add an entry to the list
- void add( const string& id, const string& rwy_no,
- const double longitude, const double latitude,
- const double heading, const double length, const double width,
- const double displ_thresh1, const double displ_thresh2,
- const double stopway1, const double stopway2,
- const string& lighting_flags, const int surface_code,
- const string& shoulder_code, const int marking_code,
- const double smoothness, const bool dist_remaining );
-
- // search for the specified apt id.
- // Returns true if successful, otherwise returns false.
- // On success, runway data is returned thru "runway" pointer.
- // "runway" is not changed if "apt" is not found.
- bool search( const string& aptid, FGRunway* runway );
- bool search( const string& aptid, const string& rwyno, FGRunway* runway );
-
- // DCL - search for runway closest to desired heading in degrees
- bool search( const string& aptid, const int hdg, FGRunway* runway );
-
- // Return the runway number of the runway closest to a given heading
- string search( const string& aptid, const int tgt_hdg );
-
- FGRunway search( const string& aptid );
- bool next( FGRunway* runway );
- FGRunway next();
-};
-
+typedef std::vector<FGRunway> FGRunwayVector;
#endif // _FG_RUNWAYS_HXX
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
#include <Airports/runways.hxx>
+#include <Airports/dynamics.hxx>
#include <string>
return _dynamics;
}
+unsigned int FGAirport::numRunways() const
+{
+ return mRunways.size();
+}
+
+FGRunway FGAirport::getRunwayByIndex(unsigned int aIndex) const
+{
+ assert(aIndex >= 0 && aIndex < mRunways.size());
+ return mRunways[aIndex];
+}
+
+bool FGAirport::hasRunwayWithIdent(const string& aIdent) const
+{
+ bool dummy;
+ return (getIteratorForRunwayIdent(aIdent, dummy) != mRunways.end());
+}
+
+FGRunway FGAirport::getRunwayByIdent(const string& aIdent) const
+{
+ bool reversed;
+ FGRunwayVector::const_iterator it = getIteratorForRunwayIdent(aIdent, reversed);
+ if (it == mRunways.end()) {
+ SG_LOG(SG_GENERAL, SG_ALERT, "no such runway '" << aIdent << "' at airport " << _id);
+ throw sg_range_exception("unknown runway " + aIdent + " at airport:" + _id, "FGAirport::getRunwayByIdent");
+ }
+
+ if (!reversed) {
+ return *it;
+ }
+
+ FGRunway result(*it);
+ result._heading += 180.0;
+ result._rwy_no = FGRunway::reverseIdent(it->_rwy_no);
+ return result;
+}
+FGRunwayVector::const_iterator
+FGAirport::getIteratorForRunwayIdent(const string& aIdent, bool& aReversed) const
+{
+ string ident(aIdent);
+ if ((aIdent.size() == 1) || !isdigit(aIdent[1])) {
+ ident = "0" + aIdent;
+ }
+
+ string reversedRunway = FGRunway::reverseIdent(ident);
+ FGRunwayVector::const_iterator it = mRunways.begin();
+
+ for (; it != mRunways.end(); ++it) {
+ if (it->_rwy_no == ident) {
+ aReversed = false;
+ return it;
+ }
+
+ if (it->_rwy_no == reversedRunway) {
+ aReversed = true;
+ return it;
+ }
+ }
+ return it; // end()
+}
+
+static double normaliseBearing(double aBearing)
+{
+ while (aBearing < -180.0) {
+ aBearing += 360.0;
+ }
+
+ while (aBearing > 180.0) {
+ aBearing -= 180.0;
+ }
+
+ return aBearing;
+}
+FGRunway FGAirport::findBestRunwayForHeading(double aHeading) const
+{
+ FGRunwayVector::const_iterator it = mRunways.begin();
+ FGRunway result;
+ double currentBestQuality = 0.0;
+
+ SGPropertyNode *param = fgGetNode("/sim/airport/runways/search", true);
+ double lengthWeight = param->getDoubleValue("length-weight", 0.01);
+ double widthWeight = param->getDoubleValue("width-weight", 0.01);
+ double surfaceWeight = param->getDoubleValue("surface-weight", 10);
+ double deviationWeight = param->getDoubleValue("deviation-weight", 1);
+
+ for (; it != mRunways.end(); ++it) {
+ double good = it->score(lengthWeight, widthWeight, surfaceWeight);
+
+ // first side
+ double dev = normaliseBearing(aHeading - it->_heading);
+ double bad = fabs(deviationWeight * dev) + 1e-20;
+ double quality = good / bad;
+
+ if (quality > currentBestQuality) {
+ currentBestQuality = quality;
+ result = *it;
+ }
+
+ dev = normaliseBearing(aHeading - it->_heading - 180.0);
+ bad = fabs(deviationWeight * dev) + 1e-20;
+ quality = good / bad;
+
+ if (quality > currentBestQuality) {
+ currentBestQuality = quality;
+ result = *it;
+ result._heading += 180.0;
+ result._rwy_no = FGRunway::reverseIdent(it->_rwy_no);
+ }
+ }
+
+ return result;
+}
+
+unsigned int FGAirport::numTaxiways() const
+{
+ return mTaxiways.size();
+}
+
+FGRunway FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
+{
+ assert(aIndex >= 0 && aIndex < mTaxiways.size());
+ return mTaxiways[aIndex];
+}
+
+void FGAirport::addRunway(const FGRunway& aRunway)
+{
+ if (aRunway.isTaxiway()) {
+ mTaxiways.push_back(aRunway);
+ } else {
+ mRunways.push_back(aRunway);
+ }
+}
+
+FGRunway FGAirport::getActiveRunwayForUsage() const
+{
+ static FGEnvironmentMgr* envMgr = NULL;
+ if (!envMgr) {
+ envMgr = (FGEnvironmentMgr *) globals->get_subsystem("environment");
+ }
+
+ FGEnvironment stationWeather(envMgr->getEnvironment(_location));
+
+ double windSpeed = stationWeather.get_wind_speed_kt();
+ double hdg = stationWeather.get_wind_from_heading_deg();
+ if (windSpeed <= 0.0) {
+ hdg = 270; // This forces West-facing rwys to be used in no-wind situations
+ // which is consistent with Flightgear's initial setup.
+ }
+
+ return findBestRunwayForHeading(hdg);
+}
/******************************************************************************
* FGAirportList
// add an entry to the list
-void FGAirportList::add( const string &id, const SGGeod& location, const SGGeod& tower_location,
+FGAirport* FGAirportList::add( const string &id, const SGGeod& location, const SGGeod& tower_location,
const string &name, bool has_metar, bool is_airport, bool is_seaport,
bool is_heliport)
{
airports_array.push_back( a );
SG_LOG( SG_GENERAL, SG_BULK, "Adding " << id << " pos = " << location.getLongitudeDeg()
<< ", " << location.getLatitudeDeg() << " elev = " << location.getElevationFt() );
+
+ return a;
}
#ifndef _FG_SIMPLE_HXX
#define _FG_SIMPLE_HXX
-
-#ifndef __cplusplus
-# error This library requires C++
-#endif
-
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
#include <simgear/math/point3d.hxx>
#include <simgear/compiler.h>
#include <set>
#include <vector>
-#include "runwayprefs.hxx"
-#include "parking.hxx"
-#include "groundnetwork.hxx"
-#include "dynamics.hxx"
-
-
-using std::string;
-using std::map;
-using std::set;
-using std::vector;
-
-
+#include "Airports/runways.hxx"
+// forward decls
+class FGAirportDynamics;
/***************************************************************************************
*
**************************************************************************************/
class FGAirport {
private:
- string _id;
+ std::string _id;
SGGeod _location;
SGGeod _tower_location;
- string _name;
+ std::string _name;
bool _has_metar;
bool _is_airport;
bool _is_seaport;
public:
FGAirport();
// FGAirport(const FGAirport &other);
- FGAirport(const string& id, const SGGeod& location, const SGGeod& tower, const string& name,
+ FGAirport(const std::string& id, const SGGeod& location, const SGGeod& tower,
+ const std::string& name,
bool has_metar, bool is_airport, bool is_seaport, bool is_heliport);
~FGAirport();
- const string& getId() const { return _id; }
- const string& getName() const { return _name; }
+ const std::string& getId() const { return _id; }
+ const std::string& getName() const { return _name; }
double getLongitude() const { return _location.getLongitudeDeg(); }
// Returns degrees
double getLatitude() const { return _location.getLatitudeDeg(); }
const SGGeod& getTowerLocation() const { return _tower_location; }
- void setId(const string& id) { _id = id; }
+ void setId(const std::string& id) { _id = id; }
void setMetar(bool value) { _has_metar = value; }
- FGAirportDynamics *getDynamics();
+ FGRunway getActiveRunwayForUsage() const;
+ FGAirportDynamics *getDynamics();
+
+ unsigned int numRunways() const;
+ FGRunway getRunwayByIndex(unsigned int aIndex) const;
+
+ bool hasRunwayWithIdent(const std::string& aIdent) const;
+ FGRunway getRunwayByIdent(const std::string& aIdent) const;
+ FGRunway findBestRunwayForHeading(double aHeading) const;
+
+ unsigned int numTaxiways() const;
+ FGRunway getTaxiwayByIndex(unsigned int aIndex) const;
+
+ void addRunway(const FGRunway& aRunway);
private:
+ /**
+ * Helper to locate a runway by ident
+ */
+ FGRunwayVector::const_iterator getIteratorForRunwayIdent(const std::string& aIdent, bool& aReversed) const;
+
FGAirport operator=(FGAirport &other);
FGAirport(const FGAirport&);
+
+ std::vector<FGRunway> mRunways;
+ std::vector<FGRunway> mTaxiways;
};
};
-typedef map < string, FGAirport* > airport_map;
+typedef std::map < std::string, FGAirport* > airport_map;
typedef airport_map::iterator airport_map_iterator;
typedef airport_map::const_iterator const_airport_map_iterator;
-typedef vector < FGAirport * > airport_list;
+typedef std::vector < FGAirport * > airport_list;
typedef airport_list::iterator airport_list_iterator;
typedef airport_list::const_iterator const_airport_list_iterator;
~FGAirportList();
// add an entry to the list
- void add( const string& id, const SGGeod& location, const SGGeod& tower,
- const string& name, bool has_metar, bool is_airport,
+ FGAirport* add( const std::string& id, const SGGeod& location, const SGGeod& tower,
+ const std::string& name, bool has_metar, bool is_airport,
bool is_seaport, bool is_heliport );
// search for the specified id.
// Returns NULL if unsucessfull.
- FGAirport* search( const string& id );
+ FGAirport* search( const std::string& id );
// Search for the next airport in ASCII sequence to the supplied id.
// eg. id = "KDC" or "KDCA" would both return "KDCA".
// NOTE: Numbers come prior to A-Z in ASCII sequence so id = "LD" would return "LD57", not "LDDP"
// Implementation assumes airport codes are unique.
// Returns NULL if unsucessfull.
- const FGAirport* findFirstById( const string& id, bool exact = false );
+ const FGAirport* findFirstById( const std::string& id, bool exact = false );
// search for the airport closest to the specified position
// (currently a linear inefficient search so it's probably not
/**
* Mark the specified airport record as not having metar
*/
- void no_metar( const string &id );
+ void no_metar( const std::string &id );
/**
* Mark the specified airport record as (yes) having metar
*/
- void has_metar( const string &id );
+ void has_metar( const std::string &id );
};
// find basic airport location info from airport database
-const FGAirport *fgFindAirportID( const string& id);
+const FGAirport *fgFindAirportID( const std::string& id);
// get airport elevation
-double fgGetAirportElev( const string& id );
+double fgGetAirportElev( const std::string& id );
// get airport position
-Point3D fgGetAirportPos( const string& id );
+Point3D fgGetAirportPos( const std::string& id );
#endif // _FG_SIMPLE_HXX
bool runway_instr::get_active_runway(FGRunway& runway)
{
- FGEnvironment stationweather =
- ((FGEnvironmentMgr *)globals->get_subsystem("environment"))->getEnvironment();
- double hdg = stationweather.get_wind_from_heading_deg();
- return globals->get_runways()->search(fgGetString("/sim/presets/airport-id"), int(hdg), &runway);
+ const FGAirport* apt = fgFindAirportID(fgGetString("/sim/presets/airport-id"));
+ if (!apt) return false;
+
+ runway = apt->getActiveRunwayForUsage();
+ return (!runway._rwy_no.empty());
}
else
alt_nm *= SG_METER_TO_NM;
- //Calculate distance away from runway, C = v(A²+B²)
+ //Calculate distance away from runway, C = v(A≤+B≤)
distance = sqrt(alt_nm * alt_nm + distance*distance);
if (distance < scaleDist)
glLineWidth(1.0 + ((lnScale - 1) * ((scaleDist - distance) / scaleDist)));
#include <stdio.h> // sprintf
#include <string.h>
+#include <iostream>
#include <osg/CullFace>
#include <osg/Depth>
return env;
}
+FGEnvironment
+FGEnvironmentMgr::getEnvironment(const SGGeod& aPos) const
+{
+ // Always returns the same environment
+ // for now; we'll make it interesting
+ // later.
+ FGEnvironment env = *_environment;
+ env.set_elevation_ft(aPos.getElevationFt());
+ return env;
+
+}
+
void
FGEnvironmentMgr::_update_fdm () const
{
#include <simgear/compiler.h>
#include <simgear/structure/subsystem_mgr.hxx>
+#include <simgear/math/SGMath.hxx>
#ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
virtual FGEnvironment getEnvironment (double lat, double lon,
double alt) const;
+ virtual FGEnvironment getEnvironment(const SGGeod& aPos) const;
private:
void _update_fdm () const;
bool HUD::Runway::get_active_runway(FGRunway& runway)
{
- FGEnvironment stationweather =
- ((FGEnvironmentMgr *)globals->get_subsystem("environment"))->getEnvironment();
- double hdg = stationweather.get_wind_from_heading_deg();
- return globals->get_runways()->search(fgGetString("/sim/presets/airport-id"), int(hdg), &runway);
+ const FGAirport* apt = fgFindAirportID(fgGetString("/sim/presets/airport-id"));
+ if (!apt) return false;
+
+ runway = apt->getActiveRunwayForUsage();
+ return (!runway._rwy_no.empty());
}
+
void HUD::Runway::get_rwy_points(sgdVec3 *_points3d)
{
double alt = current_aircraft.fdm_state->get_Runway_altitude() * SG_FEET_TO_METER;
alt_nm *= SG_METER_TO_NM;
- //Calculate distance away from runway, C = v(A²+B²)
+ //Calculate distance away from runway, C = v(A≤+B≤)
distance = sqrt(alt_nm * alt_nm + distance*distance);
if (distance < _scale_dist)
glLineWidth(1.0 + ((_line_scale - 1) * ((_scale_dist - distance) / _scale_dist)));
// Runways
_aptRwys.clear();
- FGRunway r;
- bool haveRwy = globals->get_runways()->search(id, &r);
- while(haveRwy && r._id == id) {
- // Insert the runway with longest at the start of the array
- for(unsigned int i = 0; i <= _aptRwys.size(); ++i) {
- if(i == _aptRwys.size()) {
- _aptRwys.push_back(r);
- break;
- } else {
- if(r._length > _aptRwys[i]._length) {
- _aptRwys.insert(_aptRwys.begin() + i, r);
- break;
- }
- }
- }
- haveRwy = globals->get_runways()->next(&r);
- }
+ const FGAirport* apt = fgFindAirportID(id);
+ assert(apt);
+
+ // build local array, longest runway first
+ for (unsigned int r=0; r<apt->numRunways(); ++r) {
+ FGRunway rwy(apt->getRunwayByIndex(r));
+ if ((r > 0) && (rwy._length > _aptRwys.front()._length)) {
+ _aptRwys.insert(_aptRwys.begin(), rwy);
+ } else {
+ _aptRwys.push_back(rwy);
+ }
+ }
+
_nRwyPages = (_aptRwys.size() + 1) / 2; // 2 runways per page.
if(_nFreqPages < 1) _nFreqPages = 1;
if(_nRwyPages < 1) _nRwyPages = 1;
#endif
#include "kln89_page_fpl.hxx"
+
#include <algorithm>
+#include <iostream>
using namespace std;
FGTextureManager::addTexture(texture_name, getTexture());
}
+void GroundRadar::addRunwayVertices(const FGRunway& aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices)
+{
+ double az1, az2, dist_m;
+ geo_inverse_wgs_84(aTowerLat, aTowerLon, aRunway._lat, aRunway._lon, &az1, &az2, &dist_m);
+
+ osg::Vec3 center = fromPolar(az1, dist_m * aScale) + osg::Vec3(256, 256, 0);
+ osg::Vec3 leftcenter = fromPolar(aRunway._heading, aRunway._length * SG_FEET_TO_METER * aScale / 2) + center;
+ osg::Vec3 lefttop = fromPolar(aRunway._heading - 90, aRunway._width * SG_FEET_TO_METER * aScale / 2) + leftcenter;
+ osg::Vec3 leftbottom = leftcenter * 2 - lefttop;
+ osg::Vec3 rightbottom = center * 2 - lefttop;
+ osg::Vec3 righttop = center * 2 - leftbottom;
+
+ aVertices->push_back(lefttop);
+ aVertices->push_back(leftbottom);
+ aVertices->push_back(rightbottom);
+ aVertices->push_back(righttop);
+}
+
void GroundRadar::updateTexture()
{
osg::ref_ptr<osg::Vec3Array> rwy_vertices = new osg::Vec3Array;
osg::ref_ptr<osg::Vec3Array> taxi_vertices = new osg::Vec3Array;
const string airport_name = _airport_node->getStringValue();
- FGRunwayList* runways = globals->get_runways();
const FGAirport* airport = fgFindAirportID(airport_name);
if (airport == 0)
const double tower_lat = tower_location.getLatitudeDeg();
const double tower_lon = tower_location.getLongitudeDeg();
double scale = SG_METER_TO_NM * 200 / _range_node->getDoubleValue();
+
+ const FGAirport* apt = fgFindAirportID(airport_name);
+ assert(apt);
- for (FGRunway runway = runways->search(airport_name); runway._id == airport_name; runway = runways->next())
+ for (unsigned int i=0; i<apt->numRunways(); ++i)
{
- double az1, az2, dist_m;
- geo_inverse_wgs_84(tower_lat, tower_lon, runway._lat, runway._lon, &az1, &az2, &dist_m);
-
- osg::Vec3 center = fromPolar(az1, dist_m * scale) + osg::Vec3(256, 256, 0);
- osg::Vec3 leftcenter = fromPolar(runway._heading, runway._length * SG_FEET_TO_METER * scale / 2) + center;
- osg::Vec3 lefttop = fromPolar(runway._heading - 90, runway._width * SG_FEET_TO_METER * scale / 2) + leftcenter;
- osg::Vec3 leftbottom = leftcenter * 2 - lefttop;
- osg::Vec3 rightbottom = center * 2 - lefttop;
- osg::Vec3 righttop = center * 2 - leftbottom;
-
- osg::Vec3Array* vertices = runway._rwy_no[0] == 'x' ? taxi_vertices.get() : rwy_vertices.get();
- vertices->push_back(lefttop);
- vertices->push_back(leftbottom);
- vertices->push_back(rightbottom);
- vertices->push_back(righttop);
+ FGRunway runway(apt->getRunwayByIndex(i));
+ addRunwayVertices(runway, tower_lat, tower_lon, scale, rwy_vertices.get());
}
-
+
+ for (unsigned int i=0; i<apt->numTaxiways(); ++i)
+ {
+ FGRunway runway(apt->getTaxiwayByIndex(i));
+ addRunwayVertices(runway, tower_lat, tower_lon, scale, taxi_vertices.get());
+ }
+
osg::Vec3Array* vertices = new osg::Vec3Array(*taxi_vertices.get());
vertices->insert(vertices->end(), rwy_vertices->begin(), rwy_vertices->end());
_geom->setVertexArray(vertices);
#include <simgear/props/props.hxx>
#include "od_gauge.hxx"
+// forward decls
+class FGRunway;
+
////////////////////////////////////////////////////////////////////////
// Built-in layer for the atc radar.
////////////////////////////////////////////////////////////////////////
protected:
void createTexture(const char* texture_name);
-
+
+ void addRunwayVertices(const FGRunway& aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices);
+
osg::ref_ptr<osg::Geometry> _geom;
SGPropertyNode_ptr _airport_node;
SGPropertyNode_ptr _range_node;
bool
MK_VIII::Mode6Handler::test_airport (const FGAirport *airport)
{
- FGRunway r;
- if (globals->get_runways()->search(airport->getId(), &r))
- do
- {
- if (test_runway(&r))
- return true;
-
- // reciprocal runway
- r._heading = get_reciprocal_heading(r._heading);
- if (test_runway(&r))
- return true;
- }
- while (globals->get_runways()->next(&r) && r._id == airport->getId());
+ for (unsigned int r=0; r<airport->numRunways(); ++r) {
+ FGRunway rwy(airport->getRunwayByIndex(r));
+
+ if (test_runway(&rwy)) return true;
+
+ // reciprocal runway
+ rwy._heading = get_reciprocal_heading(rwy._heading);
+ if (test_runway(&rwy)) return true;
+ }
return false;
}
MK_VIII::TCFHandler::select_runway (const FGAirport *airport,
FGRunway *_runway)
{
+/*
FGRunway r;
bool status = globals->get_runways()->search(airport->getId(), &r);
assert(status);
+ }
+ while (globals->get_runways()->next(&r) && r._id == airport->getId());
+ */
+
double min_diff = 360;
- do
+
+ for (unsigned int r=0; r<airport->numRunways(); ++r) {
+ FGRunway rwy(airport->getRunwayByIndex(r));
+ double diff = get_azimuth_difference(&rwy);
+ if (diff < min_diff)
+ {
+ min_diff = diff;
+ *_runway = rwy;
+ }
+
+ // reciprocal runway
+ rwy._heading = get_reciprocal_heading(rwy._heading);
+ diff = get_azimuth_difference(&rwy);
+ if (diff < min_diff)
{
- double diff;
-
- diff = get_azimuth_difference(&r);
- if (diff < min_diff)
- {
- min_diff = diff;
- *_runway = r;
- }
-
- // reciprocal runway
- r._heading = get_reciprocal_heading(r._heading);
- diff = get_azimuth_difference(&r);
- if (diff < min_diff)
- {
- min_diff = diff;
- *_runway = r;
- }
+ min_diff = diff;
+ *_runway = rwy;
}
- while (globals->get_runways()->next(&r) && r._id == airport->getId());
+ } // of airport runways iteration
}
bool
MK_VIII::TCFHandler::test_airport (const FGAirport *airport)
{
- FGRunway r;
- if (globals->get_runways()->search(airport->getId(), &r))
- do
- {
- if (r._length >= mk->conf.runway_database)
- return true;
- }
- while (globals->get_runways()->next(&r) && r._id == airport->getId());
-
+ for (unsigned int r=0; r<airport->numRunways(); ++r) {
+ if (airport->getRunwayByIndex(r)._length >= mk->conf.runway_database) {
+ return true;
+ }
+ }
+
return false;
}
#include <Airports/apt_loader.hxx>
#include <Airports/runways.hxx>
#include <Airports/simple.hxx>
+#include <Airports/dynamics.hxx>
+
#include <AIModel/AIManager.hxx>
#include <ATCDCL/ATCmgr.hxx>
#include <ATCDCL/AIMgr.hxx>
// Set current_options lon/lat given an airport id and heading (degrees)
static bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
- FGRunway r;
-
if ( id.empty() )
return false;
"Attempting to set starting position from airport code "
<< id << " heading " << tgt_hdg );
- if ( ! globals->get_runways()->search( id, (int)tgt_hdg, &r ) ) {
- SG_LOG( SG_GENERAL, SG_ALERT,
- "Failed to find a good runway for " << id << '\n' );
- return false;
- }
+ const FGAirport* apt = fgFindAirportID(id);
+ if (!apt) return false;
+ FGRunway r = apt->findBestRunwayForHeading(tgt_hdg);
fgSetString("/sim/atc/runway", r._rwy_no.c_str());
double lat2, lon2, az2;
// Set current_options lon/lat given an airport id and runway number
static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy, bool rwy_req ) {
- FGRunway r;
-
if ( id.empty() )
return false;
"Attempting to set starting position for "
<< id << ":" << rwy );
- if ( ! globals->get_runways()->search( id, rwy, &r ) ) {
- SG_LOG( SG_GENERAL, rwy_req ? SG_ALERT : SG_INFO,
+ const FGAirport* apt = fgFindAirportID(id);
+ if (!apt) {
+ SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find airport:" << id);
+ return false;
+ }
+
+ if (!apt->hasRunwayWithIdent(rwy)) {
+ SG_LOG( SG_GENERAL, rwy_req ? SG_ALERT : SG_INFO,
"Failed to find runway " << rwy <<
" at airport " << id << ". Using default runway." );
- return false;
+ return false;
}
+
+ FGRunway r(apt->getRunwayByIdent(rwy));
fgSetString("/sim/atc/runway", r._rwy_no.c_str());
double lat2, lon2, az2;
FGAirportList *airports = new FGAirportList();
globals->set_airports( airports );
- FGRunwayList *runways = new FGRunwayList();
- globals->set_runways( runways );
- fgAirportDBLoad( airports, runways, aptdb.str(), p_metar.str() );
+ fgAirportDBLoad( airports, aptdb.str(), p_metar.str() );
FGNavList *navlist = new FGNavList;
FGNavList *loclist = new FGNavList;
double threshold
= fgGetDouble( "/sim/navdb/localizers/auto-align-threshold-deg",
5.0 );
- fgNavDBAlignLOCwithRunway( runways, loclist, threshold );
+ fgNavDBAlignLOCwithRunway( airports, loclist, threshold );
}
SG_LOG(SG_GENERAL, SG_INFO, " Fixes");
current_panel( NULL ),
soundmgr( NULL ),
airports( NULL ),
- runways( NULL ),
ATC_mgr( NULL ),
AI_mgr( NULL ),
controls( NULL ),
delete soundmgr;
delete airports;
- delete runways;
delete ATC_mgr;
delete AI_mgr;
delete controls;
class SGSubsystem;
class FGAirportList;
-class FGRunwayList;
class FGAIMgr;
class FGATCMgr;
class FGAircraftModel;
// Simple Airport List
FGAirportList *airports;
- // Runway List
- FGRunwayList *runways;
-
// ATC manager
FGATCMgr *ATC_mgr;
inline FGAirportList *get_airports() const { return airports; }
inline void set_airports( FGAirportList *a ) {airports = a; }
- inline FGRunwayList *get_runways() const { return runways; }
- inline void set_runways( FGRunwayList *r ) {runways = r; }
-
inline FGATCMgr *get_ATC_mgr() const { return ATC_mgr; }
inline void set_ATC_mgr( FGATCMgr *a ) {ATC_mgr = a; }
# include <signal.h>
#endif
+#include <iostream>
+
#include <plib/netSocket.h>
#include <osg/Camera>
using namespace flightgear;
+using std::cerr;
+
// This is a record containing a bit of global housekeeping information
FGGeneral general;
#include <string.h> // strcmp()
#include <algorithm>
+#include <iostream>
#include <string>
#include <plib/ul.h>
using std::string;
using std::sort;
+using std::cout;
+using std::cerr;
+using std::endl;
#ifndef VERSION
#define VERSION "CVS "__DATE__
#include <config.h>
#endif
+#include <iostream>
#include <plib/netSocket.h>
#include <simgear/misc/stdint.hxx>
#include "multiplaymgr.hxx"
#include "mpmessages.hxx"
+using std::cerr;
+
#define MAX_PACKET_SIZE 1200
#define MAX_TEXT_SIZE 128
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/misc/strutils.hxx>
#include <Airports/runways.hxx>
#include <Airports/simple.hxx>
// it then "moves" the localizer and updates it's heading so it
// *perfectly* aligns with the runway, but is still the same distance
// from the runway threshold.
-void fgNavDBAlignLOCwithRunway( FGRunwayList *runways, FGNavList *loclist,
+void fgNavDBAlignLOCwithRunway( FGAirportList *airports, FGNavList *loclist,
double threshold ) {
nav_map_type navmap = loclist->get_navaids();
nav_list_type locs = freq->second;
nav_list_const_iterator loc = locs.begin();
while ( loc != locs.end() ) {
- string name = (*loc)->get_name();
- string::size_type pos1 = name.find(" ");
- string id = name.substr(0, pos1);
- name = name.substr(pos1+1);
- string::size_type pos2 = name.find(" ");
- string rwy = name.substr(0, pos2);
-
- FGRunway r;
- if ( runways->search(id, rwy, &r) ) {
- update_loc_position( (*loc), &r, threshold );
- }
- ++loc;
+ vector<string> parts = simgear::strutils::split((*loc)->get_name());
+ if (parts.size() < 2) {
+ SG_LOG(SG_GENERAL, SG_ALERT, "can't parse navaid " << (*loc)->get_ident()
+ << " name for airport/runway:" << (*loc)->get_name());
+ continue;
+ }
+
+ FGAirport* airport = airports->search(parts[0]);
+ if (!airport) continue; // not found
+
+ FGRunway r = airport->getRunwayByIdent(parts[1]);
+ update_loc_position( (*loc), &r, threshold );
+ ++loc;
}
++freq;
}
// it then "moves" the localizer and updates it's heading so it
// *perfectly* aligns with the runway, but is still the same distance
// from the runway threshold.
-void fgNavDBAlignLOCwithRunway( FGRunwayList *runways, FGNavList *loclist,
+void fgNavDBAlignLOCwithRunway( FGAirportList *airport, FGNavList *loclist,
double threshold );
#endif // _FG_NAVDB_HXX
string id = apt->getId();
string name = apt->getName();
-
+
// set runway hash
- FGRunwayList *rwylst = globals->get_runways();
- FGRunway rwy;
naRef rwys = naNewHash(c);
- if(rwylst->search(id, &rwy)) {
- do {
- if(rwy._id != id) break;
- if(rwy._type[0] != 'r') continue;
-
- naRef rwyid = naStr_fromdata(naNewString(c),
+ for (unsigned int r=0; r<apt->numRunways(); ++r) {
+ FGRunway rwy(apt->getRunwayByIndex(r));
+
+ naRef rwyid = naStr_fromdata(naNewString(c),
const_cast<char *>(rwy._rwy_no.c_str()),
rwy._rwy_no.length());
- naRef rwydata = naNewHash(c);
+ naRef rwydata = naNewHash(c);
#define HASHSET(s,l,n) naHash_set(rwydata, naStr_fromdata(naNewString(c),s,l),n)
- HASHSET("id", 2, rwyid);
- HASHSET("lat", 3, naNum(rwy._lat));
- HASHSET("lon", 3, naNum(rwy._lon));
- HASHSET("heading", 7, naNum(rwy._heading));
- HASHSET("length", 6, naNum(rwy._length * SG_FEET_TO_METER));
- HASHSET("width", 5, naNum(rwy._width * SG_FEET_TO_METER));
- HASHSET("threshold1", 10, naNum(rwy._displ_thresh1 * SG_FEET_TO_METER));
- HASHSET("threshold2", 10, naNum(rwy._displ_thresh2 * SG_FEET_TO_METER));
- HASHSET("stopway1", 8, naNum(rwy._stopway1 * SG_FEET_TO_METER));
- HASHSET("stopway2", 8, naNum(rwy._stopway2 * SG_FEET_TO_METER));
+ HASHSET("id", 2, rwyid);
+ HASHSET("lat", 3, naNum(rwy._lat));
+ HASHSET("lon", 3, naNum(rwy._lon));
+ HASHSET("heading", 7, naNum(rwy._heading));
+ HASHSET("length", 6, naNum(rwy._length * SG_FEET_TO_METER));
+ HASHSET("width", 5, naNum(rwy._width * SG_FEET_TO_METER));
+ HASHSET("threshold1", 10, naNum(rwy._displ_thresh1 * SG_FEET_TO_METER));
+ HASHSET("threshold2", 10, naNum(rwy._displ_thresh2 * SG_FEET_TO_METER));
+ HASHSET("stopway1", 8, naNum(rwy._stopway1 * SG_FEET_TO_METER));
+ HASHSET("stopway2", 8, naNum(rwy._stopway2 * SG_FEET_TO_METER));
#undef HASHSET
- naHash_set(rwys, rwyid, rwydata);
- } while(rwylst->next(&rwy));
+ naHash_set(rwys, rwyid, rwydata);
}
-
+
// set airport hash
naRef aptdata = naNewHash(c);
#define HASHSET(s,l,n) naHash_set(aptdata, naStr_fromdata(naNewString(c),s,l),n)