From 13bb01a70e9e905764d5174540725eade5df12d6 Mon Sep 17 00:00:00 2001
From: curt <curt>
Date: Sun, 17 Nov 2002 04:04:21 +0000
Subject: [PATCH] Added a --runway= option which can be used in conjunction
 with the --airport= option to specify a starting airport + specific runway. 
 If you don't specify a runway, you get the one that's closest to your
 specified (or default) heading.

---
 src/Main/fg_init.cxx | 194 +++++++++++++++++++++++++++++++++++++------
 src/Main/options.cxx |   5 +-
 2 files changed, 174 insertions(+), 25 deletions(-)

diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx
index e876fd6a3..ac84226de 100644
--- a/src/Main/fg_init.cxx
+++ b/src/Main/fg_init.cxx
@@ -647,16 +647,6 @@ static bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
                 "Attempting to set starting position from runway code "
                 << id << " heading " << tgt_hdg );
 
-        // SGPath inpath( globals->get_fg_root() );
-        // inpath.append( "Airports" );
-        // inpath.append( "apt_simple" );
-        // airports.load( inpath.c_str() );
-
-        // SGPath outpath( globals->get_fg_root() );
-        // outpath.append( "Airports" );
-        // outpath.append( "simple.gdbm" );
-        // airports.dump_gdbm( outpath.c_str() );
-
         if ( ! runways.search( id, &r ) ) {
             SG_LOG( SG_GENERAL, SG_ALERT,
                     "Failed to find " << id << " in database." );
@@ -756,6 +746,144 @@ static bool fgSetPosFromAirportIDandHdg( const string& id, double tgt_hdg ) {
 }
 
 
+// Set current_options lon/lat given an airport id and heading (degrees)
+static bool fgSetPosFromAirportIDandRwy( const string& id, const string& rwy ) {
+    FGRunway r;
+    FGRunway found_r;
+    double heading = 0.0;
+    string runway;
+
+    // standardize input number
+    string tmp = rwy.substr(1, 1);
+    if ( tmp == "L" || tmp == "R" || tmp == "C" ) {
+        runway = "0";
+        runway += rwy;
+    } else {
+        runway = rwy;
+    }
+
+    if ( id.length() ) {
+        // set initial position from runway and heading
+
+        SGPath path( globals->get_fg_root() );
+        path.append( "Airports" );
+        path.append( "runways.mk4" );
+        FGRunways runways( path.c_str() );
+
+        SG_LOG( SG_GENERAL, SG_INFO,
+                "Attempting to set starting position for "
+                << id << ":" << runway );
+
+        if ( ! runways.search( id, &r ) ) {
+            SG_LOG( SG_GENERAL, SG_ALERT,
+                    "Failed to find " << id << " in database." );
+            return false;
+        }
+
+        while ( r.id == id ) {
+            // forward direction
+            if ( r.rwy_no == runway ) {
+                found_r = r;
+                heading = r.heading;
+                SG_LOG( SG_GENERAL, SG_INFO,
+                        "Runway " << r.rwy_no << " heading = " << heading );
+            }
+
+            // calculate reciprocal runway number
+            string snum = r.rwy_no;
+            int len = snum.length();
+            string letter = "";
+            string rev_letter = "";
+            int i;
+            for ( i = 0; i < len; ++i ) {
+                string tmp = snum.substr(i, 1);
+                if ( tmp == "L" ) {
+                    letter = "L";
+                    rev_letter = "R";
+                } else if ( tmp == "R" ) {
+                    letter = "R";
+                    rev_letter = "L";
+                } else if ( tmp == "C" ) {
+                    letter == "C";
+                    rev_letter = "C";
+                }
+            }
+            for ( i = 0; i < len; ++i ) {
+                string tmp = snum.substr(i, 1);
+                if ( tmp == "L" || tmp == "R" || tmp == "C" || tmp == " " ) {
+                    snum = snum.substr(0, i);
+                }
+            }
+            SG_LOG(SG_GENERAL, SG_DEBUG, "Runway num = '" << snum << "'");
+            int num = atoi( snum.c_str() ) + 18;
+            while ( num > 36 ) { num -= 36; }
+            while ( num <= 0 ) { num += 36; }
+
+            char recip_no[10];
+            snprintf( recip_no, 10, "%02d%s", num, rev_letter.c_str() );
+
+            // reverse direction
+            if ( (string)recip_no == runway ) {
+                found_r = r;
+                heading = r.heading + 180;
+                while ( heading > 360.0 ) { heading -= 360; }
+                SG_LOG( SG_GENERAL, SG_INFO,
+                        "Runway " << r.rwy_no << " heading = " << heading );
+            }
+
+            runways.next( &r );
+        }
+    } else {
+        return false;
+    }
+
+    double lat2, lon2, az2;
+    double azimuth = heading + 180.0;
+    while ( azimuth >= 360.0 ) { azimuth -= 360.0; }
+
+    SG_LOG( SG_GENERAL, SG_INFO,
+            "runway =  " << found_r.lon << ", " << found_r.lat
+            << " length = " << found_r.length * SG_FEET_TO_METER * 0.5 
+            << " heading = " << azimuth );
+    
+    geo_direct_wgs_84 ( 0, found_r.lat, found_r.lon, 
+                        azimuth, found_r.length * SG_FEET_TO_METER * 0.5 - 5.0,
+                        &lat2, &lon2, &az2 );
+
+    if ( fabs( fgGetDouble("/sim/presets/offset-distance") ) > SG_EPSILON ) {
+        double olat, olon;
+        double odist = fgGetDouble("/sim/presets/offset-distance");
+        odist *= SG_NM_TO_METER;
+        double oaz = azimuth;
+        if ( fabs(fgGetDouble("/sim/presets/offset-azimuth")) > SG_EPSILON ) {
+            oaz = fgGetDouble("/sim/presets/offset-azimuth") + 180;
+        }
+        while ( oaz >= 360.0 ) { oaz -= 360.0; }
+        geo_direct_wgs_84 ( 0, lat2, lon2, oaz, odist, &olat, &olon, &az2 );
+        lat2=olat;
+        lon2=olon;
+    }
+
+    // presets
+    fgSetDouble("/sim/presets/longitude-deg",  lon2 );
+    fgSetDouble("/sim/presets/latitude-deg",  lat2 );
+    fgSetDouble("/sim/presets/heading-deg", heading );
+
+    // other code depends on the actual values being set ...
+    fgSetDouble("/position/longitude-deg",  lon2 );
+    fgSetDouble("/position/latitude-deg",  lat2 );
+    fgSetDouble("/orientation/heading-deg", heading );
+
+    SG_LOG( SG_GENERAL, SG_INFO,
+            "Position for " << id << " is ("
+            << lon2 << ", "
+            << lat2 << ") new heading is "
+            << heading );
+
+    return true;
+}
+
+
 static void fgSetDistOrAltFromGlideSlope() {
     double gs = fgGetDouble("/sim/presets/glideslope");
     double od = fgGetDouble("/sim/presets/offset-distance");
@@ -786,8 +914,11 @@ static void fgSetDistOrAltFromGlideSlope() {
 
 // Set the initial position based on presets (or defaults)
 bool fgInitPosition() {
-    // Calculate offset-distance or altitude relative to glide slope
-    // if either was not specified.
+    bool set_pos = false;
+
+    // If glideslope is specified, then calculate offset-distance or
+    // altitude relative to glide slope if either of those was not
+    // specified.
     fgSetDistOrAltFromGlideSlope();
 
     // If we have an explicit, in-range lon/lat, don't change it, just use it.
@@ -801,25 +932,40 @@ bool fgInitPosition() {
     if ( lon_deg >= -180.0 && lon_deg <= 180.0
          && lat_deg >= -90.0 && lat_deg <= 90.0 )
     {
-        // valid lon/lat specified, use it.
-    } else {
-        string apt = fgGetString("/sim/presets/airport-id");
-        double hdg = fgGetDouble("/sim/presets/heading-deg");
-        if ( !apt.empty() ) {
-            // An airport id is requested, set position from that.
-            fgSetPosFromAirportIDandHdg( apt, hdg );
+        set_pos = true;
+    }
 
+    string apt = fgGetString("/sim/presets/airport-id");
+    string rwy_no = fgGetString("/sim/presets/runway");
+    double hdg = fgGetDouble("/sim/presets/heading-deg");
+    if ( !set_pos && !apt.empty() && !rwy_no.empty() ) {
+        // An airport + runway is requested
+        if ( fgSetPosFromAirportIDandRwy( apt, rwy_no ) ) {
             // set tower position (a little off the heading for single
             // runway airports)
             fgSetTowerPosFromAirportID( apt, hdg );
-        } else {
-            // No lon/lat specified, no airport specified, default to
-            // middle of KSFO field.
-            fgSetDouble("/sim/presets/longitude-deg", -122.374843);
-            fgSetDouble("/sim/presets/latitude-deg", 37.619002);
+
+            set_pos = true;
         }
     }
 
+    if ( !set_pos && !apt.empty() ) {
+        if ( fgSetPosFromAirportIDandHdg( apt, hdg ) ) {
+            // set tower position (a little off the heading for single
+            // runway airports)
+            fgSetTowerPosFromAirportID( apt, hdg );
+
+            set_pos = true;
+        }
+    }
+
+    if ( !set_pos ) {
+        // No lon/lat specified, no airport specified, default to
+        // middle of KSFO field.
+        fgSetDouble("/sim/presets/longitude-deg", -122.374843);
+        fgSetDouble("/sim/presets/latitude-deg", 37.619002);
+    }
+
     fgSetDouble( "/position/longitude-deg",
                  fgGetDouble("/sim/presets/longitude-deg") );
     fgSetDouble( "/position/latitude-deg",
diff --git a/src/Main/options.cxx b/src/Main/options.cxx
index b389ab6a0..7a7eb7f44 100644
--- a/src/Main/options.cxx
+++ b/src/Main/options.cxx
@@ -681,9 +681,12 @@ parse_option (const string& arg)
 	fgSetBool("/sim/sound/audible", false);
     } else if ( arg == "--enable-sound" ) {
 	fgSetBool("/sim/sound/audible", true);
+    } else if ( arg.find( "--airport=") == 0 ) {
+	fgSetString("/sim/presets/airport-id", arg.substr(10).c_str());
     } else if ( arg.find( "--airport-id=") == 0 ) {
-				// NB: changed property name!!!
 	fgSetString("/sim/presets/airport-id", arg.substr(13).c_str());
+    } else if ( arg.find( "--runway=") == 0 ) {
+	fgSetString("/sim/presets/runway", arg.substr(9).c_str());
     } else if ( arg.find( "--offset-distance=") == 0 ) {
 	fgSetDouble("/sim/presets/offset-distance", atof(arg.substr(18)));
     } else if ( arg.find( "--offset-azimuth=") == 0 ) {