Convert FGRunway to be heap-based, and inherit FGPositioned. This is a large, ugly change, since FGRunway was essentially a plain struct, with no accessors or abstraction. This change adds various helpers and accessors to FGRunway, but doesn't change many places to use them - that will be a follow up series of patches. It's still a large patch, but outside of FGAirport and FGRunway, mostly mechanical search-and-replace.
An interesting part of this change is that reciprocal runways now exist as independent objects, rather than being created on the fly by the search methods. This simplifies some pieces of code that search for and iterate runways. For users who only want one 'end' of a runway, the new 'isReciprocal' predicate allows them to ignore the 'other' end. Current the only user of this is the 'ground-radar' ATC feature. If we had data on which runways are truly 'single-ended', it would now be trivial to use this in the airport loader to *not* create the reciprocal.
#include <string>
#include <Airports/simple.hxx>
-#include <Airports/runways.hxx>
#include <Navaids/awynet.hxx>
#include "AIBase.hxx"
using std::string;
class FGTaxiRoute;
+class FGRunway;
class FGAIFlightPlan {
void setTime(time_t st) { start_time = st; }
int getGate() const { return gateId; }
double getLeadInAngle() const { return leadInAngle; }
- const string& getRunway() const { return rwy._rwy_no; }
+ const string& getRunway() const;
+
void setRepeat(bool r) { repeat = r; }
bool getRepeat(void) const { return repeat; }
void restart(void);
bool isActive(time_t time) {return time >= this->getStartTime();}
private:
- FGRunway rwy;
+ FGRunway* rwy;
typedef vector <waypoint*> wpt_vector_type;
typedef wpt_vector_type::const_iterator wpt_vector_iterator;
rwy = apt->getRunwayByIdent(activeRunway);
// Determine the beginning of he runway
- heading = rwy._heading;
+ heading = rwy->headingDeg();
double azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- rwy._length * SG_FEET_TO_METER * 0.5 - 5.0,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
+ rwy->lengthM() * 0.5 - 5.0,
&lat2, &lon2, &az2 );
if (apt->getDynamics()->getGroundNetwork()->exists())
rwy = apt->getRunwayByIdent(activeRunway);
}
// Acceleration point, 105 meters into the runway,
- heading = rwy._heading;
+ heading = rwy->headingDeg();
double azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- rwy._length * SG_FEET_TO_METER * 0.5 - 105.0,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
+ rwy->lengthM() * 0.5 - 105.0,
&lat2, &lon2, &az2 );
wpt = new waypoint;
wpt->name = "accel";
wpt = new waypoint;
wpt->name = "SOC";
- wpt->latitude = rwy._lat;
- wpt->longitude = rwy._lon;
+ wpt->latitude = rwy->latitude();
+ wpt->longitude = rwy->longitude();
wpt->altitude = apt->getElevation()+1000;
wpt->speed = speed;
wpt->crossat = -10000;
waypoints.push_back(wpt);
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
- rwy._length * SG_FEET_TO_METER,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading,
+ rwy->lengthM(),
&lat2, &lon2, &az2 );
wpt = new waypoint;
// Tower control until they have reached the 3000 ft climb point
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading,
5000,
&lat2, &lon2, &az2 );
wpt->routeIndex = 0;
waypoints.push_back(wpt);
- // geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
+ // geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading,
// 100000,
// &lat2, &lon2, &az2 );
// wpt = new waypoint;
}
- heading = rwy._heading;
+ heading = rwy->headingDeg();
double azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
//cerr << "Creating climb at : " << rwy._id << " " << rwy._rwy_no << endl;
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading,
10*SG_NM_TO_METER,
&lat2, &lon2, &az2 );
wpt = new waypoint;
waypoints.push_back(wpt);
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading,
20*SG_NM_TO_METER,
&lat2, &lon2, &az2 );
wpt = new waypoint;
// " at airport " << arr->getId());
// exit(1);
// }
-// heading = rwy._heading;
+// heading = rwy->headingDeg();
// azimuth = heading + 180.0;
// while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
-// geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+// geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
// 110000,
// &lat2, &lon2, &az2 );
// wpt = new waypoint;
apt->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway);
rwy = apt->getRunwayByIdent(activeRunway);
- heading = rwy._heading;
+ heading = rwy->headingDeg();
azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
100000,
&lat2, &lon2, &az2 );
waypoints.push_back(wpt);
// Three thousand ft. Slowing down to 160 kts
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
8*SG_NM_TO_METER,
&lat2, &lon2, &az2 );
wpt = new waypoint;
waypoint *wpt;
- heading = rwy._heading;
+ heading = rwy->headingDeg();
azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
//Runway Threshold
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- rwy._length*0.45 * SG_FEET_TO_METER,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
+ rwy->lengthM() *0.45,
&lat2, &lon2, &az2 );
wpt = new waypoint;
wpt->name = "Threshold"; //wpt_node->getStringValue("name", "END");
waypoints.push_back(wpt);
//Full stop at the runway centerpoint
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
- rwy._length*0.45,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
+ rwy->lengthFt() *0.45,
&lat2, &lon2, &az2 );
wpt = new waypoint;
wpt->name = "Center"; //wpt_node->getStringValue("name", "END");
- wpt->latitude = rwy._lat;
- wpt->longitude = rwy._lon;
+ wpt->latitude = rwy->latitude();
+ wpt->longitude = rwy->longitude();
wpt->altitude = apt->getElevation();
wpt->speed = 30;
wpt->crossat = -10000;
wpt->routeIndex = 0;
waypoints.push_back(wpt);
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, heading,
- rwy._length*0.45 * SG_FEET_TO_METER,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), heading,
+ rwy->lengthM() *0.45,
&lat2, &lon2, &az2 );
wpt = new waypoint;
wpt->name = "Threshold"; //wpt_node->getStringValue("name", "END");
// {
// cerr << "Creating cruise to EHAM " << latitude << " " << longitude << endl;
// }
- heading = rwy._heading;
+ heading = rwy->headingDeg();
azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
arr->getDynamics()->getActiveRunway(rwyClass, 2, activeRunway);
rwy = arr->getRunwayByIdent(activeRunway);
- heading = rwy._heading;
+ heading = rwy->headingDeg();
azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
- geo_direct_wgs_84 ( 0, rwy._lat, rwy._lon, azimuth,
+ geo_direct_wgs_84 ( 0, rwy->latitude(), rwy->longitude(), azimuth,
110000,
&lat2, &lon2, &az2 );
wpt = new waypoint;
const FGAirport* apt = fgFindAirportID(id);
assert(apt);
- FGRunway runway(apt->getActiveRunwayForUsage());
+ FGRunway* runway(apt->getActiveRunwayForUsage());
- double hdg = runway._heading;
+ double hdg = runway->headingDeg();
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);
+ Point3D origin = Point3D(runway->longitude(), runway->latitude(), 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;
+ rwy.length = runway->lengthM();
+ rwy.width = runway->widthM();
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(), hdg,
// Runway stuff
// Given a Point3D (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway
-bool OnRunway(const Point3D& pt, const FGRunway& rwy) {
+bool OnRunway(const Point3D& pt, const FGRunway* rwy) {
FGATCAlignedProjection ortho;
- Point3D centre(rwy._lon, rwy._lat, 0.0); // We don't need the elev
- ortho.Init(centre, rwy._heading);
+ Point3D centre(rwy->longitude(), rwy->latitude(), 0.0); // We don't need the elev
+ ortho.Init(centre, rwy->headingDeg());
Point3D xyc = ortho.ConvertToLocal(centre);
Point3D xyp = ortho.ConvertToLocal(pt);
//cout << "Length offset = " << fabs(xyp.y() - xyc.y()) << '\n';
//cout << "Width offset = " << fabs(xyp.x() - xyc.x()) << '\n';
- if((fabs(xyp.y() - xyc.y()) < ((rwy._length/2.0) + 5.0))
- && (fabs(xyp.x() - xyc.x()) < (rwy._width/2.0))) {
+ if((fabs(xyp.y() - xyc.y()) < ((rwy->lengthFt()/2.0) + 5.0))
+ && (fabs(xyp.x() - xyc.x()) < (rwy->widthFt()/2.0))) {
return(true);
}
****************/
// Given a Point3D (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway
-bool OnRunway(const Point3D& pt, const FGRunway& rwy);
+bool OnRunway(const Point3D& pt, const FGRunway* rwy);
const FGAirport* apt = fgFindAirportID(ident);
assert(apt);
- FGRunway runway = apt->getActiveRunwayForUsage();
+ 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;
+ active_runway = runway->ident();
+ active_rw_hdg = runway->headingDeg();
+ active_rw_lon = runway->longitude();
+ active_rw_lat = runway->latitude();
+ active_rw_len = runway->lengthFt();
}
// ========================================================================
const FGAirport* apt = fgFindAirportID(ident);
assert(apt);
- string rwy_no = apt->getActiveRunwayForUsage()._rwy_no;
+ string rwy_no = apt->getActiveRunwayForUsage()->ident();
if(rwy_no != "NN") {
transmission += " / Landing_and_departing_runway ";
transmission += ConvertRwyNumToSpokenString(atoi(rwy_no.c_str()));
const FGAirport* apt = fgFindAirportID(ident);
assert(apt);
- FGRunway runway = apt->getActiveRunwayForUsage();
+ FGRunway* runway = apt->getActiveRunwayForUsage();
- activeRwy = runway._rwy_no;
- rwy.rwyID = runway._rwy_no;
+ activeRwy = runway->ident();
+ rwy.rwyID = runway->ident();
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;
+ double other_way = runway->headingDeg() - 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 origin = Point3D(runway->longitude(), runway->latitude(), aptElev);
Point3D ref = origin;
double tshlon, tshlat, tshr;
double tolon, tolat, tor;
- rwy.length = runway._length * SG_FEET_TO_METER;
+ rwy.length = runway->lengthM();
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,
+ geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), runway->headingDeg(),
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
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;
+ rwy.hdg = runway->headingDeg();
// 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
const FGAirport* apt = fgFindAirportID(ident);
assert(apt);
- FGRunway runway = apt->getActiveRunwayForUsage();
-
- //cout << "RUNWAY GOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOD\n";
+ FGRunway* runway = apt->getActiveRunwayForUsage();
- activeRwy = runway._rwy_no;
- rwy.rwyID = runway._rwy_no;
- SG_LOG(SG_ATC, SG_INFO, "Active runway for airport " << ident << " is " << activeRwy);
+ activeRwy = runway->ident();
+ rwy.rwyID = runway->ident();
+ 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;
+ double other_way = runway->headingDeg() - 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 origin = Point3D(runway->longitude(), runway->latitude(), 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;
+ rwy.length = runway->lengthM();
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,
+ geo_direct_wgs_84 ( aptElev, ref.lat(), ref.lon(), runway->headingDeg(),
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;
+ rwy.hdg = runway->headingDeg();
// 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
string line;
char tmp[2049];
tmp[2048] = 0;
- vector<FGRunway> runways;
+ vector<FGRunwayPtr> runways;
unsigned int line_id = 0;
unsigned int line_num = 0;
int surface_code = atoi( token[10].c_str() );
- FGRunway rwy(rwy_no, lon, lat, heading, length,
- width, displ_thresh1, displ_thresh2,
- stopway1, stopway2, surface_code);
+ FGRunway* rwy = new FGRunway(NULL, rwy_no, lon, lat, heading, length,
+ width, displ_thresh1, stopway1, surface_code, false);
+
+ FGRunway* reciprocal = new FGRunway(NULL, FGRunway::reverseIdent(rwy_no),
+ lon, lat, heading + 180.0, length, width,
+ displ_thresh2, stopway2, surface_code, true);
+
runways.push_back(rwy);
+ runways.push_back(reciprocal);
} else if ( line_id == 18 ) {
// beacon entry (ignore)
} else if ( line_id == 14 ) {
string FGAirportDynamics::chooseRunwayFallback()
{
- FGRunway rwy = _ap->getActiveRunwayForUsage();
- return rwy._rwy_no;
+ FGRunway* rwy = _ap->getActiveRunwayForUsage();
+ return rwy->ident();
}
void FGAirportDynamics::addParking(FGParking& park) {
stringVec *currentlyActive)
{
- FGRunway rwy;
+ FGRunway* rwy;
int activeRwys = rwyList.size(); // get the number of runways active
int nrOfPreferences;
// bool found = true;
rwy = airport->getRunwayByIdent(rwyList[j].getRwyList(i));
//cerr << "Succes" << endl;
- hdgDiff = fabs(windHeading - rwy._heading);
+ hdgDiff = fabs(windHeading - rwy->headingDeg());
//cerr << "Wind Heading: " << windHeading << "Runway Heading: " <<rwy._heading << endl;
//cerr << "Wind Speed : " << windSpeed << endl;
if (hdgDiff > 180)
rwy = airport->getRunwayByIdent(name);
//cerr << "Succes" << endl;
- hdgDiff = fabs(windHeading - rwy._heading);
+ hdgDiff = fabs(windHeading - rwy->headingDeg());
if (hdgDiff > 180)
hdgDiff = 360 - hdgDiff;
hdgDiff *= ((2*M_PI)/360.0); // convert to radians
using std::multimap;
using std::string;
-FGRunway::FGRunway()
+static FGPositioned::Type runwayTypeFromNumber(const std::string& aRwyNo)
{
+ return (aRwyNo[0] == 'x') ? FGPositioned::TAXIWAY : FGPositioned::RUNWAY;
}
-FGRunway::FGRunway(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 int surface_code)
+static std::string cleanRunwayNo(const std::string& aRwyNo)
{
- _rwy_no = rwy_no;
- if (rwy_no[0] == 'x') {
- _type = "taxiway";
- } else {
- _type = "runway";
-
+ if (aRwyNo[0] == 'x') {
+ return std::string(); // no ident for taxiways
+ }
+
+ string result(aRwyNo);
// canonicalise runway ident
- if ((rwy_no.size() == 1) || !isdigit(rwy_no[1])) {
- _rwy_no = "0" + rwy_no;
- }
+ if ((aRwyNo.size() == 1) || !isdigit(aRwyNo[1])) {
+ result = "0" + aRwyNo;
+ }
- if ((_rwy_no.size() > 2) && (_rwy_no[2] == 'x')) {
- _rwy_no = _rwy_no.substr(0, 2);
+ // trim off trailing garbage
+ if (result.size() > 2) {
+ char suffix = toupper(result[2]);
+ if (suffix == 'X') {
+ result = result.substr(0, 2);
}
}
+
+ return result;
+}
+FGRunway::FGRunway(FGAirport* aAirport, const string& rwy_no,
+ const double longitude, const double latitude,
+ const double heading, const double length,
+ const double width,
+ const double displ_thresh,
+ const double stopway,
+ const int surface_code,
+ bool reciprocal) :
+ FGPositioned(runwayTypeFromNumber(rwy_no), cleanRunwayNo(rwy_no), latitude, longitude, 0.0),
+ _airport(aAirport),
+ _reciprocal(reciprocal)
+{
+ _rwy_no = ident();
+
_lon = longitude;
_lat = latitude;
_heading = heading;
_length = length;
_width = width;
- _displ_thresh1 = displ_thresh1;
- _displ_thresh2 = displ_thresh2;
- _stopway1 = stopway1;
- _stopway2 = stopway2;
+ _displ_thresh = displ_thresh;
+ _stopway = stopway;
_surface_code = surface_code;
}
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';
+ char suffix = toupper(ident[2]);
+ if(suffix == 'L') {
+ buf[2] = 'R';
+ } else if (suffix == 'R') {
+ buf[2] = 'L';
} else {
- SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code "
- << aRunwayIdent << " passed to FGRunway::reverseIdent");
+ // something else, just copy
+ buf[2] = suffix;
}
+
+ buf[3] = 0;
}
return buf;
bool FGRunway::isTaxiway() const
{
- return (_rwy_no[0] == 'x');
+ return (type() == TAXIWAY);
+}
+
+SGGeod FGRunway::threshold() const
+{
+ return pointOnCenterline(0.0);
+}
+
+SGGeod FGRunway::reverseThreshold() const
+{
+ return pointOnCenterline(lengthM());
+}
+
+SGGeod FGRunway::displacedThreshold() const
+{
+ return pointOnCenterline(_displ_thresh * SG_FEET_TO_METER);
+}
+
+SGGeod FGRunway::pointOnCenterline(double aOffset) const
+{
+ SGGeod result;
+ double dummyAz2;
+ double halfLengthMetres = lengthM() * 0.5;
+
+ SGGeodesy::direct(mPosition, _heading,
+ aOffset - halfLengthMetres,
+ result, dummyAz2);
+ return result;
}
#include <simgear/compiler.h>
+#include <simgear/math/sg_geodesy.hxx>
+
+#include "Navaids/positioned.hxx"
+
#include <string>
-#include <vector>
-class FGRunway
-{
+// forward decls
+class FGAirport;
+
+class FGRunway : public FGPositioned
+{
+ FGAirport* _airport; ///< owning airport
+ bool _reciprocal;
public:
- FGRunway();
- FGRunway(const std::string& rwy_no,
+ FGRunway(FGAirport* aAirport, 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 int surface_code);
+ const double displ_thresh,
+ const double stopway,
+ const int surface_code,
+ const bool reciprocal);
/**
* given a runway identifier (06, 18L, 31R) compute the identifier for the
- * opposite heading runway (24, 36R, 13L) string.
+ * reciprocal 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;
+ /**
+ * Test if this runway is the reciprocal. This allows users who iterate
+ * over runways to avoid counting runways twice, if desired.
+ */
+ bool isReciprocal() const
+ { return _reciprocal; }
+
+ /**
+ * Test if this is a taxiway or not
+ */
bool isTaxiway() const;
+ /**
+ * Get the runway threshold point - this is syntatic sugar, equivalent to
+ * calling pointOnCenterline(0.0);
+ */
+ SGGeod threshold() const;
+
+ /**
+ * Get the (possibly displaced) threshold point.
+ */
+ SGGeod displacedThreshold() const;
+
+ /**
+ * Get the opposite threshold - this is equivalent to calling
+ * pointOnCenterline(lengthFt());
+ */
+ SGGeod reverseThreshold() const;
+
+ /**
+ * Retrieve a position on the extended runway centerline. Positive values
+ * are in the direction of the runway heading, negative values are in the
+ * opposited direction. 0.0 corresponds to the (non-displaced) threshold
+ */
+ SGGeod pointOnCenterline(double aOffset) const;
+
+ /**
+ * Runway length in ft
+ */
+ double lengthFt() const
+ { return _length; }
+
+ double lengthM() const
+ { return _length * SG_FEET_TO_METER; }
+
+ double widthFt() const
+ { return _width; }
+
+ double widthM() const
+ { return _width * SG_FEET_TO_METER; }
+
+ /**
+ * Runway heading in degrees.
+ */
+ double headingDeg() const
+ { return _heading; }
+
+ /**
+ * Airport this runway is located at
+ */
+ FGAirport* airport() const
+ { return _airport; }
+
+ // FIXME - should die once airport / runway creation is cleaned up
+ void setAirport(FGAirport* aAirport)
+ { _airport = aAirport; }
+
std::string _rwy_no;
- std::string _type; // runway / taxiway
double _lon;
double _lat;
+ double _displ_thresh;
+ double _stopway;
+
double _heading;
double _length;
double _width;
- double _displ_thresh1;
- double _displ_thresh2;
- double _stopway1;
- double _stopway2;
-
+
int _surface_code;
};
-typedef std::vector<FGRunway> FGRunwayVector;
-
#endif // _FG_RUNWAYS_HXX
#include <Main/fg_props.hxx>
#include <Airports/runways.hxx>
#include <Airports/dynamics.hxx>
+#include <Airports/runways.hxx>
#include <string>
return mRunways.size();
}
-FGRunway FGAirport::getRunwayByIndex(unsigned int aIndex) const
+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());
+ return (getIteratorForRunwayIdent(aIdent) != mRunways.end());
}
-FGRunway FGAirport::getRunwayByIdent(const string& aIdent) const
+FGRunway* FGAirport::getRunwayByIdent(const string& aIdent) const
{
- bool reversed;
- FGRunwayVector::const_iterator it = getIteratorForRunwayIdent(aIdent, reversed);
+ Runway_iterator it = getIteratorForRunwayIdent(aIdent);
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;
+ return *it;
}
-FGRunwayVector::const_iterator
-FGAirport::getIteratorForRunwayIdent(const string& aIdent, bool& aReversed) const
+FGAirport::Runway_iterator
+FGAirport::getIteratorForRunwayIdent(const string& aIdent) 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();
-
+ Runway_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;
+ if ((*it)->ident() == ident) {
return it;
}
}
return aBearing;
}
-FGRunway FGAirport::findBestRunwayForHeading(double aHeading) const
+FGRunway* FGAirport::findBestRunwayForHeading(double aHeading) const
{
- FGRunwayVector::const_iterator it = mRunways.begin();
- FGRunway result;
+ Runway_iterator it = mRunways.begin();
+ FGRunway* result = NULL;
double currentBestQuality = 0.0;
SGPropertyNode *param = fgGetNode("/sim/airport/runways/search", true);
double deviationWeight = param->getDoubleValue("deviation-weight", 1);
for (; it != mRunways.end(); ++it) {
- double good = it->score(lengthWeight, widthWeight, surfaceWeight);
+ double good = (*it)->score(lengthWeight, widthWeight, surfaceWeight);
- // first side
- double dev = normaliseBearing(aHeading - it->_heading);
+ double dev = normaliseBearing(aHeading - (*it)->headingDeg());
double bad = fabs(deviationWeight * dev) + 1e-20;
double quality = good / bad;
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;
return mTaxiways.size();
}
-FGRunway FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
+FGRunway* FGAirport::getTaxiwayByIndex(unsigned int aIndex) const
{
assert(aIndex >= 0 && aIndex < mTaxiways.size());
return mTaxiways[aIndex];
}
-void FGAirport::addRunway(const FGRunway& aRunway)
+void FGAirport::addRunway(FGRunway* aRunway)
{
- if (aRunway.isTaxiway()) {
+ aRunway->setAirport(this);
+
+ if (aRunway->isTaxiway()) {
mTaxiways.push_back(aRunway);
} else {
mRunways.push_back(aRunway);
}
}
-FGRunway FGAirport::getActiveRunwayForUsage() const
+FGRunway* FGAirport::getActiveRunwayForUsage() const
{
static FGEnvironmentMgr* envMgr = NULL;
if (!envMgr) {
#ifndef _FG_SIMPLE_HXX
#define _FG_SIMPLE_HXX
-#include <simgear/math/point3d.hxx>
-
#include <simgear/compiler.h>
#include <string>
#include <set>
#include <vector>
-#include "Airports/runways.hxx"
+#include <simgear/math/point3d.hxx>
+
+#include "Navaids/positioned.hxx"
// forward decls
class FGAirportDynamics;
+class FGRunway;
+
+typedef SGSharedPtr<FGRunway> FGRunwayPtr;
/***************************************************************************************
*
void setId(const std::string& id) { _id = id; }
void setMetar(bool value) { _has_metar = value; }
- FGRunway getActiveRunwayForUsage() const;
+ FGRunway* getActiveRunwayForUsage() const;
FGAirportDynamics *getDynamics();
unsigned int numRunways() const;
- FGRunway getRunwayByIndex(unsigned int aIndex) 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;
+ FGRunway* getRunwayByIdent(const std::string& aIdent) const;
+ FGRunway* findBestRunwayForHeading(double aHeading) const;
unsigned int numTaxiways() const;
- FGRunway getTaxiwayByIndex(unsigned int aIndex) const;
+ FGRunway* getTaxiwayByIndex(unsigned int aIndex) const;
- void addRunway(const FGRunway& aRunway);
+ void addRunway(FGRunway* aRunway);
private:
+ typedef std::vector<FGRunwayPtr>::const_iterator Runway_iterator;
+
/**
* Helper to locate a runway by ident
*/
- FGRunwayVector::const_iterator getIteratorForRunwayIdent(const std::string& aIdent, bool& aReversed) const;
+ Runway_iterator getIteratorForRunwayIdent(const std::string& aIdent) const;
FGAirport operator=(FGAirport &other);
FGAirport(const FGAirport&);
- std::vector<FGRunway> mRunways;
- std::vector<FGRunway> mTaxiways;
+ std::vector<FGRunwayPtr> mRunways;
+ std::vector<FGRunwayPtr> mTaxiways;
};
#include <GUI/new_gui.hxx> // FGFontCache
#include <Main/globals.hxx>
#include <Scenery/scenery.hxx>
+#include <Airports/runways.hxx>
#include "hud.hxx"
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include <Main/viewmgr.hxx>
-#include <Airports/runways.hxx>
#include <plib/sg.h>
+class FGRunway;
+
using std::deque;
using std::vector;
bool drawLine(const sgdVec3& a1, const sgdVec3& a2,
const sgdVec3& p1, const sgdVec3& p2);
void drawArrow();
- bool get_active_runway(FGRunway& rwy);
+ FGRunway* get_active_runway();
void get_rwy_points(sgdVec3 *points);
void setLineWidth(void);
double mm[16],pm[16], arrowScale, arrowRad, lnScale;
double scaleDist, default_pitch, default_heading;
GLint view[4];
- FGRunway runway;
+ FGRunway* runway;
FGViewer* cockpit_view;
unsigned short stippleOut, stippleCen;
bool drawIA, drawIAAlways;
void runway_instr::draw()
{
- if (!is_broken() && get_active_runway(runway)) {
+ if (!is_broken() && (runway = get_active_runway())) {
glPushAttrib(GL_LINE_STIPPLE | GL_LINE_STIPPLE_PATTERN | GL_LINE_WIDTH);
float modelView[4][4], projMat[4][4];
bool anyLines;
}
-bool runway_instr::get_active_runway(FGRunway& runway)
+FGRunway* runway_instr::get_active_runway()
{
const FGAirport* apt = fgFindAirportID(fgGetString("/sim/presets/airport-id"));
- if (!apt) return false;
+ if (!apt) return NULL;
- runway = apt->getActiveRunwayForUsage();
- return (!runway._rwy_no.empty());
+ return apt->getActiveRunwayForUsage();
}
void runway_instr::get_rwy_points(sgdVec3 *points3d)
{
double alt = current_aircraft.fdm_state->get_Runway_altitude() * SG_FEET_TO_METER;
- double length = (runway._length / 2.0) * SG_FEET_TO_METER;
- double width = (runway._width / 2.0) * SG_FEET_TO_METER;
+ double length = runway->lengthM() * 0.5;
+ double width = runway->widthM() * 0.5;
double frontLat, frontLon, backLat, backLon,az, tempLat, tempLon;
- geo_direct_wgs_84(alt, runway._lat, runway._lon, runway._heading, length, &backLat, &backLon, &az);
+ geo_direct_wgs_84(alt, runway->_lat, runway->_lon, runway->_heading, length, &backLat, &backLon, &az);
sgGeodToCart(backLat * SG_DEGREES_TO_RADIANS, backLon * SG_DEGREES_TO_RADIANS, alt, points3d[4]);
- geo_direct_wgs_84(alt, runway._lat, runway._lon, runway._heading + 180, length, &frontLat, &frontLon, &az);
+ geo_direct_wgs_84(alt, runway->_lat, runway->_lon, runway->_heading + 180, length, &frontLat, &frontLon, &az);
sgGeodToCart(frontLat * SG_DEGREES_TO_RADIANS, frontLon * SG_DEGREES_TO_RADIANS, alt, points3d[5]);
- geo_direct_wgs_84(alt, backLat, backLon, runway._heading + 90, width, &tempLat, &tempLon, &az);
+ geo_direct_wgs_84(alt, backLat, backLon, runway->_heading + 90, width, &tempLat, &tempLon, &az);
sgGeodToCart(tempLat * SG_DEGREES_TO_RADIANS, tempLon * SG_DEGREES_TO_RADIANS, alt, points3d[0]);
- geo_direct_wgs_84(alt, backLat, backLon, runway._heading - 90, width, &tempLat, &tempLon, &az);
+ geo_direct_wgs_84(alt, backLat, backLon, runway->_heading - 90, width, &tempLat, &tempLon, &az);
sgGeodToCart(tempLat * SG_DEGREES_TO_RADIANS, tempLon * SG_DEGREES_TO_RADIANS, alt, points3d[1]);
- geo_direct_wgs_84(alt, frontLat, frontLon, runway._heading - 90, width, &tempLat, &tempLon, &az);
+ geo_direct_wgs_84(alt, frontLat, frontLon, runway->_heading - 90, width, &tempLat, &tempLon, &az);
sgGeodToCart(tempLat * SG_DEGREES_TO_RADIANS, tempLon * SG_DEGREES_TO_RADIANS, alt, points3d[2]);
- geo_direct_wgs_84(alt, frontLat, frontLon, runway._heading + 90, width, &tempLat, &tempLon, &az);
+ geo_direct_wgs_84(alt, frontLat, frontLon, runway->_heading + 90, width, &tempLat, &tempLon, &az);
sgGeodToCart(tempLat * SG_DEGREES_TO_RADIANS, tempLon * SG_DEGREES_TO_RADIANS, alt, points3d[3]);
}
Point3D ac(0.0), rwy(0.0);
ac.setlat(current_aircraft.fdm_state->get_Latitude_deg());
ac.setlon(current_aircraft.fdm_state->get_Longitude_deg());
- rwy.setlat(runway._lat);
- rwy.setlon(runway._lon);
+ rwy.setlat(runway->_lat);
+ rwy.setlon(runway->_lon);
float theta = GetHeadingFromTo(ac, rwy);
theta -= fgGetDouble("/orientation/heading-deg");
theta = -theta;
{
//Calculate the distance from the runway, A
double course, distance;
- calc_gc_course_dist(Point3D(runway._lon * SGD_DEGREES_TO_RADIANS,
- runway._lat * SGD_DEGREES_TO_RADIANS, 0.0),
+ calc_gc_course_dist(Point3D(runway->longitude() * SGD_DEGREES_TO_RADIANS,
+ runway->latitude() * SGD_DEGREES_TO_RADIANS, 0.0),
Point3D(current_aircraft.fdm_state->get_Longitude(),
current_aircraft.fdm_state->get_Latitude(), 0.0 ),
&course, &distance);
bool boundOutsidePoints(sgdVec3& v, sgdVec3& m);
bool drawLine(const sgdVec3& a1, const sgdVec3& a2, const sgdVec3& p1, const sgdVec3& p2);
void drawArrow();
- bool get_active_runway(FGRunway& rwy);
+ FGRunway* get_active_runway();
void get_rwy_points(sgdVec3 *points);
void setLineWidth();
double _default_pitch;
double _default_heading;
GLint _view[4];
- FGRunway _runway;
+ FGRunway* _runway;
FGViewer* _cockpit_view;
unsigned short _stipple_out; // stipple pattern of the outline of the runway
unsigned short _stipple_center; // stipple pattern of the center line of the runway
void HUD::Runway::draw()
{
- if (!get_active_runway(_runway))
+ _runway = get_active_runway();
+ if (!_runway)
return;
glPushAttrib(GL_LINE_STIPPLE | GL_LINE_STIPPLE_PATTERN | GL_LINE_WIDTH);
}
-bool HUD::Runway::get_active_runway(FGRunway& runway)
+FGRunway* HUD::Runway::get_active_runway()
{
const FGAirport* apt = fgFindAirportID(fgGetString("/sim/presets/airport-id"));
- if (!apt) return false;
+ if (!apt) return NULL;
- runway = apt->getActiveRunwayForUsage();
- return (!runway._rwy_no.empty());
+ return apt->getActiveRunwayForUsage();
}
void HUD::Runway::get_rwy_points(sgdVec3 *_points3d)
{
double alt = current_aircraft.fdm_state->get_Runway_altitude() * SG_FEET_TO_METER;
- double length = (_runway._length / 2.0) * SG_FEET_TO_METER;
- double width = (_runway._width / 2.0) * SG_FEET_TO_METER;
+ double length = _runway->lengthM() * 0.5;
+ double width = _runway->widthM() * 0.5;
double frontLat, frontLon, backLat, backLon,az, tempLat, tempLon;
- geo_direct_wgs_84(alt, _runway._lat, _runway._lon, _runway._heading, length, &backLat, &backLon, &az);
+ geo_direct_wgs_84(alt, _runway->latitude(), _runway->longitude(), _runway->headingDeg(), length, &backLat, &backLon, &az);
sgGeodToCart(backLat * SG_DEGREES_TO_RADIANS, backLon * SG_DEGREES_TO_RADIANS, alt, _points3d[4]);
- geo_direct_wgs_84(alt, _runway._lat, _runway._lon, _runway._heading + 180, length, &frontLat, &frontLon, &az);
+ geo_direct_wgs_84(alt, _runway->latitude(), _runway->longitude(), _runway->headingDeg() + 180, length, &frontLat, &frontLon, &az);
sgGeodToCart(frontLat * SG_DEGREES_TO_RADIANS, frontLon * SG_DEGREES_TO_RADIANS, alt, _points3d[5]);
- geo_direct_wgs_84(alt, backLat, backLon, _runway._heading + 90, width, &tempLat, &tempLon, &az);
+ geo_direct_wgs_84(alt, backLat, backLon, _runway->headingDeg() + 90, width, &tempLat, &tempLon, &az);
sgGeodToCart(tempLat * SG_DEGREES_TO_RADIANS, tempLon * SG_DEGREES_TO_RADIANS, alt, _points3d[0]);
- geo_direct_wgs_84(alt, backLat, backLon, _runway._heading - 90, width, &tempLat, &tempLon, &az);
+ geo_direct_wgs_84(alt, backLat, backLon, _runway->headingDeg() - 90, width, &tempLat, &tempLon, &az);
sgGeodToCart(tempLat * SG_DEGREES_TO_RADIANS, tempLon * SG_DEGREES_TO_RADIANS, alt, _points3d[1]);
- geo_direct_wgs_84(alt, frontLat, frontLon, _runway._heading - 90, width, &tempLat, &tempLon, &az);
+ geo_direct_wgs_84(alt, frontLat, frontLon, _runway->headingDeg() - 90, width, &tempLat, &tempLon, &az);
sgGeodToCart(tempLat * SG_DEGREES_TO_RADIANS, tempLon * SG_DEGREES_TO_RADIANS, alt, _points3d[2]);
- geo_direct_wgs_84(alt, frontLat, frontLon, _runway._heading + 90, width, &tempLat, &tempLon, &az);
+ geo_direct_wgs_84(alt, frontLat, frontLon, _runway->headingDeg() + 90, width, &tempLat, &tempLon, &az);
sgGeodToCart(tempLat * SG_DEGREES_TO_RADIANS, tempLon * SG_DEGREES_TO_RADIANS, alt, _points3d[3]);
}
Point3D ac(0.0), rwy(0.0);
ac.setlat(current_aircraft.fdm_state->get_Latitude_deg());
ac.setlon(current_aircraft.fdm_state->get_Longitude_deg());
- rwy.setlat(_runway._lat);
- rwy.setlon(_runway._lon);
+ rwy.setlat(_runway->latitude());
+ rwy.setlon(_runway->longitude());
float theta = GetHeadingFromTo(ac, rwy);
theta -= fgGetDouble("/orientation/heading-deg");
theta = -theta;
{
//Calculate the distance from the runway, A
double course, distance;
- calc_gc_course_dist(Point3D(_runway._lon * SGD_DEGREES_TO_RADIANS,
- _runway._lat * SGD_DEGREES_TO_RADIANS, 0.0),
+ calc_gc_course_dist(Point3D(_runway->longitude() * SGD_DEGREES_TO_RADIANS,
+ _runway->latitude() * SGD_DEGREES_TO_RADIANS, 0.0),
Point3D(current_aircraft.fdm_state->get_Longitude(),
current_aircraft.fdm_state->get_Latitude(), 0.0 ),
&course, &distance);
#include "kln89_page_apt.hxx"
#include <ATCDCL/commlist.hxx>
#include <Main/globals.hxx>
+#include <Airports/runways.hxx>
+
// This function is copied from Airports/runways.cxx
// TODO - Make the original properly available and remove this instance!!!!
// I guess we can make a heuristic guess as to fuel availability from the runway sizes
// For now assume that airports with asphalt or concrete runways will have at least 100L,
// and that runways over 4000ft will have JET.
- if(_aptRwys[0]._surface_code <= 2) {
- if(_aptRwys[0]._length >= 4000) {
+ if(_aptRwys[0]->_surface_code <= 2) {
+ if(_aptRwys[0]->lengthFt() >= 4000) {
_kln89->DrawText("JET 100L", 2, 0, 1);
} else {
_kln89->DrawText("100L", 2, 0, 1);
string s;
if(i < _aptRwys.size()) {
// Rwy No.
- string s = _aptRwys[i]._rwy_no;
+ string s = _aptRwys[i]->ident();
_kln89->DrawText(s, 2, 9, 3);
_kln89->DrawText("/", 2, 12, 3);
_kln89->DrawText(GetReverseRunwayNo(s), 2, 13, 3);
// Length
- s = GPSitoa(int(float(_aptRwys[i]._length) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
+ s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
_kln89->DrawText(s, 2, 5 - s.size(), 2);
_kln89->DrawText((_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m"), 2, 5, 2);
// Surface
// TODO - why not store these strings as an array?
- switch(_aptRwys[i]._surface_code) {
+ switch(_aptRwys[i]->_surface_code) {
case 1:
// Asphalt - fall through
case 2:
i++;
if(i < _aptRwys.size()) {
// Rwy No.
- string s = _aptRwys[i]._rwy_no;
+ string s = _aptRwys[i]->ident();
_kln89->DrawText(s, 2, 9, 1);
_kln89->DrawText("/", 2, 12, 1);
_kln89->DrawText(GetReverseRunwayNo(s), 2, 13, 1);
// Length
- s = GPSitoa(int(float(_aptRwys[i]._length) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
+ s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
_kln89->DrawText(s, 2, 5 - s.size(), 0);
_kln89->DrawText((_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m"), 2, 5, 0);
// Surface
// TODO - why not store these strings as an array?
- switch(_aptRwys[i]._surface_code) {
+ switch(_aptRwys[i]->_surface_code) {
case 1:
// Asphalt - fall through
case 2:
// 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)) {
+ FGRunway* rwy(apt->getRunwayByIndex(r));
+ if ((r > 0) && (rwy->lengthFt() > _aptRwys.front()->lengthFt())) {
_aptRwys.insert(_aptRwys.begin(), rwy);
} else {
_aptRwys.push_back(rwy);
#include "kln89.hxx"
-#include <Airports/runways.hxx>
+class FGRunway;
struct AptFreq {
string service;
string _save_apt_id;
const FGAirport* ap;
- vector<FGRunway> _aptRwys;
+ vector<FGRunway*> _aptRwys;
vector<AptFreq> _aptFreqs;
iap_list_type _iaps;
FGTextureManager::addTexture(texture_name, getTexture());
}
-void GroundRadar::addRunwayVertices(const FGRunway& aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices)
+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);
+ geo_inverse_wgs_84(aTowerLat, aTowerLon, aRunway->latitude(), aRunway->longitude(), &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 leftcenter = fromPolar(aRunway->headingDeg(), aRunway->lengthM() * aScale / 2) + center;
+ osg::Vec3 lefttop = fromPolar(aRunway->headingDeg() - 90, aRunway->widthM() * aScale / 2) + leftcenter;
osg::Vec3 leftbottom = leftcenter * 2 - lefttop;
osg::Vec3 rightbottom = center * 2 - lefttop;
osg::Vec3 righttop = center * 2 - leftbottom;
for (unsigned int i=0; i<apt->numRunways(); ++i)
{
- FGRunway runway(apt->getRunwayByIndex(i));
+ FGRunway* runway(apt->getRunwayByIndex(i));
+ if (runway->isReciprocal()) continue;
+
addRunwayVertices(runway, tower_lat, tower_lon, scale, rwy_vertices.get());
}
for (unsigned int i=0; i<apt->numTaxiways(); ++i)
{
- FGRunway runway(apt->getTaxiwayByIndex(i));
+ FGRunway* runway(apt->getTaxiwayByIndex(i));
addRunwayVertices(runway, tower_lat, tower_lon, scale, taxi_vertices.get());
}
protected:
void createTexture(const char* texture_name);
- void addRunwayVertices(const FGRunway& aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices);
+ void addRunwayVertices(const FGRunway* aRunway, double aTowerLat, double aTowerLon, double aScale, osg::Vec3Array* aVertices);
osg::ref_ptr<osg::Geometry> _geom;
SGPropertyNode_ptr _airport_node;
MK_VIII::Mode6Handler::test_airport (const FGAirport *airport)
{
for (unsigned int r=0; r<airport->numRunways(); ++r) {
- FGRunway rwy(airport->getRunwayByIndex(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;
+ 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;
for (unsigned int r=0; r<airport->numRunways(); ++r) {
- FGRunway rwy(airport->getRunwayByIndex(r));
- double diff = get_azimuth_difference(&rwy);
+ 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)
- {
- min_diff = diff;
- *_runway = rwy;
+ _runway = rwy;
}
} // of airport runways iteration
}
bool MK_VIII::TCFHandler::AirportFilter::pass(FGAirport *a)
{
for (unsigned int r=0; r<a->numRunways(); ++r) {
- if (a->getRunwayByIndex(r)._length >= mk->conf.runway_database) {
+ if (a->getRunwayByIndex(r)->lengthFt() >= mk->conf.runway_database) {
return true;
}
}
has_runway = true;
- FGRunway _runway;
- select_runway(airport, &_runway);
+ FGRunway* _runway;
+ select_runway(airport, _runway);
- runway.center.latitude = _runway._lat;
- runway.center.longitude = _runway._lon;
+ runway.center.latitude = _runway->latitude();
+ runway.center.longitude = _runway->longitude();
runway.elevation = airport->getElevation();
- double half_length_m = _runway._length / 2 * SG_FEET_TO_METER;
+ double half_length_m = _runway->lengthM() * 0.5;
runway.half_length = half_length_m * SG_METER_TO_NM;
// b3 ________________ b0
// b2 b1
// get heading to runway threshold (h0) and end (h1)
- runway.edges[0].heading = _runway._heading;
- runway.edges[1].heading = get_reciprocal_heading(_runway._heading);
+ runway.edges[0].heading = _runway->headingDeg();
+ runway.edges[1].heading = get_reciprocal_heading(_runway->headingDeg());
double az;
&runway.edges[1].position.longitude,
&az);
- double half_width_m = _runway._width / 2 * SG_FEET_TO_METER;
+ double half_width_m = _runway->widthM() * 0.5;
// get position of threshold bias area edges (b0 and b1)
get_bias_area_edges(&runway.edges[0].position,
const FGAirport* apt = fgFindAirportID(id);
if (!apt) return false;
- FGRunway r = apt->findBestRunwayForHeading(tgt_hdg);
- fgSetString("/sim/atc/runway", r._rwy_no.c_str());
+ FGRunway* r = apt->findBestRunwayForHeading(tgt_hdg);
+ fgSetString("/sim/atc/runway", r->ident().c_str());
double lat2, lon2, az2;
- double heading = r._heading;
+ double heading = r->headingDeg();
double azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
- SG_LOG( SG_GENERAL, SG_INFO,
- "runway = " << r._lon << ", " << r._lat
- << " length = " << r._length * SG_FEET_TO_METER
- << " heading = " << azimuth );
-
- geo_direct_wgs_84 ( 0, r._lat, r._lon, azimuth, r._length * SG_FEET_TO_METER * 0.5
+ geo_direct_wgs_84 ( 0, r->latitude(), r->longitude(), azimuth, r->lengthM() * 0.5
- fgGetDouble("/sim/airport/runways/start-offset-m", 5.0),
&lat2, &lon2, &az2 );
return false;
}
- FGRunway r(apt->getRunwayByIdent(rwy));
- fgSetString("/sim/atc/runway", r._rwy_no.c_str());
+ FGRunway* r(apt->getRunwayByIdent(rwy));
+ fgSetString("/sim/atc/runway", r->ident().c_str());
double lat2, lon2, az2;
- double heading = r._heading;
+ double heading = r->headingDeg();
double azimuth = heading + 180.0;
while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
- SG_LOG( SG_GENERAL, SG_INFO,
- "runway = " << r._lon << ", " << r._lat
- << " length = " << r._length * SG_FEET_TO_METER
- << " heading = " << azimuth );
-
- geo_direct_wgs_84 ( 0, r._lat, r._lon, azimuth, r._length * SG_FEET_TO_METER * 0.5
+ geo_direct_wgs_84 ( 0, r->latitude(), r->longitude(), azimuth, r->lengthM() * 0.5
- fgGetDouble("/sim/airport/runways/start-offset-m", 5.0),
&lat2, &lon2, &az2 );
static void update_loc_position( FGNavRecord *loc, FGRunway *rwy,
double threshold )
{
- double hdg = rwy->_heading;
+ double hdg = rwy->headingDeg();
hdg += 180.0;
if ( hdg > 360.0 ) {
hdg -= 360.0;
// calculate runway threshold point
double thresh_lat, thresh_lon, return_az;
- geo_direct_wgs_84 ( 0.0, rwy->_lat, rwy->_lon, hdg,
- rwy->_length/2.0 * SG_FEET_TO_METER,
+ geo_direct_wgs_84 ( 0.0, rwy->latitude(), rwy->longitude(), hdg,
+ rwy->lengthM() * 0.5,
&thresh_lat, &thresh_lon, &return_az );
// cout << "Threshold = " << thresh_lat << "," << thresh_lon << endl;
// cout << "orig heading = " << loc->get_multiuse() << endl;
// cout << "new heading = " << rwy->_heading << endl;
- double hdg_diff = loc->get_multiuse() - rwy->_heading;
+ double hdg_diff = loc->get_multiuse() - rwy->headingDeg();
// clamp to [-180.0 ... 180.0]
if ( hdg_diff < -180.0 ) {
if ( fabs(hdg_diff) <= threshold ) {
loc->set_lat( nloc_lat );
loc->set_lon( nloc_lon );
- loc->set_multiuse( rwy->_heading );
+ loc->set_multiuse( rwy->headingDeg() );
}
}
FGAirport* airport = airports->search(parts[0]);
if (!airport) continue; // not found
- FGRunway r = airport->getRunwayByIdent(parts[1]);
- update_loc_position( (*loc), &r, threshold );
+ FGRunway* r = airport->getRunwayByIdent(parts[1]);
+ update_loc_position( (*loc), r, threshold );
++loc;
}
++freq;
// set runway hash
naRef rwys = naNewHash(c);
for (unsigned int r=0; r<apt->numRunways(); ++r) {
- FGRunway rwy(apt->getRunwayByIndex(r));
+ FGRunway* rwy(apt->getRunwayByIndex(r));
naRef rwyid = naStr_fromdata(naNewString(c),
- const_cast<char *>(rwy._rwy_no.c_str()),
- rwy._rwy_no.length());
+ const_cast<char *>(rwy->ident().c_str()),
+ rwy->ident().length());
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("lat", 3, naNum(rwy->latitude()));
+ HASHSET("lon", 3, naNum(rwy->longitude()));
+ HASHSET("heading", 7, naNum(rwy->headingDeg()));
+ HASHSET("length", 6, naNum(rwy->lengthM()));
+ HASHSET("width", 5, naNum(rwy->widthM()));
+ HASHSET("threshold1", 10, naNum(rwy->_displ_thresh * SG_FEET_TO_METER));
+ HASHSET("stopway1", 8, naNum(rwy->_stopway * SG_FEET_TO_METER));
#undef HASHSET
naHash_set(rwys, rwyid, rwydata);
}