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.
This commit is contained in:
parent
716aa4f7ea
commit
7543409e47
29 changed files with 3162 additions and 40 deletions
137
src/ATC/AIEntity.cxx
Normal file
137
src/ATC/AIEntity.cxx
Normal file
|
@ -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 <Main/globals.hxx>
|
||||
#include <Scenery/scenery.hxx>
|
||||
//#include <simgear/constants.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <string>
|
||||
|
||||
#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 );
|
||||
}
|
71
src/ATC/AIEntity.hxx
Normal file
71
src/ATC/AIEntity.hxx
Normal file
|
@ -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 <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
|
||||
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
|
100
src/ATC/AILocalTraffic.cxx
Normal file
100
src/ATC/AILocalTraffic.cxx
Normal file
|
@ -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 <Main/globals.hxx>
|
||||
//#include <simgear/constants.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <string>
|
||||
|
||||
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++;
|
||||
}
|
100
src/ATC/AILocalTraffic.hxx
Normal file
100
src/ATC/AILocalTraffic.hxx
Normal file
|
@ -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 <plib/sg.h>
|
||||
#include <plib/ssg.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
|
||||
#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
|
70
src/ATC/AIMgr.cxx
Normal file
70
src/ATC/AIMgr.cxx
Normal file
|
@ -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 <Main/fgfs.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include <list>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
96
src/ATC/AIMgr.hxx
Normal file
96
src/ATC/AIMgr.hxx
Normal file
|
@ -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 <Main/fgfs.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include <list>
|
||||
|
||||
#include "AIEntity.hxx"
|
||||
|
||||
SG_USING_STD(list);
|
||||
|
||||
class FGAIMgr : public FGSubsystem
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
// A list of pointers to all currently active AI stuff
|
||||
typedef list <FGAIEntity*> 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
|
|
@ -27,6 +27,12 @@ FGATC::~FGATC() {
|
|||
void FGATC::Update() {
|
||||
}
|
||||
|
||||
void FGATC::AddPlane(string pid) {
|
||||
}
|
||||
|
||||
int FGATC::RemovePlane() {
|
||||
}
|
||||
|
||||
void FGATC::SetDisplay() {
|
||||
}
|
||||
|
||||
|
@ -40,3 +46,23 @@ const char* FGATC::GetIdent() {
|
|||
atc_type FGATC::GetType() {
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
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 << ");
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@
|
|||
#ifndef _FG_ATC_HXX
|
||||
#define _FG_ATC_HXX
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
// Possible types of ATC type that the radios may be tuned to.
|
||||
// INVALID implies not tuned in to anything.
|
||||
enum atc_type {
|
||||
|
@ -34,6 +37,8 @@ enum atc_type {
|
|||
ENROUTE
|
||||
};
|
||||
|
||||
ostream& operator << (ostream& os, atc_type atc);
|
||||
|
||||
class FGATC {
|
||||
|
||||
public:
|
||||
|
@ -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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_valid) {
|
||||
RemoveFromList(comm1_ident, ATIS);
|
||||
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) && (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; i<num_app; i++ ) {
|
||||
bool new_app = true;
|
||||
approach_ident = approaches[i].GetIdent();
|
||||
|
||||
// check if station already exists on ATC stack
|
||||
atc_list_itr = atc_list.begin();
|
||||
while(atc_list_itr != atc_list.end()) {
|
||||
//cout << "ATC list: " << (*atc_list_itr)->GetIdent() << 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,18 +25,59 @@
|
|||
#include <Main/fgfs.hxx>
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#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 <FGATC*> 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
|
||||
|
|
0
src/ATC/ATCutils.cxx
Normal file
0
src/ATC/ATCutils.cxx
Normal file
|
@ -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
|
||||
|
|
366
src/ATC/approach.cxx
Normal file
366
src/ATC/approach.cxx
Normal file
|
@ -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 <Airports/runways.hxx>
|
||||
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
#include <WeatherCM/FGLocalWeatherDatabase.h>
|
||||
|
||||
|
||||
//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; i<max_planes; i++) {
|
||||
planes[i].contact = 0;
|
||||
planes[i].wpn = 0;
|
||||
planes[i].dnwp = -999.;
|
||||
planes[i].on_crs = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Destructor
|
||||
FGApproach::~FGApproach(){
|
||||
}
|
||||
|
||||
void FGApproach::Init() {
|
||||
display = false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// the main update function
|
||||
// ============================================================================
|
||||
void FGApproach::Update() {
|
||||
|
||||
int wpn;
|
||||
double course, d;
|
||||
|
||||
update_plane_dat();
|
||||
if ( active_runway == "" ) get_active_runway();
|
||||
|
||||
for ( int i=0; i<num_planes; i++ ) {
|
||||
|
||||
if ( planes[i].contact == 0) {
|
||||
double comm1_freq = comm1_node->getDoubleValue();
|
||||
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; i<num_planes; i++) {
|
||||
planes[i].lon = lon_node->getDoubleValue();
|
||||
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<num_planes; i++) {
|
||||
if ( planes[i].ident == pid) {
|
||||
//cout << "Plane already registered: " << ident << " " << num_planes << endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
planes[num_planes].ident = pid;
|
||||
++num_planes;
|
||||
//cout << "Plane added to list: " << ident << " " << num_planes << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// closest distance between a point and a straigt line in 2 dim.
|
||||
// ========================================================================
|
||||
double FGApproach::calc_psl_dist(const double &h1, const double &d1,
|
||||
const double &h2, const double &d2,
|
||||
const double &h3)
|
||||
{
|
||||
double a1 = h1 * SGD_DEGREES_TO_RADIANS;
|
||||
double a2 = h2 * SGD_DEGREES_TO_RADIANS;
|
||||
double a3 = h3 * SGD_DEGREES_TO_RADIANS;
|
||||
double x1 = cos(a1) * d1;
|
||||
double y1 = sin(a1) * d1;
|
||||
double x2 = cos(a2) * d2;
|
||||
double y2 = sin(a2) * d2;
|
||||
double x3 = cos(a3);
|
||||
double y3 = sin(a3);
|
||||
|
||||
// formula: dis = sqrt( (v1-v2)**2 - ((v1-v2)*v3)**2 ); vi = (xi,yi)
|
||||
double val1 = (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2);
|
||||
double val2 = ((x1-x2)*x3 + (y1-y2)*y3) * ((x1-x2)*x3 + (y1-y2)*y3);
|
||||
double dis = val1 - val2;
|
||||
// now get sign for offset
|
||||
//cout << x1 << " " << x2 << " " << y1 << " " << y2 << " "
|
||||
// << x3 << " " << y3 << " "
|
||||
// << val1 << " " << val2 << " " << dis << endl;
|
||||
x3 *= sqrt(val2);
|
||||
y3 *= sqrt(val2);
|
||||
if ( x3*(x1-x2) < 0.0 && y3*(y1-y2) < 0.0) {
|
||||
x3 *= -1.0;
|
||||
y3 *= -1.0;
|
||||
}
|
||||
//cout << x3 << " " << y3 << endl;
|
||||
double dis1 = x1-x2-x3;
|
||||
double dis2 = y1-y2-y3;
|
||||
dis = sqrt(dis);
|
||||
if (atan2(dis2,dis1) < a3) dis *= -1.0;
|
||||
//cout << dis1 << " " << dis2 << " " << atan2(dis2,dis1)*SGD_RADIANS_TO_DEGREES << " " << h3
|
||||
// << " " << sqrt(dis1*dis1 + dis2*dis2) << " " << dis << endl;
|
||||
//cout << atan2(dis2,dis1)*SGD_RADIANS_TO_DEGREES << " " << dis << endl;
|
||||
|
||||
return dis;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// get heading and distance between two points; point1 ---> 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<num_planes; i++) {
|
||||
if (planes[i].dist > 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<num_planes; i++) {
|
||||
tmp[i] = planes[i];
|
||||
}
|
||||
|
||||
int np = 0;
|
||||
// now check which planes are still in range
|
||||
for (int i=0; i<num_planes; i++) {
|
||||
if (tmp[i].dist <= range*SG_NM_TO_METER) {
|
||||
planes[np] = tmp[i];
|
||||
np += 1;
|
||||
}
|
||||
}
|
||||
num_planes = np;
|
||||
return num_planes;
|
||||
}
|
266
src/ATC/approach.hxx
Normal file
266
src/ATC/approach.hxx
Normal file
|
@ -0,0 +1,266 @@
|
|||
// approach.hxx -- Approach class
|
||||
//
|
||||
// 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.
|
||||
|
||||
|
||||
#ifndef _FG_APPROACH_HXX
|
||||
#define _FG_APPROACH_HXX
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/magvar/magvar.hxx>
|
||||
#include <simgear/timing/sg_time.hxx>
|
||||
#include <simgear/bucket/newbucket.hxx>
|
||||
|
||||
#include <Main/fg_props.hxx>
|
||||
|
||||
#ifdef SG_HAVE_STD_INCLUDES
|
||||
# include <istream>
|
||||
#include <iomanip>
|
||||
#elif defined( SG_HAVE_NATIVE_SGI_COMPILERS )
|
||||
# include <iostream.h>
|
||||
#elif defined( __BORLANDC__ )
|
||||
# include <iostream>
|
||||
#else
|
||||
# include <istream.h>
|
||||
#include <iomanip.h>
|
||||
#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
|
234
src/ATC/approachlist.cxx
Normal file
234
src/ATC/approachlist.cxx
Normal file
|
@ -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 <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
|
||||
#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; i<bx; i++) {
|
||||
for ( int j=-by; j<by; j++) {
|
||||
buck = sgBucketOffset(lon, lat, i, j);
|
||||
long int bucket = buck.gen_index();
|
||||
//cout << "bucket number = " << bucket << endl;
|
||||
approach_list_type stations = approachlist_bck[bucket];
|
||||
approach_list_iterator current = stations.begin();
|
||||
approach_list_iterator last = stations.end();
|
||||
|
||||
double rlon = lon * SGD_DEGREES_TO_RADIANS;
|
||||
double rlat = lat * SGD_DEGREES_TO_RADIANS;
|
||||
|
||||
// double az1, az2, s;
|
||||
Point3D aircraft = sgGeodToCart( Point3D(rlon, rlat, elev) );
|
||||
Point3D station;
|
||||
double d;
|
||||
for ( ; current != last ; ++current ) {
|
||||
station = Point3D(current->get_x(), current->get_y(), current->get_z());
|
||||
d = aircraft.distance3Dsquared( station );
|
||||
/*
|
||||
cout << " dist = " << sqrt(d)
|
||||
<< " range = " << current->get_range() * SG_NM_TO_METER << endl;
|
||||
cout << " Aircraft: lon = " << lon
|
||||
<< " lat = " << lat/SGD_DEGREES_TO_RADIANS
|
||||
<< " bucket = " << bucket
|
||||
<< " elev = " << elev << endl;
|
||||
cout << " Airport: Id = " << current->GetIdent()
|
||||
<< " lon = " << current->get_lon()
|
||||
<< " lat = " << current->get_lat()
|
||||
<< " elev = " << current->get_elev()
|
||||
<< " bucket = " << current->get_bucket()
|
||||
<< " z = " << current->get_z() << endl;
|
||||
*/
|
||||
// match up to twice the published range so we can model
|
||||
// reduced signal strength
|
||||
if ( d < (current->get_range() * SG_NM_TO_METER
|
||||
* current->get_range() * SG_NM_TO_METER ) ) {
|
||||
//cout << "matched = " << current->GetIdent() << endl;
|
||||
if (num_app < max_app) {
|
||||
a[num_app] = *current;
|
||||
num_app += 1;
|
||||
}
|
||||
else {
|
||||
cout << "Approachlist error: Too many stations in range" << endl;
|
||||
}
|
||||
|
||||
//return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true; //DCL - added this to prevent a compiler warning
|
||||
}
|
||||
|
||||
|
||||
bool FGApproachList::get_name( string apt_id )
|
||||
{
|
||||
string name;
|
||||
double freq = 125.22;
|
||||
|
||||
approach_list_type stations = approachlist_freq[(int)(freq*100.0 + 0.5)];
|
||||
|
||||
approach_list_iterator current = stations.begin();
|
||||
approach_list_iterator last = stations.end();
|
||||
|
||||
if(current != last) {
|
||||
cout << "ApproachList" << endl;
|
||||
cout << "name" << current->get_name() << endl;
|
||||
cout << "bucket" << current->get_bucket() << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
79
src/ATC/approachlist.hxx
Normal file
79
src/ATC/approachlist.hxx
Normal file
|
@ -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 <simgear/compiler.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#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<int> > 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
|
|
@ -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,12 +58,8 @@ 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' ) {
|
||||
|
@ -89,18 +85,7 @@ 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();
|
||||
|
|
80
src/ATC/ground.cxx
Normal file
80
src/ATC/ground.cxx
Normal file
|
@ -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.
|
||||
}
|
150
src/ATC/ground.hxx
Normal file
150
src/ATC/ground.hxx
Normal file
|
@ -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 <vector>
|
||||
#include <list>
|
||||
//#include <map>
|
||||
|
||||
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> 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> 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 <PlaneRec> 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*> 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
|
496
src/ATC/runways.cxx
Normal file
496
src/ATC/runways.cxx
Normal file
|
@ -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 <config.h>
|
||||
#endif
|
||||
|
||||
#include <math.h> // fabs()
|
||||
#include <stdio.h> // sprintf()
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
|
||||
#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 ) {
|
||||
}
|
||||
|
||||
|
52
src/ATC/tower.cxx
Normal file
52
src/ATC/tower.cxx
Normal file
|
@ -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 <Main/globals.hxx>
|
||||
|
||||
#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;
|
||||
}
|
148
src/ATC/tower.hxx
Normal file
148
src/ATC/tower.hxx
Normal file
|
@ -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 <simgear/compiler.h>
|
||||
#include <simgear/math/point3d.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <plib/sg.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
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 <PlaneRec> 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
|
134
src/ATC/towerlist.cxx
Normal file
134
src/ATC/towerlist.cxx
Normal file
|
@ -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 <config.h>
|
||||
#endif
|
||||
|
||||
#include <simgear/debug/logstream.hxx>
|
||||
#include <simgear/misc/sgstream.hxx>
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
#include <simgear/math/sg_random.h>
|
||||
|
||||
#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;
|
||||
}
|
74
src/ATC/towerlist.hxx
Normal file
74
src/ATC/towerlist.hxx
Normal file
|
@ -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 <simgear/compiler.h>
|
||||
#include <simgear/misc/sg_path.hxx>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#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
|
|
@ -73,6 +73,9 @@
|
|||
#include <ATC/ATCdisplay.hxx>
|
||||
#include <ATC/ATCmgr.hxx>
|
||||
#include <ATC/atislist.hxx>
|
||||
#include <ATC/towerlist.hxx>
|
||||
#include <ATC/approachlist.hxx>
|
||||
#include <ATC/AIMgr.hxx>
|
||||
#include <Autopilot/auto_gui.hxx>
|
||||
#include <Autopilot/newauto.hxx>
|
||||
#include <Cockpit/cockpit.hxx>
|
||||
|
@ -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
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -879,6 +893,14 @@ bool fgInitSubsystems( void ) {
|
|||
globals->set_ATC_mgr(new FGATCMgr);
|
||||
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.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -217,6 +221,9 @@ public:
|
|||
inline FGATCDisplay *get_ATC_display() const { return ATC_display; }
|
||||
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; }
|
||||
|
||||
|
|
|
@ -81,6 +81,8 @@
|
|||
|
||||
#include <ATC/ATCmgr.hxx>
|
||||
#include <ATC/ATCdisplay.hxx>
|
||||
#include <ATC/AIMgr.hxx>
|
||||
|
||||
#include <Autopilot/newauto.hxx>
|
||||
|
||||
#include <Cockpit/cockpit.hxx>
|
||||
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue