X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAirports%2Frunways.cxx;h=3eb853823e4d39f0927fcba599c71f3d08750217;hb=386aefe69358ce41a11c9afeb8f56e26758fe56b;hp=a1d82821a2ef38c7ae09c89edb0354850e85e09f;hpb=f39e079b75e500a10dda40c1505c2a77cb5b6a79;p=flightgear.git diff --git a/src/Airports/runways.cxx b/src/Airports/runways.cxx index a1d82821a..3eb853823 100644 --- a/src/Airports/runways.cxx +++ b/src/Airports/runways.cxx @@ -2,7 +2,7 @@ // // Written by Curtis Olson, started August 2000. // -// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as @@ -16,7 +16,7 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // $Id$ @@ -25,513 +25,145 @@ # include #endif -#include // fabs() -#include // sprintf() +#include // sprintf() +#include // atoi() #include -#include -#include +#include -#include STL_STRING -#include STL_FUNCTIONAL -#include STL_ALGORITHM +#include #include "runways.hxx" -SG_USING_NAMESPACE(std); +using std::string; -#ifndef _MSC_VER -#define NDEBUG // MSVC needs this -#endif // !_MSC_VER - -#include -#include - -#ifndef _MSC_VER -#undef NDEBUG -#endif // !_MSC_VER - -#ifdef SG_HAVE_STD_INCLUDES -# include -#elif defined( __BORLANDC__ ) || defined (__APPLE__) -# include -#else -# include -#endif - -SG_USING_STD(istream); - -inline istream& -operator >> ( istream& in, FGRunway& a ) +static std::string cleanRunwayNo(const std::string& aRwyNo) +{ + if (aRwyNo[0] == 'x') { + return std::string(); // no ident for taxiways + } + + string result(aRwyNo); + // canonicalise runway ident + if ((aRwyNo.size() == 1) || !isdigit(aRwyNo[1])) { + result = "0" + aRwyNo; + } + + // 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& aIdent, + const SGGeod& aGeod, + const double heading, const double length, + const double width, + const double displ_thresh, + const double stopway, + const int surface_code, + bool reciprocal) : + FGRunwayBase(RUNWAY, cleanRunwayNo(aIdent), aGeod, heading, length, width, surface_code, true), + _airport(aAirport), + _isReciprocal(reciprocal), + _reciprocal(NULL), + _displ_thresh(displ_thresh), + _stopway(stopway), + _ils(NULL) { - int tmp; - - return in >> a.rwy_no >> a.lat >> a.lon >> a.heading >> a.length >> a.width - >> a.surface_flags >> a.end1_flags >> tmp >> tmp >> a.end2_flags - >> tmp >> tmp; -} - - -FGRunways::FGRunways( const string& file ) { - // open the specified database readonly - storage = new c4_Storage( file.c_str(), false ); - - if ( !storage->Strategy().IsValid() ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file ); - exit(-1); - } - - vRunway = new c4_View; - *vRunway = - storage->GetAs("runway[ID:S,Rwy:S,Longitude:F,Latitude:F,Heading:F,Length:F,Width:F,SurfaceFlags:S,End1Flags:S,End2Flags:S]"); - - next_index = 0; } +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); - // 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(ident.substr(0,2).c_str()); + rn += 18; + while(rn > 36) { + rn -= 36; + } + + sprintf(buf, "%02i", rn); + if(ident.size() == 3) { + char suffix = toupper(ident[2]); + if(suffix == 'L') { + buf[2] = 'R'; + } else if (suffix == 'R') { + buf[2] = 'L'; + } else { + // something else, just copy + buf[2] = suffix; } - 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 { - SG_LOG(SG_GENERAL, SG_ALERT, "Unknown runway code " - << rwyno << " passed to GetReverseRunwayNo(...)"); - } - } - return((string)buf); + buf[3] = 0; + } + + return buf; } - -// search for the specified apt id -bool FGRunways::search( const string& aptid, FGRunway* r ) { - c4_StringProp pID ("ID"); - c4_StringProp pRwy ("Rwy"); - c4_FloatProp pLon ("Longitude"); - c4_FloatProp pLat ("Latitude"); - c4_FloatProp pHdg ("Heading"); - c4_FloatProp pLen ("Length"); - c4_FloatProp pWid ("Width"); - c4_StringProp pSurf ("SurfaceFlags"); - c4_StringProp pEnd1 ("End1Flags"); - c4_StringProp pEnd2 ("End2Flags"); - - int index = vRunway->Find(pID[aptid.c_str()]); - c4_RowRef row = vRunway->GetAt(index); - - // cout << "index = " << index " row = " << row << endl; - - // explicitly check if we got what we were asking for - // because metakit is canse insensitive! - if ( strcmp(aptid.c_str(), pID(row)) ) { - return false; - } - - next_index = index + 1; - - r->id = (const char *) pID(row); - r->rwy_no = (const char *) pRwy(row); - r->lon = (double) pLon(row); - r->lat = (double) pLat(row); - r->heading = (double) pHdg(row); - r->length = (double) pLen(row); - r->width = (double) pWid(row); - r->surface_flags = (const char *) pSurf(row); - r->end1_flags = (const char *) pEnd1(row); - r->end2_flags = (const char *) pEnd2(row); - - return true; -} - - -// search for the specified apt id and runway no -bool FGRunways::search( const string& aptid, const string& rwyno, FGRunway* r ) +double FGRunway::score(double aLengthWt, double aWidthWt, double aSurfaceWt) const { - string runwayno = rwyno; - c4_StringProp pID ("ID"); - c4_StringProp pRwy ("Rwy"); - c4_FloatProp pLon ("Longitude"); - c4_FloatProp pLat ("Latitude"); - c4_FloatProp pHdg ("Heading"); - c4_FloatProp pLen ("Length"); - c4_FloatProp pWid ("Width"); - c4_StringProp pSurf ("SurfaceFlags"); - c4_StringProp pEnd1 ("End1Flags"); - c4_StringProp pEnd2 ("End2Flags"); - - int index = vRunway->Find(pID[aptid.c_str()]); - c4_RowRef row = vRunway->GetAt(index); - // cout << "index = " << index " row = " << row << endl; - - // explicitly check if we got what we were asking for - // because metakit is canse insensitive! - if ( strcmp(aptid.c_str(), pID(row)) ) { - return false; - } + 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; - // 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 ); - } - - string rowid = (const char *) pID(row); - string rowrwyno = (const char *) pRwy(row); - while ( rowid == aptid ) { - next_index = index + 1; - - if ( rowrwyno == runwayno ) { - r->id = (const char *) pID(row); - r->rwy_no = (const char *) pRwy(row); - r->lon = (double) pLon(row); - r->lat = (double) pLat(row); - r->heading = (double) pHdg(row); - r->length = (double) pLen(row); - r->width = (double) pWid(row); - r->surface_flags = (const char *) pSurf(row); - r->end1_flags = (const char *) pEnd1(row); - r->end2_flags = (const char *) pEnd2(row); - - return true; - } - - // Search again with the other-end runway number - // Remember we have to munge the heading and rwy_no results if this one matches - rowrwyno = GetReverseRunwayNo(rowrwyno); - // cout << "New rowrwyno = " << rowrwyno << '\n'; - if ( rowrwyno == runwayno ) { - r->id = (const char *) pID(row); - r->rwy_no = rowrwyno; - r->lon = (double) pLon(row); - r->lat = (double) pLat(row); - r->heading = (double) pHdg(row) + 180.0; - r->length = (double) pLen(row); - r->width = (double) pWid(row); - r->surface_flags = (const char *) pSurf(row); - r->end1_flags = (const char *) pEnd2(row); - r->end2_flags = (const char *) pEnd1(row); - // I've swapped the end flags as well - - return true; - } - - index++; - row = vRunway->GetAt(index); - rowid = (const char *) pID(row); - rowrwyno = (const char *) pRwy(row); - } - - return false; -} - - -FGRunway FGRunways::search( const string& aptid ) { - FGRunway a; - search( aptid, &a ); - return a; -} - - -// search for the specified id -bool FGRunways::next( FGRunway* r ) { - c4_StringProp pID ("ID"); - c4_StringProp pRwy ("Rwy"); - c4_FloatProp pLon ("Longitude"); - c4_FloatProp pLat ("Latitude"); - c4_FloatProp pHdg ("Heading"); - c4_FloatProp pLen ("Length"); - c4_FloatProp pWid ("Width"); - c4_StringProp pSurf ("SurfaceFlags"); - c4_StringProp pEnd1 ("End1Flags"); - c4_StringProp pEnd2 ("End2Flags"); - - int size = vRunway->GetSize(); - // cout << "total records = " << size << endl; - - int index = next_index; - // cout << "index = " << index << endl; - - if ( index == -1 || index >= size ) { - return false; - } - - next_index = index + 1; - - c4_RowRef row = vRunway->GetAt(index); - - r->id = (const char *) pID(row); - r->rwy_no = (const char *) pRwy(row); - r->lon = (double) pLon(row); - r->lat = (double) pLat(row); - r->heading = (double) pHdg(row); - r->length = (double) pLen(row); - r->width = (double) pWid(row); - r->surface_flags = (const char *) pSurf(row); - r->end1_flags = (const char *) pEnd1(row); - r->end2_flags = (const char *) pEnd2(row); - - return true; + return _length * aLengthWt + _width * aWidthWt + surface * aSurfaceWt + 1e-20; } - -// Return the runway closest to a given heading -bool FGRunways::search( const string& aptid, const int tgt_hdg, - FGRunway* runway ) +SGGeod FGRunway::begin() 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 FGRunways::search( const string& aptid, const int tgt_hdg ) { - FGRunway r; - FGRunway tmp_r; - string rn; - double found_dir = 0.0; - - if ( !search( aptid, &tmp_r ) ) { - SG_LOG( SG_GENERAL, SG_ALERT, - "Failed to find " << aptid << " in database." ); - return "NN"; - } - - double diff; - double min_diff = 360.0; - - while ( tmp_r.id == aptid ) { - r = tmp_r; - - // forward direction - diff = tgt_hdg - r.heading; - while ( diff < -180.0 ) { diff += 360.0; } - while ( diff > 180.0 ) { diff -= 360.0; } - diff = fabs(diff); - // SG_LOG( SG_GENERAL, SG_INFO, - // "Runway " << r.rwy_no << " heading = " << r.heading << - // " diff = " << diff ); - if ( diff < min_diff ) { - min_diff = diff; - rn = r.rwy_no; - found_dir = 0; - } - - // reverse direction - diff = tgt_hdg - r.heading - 180.0; - while ( diff < -180.0 ) { diff += 360.0; } - while ( diff > 180.0 ) { diff -= 360.0; } - diff = fabs(diff); - // SG_LOG( SG_GENERAL, SG_INFO, - // "Runway -" << r.rwy_no << " heading = " << - // r.heading + 180.0 << - // " diff = " << diff ); - if ( diff < min_diff ) { - min_diff = diff; - rn = r.rwy_no; - found_dir = 180.0; - } - - next( &tmp_r ); - } - - // SG_LOG( SG_GENERAL, SG_INFO, "closest runway = " << r.rwy_no - // << " + " << found_dir ); - rn = r.rwy_no; - // cout << "In search, rn = " << rn << endl; - if ( found_dir == 180 ) { - rn = GetReverseRunwayNo(rn); - //cout << "New rn = " << rn << '\n'; - } - - return rn; + return pointOnCenterline(0.0); } - -// Destructor -FGRunways::~FGRunways( void ) { - delete storage; -} - - -// Constructor -FGRunwaysUtil::FGRunwaysUtil() { -} - - -// load the data -int FGRunwaysUtil::load( const string& file ) { - FGRunway r; - string apt_id; - - runways.erase( runways.begin(), runways.end() ); - - sg_gzifstream in( file ); - if ( !in.is_open() ) { - SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << file ); - exit(-1); - } - - // skip first line of file - char tmp[2048]; - in.getline( tmp, 2048 ); - - // read in each line of the file - -#ifdef __MWERKS__ - - in >> ::skipws; - char c = 0; - while ( in.get(c) && c != '\0' ) { - if ( c == 'A' ) { - in >> apt_id; - in >> skipeol; - } else if ( c == 'R' ) { - in >> r; - r.id = apt_id; - runways.push_back(r); - } else { - in >> skipeol; - } - in >> ::skipws; - } - -#else - - in >> ::skipws; - while ( ! in.eof() ) { - char c = 0; - in.get(c); - if ( c == 'A' ) { - in >> apt_id; - in >> skipeol; - } else if ( c == 'R' ) { - in >> r; - r.id = apt_id; - // cout << apt_id << " " << r.rwy_no << endl; - runways.push_back(r); - } else { - in >> skipeol; - } - in >> ::skipws; - } - -#endif - - return 1; -} - - -// save the data in gdbm format -bool FGRunwaysUtil::dump_mk4( const string& file ) { - // open database for writing - c4_Storage storage( file.c_str(), true ); - - // need to do something about error handling here! - - // define the properties - c4_StringProp pID ("ID"); - c4_StringProp pRwy ("Rwy"); - c4_FloatProp pLon ("Longitude"); - c4_FloatProp pLat ("Latitude"); - c4_FloatProp pHdg ("Heading"); - c4_FloatProp pLen ("Length"); - c4_FloatProp pWid ("Width"); - c4_StringProp pSurf ("SurfaceFlags"); - c4_StringProp pEnd1 ("End1Flags"); - c4_StringProp pEnd2 ("End2Flags"); - - // Start with an empty view of the proper structure. - c4_View vRunway = - storage.GetAs("runway[ID:S,Rwy:S,Longitude:F,Latitude:F,Heading:F,Length:F,Width:F,SurfaceFlags:S,End1Flags:S,End2Flags:S]"); - - c4_Row row; - - iterator current = runways.begin(); - const_iterator end = runways.end(); - while ( current != end ) { - // add each runway record - pID (row) = current->id.c_str(); - pRwy (row) = current->rwy_no.c_str(); - pLon (row) = current->lon; - pLat (row) = current->lat; - pHdg (row) = current->heading; - pLen (row) = current->length; - pWid (row) = current->width; - pSurf (row) = current->surface_flags.c_str(); - pEnd1 (row) = current->end1_flags.c_str(); - pEnd2 (row) = current->end2_flags.c_str(); - vRunway.Add(row); - - ++current; - } - - // commit our changes - storage.Commit(); - - return true; -} - - -#if 0 -// search for the specified id -bool -FGRunwaysUtil::search( const string& id, FGRunway* a ) const +SGGeod FGRunway::end() const { - const_iterator it = runways.find( FGRunway(id) ); - if ( it != runways.end() ) - { - *a = *it; - return true; - } - else - { - return false; - } + return pointOnCenterline(lengthM()); } - -FGRunway -FGRunwaysUtil::search( const string& id ) const +SGGeod FGRunway::threshold() const { - FGRunway a; - this->search( id, &a ); - return a; + return pointOnCenterline(_displ_thresh * SG_FEET_TO_METER); } -#endif -// Destructor -FGRunwaysUtil::~FGRunwaysUtil( void ) { +void FGRunway::processThreshold(SGPropertyNode* aThreshold) +{ + assert(ident() == aThreshold->getStringValue("rwy")); + + double lon = aThreshold->getDoubleValue("lon"), + lat = aThreshold->getDoubleValue("lat"); + SGGeod newThreshold(SGGeod::fromDegM(lon, lat, mPosition.getElevationM())); + + _heading = aThreshold->getDoubleValue("hdg-deg"); + _displ_thresh = aThreshold->getDoubleValue("displ-m") * SG_METER_TO_FEET; + _stopway = aThreshold->getDoubleValue("stopw-m") * SG_METER_TO_FEET; + + // compute the new runway center, based on the threshold lat/lon and length, + double offsetFt = (0.5 * _length); + SGGeod newCenter; + double dummy; + SGGeodesy::direct(newThreshold, _heading, offsetFt * SG_FEET_TO_METER, newCenter, dummy); + mPosition = newCenter; +} + +void FGRunway::setReciprocalRunway(FGRunway* other) +{ + assert(_reciprocal==NULL); + assert((other->_reciprocal == NULL) || (other->_reciprocal == this)); + + _reciprocal = other; } -