X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FATCDCL%2FATCutils.cxx;h=313405e21bdb7cd9b18e68274c4c463f96ee97f3;hb=1c5eb0fb3e66c5c3bcc021310c97ea6d208c4b84;hp=20460524e4acd4adc92ab115c4cd152878c933c7;hpb=0c5e9f46e79bb7ed991aa1fda5c382308353824e;p=flightgear.git diff --git a/src/ATCDCL/ATCutils.cxx b/src/ATCDCL/ATCutils.cxx index 20460524e..313405e21 100644 --- a/src/ATCDCL/ATCutils.cxx +++ b/src/ATCDCL/ATCutils.cxx @@ -24,13 +24,10 @@ #include -#include -#include +#include #include #include #include -#include -//#include #include #include
@@ -38,7 +35,16 @@ #include "ATCutils.hxx" #include "ATCProjection.hxx" -static const string nums[10] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "niner"}; +static const string nums[10] = {"zero", "one", "two", "three", "four", + "five", "six", "seven", "eight", "niner"}; + +static const string letters[LTRS] = { + "alpha", "bravo", "charlie", "delta", "echo", + "foxtrot", "golf", "hotel", "india", "juliet", + "kilo", "lima", "mike", "november", "oscar", + "papa", "quebec", "romeo", "sierra", "tango", + "uniform", "victor", "whiskey", "xray", "yankee", "zulu" +}; // Convert any number to spoken digits string ConvertNumToSpokenDigits(const string &n) { @@ -62,101 +68,50 @@ string ConvertNumToSpokenDigits(const string &n) { return(str); } - -// Convert an integer to spoken digits -string ConvertNumToSpokenDigits(int n) { +// Convert an integer to a decimal numeral string +string decimalNumeral(const int& n) { std::ostringstream buf; buf << n; - return(ConvertNumToSpokenDigits(buf.str())); + return buf.str(); } - -// Convert a 2 digit rwy number to a spoken-style string -string ConvertRwyNumToSpokenString(int n) { - // Basic error/sanity checking - while(n < 0) { - n += 36; - } - while(n > 36) { - n -= 36; - } - if(n == 0) { - n = 36; // Is this right? - } - - string str = ""; - int index = n/10; - str += nums[index]; - n -= (index * 10); - //str += "-"; - str += " "; //Changed this for the benefit of the voice token parser - prefer the "-" in the visual output though. - str += nums[n]; - return(str); +// Convert an integer to spoken digits +string ConvertNumToSpokenDigits(const int& n) { + return ConvertNumToSpokenDigits(decimalNumeral(n)); } -// Assumes we get a two-digit string optionally appended with L, R or C -// eg 01 07L 29R 36 + +// Assumes we get a string of digits optionally appended with L, R or C +// eg 1 7L 29R 36 // Anything else is not guaranteed to be handled correctly! -string ConvertRwyNumToSpokenString(const string &s) { - if(s.size() < 3) { - return(ConvertRwyNumToSpokenString(atoi(s.c_str()))); - } else { - string r = ConvertRwyNumToSpokenString(atoi(s.substr(0,2).c_str())); - if(s.substr(2,1) == "L") { - r += " left"; - } else if(s.substr(2,1) == "R") { - r += " right"; - } else if(s.substr(2,1) == "C") { - r += " center"; - } else { - SG_LOG(SG_ATC, SG_WARN, "WARNING: Unknown suffix " << s.substr(2,1) << " from runway ID " << s << " in ConvertRwyNumToSpokenString(...)"); - } - return(r); - } +string ConvertRwyNumToSpokenString(const string &rwy) { + string rslt; + for (size_t ii = 0; ii < rwy.length(); ii++){ + if (rslt.length()) rslt += " "; + string ch = rwy.substr(ii,1); + if (isdigit(ch[0])) rslt += ConvertNumToSpokenDigits(atoi(ch.c_str())); + else if (ch == "R") rslt += "right"; + else if (ch == "C") rslt += "center"; + else if (ch == "L") rslt += "left"; + else { + rslt += GetPhoneticLetter(ch[0]); + SG_LOG(SG_ATC, SG_WARN, "WARNING: Unknown suffix '" << ch + << "' in runway " << rwy << " in ConvertRwyNumToSpokenString(...)"); + } + } + return rslt; } // Return the phonetic letter of a letter represented as an integer 1->26 -string GetPhoneticIdent(int i) { - // TODO - Check i is between 1 and 26 and wrap if necessary - return(GetPhoneticIdent(char('a' + (i-1)))); +string GetPhoneticLetter(const int i) { + return(letters[i % LTRS]); } // Return the phonetic letter of a character in the range a-z or A-Z. // Currently always returns prefixed by lowercase. -string GetPhoneticIdent(char c) { - c = tolower(c); - // TODO - Check c is between a and z and wrap if necessary - switch(c) { - case 'a' : return("alpha"); - case 'b' : return("bravo"); - case 'c' : return("charlie"); - case 'd' : return("delta"); - case 'e' : return("echo"); - case 'f' : return("foxtrot"); - case 'g' : return("golf"); - case 'h' : return("hotel"); - case 'i' : return("india"); - case 'j' : return("juliet"); - case 'k' : return("kilo"); - case 'l' : return("lima"); - case 'm' : return("mike"); - case 'n' : return("november"); - case 'o' : return("oscar"); - case 'p' : return("papa"); - case 'q' : return("quebec"); - case 'r' : return("romeo"); - case 's' : return("sierra"); - case 't' : return("tango"); - case 'u' : return("uniform"); - case 'v' : return("victor"); - case 'w' : return("whiskey"); - case 'x' : return("x-ray"); - case 'y' : return("yankee"); - case 'z' : return("zulu"); - } - // We shouldn't get here - return("Error"); +string GetPhoneticLetter(const char c) { + return GetPhoneticLetter(int(tolower(c) - 'a')); } // Get the compass direction associated with a heading in degrees @@ -187,15 +142,15 @@ string GetCompassDirection(double h) { //================================================================================================================ // Given two positions (lat & lon in degrees), get the HORIZONTAL separation (in meters) -double dclGetHorizontalSeparation(const Point3D& pos1, const Point3D& pos2) { +double dclGetHorizontalSeparation(const SGGeod& pos1, const SGGeod& pos2) { double x; //East-West separation double y; //North-South separation double z; //Horizontal separation - z = sqrt(x^2 + y^2) - double lat1 = pos1.lat() * SG_DEGREES_TO_RADIANS; - double lon1 = pos1.lon() * SG_DEGREES_TO_RADIANS; - double lat2 = pos2.lat() * SG_DEGREES_TO_RADIANS; - double lon2 = pos2.lon() * SG_DEGREES_TO_RADIANS; + double lat1 = pos1.getLatitudeRad(); + double lon1 = pos1.getLongitudeRad(); + double lat2 = pos2.getLatitudeRad(); + double lon2 = pos2.getLongitudeRad(); y = sin(fabs(lat1 - lat2)) * SG_EQUATORIAL_RADIUS_M; x = sin(fabs(lon1 - lon2)) * SG_EQUATORIAL_RADIUS_M * (cos((lat1 + lat2) / 2.0)); @@ -226,13 +181,15 @@ double dclGetLinePointSeparation(double px, double py, double x1, double y1, dou // Given a position (lat/lon/elev), heading and vertical angle (degrees), and distance (meters), calculate the new position. // This function assumes the world is spherical. If geodetic accuracy is required use the functions is sg_geodesy instead! // Assumes that the ground is not hit!!! Expects heading and angle in degrees, distance in meters. -Point3D dclUpdatePosition(const Point3D& pos, double heading, double angle, double distance) { +SGGeod dclUpdatePosition(const SGGeod& pos, double heading, double angle, double distance) { + // FIXME: use SGGeodesy instead ... + //cout << setprecision(10) << pos.lon() << ' ' << pos.lat() << '\n'; heading *= DCL_DEGREES_TO_RADIANS; angle *= DCL_DEGREES_TO_RADIANS; - double lat = pos.lat() * DCL_DEGREES_TO_RADIANS; - double lon = pos.lon() * DCL_DEGREES_TO_RADIANS; - double elev = pos.elev(); + double lat = pos.getLatitudeRad(); + double lon = pos.getLongitudeRad(); + double elev = pos.getElevationM(); //cout << setprecision(10) << lon*DCL_RADIANS_TO_DEGREES << ' ' << lat*DCL_RADIANS_TO_DEGREES << '\n'; double horiz_dist = distance * cos(angle); @@ -253,17 +210,17 @@ Point3D dclUpdatePosition(const Point3D& pos, double heading, double angle, doub //cout << setprecision(15) << DCL_DEGREES_TO_RADIANS * DCL_RADIANS_TO_DEGREES << '\n'; - return(Point3D(lon*DCL_RADIANS_TO_DEGREES, lat*DCL_RADIANS_TO_DEGREES, elev)); + return SGGeod::fromRadM(lon, lat, elev); } // Get a heading in degrees from one lat/lon to another. // This function assumes the world is spherical. If geodetic accuracy is required use the functions is sg_geodesy instead! // Warning - at the moment we are not checking for identical points - currently it returns 0 in this instance. -double GetHeadingFromTo(const Point3D& A, const Point3D& B) { - double latA = A.lat() * DCL_DEGREES_TO_RADIANS; - double lonA = A.lon() * DCL_DEGREES_TO_RADIANS; - double latB = B.lat() * DCL_DEGREES_TO_RADIANS; - double lonB = B.lon() * DCL_DEGREES_TO_RADIANS; +double GetHeadingFromTo(const SGGeod& A, const SGGeod& B) { + double latA = A.getLatitudeRad(); + double lonA = A.getLongitudeRad(); + double latB = B.getLatitudeRad(); + double lonB = B.getLongitudeRad(); double xdist = sin(lonB - lonA) * (double)SG_EQUATORIAL_RADIUS_M * cos((latA+latB)/2.0); double ydist = sin(latB - latA) * (double)SG_EQUATORIAL_RADIUS_M; double heading = atan2(xdist, ydist) * DCL_RADIANS_TO_DEGREES; @@ -292,14 +249,14 @@ double GetAngleDiff_deg( const double &a1, const double &a2) { } // 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 FGRunwayBase* rwy) { +// Given (lon/lat/elev) and an FGRunway struct, determine if the point lies on the runway +bool OnRunway(const SGGeod& pt, const FGRunwayBase* rwy) { FGATCAlignedProjection ortho; - Point3D centre(rwy->longitude(), rwy->latitude(), 0.0); // We don't need the elev + SGGeod centre = SGGeod::fromDegM(rwy->longitude(), rwy->latitude(), 0); // We don't need the elev ortho.Init(centre, rwy->headingDeg()); - Point3D xyc = ortho.ConvertToLocal(centre); - Point3D xyp = ortho.ConvertToLocal(pt); + SGVec3d xyc = ortho.ConvertToLocal(centre); + SGVec3d xyp = ortho.ConvertToLocal(pt); //cout << "Length offset = " << fabs(xyp.y() - xyc.y()) << '\n'; //cout << "Width offset = " << fabs(xyp.x() - xyc.x()) << '\n'; @@ -311,4 +268,4 @@ bool OnRunway(const Point3D& pt, const FGRunwayBase* rwy) { return(false); } - +