From 7543409e472bbd58fd24f8f005e0d41c8f7d10ea Mon Sep 17 00:00:00 2001 From: curt Date: Wed, 3 Apr 2002 23:54:44 +0000 Subject: [PATCH] Attached are a fairly extensive series of patches to the ATC system. A chap from Germany called Alexander Kappes (cc'd) got in touch with me a few weeks ago and has written the start of Approach control. At the moment tuning in to a valid approach frequency (Dortmund or East Midlands) should result in vectors to a spot about 3 miles from the active runway, and a telling off if you stray too far from the correct course, in the console window. He seems to know what he's doing so expect this to improve rapidly!! I've added a rudimentry AI manager and a hardwired Cessna at KEMT on the runway - I'll remove it before the next release if I don't have it flying by then. There seems to be an issue with framerate which drops alarmingly when looking at it - I've a feeling that I've possibly created several Cessnas on top of each other, but am not sure. --- src/ATC/AIEntity.cxx | 137 ++++++++++ src/ATC/AIEntity.hxx | 71 ++++++ src/ATC/AILocalTraffic.cxx | 100 ++++++++ src/ATC/AILocalTraffic.hxx | 100 ++++++++ src/ATC/AIMgr.cxx | 70 ++++++ src/ATC/AIMgr.hxx | 96 +++++++ src/ATC/ATC.cxx | 28 ++- src/ATC/ATC.hxx | 13 +- src/ATC/ATCdisplay.cxx | 67 +++++ src/ATC/ATCdisplay.hxx | 8 +- src/ATC/ATCmgr.cxx | 296 +++++++++++++++++++++- src/ATC/ATCmgr.hxx | 64 ++++- src/ATC/ATCutils.cxx | 0 src/ATC/Makefile.am | 9 +- src/ATC/approach.cxx | 366 +++++++++++++++++++++++++++ src/ATC/approach.hxx | 266 ++++++++++++++++++++ src/ATC/approachlist.cxx | 234 +++++++++++++++++ src/ATC/approachlist.hxx | 79 ++++++ src/ATC/atislist.cxx | 22 +- src/ATC/ground.cxx | 80 ++++++ src/ATC/ground.hxx | 150 +++++++++++ src/ATC/runways.cxx | 496 +++++++++++++++++++++++++++++++++++++ src/ATC/tower.cxx | 52 ++++ src/ATC/tower.hxx | 148 +++++++++++ src/ATC/towerlist.cxx | 134 ++++++++++ src/ATC/towerlist.hxx | 74 ++++++ src/Main/fg_init.cxx | 26 +- src/Main/globals.hxx | 9 +- src/Main/main.cxx | 7 +- 29 files changed, 3162 insertions(+), 40 deletions(-) create mode 100644 src/ATC/AIEntity.cxx create mode 100644 src/ATC/AIEntity.hxx create mode 100644 src/ATC/AILocalTraffic.cxx create mode 100644 src/ATC/AILocalTraffic.hxx create mode 100644 src/ATC/AIMgr.cxx create mode 100644 src/ATC/AIMgr.hxx create mode 100644 src/ATC/ATCutils.cxx create mode 100644 src/ATC/approach.cxx create mode 100644 src/ATC/approach.hxx create mode 100644 src/ATC/approachlist.cxx create mode 100644 src/ATC/approachlist.hxx create mode 100644 src/ATC/ground.cxx create mode 100644 src/ATC/ground.hxx create mode 100644 src/ATC/runways.cxx create mode 100644 src/ATC/tower.cxx create mode 100644 src/ATC/tower.hxx create mode 100644 src/ATC/towerlist.cxx create mode 100644 src/ATC/towerlist.hxx diff --git a/src/ATC/AIEntity.cxx b/src/ATC/AIEntity.cxx new file mode 100644 index 000000000..67ba889eb --- /dev/null +++ b/src/ATC/AIEntity.cxx @@ -0,0 +1,137 @@ +// FGAIEntity - abstract base class an artificial intelligence entity +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +/***************************************************************** +* +* WARNING - Curt has some ideas about AI traffic so anything in here +* may get rewritten or scrapped. Contact Curt curt@flightgear.org +* before spending any time or effort on this code!!! +* +******************************************************************/ + +#include
+#include +//#include +#include +#include +#include +#include + +#include "AIEntity.hxx" + +extern ssgRoot* scene; // The global Flightgear scene graph + +FGAIEntity::~FGAIEntity() { +} + +// Run the internal calculations +void FGAIEntity::Update() { +} + +void FGAIEntity::Transform() { + + // Translate moving object w.r.t eye + Point3D sc = scenery.get_center(); + //cout << "sc0 = " << sc.x() << " sc1 = " << sc.y() << " sc2 = " << sc.z() << '\n'; + //cout << "op0 = " << obj_pos.x() << " op1 = " << obj_pos.y() << " op2 = " << obj_pos.z() << '\n'; + + sgCoord shippos; + FastWorldCoordinate(&shippos, sc); + position->setTransform( &shippos ); + scene->addKid(position); + //cout << "Transform called\n"; +} + +#if 0 +// Taken from tileentry.cxx +void FGAIEntity::WorldCoordinate(sgCoord *obj_pos, Point3D center) { + // setup transforms + Point3D geod( lon * SGD_DEGREES_TO_RADIANS, + lat * SGD_DEGREES_TO_RADIANS, + elev ); + + Point3D world_pos = sgGeodToCart( geod ); + Point3D offset = world_pos - center; + + sgMat4 POS; + sgMakeTransMat4( POS, offset.x(), offset.y(), offset.z() ); + + sgVec3 obj_rt, obj_up; + sgSetVec3( obj_rt, 0.0, 1.0, 0.0); // Y axis + sgSetVec3( obj_up, 0.0, 0.0, 1.0); // Z axis + + sgMat4 ROT_lon, ROT_lat, ROT_hdg; + sgMakeRotMat4( ROT_lon, lon, obj_up ); + sgMakeRotMat4( ROT_lat, 90 - lat, obj_rt ); + sgMakeRotMat4( ROT_hdg, hdg, obj_up ); + + sgMat4 TUX; + sgCopyMat4( TUX, ROT_hdg ); + sgPostMultMat4( TUX, ROT_lat ); + sgPostMultMat4( TUX, ROT_lon ); + sgPostMultMat4( TUX, POS ); + + sgSetCoord( obj_pos, TUX ); +} +#endif + +// Norman's 'fast hack' for above +void FGAIEntity::FastWorldCoordinate(sgCoord *obj_pos, Point3D center) { + double lon_rad = lon * SGD_DEGREES_TO_RADIANS; + double lat_rad = lat * SGD_DEGREES_TO_RADIANS; + double hdg_rad = hdg * SGD_DEGREES_TO_RADIANS; + + // setup transforms + Point3D geod( lon_rad, lat_rad, elev ); + + Point3D world_pos = sgGeodToCart( geod ); + Point3D offset = world_pos - center; + + sgMat4 mat; + + SGfloat sin_lat = (SGfloat)sin( lat_rad ); + SGfloat cos_lat = (SGfloat)cos( lat_rad ); + SGfloat cos_lon = (SGfloat)cos( lon_rad ); + SGfloat sin_lon = (SGfloat)sin( lon_rad ); + SGfloat sin_hdg = (SGfloat)sin( hdg_rad ) ; + SGfloat cos_hdg = (SGfloat)cos( hdg_rad ) ; + + mat[0][0] = cos_hdg * (SGfloat)sin_lat * (SGfloat)cos_lon - sin_hdg * (SGfloat)sin_lon; + mat[0][1] = cos_hdg * (SGfloat)sin_lat * (SGfloat)sin_lon + sin_hdg * (SGfloat)cos_lon; + mat[0][2] = -cos_hdg * (SGfloat)cos_lat; + mat[0][3] = SG_ZERO; + + mat[1][0] = -sin_hdg * (SGfloat)sin_lat * (SGfloat)cos_lon - cos_hdg * (SGfloat)sin_lon; + mat[1][1] = -sin_hdg * (SGfloat)sin_lat * (SGfloat)sin_lon + cos_hdg * (SGfloat)cos_lon; + mat[1][2] = sin_hdg * (SGfloat)cos_lat; + mat[1][3] = SG_ZERO; + + mat[2][0] = (SGfloat)cos_lat * (SGfloat)cos_lon; + mat[2][1] = (SGfloat)cos_lat * (SGfloat)sin_lon; + mat[2][2] = (SGfloat)sin_lat; + mat[2][3] = SG_ZERO; + + mat[3][0] = offset.x(); + mat[3][1] = offset.y(); + mat[3][2] = offset.z(); + mat[3][3] = SG_ONE ; + + sgSetCoord( obj_pos, mat ); +} diff --git a/src/ATC/AIEntity.hxx b/src/ATC/AIEntity.hxx new file mode 100644 index 000000000..f3ac19b2d --- /dev/null +++ b/src/ATC/AIEntity.hxx @@ -0,0 +1,71 @@ +// FGAIEntity - abstract base class an artificial intelligence entity +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +/***************************************************************** +* +* WARNING - Curt has some ideas about AI traffic so anything in here +* may get rewritten or scrapped. Contact Curt curt@flightgear.org +* before spending any time or effort on this code!!! +* +******************************************************************/ + +#ifndef _FG_AIEntity_HXX +#define _FG_AIEntity_HXX + +#include +#include +#include + +class FGAIEntity { + +public: + + // We need some way for this class to display its radio transmissions if on the + // same frequency and in the vicinity of the user's aircraft + // This may need to be done independently of ATC eg CTAF + + virtual ~FGAIEntity(); + + // Run the internal calculations + virtual void Update(); + +protected: + + double lat; //WGS84 + double lon; //WGS84 + double elev; //Meters + double hdg; //True heading in degrees + double roll; //degrees + double pitch; //degrees + + char* model_path; //Path to the 3D model + + ssgEntity* model; + ssgTransform* position; + + void Transform(); + + //void WorldCoordinate(sgCoord *obj_pos, Point3D center); + + void FastWorldCoordinate(sgCoord *obj_pos, Point3D center); + +}; + +#endif // _FG_AIEntity_HXX \ No newline at end of file diff --git a/src/ATC/AILocalTraffic.cxx b/src/ATC/AILocalTraffic.cxx new file mode 100644 index 000000000..8ecb807c6 --- /dev/null +++ b/src/ATC/AILocalTraffic.cxx @@ -0,0 +1,100 @@ +// FGAILocalTraffic - AIEntity derived class with enough logic to +// fly and interact with the traffic pattern. +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +/***************************************************************** +* +* WARNING - Curt has some ideas about AI traffic so anything in here +* may get rewritten or scrapped. Contact Curt curt@flightgear.org +* before spending any time or effort on this code!!! +* +******************************************************************/ + +#include
+//#include +#include +#include +#include +#include + +SG_USING_STD(string); + +#include "ATCmgr.hxx" +#include "AILocalTraffic.hxx" + +FGAILocalTraffic::FGAILocalTraffic() { +} + +FGAILocalTraffic::~FGAILocalTraffic() { +} + +void FGAILocalTraffic::Init() { + // Hack alert - Hardwired path!! + string planepath = "Aircraft/c172/Models/c172-dpm.ac"; + SGPath path = globals->get_fg_root(); + path.append(planepath); + ssgTexturePath((char*)path.dir().c_str()); + model = ssgLoad((char*)planepath.c_str()); + if (model == 0) { + model = ssgLoad((char*)"Models/Geometry/glider.ac"); + if (model == 0) + cout << "Failed to load an aircraft model in AILocalTraffic\n"; + } else { + cout << "AILocal Traffic Model loaded successfully\n"; + } + position = new ssgTransform; + position->addKid(model); + + // Hardwire to KEMT + lat = 34.081358; + lon = -118.037483; + elev = (287.0 + 0.5) * SG_FEET_TO_METER; // Ground is 296 so this should be above it + mag_hdg = -10.0; + pitch = 0.0; + roll = 0.0; + mag_var = -14.0; + + // Activate the tower - this is dependent on the ATC system being initialised before the AI system + AirportATC a; + if(globals->get_ATC_mgr()->GetAirportATCDetails((string)"KEMT", &a)) { + if(a.tower_freq) { // Has a tower + tower = (FGTower*)globals->get_ATC_mgr()->GetATCPointer((string)"KEMT", TOWER); // Maybe need some error checking here + } else { + // Check CTAF, unicom etc + } + } else { + cout << "Unable to find airport details in FGAILocalTraffic::Init()\n"; + } + + Transform(); +} + +// Run the internal calculations +void FGAILocalTraffic::Update() { + hdg = mag_hdg + mag_var; + + // This should become if(the plane has moved) then Transform() + static int i = 0; + if(i == 60) { + Transform(); + i = 0; + } + i++; +} diff --git a/src/ATC/AILocalTraffic.hxx b/src/ATC/AILocalTraffic.hxx new file mode 100644 index 000000000..fdbd2df46 --- /dev/null +++ b/src/ATC/AILocalTraffic.hxx @@ -0,0 +1,100 @@ +// FGAILocalTraffic - AIEntity derived class with enough logic to +// fly and interact with the traffic pattern. +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +/***************************************************************** +* +* WARNING - Curt has some ideas about AI traffic so anything in here +* may get rewritten or scrapped. Contact Curt curt@flightgear.org +* before spending any time or effort on this code!!! +* +******************************************************************/ + +#ifndef _FG_AILocalTraffic_HXX +#define _FG_AILocalTraffic_HXX + +#include +#include +#include + +#include "tower.hxx" +#include "AIEntity.hxx" + +typedef enum pattern_leg { + TAKEOFF_ROLL, + OUTWARD, + TURN1, + CROSSWIND, + TURN2, + DOWNWIND, + TURN3, + BASE, + TURN4, + FINAL, + LANDING_ROLL +}; + +class FGAILocalTraffic : public FGAIEntity { + +public: + + FGAILocalTraffic(); + ~FGAILocalTraffic(); + + // Initialise + void Init(); + + // Run the internal calculations + void Update(); + +private: + + char* airport; // The ICAO code of the airport that we're operating around + double freq; // The frequency that we're operating on - might not need this eventually + FGTower* tower; // A pointer to the tower control. + + double mag_hdg; // degrees - the heading that the physical aircraft is pointing + double mag_var; // degrees + + double vel; // velocity along track in m/s + double track; // track - degrees relative to *magnetic* north + double slope; // Actual slope that the plane is flying (degrees) - +ve is uphill + double AoA; // degrees - difference between slope and pitch + // We'll assume that the plane doesn't yaw or slip - the track/heading difference is to allow for wind + + // Performance characteristics of the plane in knots and ft/min + double Vr; + double best_rate_of_climb_speed; + double best_rate_of_climb; + double nominal_climb_speed; + double nominal_climb_rate; + double nominal_circuit_speed; + double min_circuit_speed; + double max_circuit_speed; + double nominal_descent_rate; + double nominal_approach_speed; + double stall_speed_landing_config; + + // OK, what do we need to know whilst flying the pattern + pattern_leg leg; + +}; + +#endif // _FG_AILocalTraffic_HXX \ No newline at end of file diff --git a/src/ATC/AIMgr.cxx b/src/ATC/AIMgr.cxx new file mode 100644 index 000000000..b4c341e8e --- /dev/null +++ b/src/ATC/AIMgr.cxx @@ -0,0 +1,70 @@ +// AIMgr.cxx - implementation of FGAIMgr +// - a global management class for FlightGear generated AI traffic +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +/***************************************************************** +* +* WARNING - Curt has some ideas about AI traffic so anything in here +* may get rewritten or scrapped. Contact Curt curt@flightgear.org +* before spending any time or effort on this code!!! +* +******************************************************************/ + + + +#include
+#include
+ +#include + +#include "AIMgr.hxx" +#include "AILocalTraffic.hxx" + +SG_USING_STD(list); + + +FGAIMgr::FGAIMgr() { +} + +FGAIMgr::~FGAIMgr() { +} + +void FGAIMgr::init() { + // Hard wire some local traffic for now. + // This is regardless of location and hence *very* ugly but it is a start. + FGAILocalTraffic* local_traffic = new FGAILocalTraffic; + local_traffic->Init(); + ai_list.push_back(local_traffic); +} + +void FGAIMgr::bind() { +} + +void FGAIMgr::unbind() { +} + +void FGAIMgr::update(int dt) { + // Traverse the list of active planes and run all their update methods + ai_list_itr = ai_list.begin(); + while(ai_list_itr != ai_list.end()) { + (*ai_list_itr)->Update(); + ++ai_list_itr; + } +} \ No newline at end of file diff --git a/src/ATC/AIMgr.hxx b/src/ATC/AIMgr.hxx new file mode 100644 index 000000000..3933348f8 --- /dev/null +++ b/src/ATC/AIMgr.hxx @@ -0,0 +1,96 @@ +// AIMgr.hxx - definition of FGAIMgr +// - a global management class for FlightGear generated AI traffic +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +/***************************************************************** +* +* WARNING - Curt has some ideas about AI traffic so anything in here +* may get rewritten or scrapped. Contact Curt curt@flightgear.org +* before spending any time or effort on this code!!! +* +******************************************************************/ + +#ifndef _FG_AIMGR_HXX +#define _FG_AIMGR_HXX + +#include
+#include
+ +#include + +#include "AIEntity.hxx" + +SG_USING_STD(list); + +class FGAIMgr : public FGSubsystem +{ + +private: + + // A list of pointers to all currently active AI stuff + typedef list ai_list_type; + typedef ai_list_type::iterator ai_list_iterator; + typedef ai_list_type::const_iterator ai_list_const_iterator; + + // Everything put in this list should be created dynamically + // on the heap and ***DELETED WHEN REMOVED!!!!!*** + ai_list_type ai_list; + ai_list_iterator ai_list_itr; + // Any member function of FGATCMgr is permitted to leave this iterator pointing + // at any point in or at the end of the list. + // Hence any new access must explicitly first check for atc_list.end() before dereferencing. + + // Position of the Users Aircraft + // (This may be needed to calculate the distance from the user when deciding which 3D model to render) + double current_lon; + double current_lat; + double current_elev; + // Pointers to current users position + SGPropertyNode *current_lon_node; + SGPropertyNode *current_lat_node; + SGPropertyNode *current_elev_node; + + //FGATIS atis; + //FGGround ground; + //FGTower tower; + //FGApproach approach; + //FGDeparture departure; + +public: + + FGAIMgr(); + ~FGAIMgr(); + + void init(); + + void bind(); + + void unbind(); + + void update(int dt); + +private: + + // Remove a class from the ai_list and delete it from memory + //void RemoveFromList(const char* id, atc_type tp); + +}; + +#endif // _FG_AIMGR_HXX diff --git a/src/ATC/ATC.cxx b/src/ATC/ATC.cxx index 519ff06b7..e84105835 100644 --- a/src/ATC/ATC.cxx +++ b/src/ATC/ATC.cxx @@ -27,6 +27,12 @@ FGATC::~FGATC() { void FGATC::Update() { } +void FGATC::AddPlane(string pid) { +} + +int FGATC::RemovePlane() { +} + void FGATC::SetDisplay() { } @@ -39,4 +45,24 @@ const char* FGATC::GetIdent() { atc_type FGATC::GetType() { return INVALID; -} \ No newline at end of file +} + +ostream& operator << (ostream& os, atc_type atc) { + switch(atc) { + case(INVALID): + return(os << "INVALID"); + case(ATIS): + return(os << "ATIS"); + case(GROUND): + return(os << "GROUND"); + case(TOWER): + return(os << "TOWER"); + case(APPROACH): + return(os << "APPROACH"); + case(DEPARTURE): + return(os << "DEPARTURE"); + case(ENROUTE): + return(os << "ENROUTE"); + } + return(os << "ERROR - Unknown switch in atc_type operator << "); +} diff --git a/src/ATC/ATC.hxx b/src/ATC/ATC.hxx index d0cd38daf..e3a573ec6 100644 --- a/src/ATC/ATC.hxx +++ b/src/ATC/ATC.hxx @@ -22,6 +22,9 @@ #ifndef _FG_ATC_HXX #define _FG_ATC_HXX +#include +#include + // Possible types of ATC type that the radios may be tuned to. // INVALID implies not tuned in to anything. enum atc_type { @@ -32,7 +35,9 @@ enum atc_type { APPROACH, DEPARTURE, ENROUTE -}; +}; + +ostream& operator << (ostream& os, atc_type atc); class FGATC { @@ -43,6 +48,12 @@ public: // Run the internal calculations virtual void Update(); + // Add plane to a stack + virtual void AddPlane(string pid); + + // Remove plane from stack + virtual int RemovePlane(); + // Indicate that this instance should output to the display if appropriate virtual void SetDisplay(); diff --git a/src/ATC/ATCdisplay.cxx b/src/ATC/ATCdisplay.cxx index cf00f911c..0bfce155d 100644 --- a/src/ATC/ATCdisplay.cxx +++ b/src/ATC/ATCdisplay.cxx @@ -132,8 +132,75 @@ void FGATCDisplay::update(int dt) { } } + + if(msgList.size()) { + //cout << "Attempting to render single message\n"; + // We have at least one non-repeating message to process + msgList_itr = msgList.begin(); + int i = 0; + while(msgList_itr != msgList.end()) { + atcMessage m = *msgList_itr; + //cout << "m.counter = " << m.counter << '\n'; + if(m.counter > m.stop_count) { + //cout << "Stopping single message\n"; + msgList_itr = msgList.erase(msgList_itr); + } else if(m.counter > m.start_count) { + //cout << "Displaying single message\n"; + // Display the message + // FIXME - I'm sure all this opengl code should only be called once until all drawing is finished + SGPropertyNode *xsize_node = fgGetNode("/sim/startup/xsize"); + SGPropertyNode *ysize_node = fgGetNode("/sim/startup/ysize"); + int iwidth = xsize_node->getIntValue(); + int iheight = ysize_node->getIntValue(); + glMatrixMode( GL_PROJECTION ); + glPushMatrix(); + glLoadIdentity(); + gluOrtho2D( 0, iwidth, 0, iheight ); + glMatrixMode( GL_MODELVIEW ); + glPushMatrix(); + glLoadIdentity(); + + glDisable( GL_DEPTH_TEST ); + glDisable( GL_LIGHTING ); + + glColor3f( 0.9, 0.4, 0.2 ); + + guiFnt.drawString( m.msg.c_str(), + 100, + (iheight - 40) ); // TODO - relate the distance in that the string is rendered to the string length. + glEnable( GL_DEPTH_TEST ); + glEnable( GL_LIGHTING ); + glMatrixMode( GL_PROJECTION ); + glPopMatrix(); + glMatrixMode( GL_MODELVIEW ); + glPopMatrix(); + ++m.counter; + msgList[i] = m; + ++msgList_itr; + ++i; + } else { + ++m.counter; + msgList[i] = m; + ++msgList_itr; + ++i; + } + } + } } +void FGATCDisplay::RegisterSingleMessage(string msg, int delay) { + atcMessage m; + m.msg = msg; + m.repeating = false; + m.counter = 0; + m.start_count = delay * 30; // Fixme - need to use actual FPS + m.stop_count = m.start_count + 100; // Display for 3 - 5 seconds for now - this might have to change eg. be related to length of message in future + //cout << "m.stop_count = " << m.stop_count << '\n'; + m.id = 0; + + msgList.push_back(m); + //cout << "Single message registered\n"; +} void FGATCDisplay::RegisterRepeatingMessage(string msg) { rep_msg = true; diff --git a/src/ATC/ATCdisplay.hxx b/src/ATC/ATCdisplay.hxx index 86ffca109..9c2c9805f 100644 --- a/src/ATC/ATCdisplay.hxx +++ b/src/ATC/ATCdisplay.hxx @@ -38,6 +38,9 @@ SG_USING_STD(string); struct atcMessage { string msg; bool repeating; + int counter; // count of how many iterations since posting + int start_count; // value of counter at which display should start + int stop_count; // value of counter at which display should stop int id; }; @@ -70,8 +73,9 @@ public: // Display any registered messages void update(int dt); - // Register a single message for display when possible - void RegisterSingleMessage(string msg); // OK - I know passing a string in and out is probably not good but it will have to do for now. + // Register a single message for display after a delay of delay seconds + // Will automatically stop displaying after a suitable interval. + void RegisterSingleMessage(string msg, int delay); // OK - I know passing a string in and out is probably not good but it will have to do for now. // For now we will assume only one repeating message at once // This is not really robust diff --git a/src/ATC/ATCmgr.cxx b/src/ATC/ATCmgr.cxx index 619ecf71a..5d77f1974 100644 --- a/src/ATC/ATCmgr.cxx +++ b/src/ATC/ATCmgr.cxx @@ -22,6 +22,9 @@ #include "ATCmgr.hxx" #include "atislist.hxx" +//#include "groundlist.hxx" +#include "towerlist.hxx" +#include "approachlist.hxx" /* // periodic radio station search wrapper @@ -31,6 +34,19 @@ static void fgATCSearch( void ) { */ //This wouldn't compile - including Time/event.hxx breaks it :-( FGATCMgr::FGATCMgr() { + comm1_ident = ""; + comm1_atis_ident = ""; + comm1_tower_ident = ""; + comm1_approach_ident = ""; + last_comm1_ident = ""; + last_comm1_atis_ident = ""; + last_comm1_tower_ident = ""; + last_comm1_approach_ident = ""; + approach_ident = ""; + last_in_range = false; + comm1_atis_valid = false; + comm1_tower_valid = false; + comm1_approach_valid = false; } FGATCMgr::~FGATCMgr() { @@ -53,12 +69,30 @@ void FGATCMgr::init() { // global_events.Register( "fgATCSearch()", fgATCSearch, // fgEVENT::FG_EVENT_READY, 800); // For some reason the above doesn't compile - including Time/event.hxx stops compilation. + + // Initialise the airport_atc_map - we'll cheat for now and just hardcode KEMT and any others that may be needed for development + AirportATC *a = new AirportATC; + a->lon = -118.034719; + a->lat = 34.086114; + a->elev = 296.0; + a->atis_freq = 118.75; + a->atis_active = false; + a->tower_freq = 121.2; + a->tower_active = false; + a->ground_freq = 125.9; + a->ground_active = false; + + //a->set_by_AI = true; + //a->set_by_comm_search = false; + + airport_atc_map[(string)"KEMT"] = a; } void FGATCMgr::update(int dt) { //Traverse the list of active stations. //Only update one class per update step to avoid the whole ATC system having to calculate between frames. //Eventually we should only update every so many steps. + //cout << "In FGATCMgr::update - atc_list.size = " << atc_list.size() << '\n'; if(atc_list.size()) { if(atc_list_itr == atc_list.end()) { atc_list_itr = atc_list.begin(); @@ -75,13 +109,33 @@ void FGATCMgr::update(int dt) { } ++i; } +/* +// Remove from list only if not needed by the AI system +void FGATCMgr::CommRemoveFromList(const char* id, atc_type tp) { + AirportATC a; + if(GetAirportATCDetails((string)id, &a)) { + if(a.set_by_AI) { + // Don't remove + a.set_by_comm_search = false; + airport_atc_map[(string)id] = a; + return; + } else { + // remove + +*/ +// Remove from list - should only be called from above or similar void FGATCMgr::RemoveFromList(const char* id, atc_type tp) { + //cout << "Requested type = " << tp << '\n'; + //cout << "id = " << id << '\n'; atc_list_itr = atc_list.begin(); while(atc_list_itr != atc_list.end()) { + //cout << "type = " << (*atc_list_itr)->GetType() << '\n'; + //cout << "Ident = " << (*atc_list_itr)->GetIdent() << '\n'; if( (!strcmp((*atc_list_itr)->GetIdent(), id)) && ((*atc_list_itr)->GetType() == tp) ) { //Before removing it stop it transmitting!! + //cout << "OBLITERATING FROM LIST!!!\n"; (*atc_list_itr)->SetNoDisplay(); (*atc_list_itr)->Update(); delete (*atc_list_itr); @@ -92,27 +146,94 @@ void FGATCMgr::RemoveFromList(const char* id, atc_type tp) { } } +// Returns true if the airport is found in the map +bool FGATCMgr::GetAirportATCDetails(string icao, AirportATC* a) { + if(airport_atc_map.find(icao) != airport_atc_map.end()) { + a = airport_atc_map[icao]; + return(true); + } else { + return(false); + } +} + + +// Return a pointer to a given sort of ATC at a given airport and activate if necessary +// ONLY CALL THIS FUNCTION AFTER FIRST CHECKING THE SERVICE EXISTS BY CALLING GetAirportATCDetails +FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) { + AirportATC *a = airport_atc_map[icao]; + //cout << "a->lon = " << a->lon << '\n'; + //cout << "a->elev = " << a->elev << '\n'; + //cout << "a->tower_freq = " << a->tower_freq << '\n'; + switch(type) { + case TOWER: + if(a->tower_active) { + // Get the pointer from the list + } else { + FGTower* t = new FGTower; + if(current_towerlist->query(a->lon, a->lat, a->elev, a->tower_freq, &tower)) { + *t = tower; + atc_list.push_back(t); + a->tower_active = true; + airport_atc_map[icao] = a; + return(t); + } else { + cout << "ERROR - tower that should exist in FGATCMgr::GetATCPointer for airport " << icao << " not found\n"; + } + } + break; + // Lets add the rest to get rid of the compiler warnings even though we don't need them yet. + case APPROACH: + break; + case ATIS: + cout << "ERROR - ATIS station should not be requested from FGATCMgr::GetATCPointer" << endl; + break; + case GROUND: + break; + case INVALID: + break; + case ENROUTE: + break; + case DEPARTURE: + break; + } + + cout << "ERROR IN FGATCMgr - reached end of GetATCPointer\n"; +} + + + void FGATCMgr::Search() { //////////////////////////////////////////////////////////////////////// // Comm1. //////////////////////////////////////////////////////////////////////// + //cout << "In FGATCMgr::Search() - atc_list.size = " << atc_list.size() << '\n'; comm1_freq = comm1_node->getDoubleValue(); - double lon = lon_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS; - double lat = lat_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS; + //cout << "************* comm1_freq = " << comm1_freq << '\n'; + double lon = lon_node->getDoubleValue(); + double lat = lat_node->getDoubleValue(); double elev = elev_node->getDoubleValue() * SG_FEET_TO_METER; + // Store the comm1_type + //atc_type old_comm1_type = comm1_type; + +// We must be able to generalise some of the repetetive searching below! + //Search for ATIS first if(current_atislist->query(lon, lat, elev, comm1_freq, &atis)) { //cout << "atis found in radiostack search !!!!" << endl; - comm1_ident = atis.GetIdent(); - comm1_valid = true; - if(last_comm1_ident != comm1_ident) { - if(last_comm1_ident != "") { - RemoveFromList(last_comm1_ident, ATIS); + //cout << "last_comm1_atis_ident = " << last_comm1_atis_ident << '\n'; + //cout << "comm1_type " << comm1_type << '\n'; + comm1_atis_ident = atis.GetIdent(); + comm1_atis_valid = true; + if(last_comm1_atis_ident != comm1_atis_ident) { + if(last_comm1_atis_ident != "") { + RemoveFromList(last_comm1_atis_ident, ATIS); } - last_comm1_ident = comm1_ident; + last_comm1_atis_ident = comm1_atis_ident; + //cout << "last_comm1_atis_ident = " << last_comm1_atis_ident << '\n'; + comm1_type = ATIS; comm1_elev = atis.get_elev(); comm1_range = FG_ATIS_DEFAULT_RANGE; comm1_effective_range = comm1_range; @@ -125,15 +246,168 @@ void FGATCMgr::Search() { atc_list.push_back(a); //cout << "Found a new atis station in range" << endl; //cout << " id = " << atis.GetIdent() << endl; + return; //This rather assumes that we never have more than one type of station in range. + } + } else { + if(comm1_atis_valid) { + //cout << "Removing ATIS " << comm1_atis_ident << " from list\n"; + RemoveFromList(comm1_atis_ident, ATIS); + comm1_atis_valid = false; + if(comm1_type == ATIS) { + comm1_type = INVALID; + } + comm1_atis_ident = ""; + //comm1_trans_ident = ""; + last_comm1_atis_ident = ""; + } + //cout << "not picking up atis" << endl; + } + + //Next search for tower + //cout << "comm1_freq = " << comm1_freq << '\n'; + if(current_towerlist->query(lon, lat, elev, comm1_freq, &tower)) { + //cout << "tower found in radiostack search !!!!" << endl; + comm1_tower_ident = tower.GetIdent(); + //cout << "comm1_tower_ident = " << comm1_tower_ident << '\n'; + comm1_tower_valid = true; + if(last_comm1_tower_ident != comm1_tower_ident) { + if(last_comm1_tower_ident != "") { + RemoveFromList(last_comm1_tower_ident, TOWER); + } + last_comm1_tower_ident = comm1_tower_ident; + comm1_type = TOWER; + comm1_elev = tower.get_elev(); + comm1_range = FG_TOWER_DEFAULT_RANGE; + comm1_effective_range = comm1_range; + comm1_x = tower.get_x(); + comm1_y = tower.get_y(); + comm1_z = tower.get_z(); + FGTower* t = new FGTower; + *t = tower; + t->SetDisplay(); + atc_list.push_back(t); + //cout << "Found a new tower station in range" << endl; + //cout << " id = " << tower.GetIdent() << endl; + return; //This rather assumes that we never have more than one type of station in range. + } + } else { + if(comm1_tower_valid) { + //cout << "removing tower\n"; + RemoveFromList(comm1_tower_ident, TOWER); + //comm1_valid = false; + if(comm1_type == TOWER) { + comm1_type = INVALID; // Only invalidate if we haven't switched it to something else + } + comm1_tower_valid = false; + comm1_tower_ident = ""; + last_comm1_tower_ident = ""; + //comm1_ident = ""; + //comm1_trans_ident = ""; + //last_comm1_ident = ""; + } + //cout << "not picking up tower" << endl; + } +/* + //Next search for Ground control + if(current_groundlist->query(lon, lat, elev, comm1_freq, &ground)) { + //cout << "Ground Control found in radiostack search !!!!" << endl; + comm1_ident = ground.GetIdent(); + comm1_valid = true; + if((last_comm1_ident != comm1_ident) || (comm1_type != GROUND)) { + if(last_comm1_ident != "") { + RemoveFromList(last_comm1_ident, GROUND); + } + last_comm1_ident = comm1_ident; + comm1_type = GROUND; + comm1_elev = ground.get_elev(); + comm1_range = FG_GROUND_DEFAULT_RANGE; + comm1_effective_range = comm1_range; + comm1_x = ground.get_x(); + comm1_y = ground.get_y(); + comm1_z = ground.get_z(); + FGGround* g = new FGGround; + *g = ground; + g->SetDisplay(); + atc_list.push_back(g); + // For now we will automatically make contact with ground when the radio is tuned. + // This rather assumes that the user tunes the radio at the appropriate place + // (ie. having just turned off the runway) and only uses ground control on arrival + // but its a start! + g->NewArrival(current_plane); + //cout << "Found a new ground station in range" << endl; + //cout << " id = " << ground.GetIdent() << endl; + return; //This rather assumes that we never have more than one type of station in range. } } else { - if(comm1_valid) { - RemoveFromList(comm1_ident, ATIS); + if((comm1_valid) && (comm1_type == GROUND)) { + RemoveFromList(comm1_ident, GROUND); comm1_valid = false; + comm1_type = INVALID; comm1_ident = ""; //comm1_trans_ident = ""; last_comm1_ident = ""; } - //cout << "not picking up atis" << endl; + //cout << "not picking up ground control" << endl; + } +*/ +// ================================================================================ +// Search for Approach stations +// ================================================================================ + // init number of approach stations reachable by plane + int num_app = 0; + + // search stations in range + current_approachlist->query_bck(lon, lat, elev, approaches, max_app, num_app); + if (num_app != 0) { + //cout << num_app << " approaches found in radiostack search !!!!" << endl; + + for ( int i=0; iGetIdent() << endl; + if((!strcmp((*atc_list_itr)->GetIdent(), approach_ident)) + && ((*atc_list_itr)->GetType() == APPROACH) ) { + new_app = false; + string pid = "Player"; + (*atc_list_itr)->AddPlane(pid); + (*atc_list_itr)->Update(); + break; + } + ++atc_list_itr; + } + // generate new Approach on ATC stack + if (new_app) { + FGApproach* a = new FGApproach; + *a = approaches[i]; + string pid = "Player"; + a->AddPlane(pid); + a->Update(); + a->SetDisplay(); + atc_list.push_back(a); + //cout << "Found a new approach station in range: Id = " + // << approaches[i].GetIdent() << endl; + } + } + } + + // remove planes which are out of range + atc_list_itr = atc_list.begin(); + while(atc_list_itr != atc_list.end()) { + if((*atc_list_itr)->GetType() == APPROACH ) { + int np = (*atc_list_itr)->RemovePlane(); + // if approach has no planes left remove it from ATC list + if ( np == 0) { + (*atc_list_itr)->SetNoDisplay(); + (*atc_list_itr)->Update(); + delete (*atc_list_itr); + atc_list_itr = atc_list.erase(atc_list_itr); + break; // the other stations will be checked next time + } + } + ++atc_list_itr; } } diff --git a/src/ATC/ATCmgr.hxx b/src/ATC/ATCmgr.hxx index 66dc490db..03ac392e6 100644 --- a/src/ATC/ATCmgr.hxx +++ b/src/ATC/ATCmgr.hxx @@ -25,18 +25,59 @@ #include
#include
+#include #include +#include #include "atis.hxx" +#include "tower.hxx" +#include "approach.hxx" +//#include "ground.hxx" #include "ATC.hxx" +SG_USING_STD(string); SG_USING_STD(list); +SG_USING_STD(map); + +const int max_app = 20; + +// Structure for holding details of the ATC frequencies at a given airport, and whether they are in the active list or not. +// These can then be cross referenced with the [atis][tower][etc]lists which are stored by frequency. +// Non-available services are denoted by a frequency of zero. +// Eventually the whole ATC data structures may have to be rethought if we turn out to be massive memory hogs!! +struct AirportATC { + float lon; + float lat; + float elev; + float atis_freq; + bool atis_active; + float tower_freq; + bool tower_active; + float ground_freq; + bool ground_active; + //float approach_freq; + //bool approach_active; + //float departure_freq; + //bool departure_active; + + // Flags to ensure the stations don't get wrongly deactivated + bool set_by_AI; // true when the AI manager has activated this station + bool set_by_comm_search; // true when the comm_search has activated this station +}; class FGATCMgr : public FGSubsystem { private: + // A map of airport ID vs frequencies and ATC provision + typedef map < string, AirportATC* > airport_atc_map_type; + typedef airport_atc_map_type::iterator airport_atc_map_iterator; + typedef airport_atc_map_type::const_iterator airport_atc_map_const_iterator; + + airport_atc_map_type airport_atc_map; + airport_atc_map_iterator airport_atc_map_itr; + // A list of pointers to all currently active ATC classes typedef list atc_list_type; typedef atc_list_type::iterator atc_list_iterator; @@ -55,6 +96,7 @@ private: double lat; double elev; + // Type of ATC control that the user's radios are tuned to. atc_type comm1_type; atc_type comm2_type; @@ -75,8 +117,19 @@ private: double comm1_x, comm1_y, comm1_z, comm1_elev; double comm1_range, comm1_effective_range; bool comm1_valid; + bool comm1_atis_valid; + bool comm1_tower_valid; + bool comm1_approach_valid; const char* comm1_ident; + const char* comm1_atis_ident; + const char* comm1_tower_ident; + const char* comm1_approach_ident; const char* last_comm1_ident; + const char* last_comm1_atis_ident; + const char* last_comm1_tower_ident; + const char* last_comm1_approach_ident; + const char* approach_ident; + bool last_in_range; double comm2_x, comm2_y, comm2_z, comm2_elev; double comm2_range, comm2_effective_range; bool comm2_valid; @@ -84,9 +137,10 @@ private: const char* last_comm2_ident; FGATIS atis; - //FGTower tower; //FGGround ground; - //FGApproach approach; + FGTower tower; + FGApproach approaches[max_app]; + FGApproach approach; //FGDeparture departure; public: @@ -102,6 +156,12 @@ public: void update(int dt); + // Returns true if the airport is found in the map + bool GetAirportATCDetails(string icao, AirportATC* a); + + // Return a pointer to a given sort of ATC at a given airport and activate if necessary + FGATC* GetATCPointer(string icao, atc_type type); + private: // Remove a class from the atc_list and delete it from memory diff --git a/src/ATC/ATCutils.cxx b/src/ATC/ATCutils.cxx new file mode 100644 index 000000000..e69de29bb diff --git a/src/ATC/Makefile.am b/src/ATC/Makefile.am index 1d6e1f4d6..d72f2bbc8 100644 --- a/src/ATC/Makefile.am +++ b/src/ATC/Makefile.am @@ -2,10 +2,15 @@ noinst_LIBRARIES = libATC.a libATC_a_SOURCES = \ ATC.hxx ATC.cxx \ + atis.hxx atis.cxx atislist.hxx atislist.cxx \ + tower.hxx tower.cxx towerlist.hxx towerlist.cxx \ + approach.hxx approach.cxx approachlist.hxx approachlist.cxx \ ATCdisplay.hxx ATCdisplay.cxx \ ATCmgr.hxx ATCmgr.cxx \ - atis.cxx atis.hxx \ - atislist.hxx atislist.cxx + ATCutils.hxx ATCutils.cxx \ + AIMgr.hxx AIMgr.cxx \ + AIEntity.hxx AIEntity.cxx \ + AILocalTraffic.hxx AILocalTraffic.cxx if OLD_AUTOMAKE INCLUDES += -I$(top_srcdir) -I$(top_srcdir)/src diff --git a/src/ATC/approach.cxx b/src/ATC/approach.cxx new file mode 100644 index 000000000..5d9670687 --- /dev/null +++ b/src/ATC/approach.cxx @@ -0,0 +1,366 @@ +// FGApproach - a class to provide approach control at larger airports. +// +// Written by Alexander Kappes, started March 2002. +// +// Copyright (C) 2002 Alexander Kappes +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +#include "approach.hxx" +#include "ATCdisplay.hxx" +#include + +#include +#include + + +//Constructor +FGApproach::FGApproach(){ + comm1_node = fgGetNode("/radios/comm[0]/frequencies/selected-mhz", true); + comm2_node = fgGetNode("/radios/comm[1]/frequencies/selected-mhz", true); + + num_planes = 0; + lon_node = fgGetNode("/position/longitude-deg", true); + lat_node = fgGetNode("/position/latitude-deg", true); + elev_node = fgGetNode("/position/altitude-ft", true); + first = true; + active_runway = ""; + for ( int i=0; igetDoubleValue(); + if ( (int)(comm1_freq*100.0 + 0.5) == freq ) planes[i].contact = 1; + } + else if ( planes[i].contact == 1 ) { + if ( planes[i].wpn == 0 ) { // calculate initial waypoints + wpn = planes[i].wpn; + // airport + planes[i].wpts[wpn][0] = active_rw_hdg; + planes[i].wpts[wpn][1] = 0.0; + planes[i].wpts[wpn][2] = elev; + planes[i].wpts[wpn][4] = 0.0; + planes[i].wpts[wpn][5] = 0.0; + wpn += 1; + + planes[i].wpts[wpn][0] = active_rw_hdg + 180.0; + if ( planes[i].wpts[wpn][0] > 360.0 ) planes[i].wpts[wpn][0] -= 360.0; + planes[i].wpts[wpn][1] = 5; + planes[i].wpts[wpn][2] = elev + 1000.0; + calc_hd_course_dist(planes[i].wpts[wpn][0], planes[i].wpts[wpn][1], + planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1], + &course, &d); + planes[i].wpts[wpn][4] = course; + planes[i].wpts[wpn][5] = d; + wpn += 1; + + planes[i].wpts[wpn][0] = planes[i].brg; + planes[i].wpts[wpn][1] = planes[i].dist; + planes[i].wpts[wpn][2] = planes[i].alt; + calc_hd_course_dist(planes[i].wpts[wpn][0], planes[i].wpts[wpn][1], + planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1], + &course, &d); + planes[i].wpts[wpn][4] = course; + planes[i].wpts[wpn][5] = d; + wpn += 1; + + planes[i].wpn = wpn; + + planes[i].ahdg = planes[i].wpts[wpn-1][4]; + cout << endl; + cout << "Contact " << planes[i].wpn << endl; + cout << "Turn to heading = " << (int)(planes[i].ahdg) << endl; + cout << endl; + planes[i].on_crs = true; + } + + // reached waypoint? + if ( fabs(planes[i].dnc) < 0.3 && planes[i].dnwp < 1.0 ) { + planes[i].wpn -= 1; + wpn = planes[i].wpn-1; + planes[i].ahdg = planes[i].wpts[wpn][4]; + cout << endl; + cout << "Next waypoint = " << planes[i].wpn << endl; + cout << "New heading = " << planes[i].ahdg << endl; + cout << endl; + planes[i].on_crs = true; + } + + // update assigned parameters + wpn = planes[i].wpn-1; // this is the current waypoint + + planes[i].dcc = calc_psl_dist(planes[i].brg, planes[i].dist, + planes[i].wpts[wpn][0], planes[i].wpts[wpn][1], + planes[i].wpts[wpn][4]); + planes[i].dnc = calc_psl_dist(planes[i].brg, planes[i].dist, + planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1], + planes[i].wpts[wpn-1][4]); + calc_hd_course_dist(planes[i].brg, planes[i].dist, + planes[i].wpts[wpn-1][0], planes[i].wpts[wpn-1][1], + &course, &d); + planes[i].dnwp = d; + + //cout << planes[i].brg << " " << planes[i].dist << " " << planes[i].wpts[wpn+1][0] + //<< " " << planes[i].wpts[wpn+1][1] << " " << planes[i].wpts[wpn+1][4] + //cout << " distance to current course = " << planes[i].dcc << endl; + + // come off course ? + if ( fabs(planes[i].dcc) > 0.5 && planes[i].on_crs) { + wpn = wpn-1; + if ( planes[i].wpts[wpn][4] < 0) { + planes[i].ahdg += 30.0; + } + else { + planes[i].ahdg -= 30.0; + } + planes[i].on_crs = false; + + cout << endl; + cout << "Your are " << planes[i].dcc << " miles off the asigned course: " << endl; + cout << "New heading = " << (int)(planes[i].ahdg) << endl; + cout << endl; + } + else if ( fabs(planes[i].dcc) < 0.1 && !planes[i].on_crs) { + planes[i].ahdg = fabs(planes[i].wpts[wpn][4]); + planes[i].on_crs = true; + + cout << endl; + cout << "New heading = " << (int)(planes[i].ahdg) << endl; + cout << endl; + } + + // In range of tower? + if ( planes[i].wpn == 2 && planes[i].dnwp < 3. ) { + cout << endl; + cout << "Contact Tower"; + cout << endl; + planes[i].contact = 2; + } + } + } + +} + +// ============================================================================ +// get active runway +// ============================================================================ +void FGApproach::get_active_runway() { + + sgVec3 position = { lat, lon, elev }; + FGPhysicalProperty stationweather = WeatherDatabase->get(position); + + SGPath path( globals->get_fg_root() ); + path.append( "Airports" ); + path.append( "runways.mk4" ); + FGRunways runways( path.c_str() ); + + //Set the heading to into the wind + double wind_x = stationweather.Wind[0]; + double wind_y = stationweather.Wind[1]; + + double speed = sqrt( wind_x*wind_x + wind_y*wind_y ) * SG_METER_TO_NM / (60.0*60.0); + double hdg; + + //If no wind use 270degrees + if(speed == 0) { + hdg = 270; + } else { + // //normalize the wind to get the direction + //wind_x /= speed; wind_y /= speed; + + hdg = - atan2 ( wind_x, wind_y ) * SG_RADIANS_TO_DEGREES ; + if (hdg < 0.0) + hdg += 360.0; + } + + FGRunway runway; + if ( runways.search( ident, int(hdg), &runway) ) { + active_runway = runway.rwy_no; + active_rw_hdg = runway.heading; + //cout << "Active runway is: " << active_runway << " heading = " + // << active_rw_hdg << endl; + } + else cout << "FGRunways search failed" << endl; + +} + +// ======================================================================== +// update infos about plane +// ======================================================================== +void FGApproach::update_plane_dat() { + + //cout << "Update Approach " << ident << " " << num_planes << " registered" << endl; + // update plane positions + for (int i=0; igetDoubleValue(); + planes[i].lat = lat_node->getDoubleValue(); + planes[i].alt = elev_node->getDoubleValue(); +// Point3D aircraft = sgGeodToCart( Point3D(planes[i].lon*SGD_DEGREES_TO_RADIANS, +// planes[i].lat*SGD_DEGREES_TO_RADIANS, +// planes[i].alt*SG_FEET_TO_METER) ); + double course, distance; + calc_gc_course_dist(Point3D(lon*SGD_DEGREES_TO_RADIANS, lat*SGD_DEGREES_TO_RADIANS, 0.0), + Point3D(planes[i].lon*SGD_DEGREES_TO_RADIANS,planes[i].lat*SGD_DEGREES_TO_RADIANS, 0.0 ), + &course, &distance); + planes[i].dist = distance/SG_NM_TO_METER; + planes[i].brg = 360.0-course*SGD_RADIANS_TO_DEGREES; + + //cout << "Plane Id: " << planes[i].ident << " Distance to " << ident + //<< " is " << planes[i].dist << " m" << endl; + + //if (first) { + //transmission = ident; + //globals->get_ATC_display()->RegisterRepeatingMessage(transmission); + //first = false; + //} + } +} + +// ======================================================================= +// Add plane to Approach list +// ======================================================================= +void FGApproach::AddPlane(string pid) { + for ( int i=0; i point2 +// ======================================================================== +void FGApproach::calc_hd_course_dist(const double &h1, const double &d1, + const double &h2, const double &d2, + double *course, double *dist) +{ + double a1 = h1 * SGD_DEGREES_TO_RADIANS; + double a2 = h2 * SGD_DEGREES_TO_RADIANS; + double x1 = cos(a1) * d1; + double y1 = sin(a1) * d1; + double x2 = cos(a2) * d2; + double y2 = sin(a2) * d2; + + *dist = sqrt( (y2-y1)*(y2-y1) + (x2-x1)*(x2-x1) ); + *course = atan2( (y2-y1), (x2-x1) ) * SGD_RADIANS_TO_DEGREES; + if ( *course < 0 ) *course = *course+360; + //cout << x1 << " " << y1 << " " << x2 << " " << y2 << " " << *dist << " " << *course << endl; +} + + + +int FGApproach::RemovePlane() { + + // first check if anything has to be done + bool rmplane = false; + for (int i=0; i range*SG_NM_TO_METER) { + rmplane = true; + break; + } + } + if (!rmplane) return num_planes; + + // now make a copy of the plane list + PlaneApp tmp[max_planes]; + for (int i=0; i + +#include +#include +#include +#include +#include +#include + +#include
+ +#ifdef SG_HAVE_STD_INCLUDES +# include +#include +#elif defined( SG_HAVE_NATIVE_SGI_COMPILERS ) +# include +#elif defined( __BORLANDC__ ) +# include +#else +# include +#include +#endif + +#if ! defined( SG_HAVE_NATIVE_SGI_COMPILERS ) +SG_USING_STD(istream); +#endif + +SG_USING_STD(string); + +#include "ATC.hxx" + +//DCL - a complete guess for now. +#define FG_APPROACH_DEFAULT_RANGE 100 + +// Contains all information about a plane that the approach control needs +const int max_planes = 20; // max number of planes on the stack +const int max_wp = 10; // max number of waypoints for approach phase +struct PlaneApp { + + // variables for plane if it's on the radar + string ident; // indentification of plane + double lon; // longitude in degrees + double lat; // latitude in degrees + double alt; // Altitute above sea level in feet + double hdg; // heading of plane in degrees + double dist; // distance to airport in miles + double brg; // bearing relative to airport in degrees + double spd; // speed above ground + int contact; // contact with approach established? + // 0 = no contact yet + // 1 = in contact + // 2 = handed off to tower + + // additional variables if contact has been established + int wpn; // number of waypoints + double wpts[max_wp][6]; // assigned waypoints for approach phase + // first wp in list is airport + // last waypoint point at which contact was established + // second index: 0 = bearing to airport + // second index: 1 = distance to aiport + // second index: 2 = alt + // second index: 3 = ETA + // second index: 4 = heading to next waypoint + // second index: 5 = distance to next waypoint + + double dnwp; // distance to next waypoint + double dcc; // closest distance to current assigned course + double dnc; // closest distance to course from next to next to next wp + double aalt; // assigned alt at next waypoint + double ahdg; // assigned heading + bool on_crs; // is the plane on course? + double tlm; // time when last message was sent +}; + + +class FGApproach : public FGATC { + + char type; + double lon, lat; + double elev; + double x, y, z; + int freq; + int bucket; + double range; + + string active_runway; + double active_rw_hdg; + + bool display; // Flag to indicate whether we should be outputting to the display. + bool displaying; // Flag to indicate whether we are outputting to the display. + string ident; // Code of the airport its at. + string name; // Name transmitted in the broadcast. + int num_planes; // number of planes on the stack + PlaneApp planes[max_planes]; // Array of planes + string transmission; + bool first; + + SGPropertyNode *comm1_node; + SGPropertyNode *comm2_node; + + // for failure modeling + string trans_ident; // transmitted ident + bool approach_failed; // approach failed? + +public: + + FGApproach(void); + ~FGApproach(void); + + void Init(); + + void Update(); + + // Add new plane to stack if not already registered + // Input: pid - id of plane (name) + // Output: "true" if added; "false" if already existend + void AddPlane(string pid); + + // Remove plane from stack if out of range + int RemovePlane(); + + //Indicate that this instance should be outputting to the ATC display + inline void SetDisplay(void) {display = true;} + + //Indicate that this instance should not be outputting to the ATC display + inline void SetNoDisplay(void) {display = false;} + + inline char get_type() const { return type; } + inline double get_lon() const { return lon; } + inline double get_lat() const { return lat; } + inline double get_elev() const { return elev; } + inline double get_x() const { return x; } + inline double get_y() const { return y; } + inline double get_z() const { return z; } + inline double get_bucket() const { return bucket; } + inline int get_freq() const { return freq; } + inline double get_range() const { return range; } + inline int get_pnum() const { return num_planes; } + inline const char* GetIdent() { return ident.c_str(); } + inline string get_trans_ident() { return trans_ident; } + inline string get_name() { return name; } + inline atc_type GetType() { return APPROACH; } + +private: + + void update_plane_dat(); + + void get_active_runway(); + +// ======================================================================== +// get heading and distance between two points; point2 ---> point1 +// input: point1 = heading in degrees, distance +// input: point2 = heading in degrees, distance +// ouput: course in degrees, distance +// ======================================================================== + void calc_hd_course_dist(const double &h1, const double &d1, + const double &h2, const double &d2, + double *course, double *dist); + +// ======================================================================== +// closest distance between a point and a straigt line in 2 dim. +// the input variables are given in (heading, distance) +// relative to a common point +// input: point = heading in degrees, distance +// input: straigt line = anker vector (heading in degrees, distance), +// heading of direction vector +// output: distance +// ======================================================================== + double calc_psl_dist(const double &h1, const double &d1, + const double &h2, const double &d2, + const double &h3); + + // Pointers to current users position + SGPropertyNode *lon_node; + SGPropertyNode *lat_node; + SGPropertyNode *elev_node; + + //Update the transmission string + void UpdateTransmission(void); + + friend istream& operator>> ( istream&, FGApproach& ); +}; + + +inline istream& +operator >> ( istream& in, FGApproach& a ) +{ + double f; + char ch; + + static bool first_time = true; + static double julian_date = 0; + static const double MJD0 = 2415020.0; + if ( first_time ) { + julian_date = sgTimeCurrentMJD(0, 0) + MJD0; + first_time = false; + } + + in >> a.type; + + if ( a.type == '[' ) + return in >> skipeol; + + in >> a.lat >> a.lon >> a.elev >> f >> a.range + >> a.ident; + + a.name = ""; + in >> ch; + a.name += ch; + while(1) { + //in >> noskipws + in.unsetf(ios::skipws); + in >> ch; + a.name += ch; + if((ch == '"') || (ch == 0x0A)) { + break; + } // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the " + } + in.setf(ios::skipws); + //cout << "approach.name = " << a.name << '\n'; + + a.freq = (int)(f*100.0 + 0.5); + + // generate cartesian coordinates + Point3D geod( a.lon * SGD_DEGREES_TO_RADIANS , a.lat * SGD_DEGREES_TO_RADIANS, + a.elev * SG_FEET_TO_METER ); + Point3D cart = sgGeodToCart( geod ); + a.x = cart.x(); + a.y = cart.y(); + a.z = cart.z(); + + // get bucket number + SGBucket buck(a.lon, a.lat); + a.bucket = buck.gen_index(); + + a.trans_ident = a.ident; + a.approach_failed = false; + + return in >> skipeol; +} + +#endif // _FG_APPROACH_HXX \ No newline at end of file diff --git a/src/ATC/approachlist.cxx b/src/ATC/approachlist.cxx new file mode 100644 index 000000000..db399e526 --- /dev/null +++ b/src/ATC/approachlist.cxx @@ -0,0 +1,234 @@ +// approachlist.cxx -- Approach data management class +// +// Written by Alexander Kappes, started March 2002. +// Based on navlist.cxx by Curtis Olson, started April 2000. +// +// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. +// +// $Id$ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +#include "approachlist.hxx" + + +FGApproachList *current_approachlist; + + +// Constructor +FGApproachList::FGApproachList( void ) { +} + + +// Destructor +FGApproachList::~FGApproachList( void ) { +} + + +// load the approach data and build the map +bool FGApproachList::init( SGPath path ) { + + approachlist_freq.erase( approachlist_freq.begin(), approachlist_freq.end() ); + approachlist_bck.erase( approachlist_bck.begin(), approachlist_bck.end() ); + + sg_gzifstream in( path.str() ); + if ( !in.is_open() ) { + SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() ); + exit(-1); + } + + // read in each line of the file + + // in >> skipeol; + in >> skipcomment; + + cout << " APPROACH " << endl; +#ifdef __MWERKS__ + char c = 0; + while ( in.get(c) && c != '\0' ) { + in.putback(c); +#else + while ( !in.eof() ) { +#endif + + FGApproach a; + in >> a; + if ( a.get_type() == '[' ) { + break; + } + //cout << " type = " << a.get_type() << endl; + //cout << " lon = " << a.get_lon() << endl; + //cout << " lat = " << a.get_lat() << endl; + //cout << " elev = " << a.get_elev() << endl; + //cout << " freq = " << a.get_freq() << endl; + //cout << " Airport Code = " << a.GetIdent() << endl; + //cout << " Name = " << a.get_name() << endl; + + approachlist_freq[a.get_freq()].push_back(a); + approachlist_bck[a.get_bucket()].push_back(a); + in >> skipcomment; + + } + + return true; +} + + +// query the database for the specified frequency, lon and lat are in +// degrees, elev is in meters +bool FGApproachList::query_freq( double lon, double lat, double elev, double freq, + FGApproach *a ) +{ + lon *= SGD_DEGREES_TO_RADIANS; + lat *= SGD_DEGREES_TO_RADIANS; + + approach_list_type stations = approachlist_freq[(int)(freq*100.0 + 0.5)]; + + approach_list_iterator current = stations.begin(); + approach_list_iterator last = stations.end(); + + // double az1, az2, s; + Point3D aircraft = sgGeodToCart( Point3D(lon, lat, elev) ); + Point3D station; + double d; + for ( ; current != last ; ++current ) { + //cout << "testing " << current->GetIdent() << endl; + station = Point3D(current->get_x(), current->get_y(), current->get_z()); + //cout << "aircraft = " << aircraft << endl; + //cout << "station = " << station << endl; + + d = aircraft.distance3Dsquared( station ); + + //cout << " dist = " << sqrt(d) + // << " range = " << current->get_range() * SG_NM_TO_METER << endl; + //cout << " Aircraft: lon = " << lon << " lat = " << lat + // << " elev = " << elev << endl; + //cout << " Airport: lon = " << current->get_lon() + // << " lat = " << current->get_lat() + // << " elev = " << current->get_elev() + // << " z = " << current->get_z() << endl; + + // match up to twice the published range so we can model + // reduced signal strength + if ( d < (2 * current->get_range() * SG_NM_TO_METER + * 2 * current->get_range() * SG_NM_TO_METER ) ) { + //cout << "matched = " << current->GetIdent() << endl; + *a = *current; + return true; + } + } + return false; +} + +// query the database for the specified frequency, lon and lat are in +// degrees, elev is in meters +bool FGApproachList::query_bck( double lon, double lat, double elev, FGApproach *a, + int max_app, int &num_app) +{ + + // get bucket number for plane position + SGBucket buck(lon, lat); + + //cout << "plane bucket" << bucket << endl; + + // get neigboring buckets + double max_range = 100; + int bx = int ( max_range*SG_NM_TO_METER / buck.get_width_m() / 2); + int by = int ( max_range*SG_NM_TO_METER / buck.get_height_m() / 2 ); + + // loop over bucket range + for ( int i=-bx; iget_name() << endl; + cout << "bucket" << current->get_bucket() << endl; + } + + return 0; + +} \ No newline at end of file diff --git a/src/ATC/approachlist.hxx b/src/ATC/approachlist.hxx new file mode 100644 index 000000000..cc53bd4f4 --- /dev/null +++ b/src/ATC/approachlist.hxx @@ -0,0 +1,79 @@ +// approachlist.hxx -- approach management class +// +// Written by Alexander Kappes, started March 2002. +// Based on navlist.hxx by Curtis Olson, started April 2000. +// +// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. +// + + +#ifndef _FG_APPROACHLIST_HXX +#define _FG_APPROACHLIST_HXX + + +#include +#include + +#include +#include + +#include "approach.hxx" + +SG_USING_STD(map); +SG_USING_STD(vector); + + +class FGApproachList { + + // convenience types + typedef vector < FGApproach > approach_list_type; + typedef approach_list_type::iterator approach_list_iterator; + typedef approach_list_type::const_iterator approach_list_const_iterator; + + // typedef map < int, approach_list_type, less > approach_map_type; + typedef map < int, approach_list_type > approach_map_type; + typedef approach_map_type::iterator approach_map_iterator; + typedef approach_map_type::const_iterator approach_map_const_iterator; + + approach_map_type approachlist_freq; + approach_map_type approachlist_bck; + +public: + + FGApproachList(); + ~FGApproachList(); + + // load the approach data and build the map + bool init( SGPath path ); + + // query the database for the specified frequency, lon and lat are + // in degrees, elev is in meters + bool query_freq( double lon, double lat, double elev, double freq, FGApproach *a ); + + // query the database for the specified bucket number, lon and lat are + // in degrees + bool query_bck( double lon, double lat, double elev, FGApproach *a, int max_app, int &num_app ); + + bool get_name( string apt_id ); + +}; + + +extern FGApproachList *current_approachlist; + + +#endif // _FG_APPROACHLIST_HXX diff --git a/src/ATC/atislist.cxx b/src/ATC/atislist.cxx index 1245dad32..08e440fec 100644 --- a/src/ATC/atislist.cxx +++ b/src/ATC/atislist.cxx @@ -1,4 +1,4 @@ -// atislist.cxx -- navaids management class +// atislist.cxx -- ATIS data management class // // Written by David Luff, started October 2001. // Based on navlist.cxx by Curtis Olson, started April 2000. @@ -58,18 +58,14 @@ bool FGATISList::init( SGPath path ) { // read in each line of the file - // in >> skipeol; in >> skipcomment; - // double min = 100000; - // double max = 0; - #ifdef __MWERKS__ char c = 0; while ( in.get(c) && c != '\0' ) { in.putback(c); #else - while ( ! in.eof() ) { + while ( !in.eof() ) { #endif FGATIS a; @@ -89,19 +85,8 @@ bool FGATISList::init( SGPath path ) { atislist[a.get_freq()].push_back(a); in >> skipcomment; - /* if ( a.get_type() != 'N' ) { - if ( a.get_freq() < min ) { - min = a.get_freq(); - } - if ( a.get_freq() > max ) { - max = a.get_freq(); - } - } */ } - // cout << "min freq = " << min << endl; - // cout << "max freq = " << max << endl; - return true; } @@ -111,6 +96,9 @@ bool FGATISList::init( SGPath path ) { bool FGATISList::query( double lon, double lat, double elev, double freq, FGATIS *a ) { + lon *= SGD_DEGREES_TO_RADIANS; + lat *= SGD_DEGREES_TO_RADIANS; + atis_list_type stations = atislist[(int)(freq*100.0 + 0.5)]; atis_list_iterator current = stations.begin(); diff --git a/src/ATC/ground.cxx b/src/ATC/ground.cxx new file mode 100644 index 000000000..d70957e43 --- /dev/null +++ b/src/ATC/ground.cxx @@ -0,0 +1,80 @@ +// FGGround - a class to provide ground control at larger airports. +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +#include "ground.hxx" + +void FGGround::Init() { + display = false; +} + +void FGGround::Update() { + // Each time step, what do we need to do? + // We need to go through the list of outstanding requests and acknowedgements + // and process at least one of them. + // We need to go through the list of planes under our control and check if + // any need to be addressed. + // We need to check for planes not under our control coming within our + // control area and address if necessary. + + // Lets take the example of a plane which has just contacted ground + // following landing - presumably requesting where to go? + // First we need to establish the position of the plane within the logical network. + // Next we need to decide where its going. +} + +void FGGround::NewArrival(plane_rec plane) { + // What are we going to do here? + // We need to start a new ground_rec and add the plane_rec to it + // We need to decide what gate we are going to clear it to. + // Then we need to add clearing it to that gate to the pending transmissions queue? - or simply transmit? + // Probably simply transmit for now and think about a transmission queue later if we need one. + // We might need one though in order to add a little delay for response time. + ground_rec* g = new ground_rec; + g->plane_rec = plane; + g->current_pos = ConvertWGS84ToXY(plane.pos); + g->node = GetNode(g->current_pos); // TODO - might need to sort out node/arc here + AssignGate(g); + g->cleared = false; + ground_traffic.push_back(g); + NextClearance(g); +} + +void FGGround::NewContact(plane_rec plane) { + // This is a bit of a convienience function at the moment and is likely to change. + if(at a gate or apron) + NewDeparture(plane); + else + NewArrival(plane); +} + +void FGGround::NextClearance(ground_rec &g) { + // Need to work out where we can clear g to. + // Assume the pilot doesn't need progressive instructions + // We *should* already have a gate or holding point assigned by the time we get here + // but it wouldn't do any harm to check. + + // For now though we will hardwire it to clear to the final destination. +} + +void FGGround::AssignGate(ground_rec &g) { + // We'll cheat for now - since we only have the user's aircraft and a couple of airports implemented + // we'll hardwire the gate! + // In the long run the logic of which gate or area to send the plane to could be somewhat non-trivial. +} \ No newline at end of file diff --git a/src/ATC/ground.hxx b/src/ATC/ground.hxx new file mode 100644 index 000000000..18dd100e9 --- /dev/null +++ b/src/ATC/ground.hxx @@ -0,0 +1,150 @@ +// FGGround - a class to provide ground control at larger airports. +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +#ifndef _FG_GROUND_HXX +#define _FG_GROUND_HXX + +#include +#include +//#include + +SG_USING_STD(vector); +SG_USING_STD(list); +//SG_USING_STD(map); + +////////////////////////////////////////////////////// +// Types for the logical network data structure +typedef enum arc_type { + RUNWAY, + TAXIWAY +}; + +typedef enum node_type { + GATE, + APRON, + HOLD +}; + +typedef struct arc { + int distance; + char* name; + arc_type type; +}; + +typedef list arc_list_type; +typedef arc_list_type::iterator arc_list_itr; +typedef arc_list_type::const_iterator arc_list_const_itr; + +typedef struct node { + point pos; + char* name; + node_type node; + arc_list arcs; +}; + +typedef vector node_array_type; +typedef node_array_type::iterator node_array_itr; +typedef node_array_type::const_iterator node_array_const_itr; +// end logical network types +/////////////////////////////////////////////////////// + +// somewhere in the ATC/AI system we are going to have defined something like +// typedef struct plane_rec +// list plane_rec_list_type + +// A more specialist plane rec to include ground information +typedef struct ground_rec { + plane_rec plane; + point current_pos; + node destination; + node last_clearance; + bool cleared; // set true when the plane has been cleared to somewhere + bool incoming; //true for arrivals, false for departures + // status? + // Almost certainly need to add more here +}; + +typedef list ground_rec_list; +typedef ground_rec_list::iterator ground_rec_list_itr; +typedef ground_rec_list::const_iterator ground_rec_list_const_itr; + +/////////////////////////////////////////////////////////////////////////////// +// +// FGGround +// +/////////////////////////////////////////////////////////////////////////////// +class FGGround : public FGATC { + +private: + + // Need a data structure to hold details of the various active planes + // Need a data structure to hold details of the logical network + // including which gates are filled - or possibly another data structure + // with the positions of the inactive planes. + // Need a data structure to hold outstanding communications from aircraft. + // Possibly need a data structure to hold outstanding communications to aircraft. + + // logical network + node_array_type network; + + // Planes currently active + ground_rec_list ground_traffic; + +public: + + void Init(); + + void Update(); + + inline void SetDisplay() {display = true;} + inline void SetNoDisplay() {display = false;} + + // Its possible that NewArrival and NewDeparture should simply be rolled into Request. + + // Contact ground control on arrival, assumed to request any gate + void NewArrival(plane_rec plane); + + // Contact ground control on departure, assumed to request currently active runway. + void NewDeparture(plane_rec plane); + + // Contact ground control when the calling routine doesn't know if arrival + // or departure is appropriate. + void NewContact(plane_rec plane); + + // Make a request of ground control. + void Request(ground_request request); + +private: + + // Find the shortest route through the logical network between two points. + FindShortestRoute(point a, point b); + + // Project a point in WGS84 lat/lon onto the local gnomonic. + ConvertWGS84ToXY(sgVec3 wgs84, point xy); + + // Assign a gate or parking location to a new arrival + AssignGate(ground_rec &g); + + // Generate the next clearance for an airplane + NextClearance(ground_rec &g); + +}; + +#endif //_FG_GROUND_HXX \ No newline at end of file diff --git a/src/ATC/runways.cxx b/src/ATC/runways.cxx new file mode 100644 index 000000000..d45b5abf1 --- /dev/null +++ b/src/ATC/runways.cxx @@ -0,0 +1,496 @@ +// runways.hxx -- a simple class to manage airport runway info +// +// Written by Curtis Olson, started August 2000. +// +// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. +// +// $Id$ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include // fabs() +#include // sprintf() + +#include + +#include +#include + +#include STL_STRING +#include STL_FUNCTIONAL +#include STL_ALGORITHM + +#include "runways.hxx" + +SG_USING_NAMESPACE(std); + + +FGRunway::FGRunway() { +} + + +FGRunway::~FGRunway() { +} + + +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; +} + + +// 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()]); + // cout << "index = " << index << endl; + + if ( index == -1 ) { + 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; +} + + +// search for the specified apt id and runway no +bool FGRunways::search( const string& aptid, const string& rwyno, 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()]); + // cout << "index = " << index << endl; + + if ( index == -1 ) { + return false; + } + + c4_RowRef row = vRunway->GetAt(index); + string rowid = (const char *) pID(row); + string rowrwyno = (const char *) pRwy(row); + while ( rowid == aptid ) { + next_index = index + 1; + + if ( rowrwyno == rwyno ) { + 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; + } + + index++; + c4_RowRef row = vRunway->GetAt(index); + string rowid = (const char *) pID(row); + string 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 the runway closest to a given heading +bool FGRunways::search( const string& aptid, const int tgt_hdg, + FGRunway* runway ) +{ + FGRunway r; + FGRunway br; + double found_dir = 0.0; + + if ( !search( aptid, &r ) ) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Failed to find " << aptid << " in database." ); + return false; + } + + double diff; + double min_diff = 360.0; + + while ( r.id == aptid ) { + // 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; + //runway = &r; + br = r; + 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; + //runway = &r; + br = r; + found_dir = 180.0; + } + next( &r ); + } + + // SG_LOG( SG_GENERAL, SG_INFO, "closest runway = " << runway->rwy_no + // << " + " << found_dir ); + + *runway = br; + double heading = runway->heading + found_dir; + while ( heading >= 360.0 ) { heading -= 360.0; } + runway->heading = heading; + //cout << runway->heading << " " << runway->rwy_no + // << " " << runway->id << endl; + return true; +} + + +// Return the runway number of the runway closest to a given heading +string FGRunways::search( const string& aptid, const int tgt_hdg ) { + FGRunway r; + string rn; + double found_dir = 0.0; + + if ( !search( aptid, &r ) ) { + SG_LOG( SG_GENERAL, SG_ALERT, + "Failed to find " << aptid << " in database." ); + return "NN"; + } + + double diff; + double min_diff = 360.0; + + while ( r.id == aptid ) { + // 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( &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 ) { + int irn = atoi(rn.c_str()); + irn += 18; + if ( irn > 36 ) { + irn -= 36; + } + char buf[4]; // 2 chars + string terminator + 1 for safety + sprintf(buf, "%i", irn); + rn = buf; + } + + return rn; +} + + +// 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 +{ + const_iterator it = runways.find( FGRunway(id) ); + if ( it != runways.end() ) + { + *a = *it; + return true; + } + else + { + return false; + } +} + + +FGRunway +FGRunwaysUtil::search( const string& id ) const +{ + FGRunway a; + this->search( id, &a ); + return a; +} +#endif + +// Destructor +FGRunwaysUtil::~FGRunwaysUtil( void ) { +} + + diff --git a/src/ATC/tower.cxx b/src/ATC/tower.cxx new file mode 100644 index 000000000..e22713efc --- /dev/null +++ b/src/ATC/tower.cxx @@ -0,0 +1,52 @@ +// FGTower - a class to provide tower control at towered airports. +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +#include
+ +#include "tower.hxx" +#include "ATCdisplay.hxx" + +FGTower::FGTower() { +} + +FGTower::~FGTower() { +} + +void FGTower::Init() { + display = false; +} + +void FGTower::Update() { + // Each time step, what do we need to do? + // We need to go through the list of outstanding requests and acknowedgements + // and process at least one of them. + // We need to go through the list of planes under our control and check if + // any need to be addressed. + // We need to check for planes not under our control coming within our + // control area and address if necessary. + + // Hardwired for testing + static int play = 0; + if(play == 200) { + //cout << "Registering message in tower.cxx ****************************\n"; + //globals->get_ATC_display()->RegisterSingleMessage((string)"Cessna eight-two-zero Cleared for takeoff", 2); + } + ++play; +} diff --git a/src/ATC/tower.hxx b/src/ATC/tower.hxx new file mode 100644 index 000000000..2d66b091d --- /dev/null +++ b/src/ATC/tower.hxx @@ -0,0 +1,148 @@ +// FGTower - a class to provide tower control at towered airports. +// +// Written by David Luff, started March 2002. +// +// Copyright (C) 2002 David C. Luff - david.luff@nottingham.ac.uk +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + +#ifndef _FG_TOWER_HXX +#define _FG_TOWER_HXX + +#include +#include +#include +#include +#include + +#include + +SG_USING_STD(string); + +#include "ATC.hxx" + +//DCL - a complete guess for now. +#define FG_TOWER_DEFAULT_RANGE 30 + +// somewhere in the ATC/AI system we are going to have defined something like +// struct plane_rec +// list plane_rec_list_type + +class FGTower : public FGATC { + +private: + + // Need a data structure to hold details of the various active planes + // or possibly another data structure with the positions of the inactive planes. + // Need a data structure to hold outstanding communications from aircraft. + + +public: + + FGTower(); + ~FGTower(); + + void Init(); + + void Update(); + + inline void SetDisplay() {display = true;} + inline void SetNoDisplay() {display = false;} + + inline char get_type() const { return type; } + inline double get_lon() const { return lon; } + inline double get_lat() const { return lat; } + inline double get_elev() const { return elev; } + inline double get_x() const { return x; } + inline double get_y() const { return y; } + inline double get_z() const { return z; } + inline int get_freq() const { return freq; } + inline int get_range() const { return range; } + inline const char* GetIdent() { return ident.c_str(); } + inline string get_trans_ident() { return trans_ident; } + inline atc_type GetType() { return TOWER; } + + // Make a request of tower control + //void Request(tower_request request); + +private: + + char type; + double lon, lat; + double elev; + double x, y, z; + int freq; + int range; + bool display; // Flag to indicate whether we should be outputting to the ATC display. + bool displaying; // Flag to indicate whether we are outputting to the ATC display. + string ident; // Code of the airport its at. + string name; // Name generally used in transmissions. + + // for failure modeling + string trans_ident; // transmitted ident + bool tower_failed; // tower failed? + + friend istream& operator>> ( istream&, FGTower& ); +}; + + +inline istream& +operator >> ( istream& in, FGTower& t ) +{ + double f; + char ch; + + in >> t.type; + + if ( t.type == '[' ) + return in >> skipeol; + + in >> t.lat >> t.lon >> t.elev >> f >> t.range + >> t.ident; + + t.name = ""; + in >> ch; + t.name += ch; + while(1) { + //in >> noskipws + in.unsetf(ios::skipws); + in >> ch; + t.name += ch; + if((ch == '"') || (ch == 0x0A)) { + break; + } // we shouldn't need the 0x0A but it makes a nice safely in case someone leaves off the " + } + in.setf(ios::skipws); + //cout << "tower.name = " << t.name << '\n'; + + t.freq = (int)(f*100.0 + 0.5); + + // cout << t.ident << endl; + + // generate cartesian coordinates + Point3D geod( t.lon * SGD_DEGREES_TO_RADIANS, t.lat * SGD_DEGREES_TO_RADIANS, t.elev ); + Point3D cart = sgGeodToCart( geod ); + t.x = cart.x(); + t.y = cart.y(); + t.z = cart.z(); + + t.trans_ident = t.ident; + t.tower_failed = false; + + return in >> skipeol; +} + + +#endif //_FG_TOWER_HXX \ No newline at end of file diff --git a/src/ATC/towerlist.cxx b/src/ATC/towerlist.cxx new file mode 100644 index 000000000..ba3b4c7b5 --- /dev/null +++ b/src/ATC/towerlist.cxx @@ -0,0 +1,134 @@ +// towerlist.cxx -- ATC Tower data management class +// +// Written by David Luff, started March 2002. +// Based on navlist.cxx by Curtis Olson, started April 2000. +// +// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "towerlist.hxx" + +FGTowerList *current_towerlist; + +// Constructor +FGTowerList::FGTowerList( void ) { +} + + +// Destructor +FGTowerList::~FGTowerList( void ) { +} + + +// load the navaids and build the map +bool FGTowerList::init( SGPath path ) { + + towerlist.erase( towerlist.begin(), towerlist.end() ); + + sg_gzifstream in( path.str() ); + if ( !in.is_open() ) { + SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() ); + exit(-1); + } + + // read in each line of the file + + in >> skipcomment; + +#ifdef __MWERKS__ + char c = 0; + while ( in.get(c) && c != '\0' ) { + in.putback(c); +#else + while ( !in.eof() ) { +#endif + + FGTower t; + in >> t; + if ( t.get_type() == '[' ) { + break; + } + + //cout << "id = " << t.GetIdent() << endl; + //cout << " type = " << t.get_type() << endl; + //cout << " lon = " << t.get_lon() << endl; + //cout << " lat = " << t.get_lat() << endl; + //cout << " elev = " << t.get_elev() << endl; + //cout << " freq = " << t.get_freq() << endl; + //cout << " range = " << t.get_range() << endl; + + towerlist[t.get_freq()].push_back(t); + in >> skipcomment; + } + + return true; +} + + +// query the database for the specified frequency, lon and lat are in +// degrees, elev is in meters +bool FGTowerList::query( double lon, double lat, double elev, double freq, + FGTower *t ) +{ + lon *= SGD_DEGREES_TO_RADIANS; + lat *= SGD_DEGREES_TO_RADIANS; + //cout << "lon = " << lon << '\n'; + //cout << "lat = " << lat << '\n'; + //cout << "elev = " << elev << '\n'; + //cout << "freq = " << freq << '\n'; + + tower_list_type stations = towerlist[(int)(freq*100.0 + 0.5)]; + + tower_list_iterator current = stations.begin(); + tower_list_iterator last = stations.end(); + + // double az1, az2, s; + Point3D aircraft = sgGeodToCart( Point3D(lon, lat, elev) ); + Point3D station; + double d; + for ( ; current != last ; ++current ) { + //cout << "testing " << current->GetIdent() << endl; + station = Point3D(current->get_x(), current->get_y(), current->get_z()); + //cout << "aircraft = " << aircraft << endl; + //cout << "station = " << station << endl; + + d = aircraft.distance3Dsquared( station ); + + //cout << " dist = " << sqrt(d) + // << " range = " << current->get_range() * SG_NM_TO_METER << endl; + + // match up to twice the published range so we can model + // reduced signal strength + if ( d < (2 * current->get_range() * SG_NM_TO_METER + * 2 * current->get_range() * SG_NM_TO_METER ) ) { + //cout << "matched = " << current->GetIdent() << endl; + *t = *current; + return true; + } + } + + return false; +} \ No newline at end of file diff --git a/src/ATC/towerlist.hxx b/src/ATC/towerlist.hxx new file mode 100644 index 000000000..5dc6e2fdb --- /dev/null +++ b/src/ATC/towerlist.hxx @@ -0,0 +1,74 @@ +// towerlist.hxx -- ATC Tower data management class +// +// Written by David Luff, started March 2002. +// Based on navlist.hxx by Curtis Olson, started April 2000. +// +// Copyright (C) 2000 Curtis L. Olson - curt@flightgear.org +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// 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. + + +#ifndef _FG_TOWERLIST_HXX +#define _FG_TOWERLIST_HXX + + +#include +#include + +#include +#include +#include + +#include "tower.hxx" + +SG_USING_STD(map); +SG_USING_STD(vector); +SG_USING_STD(string); + + +class FGTowerList { + + // convenience types + typedef vector < FGTower > tower_list_type; + typedef tower_list_type::iterator tower_list_iterator; + typedef tower_list_type::const_iterator tower_list_const_iterator; + + // Map containing FGTower keyed by frequency. + // A vector of FGTower is kept at each node since some may share frequency + typedef map < int, tower_list_type > tower_map_type; + typedef tower_map_type::iterator tower_map_iterator; + typedef tower_map_type::const_iterator tower_map_const_iterator; + + tower_map_type towerlist; + +public: + + FGTowerList(); + ~FGTowerList(); + + // load all atis and build the map + bool init( SGPath path ); + + // query the database for the specified frequency, lon and lat are + // in degrees, elev is in meters + bool query( double lon, double lat, double elev, double freq, FGTower *t ); + +}; + + +extern FGTowerList *current_towerlist; + + +#endif // _FG_TOWERLIST_HXX \ No newline at end of file diff --git a/src/Main/fg_init.cxx b/src/Main/fg_init.cxx index 4f4abe566..4dae0a6ab 100644 --- a/src/Main/fg_init.cxx +++ b/src/Main/fg_init.cxx @@ -73,6 +73,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -856,13 +859,24 @@ bool fgInitSubsystems( void ) { // Initialize ATC list management and query systems //////////////////////////////////////////////////////////////////// - //DCL SG_LOG(SG_GENERAL, SG_INFO, " ATIS"); current_atislist = new FGATISList; SGPath p_atis( globals->get_fg_root() ); p_atis.append( "ATC/default.atis" ); current_atislist->init( p_atis ); + SG_LOG(SG_GENERAL, SG_INFO, " Tower"); + current_towerlist = new FGTowerList; + SGPath p_tower( globals->get_fg_root() ); + p_tower.append( "ATC/default.tower" ); + current_towerlist->init( p_tower ); + + SG_LOG(SG_GENERAL, SG_INFO, " Approach"); + current_approachlist = new FGApproachList; + SGPath p_approach( globals->get_fg_root() ); + p_approach.append( "ATC/default.approach" ); + current_approachlist->init( p_approach ); + //////////////////////////////////////////////////////////////////// // Initialise ATC display system //////////////////////////////////////////////////////////////////// @@ -877,7 +891,15 @@ bool fgInitSubsystems( void ) { SG_LOG(SG_GENERAL, SG_INFO, " ATC Manager"); globals->set_ATC_mgr(new FGATCMgr); - globals->get_ATC_mgr()->init(); + globals->get_ATC_mgr()->init(); + + //////////////////////////////////////////////////////////////////// + // Initialise the AI Manager + //////////////////////////////////////////////////////////////////// + + SG_LOG(SG_GENERAL, SG_INFO, " AI Manager"); + globals->set_AI_mgr(new FGAIMgr); + globals->get_AI_mgr()->init(); //////////////////////////////////////////////////////////////////// // Initialize the built-in commands. diff --git a/src/Main/globals.hxx b/src/Main/globals.hxx index 75c119313..4bcdf73e9 100644 --- a/src/Main/globals.hxx +++ b/src/Main/globals.hxx @@ -64,6 +64,7 @@ class FGFX; class FGViewer; class FGATCMgr; class FGATCDisplay; +class FGAIMgr; /** @@ -134,6 +135,9 @@ private: // ATC Renderer FGATCDisplay *ATC_display; + // AI manager + FGAIMgr *AI_mgr; + // control input state FGControls *controls; @@ -215,7 +219,10 @@ public: inline void set_ATC_mgr( FGATCMgr *a ) {ATC_mgr = a; } inline FGATCDisplay *get_ATC_display() const { return ATC_display; } - inline void set_ATC_display( FGATCDisplay *d ) {ATC_display = d; } + inline void set_ATC_display( FGATCDisplay *d ) {ATC_display = d; } + + inline FGAIMgr *get_AI_mgr() const { return AI_mgr; } + inline void set_AI_mgr( FGAIMgr *a ) {AI_mgr = a; } inline FGSoundMgr *get_soundmgr() const { return soundmgr; } inline void set_soundmgr( FGSoundMgr *sm ) { soundmgr = sm; } diff --git a/src/Main/main.cxx b/src/Main/main.cxx index ef9d70bf7..7ee6c4531 100644 --- a/src/Main/main.cxx +++ b/src/Main/main.cxx @@ -81,6 +81,8 @@ #include #include +#include + #include #include @@ -1045,7 +1047,10 @@ static void fgMainLoop( void ) { #endif // Run ATC subsystem - globals->get_ATC_mgr()->update(1); // FIXME: use real dt + globals->get_ATC_mgr()->update(1); // FIXME - use real dt. + + // Run the AI subsystem + globals->get_AI_mgr()->update(1); // FIXME - use real dt. // Run flight model -- 2.39.5