Preliminary support for AI planes from Dave Luff. This works only at
KEMT (w120n30 scenery), and you will have to set the property /sim/ai-traffic/enabled to 'true' to see the other plane (and tune comm1 to 121.2 to hear the other plane's radio calls).
This commit is contained in:
parent
03b508adb7
commit
c581cfa395
18 changed files with 908 additions and 120 deletions
|
@ -39,10 +39,18 @@
|
||||||
FGAIEntity::~FGAIEntity() {
|
FGAIEntity::~FGAIEntity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the internal calculations
|
void FGAIEntity::Update(double dt) {
|
||||||
void FGAIEntity::Update() {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run the internal calculations
|
||||||
|
//void FGAIEntity::Update() {
|
||||||
|
void FGAIEntity::Transform() {
|
||||||
|
aip.setPosition(pos.lon(), pos.lat(), pos.elev() * SG_METER_TO_FEET);
|
||||||
|
aip.setOrientation(roll, pitch, hdg);
|
||||||
|
aip.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
void FGAIEntity::Transform() {
|
void FGAIEntity::Transform() {
|
||||||
|
|
||||||
// Translate moving object w.r.t eye
|
// Translate moving object w.r.t eye
|
||||||
|
@ -53,17 +61,17 @@ void FGAIEntity::Transform() {
|
||||||
sgCoord shippos;
|
sgCoord shippos;
|
||||||
FastWorldCoordinate(&shippos, sc);
|
FastWorldCoordinate(&shippos, sc);
|
||||||
position->setTransform( &shippos );
|
position->setTransform( &shippos );
|
||||||
globals->get_scenery()->get_scene_graph()->addKid(position);
|
|
||||||
//cout << "Transform called\n";
|
//cout << "Transform called\n";
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// Taken from tileentry.cxx
|
// Taken from tileentry.cxx
|
||||||
void FGAIEntity::WorldCoordinate(sgCoord *obj_pos, Point3D center) {
|
void FGAIEntity::WorldCoordinate(sgCoord *obj_pos, Point3D center) {
|
||||||
// setup transforms
|
// setup transforms
|
||||||
Point3D geod( lon * SGD_DEGREES_TO_RADIANS,
|
Point3D geod( pos.lon() * SGD_DEGREES_TO_RADIANS,
|
||||||
lat * SGD_DEGREES_TO_RADIANS,
|
pos.lat() * SGD_DEGREES_TO_RADIANS,
|
||||||
elev );
|
pos.elev() );
|
||||||
|
|
||||||
Point3D world_pos = sgGeodToCart( geod );
|
Point3D world_pos = sgGeodToCart( geod );
|
||||||
Point3D offset = world_pos - center;
|
Point3D offset = world_pos - center;
|
||||||
|
@ -89,15 +97,15 @@ void FGAIEntity::WorldCoordinate(sgCoord *obj_pos, Point3D center) {
|
||||||
sgSetCoord( obj_pos, TUX );
|
sgSetCoord( obj_pos, TUX );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
// Norman's 'fast hack' for above
|
// Norman's 'fast hack' for above
|
||||||
void FGAIEntity::FastWorldCoordinate(sgCoord *obj_pos, Point3D center) {
|
void FGAIEntity::FastWorldCoordinate(sgCoord *obj_pos, Point3D center) {
|
||||||
double lon_rad = lon * SGD_DEGREES_TO_RADIANS;
|
double lon_rad = pos.lon() * SGD_DEGREES_TO_RADIANS;
|
||||||
double lat_rad = lat * SGD_DEGREES_TO_RADIANS;
|
double lat_rad = pos.lat() * SGD_DEGREES_TO_RADIANS;
|
||||||
double hdg_rad = hdg * SGD_DEGREES_TO_RADIANS;
|
double hdg_rad = hdg * SGD_DEGREES_TO_RADIANS;
|
||||||
|
|
||||||
// setup transforms
|
// setup transforms
|
||||||
Point3D geod( lon_rad, lat_rad, elev );
|
Point3D geod( lon_rad, lat_rad, pos.elev() );
|
||||||
|
|
||||||
Point3D world_pos = sgGeodToCart( geod );
|
Point3D world_pos = sgGeodToCart( geod );
|
||||||
Point3D offset = world_pos - center;
|
Point3D offset = world_pos - center;
|
||||||
|
@ -133,3 +141,4 @@ void FGAIEntity::FastWorldCoordinate(sgCoord *obj_pos, Point3D center) {
|
||||||
|
|
||||||
sgSetCoord( obj_pos, mat );
|
sgSetCoord( obj_pos, mat );
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
|
@ -29,10 +29,20 @@
|
||||||
#ifndef _FG_AIEntity_HXX
|
#ifndef _FG_AIEntity_HXX
|
||||||
#define _FG_AIEntity_HXX
|
#define _FG_AIEntity_HXX
|
||||||
|
|
||||||
|
#include <Model/model.hxx>
|
||||||
#include <plib/sg.h>
|
#include <plib/sg.h>
|
||||||
#include <plib/ssg.h>
|
#include <plib/ssg.h>
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
*
|
||||||
|
* FGAIEntity - this class implements the minimum requirement
|
||||||
|
* for any AI entity - a position, an orientation, an associated
|
||||||
|
* 3D model, and the ability to be moved. It does nothing useful
|
||||||
|
* and all AI entities are expected to be derived from it.
|
||||||
|
*
|
||||||
|
******************************************************************/
|
||||||
class FGAIEntity {
|
class FGAIEntity {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -44,27 +54,29 @@ public:
|
||||||
virtual ~FGAIEntity();
|
virtual ~FGAIEntity();
|
||||||
|
|
||||||
// Run the internal calculations
|
// Run the internal calculations
|
||||||
virtual void Update();
|
virtual void Update(double dt);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
double lat; //WGS84
|
Point3D pos; // WGS84 lat & lon in degrees, elev above sea-level in meters
|
||||||
double lon; //WGS84
|
//double lat; //WGS84
|
||||||
double elev; //Meters
|
//double lon; //WGS84
|
||||||
|
//double elev; //Meters
|
||||||
double hdg; //True heading in degrees
|
double hdg; //True heading in degrees
|
||||||
double roll; //degrees
|
double roll; //degrees
|
||||||
double pitch; //degrees
|
double pitch; //degrees
|
||||||
|
|
||||||
char* model_path; //Path to the 3D model
|
char* model_path; //Path to the 3D model
|
||||||
|
FGModelPlacement aip;
|
||||||
|
|
||||||
ssgEntity* model;
|
//ssgEntity* model;
|
||||||
ssgTransform* position;
|
//ssgTransform* position;
|
||||||
|
|
||||||
void Transform();
|
void Transform();
|
||||||
|
|
||||||
//void WorldCoordinate(sgCoord *obj_pos, Point3D center);
|
//void WorldCoordinate(sgCoord *obj_pos, Point3D center);
|
||||||
|
|
||||||
void FastWorldCoordinate(sgCoord *obj_pos, Point3D center);
|
//void FastWorldCoordinate(sgCoord *obj_pos, Point3D center);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,28 +19,37 @@
|
||||||
// along with this program; if not, write to the Free Software
|
// along with this program; if not, write to the Free Software
|
||||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
// 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 <Main/globals.hxx>
|
||||||
#include <Model/loader.hxx>
|
#include <Main/location.hxx>
|
||||||
//#include <simgear/constants.h>
|
#include <Scenery/scenery.hxx>
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
#include <simgear/math/sg_geodesy.hxx>
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
#include <simgear/misc/sg_path.hxx>
|
#include <simgear/misc/sg_path.hxx>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
|
|
||||||
#include "ATCmgr.hxx"
|
#include "ATCmgr.hxx"
|
||||||
#include "AILocalTraffic.hxx"
|
#include "AILocalTraffic.hxx"
|
||||||
|
#include "ATCutils.hxx"
|
||||||
|
|
||||||
FGAILocalTraffic::FGAILocalTraffic() {
|
FGAILocalTraffic::FGAILocalTraffic() {
|
||||||
|
//Hardwire initialisation for now - a lot of this should be read in from config eventually
|
||||||
|
Vr = 70.0;
|
||||||
|
best_rate_of_climb_speed = 70.0;
|
||||||
|
//best_rate_of_climb;
|
||||||
|
//nominal_climb_speed;
|
||||||
|
//nominal_climb_rate;
|
||||||
|
//nominal_circuit_speed;
|
||||||
|
//min_circuit_speed;
|
||||||
|
//max_circuit_speed;
|
||||||
|
nominal_descent_rate = 500.0;
|
||||||
|
nominal_final_speed = 65.0;
|
||||||
|
//nominal_approach_speed;
|
||||||
|
//stall_speed_landing_config;
|
||||||
|
wind_from_hdg = 0.0;
|
||||||
|
wind_speed_knots = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAILocalTraffic::~FGAILocalTraffic() {
|
FGAILocalTraffic::~FGAILocalTraffic() {
|
||||||
|
@ -49,34 +58,75 @@ FGAILocalTraffic::~FGAILocalTraffic() {
|
||||||
void FGAILocalTraffic::Init() {
|
void FGAILocalTraffic::Init() {
|
||||||
// Hack alert - Hardwired path!!
|
// Hack alert - Hardwired path!!
|
||||||
string planepath = "Aircraft/c172/Models/c172-dpm.ac";
|
string planepath = "Aircraft/c172/Models/c172-dpm.ac";
|
||||||
model = globals->get_model_loader()->load_model(planepath);
|
SGPath path = globals->get_fg_root();
|
||||||
if (model == 0) {
|
path.append(planepath);
|
||||||
model =
|
aip.init(planepath.c_str());
|
||||||
globals->get_model_loader()
|
aip.setVisible(true);
|
||||||
->load_model("Models/Geometry/glider.ac");
|
globals->get_scenery()->get_scene_graph()->addKid(aip.getSceneGraph());
|
||||||
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
|
#define DCL_KEMT true
|
||||||
lat = 34.081358;
|
//#define DCL_KPAO true
|
||||||
lon = -118.037483;
|
#ifdef DCL_KEMT
|
||||||
hdg = 0.0;
|
// Hardwire to KEMT for now
|
||||||
elev = (287.0 + 0.5) * SG_FEET_TO_METER; // Ground is 296 so this should be above it
|
// Hardwired points at each end of KEMT runway
|
||||||
mag_hdg = -10.0;
|
Point3D P010(-118.037483, 34.081358, 296 * SG_FEET_TO_METER);
|
||||||
|
Point3D P190(-118.032308, 34.090456, 299.395263 * SG_FEET_TO_METER);
|
||||||
|
Point3D takeoff_end;
|
||||||
|
bool d010 = true; // use this to change the hardwired runway direction
|
||||||
|
if(d010) {
|
||||||
|
rwy.threshold_pos = P010;
|
||||||
|
takeoff_end = P190;
|
||||||
|
rwy.hdg = 25.32; //from default.apt
|
||||||
|
patternDirection = -1; // Left
|
||||||
|
pos.setelev(rwy.threshold_pos.elev() + (-8.5 * SG_FEET_TO_METER)); // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
|
||||||
|
} else {
|
||||||
|
rwy.threshold_pos = P190;
|
||||||
|
takeoff_end = P010;
|
||||||
|
rwy.hdg = 205.32;
|
||||||
|
patternDirection = 1; // Right
|
||||||
|
pos.setelev(rwy.threshold_pos.elev() + (-0.0 * SG_FEET_TO_METER)); // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
//KPAO - might be a better choice since its in the default scenery
|
||||||
|
//Hardwire it to the default (no wind) direction
|
||||||
|
Point3D threshold_end(-122.1124358, 37.45848783, 6.8 * SG_FEET_TO_METER); // These positions are from airnav.com and don't quite seem to correspond with the sim scenery
|
||||||
|
Point3D takeoff_end(-122.1176522, 37.463752, 6.7 * SG_FEET_TO_METER);
|
||||||
|
rwy.threshold_pos = threshold_end;
|
||||||
|
rwy.hdg = 315.0;
|
||||||
|
patternDirection = 1; // Right
|
||||||
|
pos.setelev(rwy.threshold_pos.elev() + (-0.0 * SG_FEET_TO_METER)); // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//rwy.threshold_pos.setlat(34.081358);
|
||||||
|
//rwy.threshold_pos.setlon(-118.037483);
|
||||||
|
//rwy.mag_hdg = 12.0;
|
||||||
|
//rwy.mag_var = 14.0;
|
||||||
|
//rwy.hdg = rwy.mag_hdg + rwy.mag_var;
|
||||||
|
//rwy.threshold_pos.setelev(296 * SG_FEET_TO_METER);
|
||||||
|
|
||||||
|
// Initial position on threshold for now
|
||||||
|
// TODO - check wind / default runway
|
||||||
|
pos.setlat(rwy.threshold_pos.lat());
|
||||||
|
pos.setlon(rwy.threshold_pos.lon());
|
||||||
|
hdg = rwy.hdg;
|
||||||
|
|
||||||
pitch = 0.0;
|
pitch = 0.0;
|
||||||
roll = 0.0;
|
roll = 0.0;
|
||||||
mag_var = -14.0;
|
leg = TAKEOFF_ROLL;
|
||||||
|
vel = 0.0;
|
||||||
|
slope = 0.0;
|
||||||
|
|
||||||
|
// Now set the position of the plane and then re-get the elevation!! (Didn't work - elev always returned as zero) :-(
|
||||||
|
//aip.setPosition(pos.lon(), pos.lat(), pos.elev() * SG_METER_TO_FEET);
|
||||||
|
//cout << "*********************** elev in FGAILocalTraffic = " << aip.getFGLocation()->get_cur_elev_m() << '\n';
|
||||||
|
|
||||||
// Activate the tower - this is dependent on the ATC system being initialised before the AI system
|
// Activate the tower - this is dependent on the ATC system being initialised before the AI system
|
||||||
AirportATC a;
|
AirportATC a;
|
||||||
if(globals->get_ATC_mgr()->GetAirportATCDetails((string)"KEMT", &a)) {
|
if(globals->get_ATC_mgr()->GetAirportATCDetails((string)"KEMT", &a)) {
|
||||||
if(a.tower_freq) { // Has a tower
|
if(a.tower_freq) { // Has a tower
|
||||||
tower = (FGTower*)globals->get_ATC_mgr()->GetATCPointer((string)"KEMT", TOWER); // Maybe need some error checking here
|
tower = (FGTower*)globals->get_ATC_mgr()->GetATCPointer((string)"KEMT", TOWER); // Maybe need some error checking here
|
||||||
|
freq = (double)tower->get_freq() / 100.0;
|
||||||
|
//cout << "***********************************AILocalTraffic freq = " << freq << '\n';
|
||||||
} else {
|
} else {
|
||||||
// Check CTAF, unicom etc
|
// Check CTAF, unicom etc
|
||||||
}
|
}
|
||||||
|
@ -84,18 +134,254 @@ void FGAILocalTraffic::Init() {
|
||||||
cout << "Unable to find airport details in FGAILocalTraffic::Init()\n";
|
cout << "Unable to find airport details in FGAILocalTraffic::Init()\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the projection for the local area
|
||||||
|
ortho.Init(rwy.threshold_pos, rwy.hdg);
|
||||||
|
rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
|
||||||
|
// Hardwire to KEMT for now
|
||||||
|
rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
|
||||||
|
//cout << "*********************************************************************************\n";
|
||||||
|
//cout << "*********************************************************************************\n";
|
||||||
|
//cout << "*********************************************************************************\n";
|
||||||
|
//cout << "end1ortho = " << rwy.end1ortho << '\n';
|
||||||
|
//cout << "end2ortho = " << rwy.end2ortho << '\n'; // end2ortho.x() should be zero or thereabouts
|
||||||
|
|
||||||
Transform();
|
Transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the internal calculations
|
// Run the internal calculations
|
||||||
void FGAILocalTraffic::Update() {
|
void FGAILocalTraffic::Update(double dt) {
|
||||||
hdg = mag_hdg + mag_var;
|
std::cout << "In FGAILocalTraffic::Update\n";
|
||||||
|
// Hardwire flying traffic pattern for now - eventually also needs to be able to taxi to and from runway and GA parking area.
|
||||||
|
FlyTrafficPattern(dt);
|
||||||
|
Transform();
|
||||||
|
//cout << "elev in FGAILocalTraffic = " << aip.getFGLocation()->get_cur_elev_m() << '\n';
|
||||||
// This should become if(the plane has moved) then Transform()
|
// This should become if(the plane has moved) then Transform()
|
||||||
static int i = 0;
|
}
|
||||||
if(i == 60) {
|
|
||||||
Transform();
|
// Fly a traffic pattern
|
||||||
i = 0;
|
// FIXME - far too much of the mechanics of turning, rolling, accellerating, descending etc is in here.
|
||||||
}
|
// Move it out to FGAIPlane and have FlyTrafficPattern just specify what to do, not the implementation.
|
||||||
i++;
|
void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
||||||
|
// Need to differentiate between in-air (IAS governed) and on-ground (vel governed)
|
||||||
|
// Take-off is an interesting case - we are on the ground but takeoff speed is IAS governed.
|
||||||
|
bool inAir = true; // FIXME - possibly make into a class variable
|
||||||
|
|
||||||
|
static bool transmitted = false; // FIXME - this is a hack
|
||||||
|
|
||||||
|
// WIND
|
||||||
|
// Wind has two effects - a mechanical one in that IAS translates to a different vel, and the hdg != track,
|
||||||
|
// but also a piloting effect, in that the AI must be able to descend at a different rate in order to hit the threshold.
|
||||||
|
|
||||||
|
//cout << "dt = " << dt << '\n';
|
||||||
|
double dist = 0;
|
||||||
|
// ack - I can't remember how long a rate 1 turn is meant to take.
|
||||||
|
double turn_time = 60.0; // seconds - TODO - check this guess
|
||||||
|
double turn_circumference;
|
||||||
|
double turn_radius;
|
||||||
|
Point3D orthopos = ortho.ConvertToLocal(pos); // ortho position of the plane
|
||||||
|
//cout << "runway elev = " << rwy.threshold_pos.elev() << ' ' << rwy.threshold_pos.elev() * SG_METER_TO_FEET << '\n';
|
||||||
|
//cout << "elev = " << pos.elev() << ' ' << pos.elev() * SG_METER_TO_FEET << '\n';
|
||||||
|
switch(leg) {
|
||||||
|
case TAKEOFF_ROLL:
|
||||||
|
inAir = false;
|
||||||
|
track = rwy.hdg;
|
||||||
|
if(vel < 80.0) {
|
||||||
|
double dveldt = 5.0;
|
||||||
|
vel += dveldt * dt;
|
||||||
|
}
|
||||||
|
IAS = vel + (cos((hdg - wind_from_hdg) * DCL_DEGREES_TO_RADIANS) * wind_speed_knots);
|
||||||
|
if(IAS >= 70) {
|
||||||
|
leg = CLIMBOUT;
|
||||||
|
pitch = 10.0;
|
||||||
|
IAS = best_rate_of_climb_speed;
|
||||||
|
slope = 7.0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CLIMBOUT:
|
||||||
|
track = rwy.hdg;
|
||||||
|
if((pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 600) {
|
||||||
|
leg = TURN1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TURN1:
|
||||||
|
track += (360.0 / turn_time) * dt * patternDirection;
|
||||||
|
Bank(25.0 * patternDirection);
|
||||||
|
if((track < (rwy.hdg - 89.0)) || (track > (rwy.hdg + 89.0))) {
|
||||||
|
leg = CROSSWIND;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CROSSWIND:
|
||||||
|
LevelWings();
|
||||||
|
track = rwy.hdg + (90.0 * patternDirection);
|
||||||
|
if((pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
|
||||||
|
slope = 0.0;
|
||||||
|
pitch = 0.0;
|
||||||
|
IAS = 80.0; // FIXME - use smooth transistion to new speed
|
||||||
|
}
|
||||||
|
// turn 1000m out for now
|
||||||
|
if(fabs(orthopos.x()) > 980) {
|
||||||
|
leg = TURN2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TURN2:
|
||||||
|
track += (360.0 / turn_time) * dt * patternDirection;
|
||||||
|
Bank(25.0 * patternDirection);
|
||||||
|
// just in case we didn't make height on crosswind
|
||||||
|
if((pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
|
||||||
|
slope = 0.0;
|
||||||
|
pitch = 0.0;
|
||||||
|
IAS = 80.0; // FIXME - use smooth transistion to new speed
|
||||||
|
}
|
||||||
|
if((track < (rwy.hdg - 179.0)) || (track > (rwy.hdg + 179.0))) {
|
||||||
|
leg = DOWNWIND;
|
||||||
|
transmitted = false;
|
||||||
|
//roll = 0.0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DOWNWIND:
|
||||||
|
LevelWings();
|
||||||
|
track = rwy.hdg - (180 * patternDirection); //should tend to bring track back into the 0->360 range
|
||||||
|
// just in case we didn't make height on crosswind
|
||||||
|
if((pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
|
||||||
|
slope = 0.0;
|
||||||
|
pitch = 0.0;
|
||||||
|
IAS = 90.0; // FIXME - use smooth transistion to new speed
|
||||||
|
}
|
||||||
|
if((orthopos.y() < 0) && (!transmitted)) {
|
||||||
|
TransmitPatternPositionReport();
|
||||||
|
transmitted = true;
|
||||||
|
}
|
||||||
|
if(orthopos.y() < -480) {
|
||||||
|
slope = -4.0; // FIXME - calculate to descent at 500fpm and hit the threshold (taking wind into account as well!!)
|
||||||
|
pitch = -3.0;
|
||||||
|
IAS = 85.0;
|
||||||
|
}
|
||||||
|
if(orthopos.y() < -980) {
|
||||||
|
//roll = -20;
|
||||||
|
leg = TURN3;
|
||||||
|
transmitted = false;
|
||||||
|
IAS = 80.0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TURN3:
|
||||||
|
track += (360.0 / turn_time) * dt * patternDirection;
|
||||||
|
Bank(25.0 * patternDirection);
|
||||||
|
if(fabs(rwy.hdg - track) < 91.0) {
|
||||||
|
leg = BASE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BASE:
|
||||||
|
LevelWings();
|
||||||
|
if(!transmitted) {
|
||||||
|
TransmitPatternPositionReport();
|
||||||
|
transmitted = true;
|
||||||
|
}
|
||||||
|
track = rwy.hdg - (90 * patternDirection);
|
||||||
|
slope = -6.0; // FIXME - calculate to descent at 500fpm and hit the threshold
|
||||||
|
pitch = -4.0;
|
||||||
|
IAS = 70.0; // FIXME - slowdown gradually
|
||||||
|
// Try and arrange to turn nicely onto base
|
||||||
|
turn_circumference = IAS * 0.514444 * turn_time;
|
||||||
|
//Hmmm - this is an interesting one - ground vs airspeed in relation to turn radius
|
||||||
|
//We'll leave it as a hack with IAS for now but it needs revisiting.
|
||||||
|
|
||||||
|
turn_radius = turn_circumference / (2.0 * DCL_PI);
|
||||||
|
if(fabs(orthopos.x()) < (turn_radius + 50)) {
|
||||||
|
leg = TURN4;
|
||||||
|
transmitted = false;
|
||||||
|
//roll = -20;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TURN4:
|
||||||
|
track += (360.0 / turn_time) * dt * patternDirection;
|
||||||
|
Bank(25.0 * patternDirection);
|
||||||
|
if(fabs(track - rwy.hdg) < 0.6) {
|
||||||
|
leg = FINAL;
|
||||||
|
vel = nominal_final_speed;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FINAL:
|
||||||
|
LevelWings();
|
||||||
|
if(!transmitted) {
|
||||||
|
TransmitPatternPositionReport();
|
||||||
|
transmitted = true;
|
||||||
|
}
|
||||||
|
// Try and track the extended centreline
|
||||||
|
track = rwy.hdg - (0.2 * orthopos.x());
|
||||||
|
//cout << "orthopos.x() = " << orthopos.x() << " hdg = " << hdg << '\n';
|
||||||
|
if(pos.elev() <= rwy.threshold_pos.elev()) {
|
||||||
|
pos.setelev(rwy.threshold_pos.elev());// + (-8.5 * SG_FEET_TO_METER)); // This is a complete hack - the rendered runway takes the underlying scenery elev rather than the published runway elev so I should use height above terrain or something.
|
||||||
|
slope = 0.0;
|
||||||
|
pitch = 0.0;
|
||||||
|
leg = LANDING_ROLL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LANDING_ROLL:
|
||||||
|
inAir = false;
|
||||||
|
track = rwy.hdg;
|
||||||
|
double dveldt = -5.0;
|
||||||
|
vel += dveldt * dt;
|
||||||
|
if(vel <= 15.0) {
|
||||||
|
leg = TAKEOFF_ROLL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
yaw = 0.0; //yaw = f(track, wind);
|
||||||
|
hdg = track + yaw;
|
||||||
|
// Apply wind to ground-relative velocity if in the air
|
||||||
|
if(inAir) {
|
||||||
|
vel = IAS - (cos((hdg - wind_from_hdg) * DCL_DEGREES_TO_RADIANS) * wind_speed_knots);
|
||||||
|
}
|
||||||
|
dist = vel * 0.514444 * dt;
|
||||||
|
pos = dclUpdatePosition(pos, track, slope, dist);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAILocalTraffic::TransmitPatternPositionReport(void) {
|
||||||
|
// airport name + "traffic" + airplane callsign + pattern direction + pattern leg + rwy + ?
|
||||||
|
string trns = "";
|
||||||
|
|
||||||
|
trns += tower->get_name();
|
||||||
|
trns += " Traffic ";
|
||||||
|
// FIXME - add the callsign to the class variables
|
||||||
|
trns += "Trainer-two-five-charlie ";
|
||||||
|
if(patternDirection == 1) {
|
||||||
|
trns += "right ";
|
||||||
|
} else {
|
||||||
|
trns += "left ";
|
||||||
|
}
|
||||||
|
|
||||||
|
// We could probably get rid of this whole switch statement and just pass a string containing the leg from the FlyPattern function.
|
||||||
|
switch(leg) { // We'll assume that transmissions in turns are intended for next leg - do pilots ever call out that they are in the turn?
|
||||||
|
case TURN1:
|
||||||
|
// Fall through to CROSSWIND
|
||||||
|
case CROSSWIND: // I don't think this case will be used here but it can't hurt to leave it in
|
||||||
|
trns += "crosswind ";
|
||||||
|
break;
|
||||||
|
case TURN2:
|
||||||
|
// Fall through to DOWNWIND
|
||||||
|
case DOWNWIND:
|
||||||
|
trns += "downwind ";
|
||||||
|
break;
|
||||||
|
case TURN3:
|
||||||
|
// Fall through to BASE
|
||||||
|
case BASE:
|
||||||
|
trns += "base ";
|
||||||
|
break;
|
||||||
|
case TURN4:
|
||||||
|
// Fall through to FINAL
|
||||||
|
case FINAL: // maybe this should include long/short final if appropriate?
|
||||||
|
trns += "final ";
|
||||||
|
break;
|
||||||
|
default: // Hopefully this won't be used
|
||||||
|
trns += "pattern ";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// FIXME - I've hardwired the runway call as well!! (We could work this out from rwy heading and mag deviation)
|
||||||
|
trns += convertNumToSpokenString(1);
|
||||||
|
|
||||||
|
// And add the airport name again
|
||||||
|
trns += tower->get_name();
|
||||||
|
|
||||||
|
Transmit(trns);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,11 +35,12 @@
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
|
|
||||||
#include "tower.hxx"
|
#include "tower.hxx"
|
||||||
#include "AIEntity.hxx"
|
#include "AIPlane.hxx"
|
||||||
|
#include "ATCProjection.hxx"
|
||||||
|
|
||||||
typedef enum pattern_leg {
|
typedef enum PatternLeg {
|
||||||
TAKEOFF_ROLL,
|
TAKEOFF_ROLL,
|
||||||
OUTWARD,
|
CLIMBOUT,
|
||||||
TURN1,
|
TURN1,
|
||||||
CROSSWIND,
|
CROSSWIND,
|
||||||
TURN2,
|
TURN2,
|
||||||
|
@ -51,7 +52,23 @@ typedef enum pattern_leg {
|
||||||
LANDING_ROLL
|
LANDING_ROLL
|
||||||
};
|
};
|
||||||
|
|
||||||
class FGAILocalTraffic : public FGAIEntity {
|
// perhaps we could use an FGRunway instead of this
|
||||||
|
typedef struct RunwayDetails {
|
||||||
|
Point3D threshold_pos;
|
||||||
|
Point3D end1ortho; // ortho projection end1 (the threshold ATM)
|
||||||
|
Point3D end2ortho; // ortho projection end2 (the take off end in the current hardwired scheme)
|
||||||
|
double mag_hdg;
|
||||||
|
double mag_var;
|
||||||
|
double hdg; // true runway heading
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct StartofDescent {
|
||||||
|
PatternLeg leg;
|
||||||
|
double orthopos_x;
|
||||||
|
double orthopos_y;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FGAILocalTraffic : public FGAIPlane {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -62,24 +79,27 @@ public:
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
// Run the internal calculations
|
// Run the internal calculations
|
||||||
void Update();
|
void Update(double dt);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Attempt to enter the traffic pattern in a reasonably intelligent manner
|
||||||
|
void EnterTrafficPattern(double dt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FGATCAlignedProjection ortho; // Orthogonal mapping of the local area with the threshold at the origin
|
||||||
|
// and the runway aligned with the y axis.
|
||||||
|
|
||||||
|
// Airport/runway/pattern details
|
||||||
char* airport; // The ICAO code of the airport that we're operating around
|
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.
|
FGTower* tower; // A pointer to the tower control.
|
||||||
|
RunwayDetails rwy;
|
||||||
|
double patternDirection; // 1 for right, -1 for left (This is double because we multiply/divide turn rates
|
||||||
|
// with it to get RH/LH turns - DON'T convert it to int under ANY circumstances!!
|
||||||
|
double glideAngle; // Assumed to be visual glidepath angle for FGAILocalTraffic - can be found at www.airnav.com
|
||||||
|
// Its conceivable that patternDirection and glidePath could be moved into the RunwayDetails structure.
|
||||||
|
|
||||||
double mag_hdg; // degrees - the heading that the physical aircraft is pointing
|
// Performance characteristics of the plane in knots and ft/min - some of this might get moved out into FGAIPlane
|
||||||
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 Vr;
|
||||||
double best_rate_of_climb_speed;
|
double best_rate_of_climb_speed;
|
||||||
double best_rate_of_climb;
|
double best_rate_of_climb;
|
||||||
|
@ -90,11 +110,27 @@ private:
|
||||||
double max_circuit_speed;
|
double max_circuit_speed;
|
||||||
double nominal_descent_rate;
|
double nominal_descent_rate;
|
||||||
double nominal_approach_speed;
|
double nominal_approach_speed;
|
||||||
|
double nominal_final_speed;
|
||||||
double stall_speed_landing_config;
|
double stall_speed_landing_config;
|
||||||
|
|
||||||
// OK, what do we need to know whilst flying the pattern
|
// environment - some of this might get moved into FGAIPlane
|
||||||
pattern_leg leg;
|
double wind_from_hdg; // degrees
|
||||||
|
double wind_speed_knots; // knots
|
||||||
|
|
||||||
|
// Pattern details that (may) change
|
||||||
|
int numInPattern; // Number of planes in the pattern (this might get more complicated if high performance GA aircraft fly a higher pattern eventually)
|
||||||
|
int numAhead; // More importantly - how many of them are ahead of us?
|
||||||
|
double distToNext; // And even more importantly, how near are we getting to the one immediately ahead?
|
||||||
|
PatternLeg leg; // Out current position in the pattern
|
||||||
|
StartofDescent SoD; // Start of descent calculated wrt wind, pattern size & altitude, glideslope etc
|
||||||
|
|
||||||
|
void FlyTrafficPattern(double dt);
|
||||||
|
|
||||||
|
// TODO - need to add something to define what option we are flying - Touch and go / Stop and go / Landing properly / others?
|
||||||
|
|
||||||
|
void TransmitPatternPositionReport();
|
||||||
|
|
||||||
|
void CalculateStartofDescent();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _FG_AILocalTraffic_HXX
|
#endif // _FG_AILocalTraffic_HXX
|
||||||
|
|
|
@ -60,11 +60,18 @@ void FGAIMgr::bind() {
|
||||||
void FGAIMgr::unbind() {
|
void FGAIMgr::unbind() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIMgr::update(int dt) {
|
void FGAIMgr::update(double dt) {
|
||||||
|
// Don't update any planes for first 50 runs through - this avoids some possible initialisation anomalies
|
||||||
|
static int i = 0;
|
||||||
|
i++;
|
||||||
|
if(i < 50) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Traverse the list of active planes and run all their update methods
|
// Traverse the list of active planes and run all their update methods
|
||||||
ai_list_itr = ai_list.begin();
|
ai_list_itr = ai_list.begin();
|
||||||
while(ai_list_itr != ai_list.end()) {
|
while(ai_list_itr != ai_list.end()) {
|
||||||
(*ai_list_itr)->Update();
|
(*ai_list_itr)->Update(dt);
|
||||||
++ai_list_itr;
|
++ai_list_itr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ public:
|
||||||
|
|
||||||
void unbind();
|
void unbind();
|
||||||
|
|
||||||
void update(int dt);
|
void update(double dt);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
77
src/ATC/AIPlane.cxx
Normal file
77
src/ATC/AIPlane.cxx
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// FGAIPlane - abstract base class for an AI plane
|
||||||
|
//
|
||||||
|
// Written by David Luff, started 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 <Main/fg_props.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 <math.h>
|
||||||
|
#include <string>
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
|
||||||
|
#include "AIPlane.hxx"
|
||||||
|
#include "ATCdisplay.hxx"
|
||||||
|
|
||||||
|
FGAIPlane::~FGAIPlane() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIPlane::Update(double dt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIPlane::Bank(double angle) {
|
||||||
|
// This *should* bank us smoothly to any angle
|
||||||
|
if(fabs(roll - angle) > 0.6) {
|
||||||
|
roll -= ((roll - angle)/fabs(roll - angle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplication of Bank(0.0) really - should I cut this?
|
||||||
|
void FGAIPlane::LevelWings(void) {
|
||||||
|
// bring the plane back to level smoothly (this should work to come out of either bank)
|
||||||
|
if(fabs(roll) > 0.6) {
|
||||||
|
roll -= (roll/fabs(roll));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAIPlane::Transmit(string msg) {
|
||||||
|
double user_freq0 = fgGetDouble("/radios/comm[0]/frequencies/selected-mhz");
|
||||||
|
//double user_freq0 = ("/radios/comm[0]/frequencies/selected-mhz");
|
||||||
|
//comm1 is not used yet.
|
||||||
|
|
||||||
|
if(freq == user_freq0) {
|
||||||
|
// we are on the same frequency, so check distance to the user plane
|
||||||
|
if(1) {
|
||||||
|
// For now (testing) assume in range !!!
|
||||||
|
globals->get_ATC_display()->RegisterSingleMessage(msg, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
87
src/ATC/AIPlane.hxx
Normal file
87
src/ATC/AIPlane.hxx
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// FGAIPlane - abstract base class for an AI plane
|
||||||
|
//
|
||||||
|
// Written by David Luff, started 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_AI_PLANE_HXX
|
||||||
|
#define _FG_AI_PLANE_HXX
|
||||||
|
|
||||||
|
#include <Model/model.hxx>
|
||||||
|
#include <plib/sg.h>
|
||||||
|
#include <plib/ssg.h>
|
||||||
|
#include <simgear/math/point3d.hxx>
|
||||||
|
|
||||||
|
#include "AIEntity.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************
|
||||||
|
*
|
||||||
|
* FGAIPlane - this class is derived from FGAIEntity and adds the
|
||||||
|
* practical requirement for an AI plane - the ability to send radio
|
||||||
|
* communication, and simple performance details for the actual AI
|
||||||
|
* implementation to use. The AI implementation is expected to be
|
||||||
|
* in derived classes - this class does nothing useful on its own.
|
||||||
|
*
|
||||||
|
******************************************************************/
|
||||||
|
class FGAIPlane : public FGAIEntity {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~FGAIPlane();
|
||||||
|
|
||||||
|
// Run the internal calculations
|
||||||
|
virtual void Update(double dt);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
double mag_hdg; // degrees - the heading that the physical aircraft is *pointing*
|
||||||
|
double track; // track that the physical aircraft is *following* - degrees relative to *true* north
|
||||||
|
double yaw;
|
||||||
|
double mag_var; // degrees
|
||||||
|
double IAS; // Indicated airspeed in knots
|
||||||
|
double vel; // velocity along track in knots
|
||||||
|
double vel_si; // velocity along track in m/s
|
||||||
|
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
|
||||||
|
|
||||||
|
double freq; // The comm frequency that we're operating on
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// Make radio transmission - this simply sends the transmission for physical rendering if the users
|
||||||
|
// aircraft is on the same frequency and in range. It is up to the derived classes to let ATC know
|
||||||
|
// what is going on.
|
||||||
|
void Transmit(string msg);
|
||||||
|
|
||||||
|
void Bank(double angle);
|
||||||
|
void LevelWings(void);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _FG_AI_PLANE_HXX
|
||||||
|
|
76
src/ATC/ATCProjection.cxx
Normal file
76
src/ATC/ATCProjection.cxx
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#include "ATCProjection.hxx"
|
||||||
|
#include <math.h>
|
||||||
|
#include <simgear/constants.h>
|
||||||
|
|
||||||
|
#define DCL_PI 3.1415926535f
|
||||||
|
//#define SG_PI ((SGfloat) M_PI)
|
||||||
|
#define DCL_DEGREES_TO_RADIANS (DCL_PI/180.0)
|
||||||
|
#define DCL_RADIANS_TO_DEGREES (180.0/DCL_PI)
|
||||||
|
|
||||||
|
FGATCProjection::FGATCProjection() {
|
||||||
|
origin.setlat(0.0);
|
||||||
|
origin.setlon(0.0);
|
||||||
|
origin.setelev(0.0);
|
||||||
|
correction_factor = cos(origin.lat() * DCL_DEGREES_TO_RADIANS);
|
||||||
|
}
|
||||||
|
|
||||||
|
FGATCProjection::~FGATCProjection() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGATCProjection::Init(Point3D centre) {
|
||||||
|
origin = centre;
|
||||||
|
correction_factor = cos(origin.lat() * DCL_DEGREES_TO_RADIANS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3D FGATCProjection::ConvertToLocal(Point3D pt) {
|
||||||
|
double delta_lat = pt.lat() - origin.lat();
|
||||||
|
double delta_lon = pt.lon() - origin.lon();
|
||||||
|
|
||||||
|
double y = sin(delta_lat * DCL_DEGREES_TO_RADIANS) * SG_EQUATORIAL_RADIUS_M;
|
||||||
|
double x = sin(delta_lon * DCL_DEGREES_TO_RADIANS) * SG_EQUATORIAL_RADIUS_M * correction_factor;
|
||||||
|
|
||||||
|
return(Point3D(x,y,0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3D FGATCProjection::ConvertFromLocal(Point3D pt) {
|
||||||
|
return(Point3D(0,0,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************************/
|
||||||
|
|
||||||
|
FGATCAlignedProjection::FGATCAlignedProjection() {
|
||||||
|
origin.setlat(0.0);
|
||||||
|
origin.setlon(0.0);
|
||||||
|
origin.setelev(0.0);
|
||||||
|
correction_factor = cos(origin.lat() * DCL_DEGREES_TO_RADIANS);
|
||||||
|
}
|
||||||
|
|
||||||
|
FGATCAlignedProjection::~FGATCAlignedProjection() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGATCAlignedProjection::Init(Point3D centre, double heading) {
|
||||||
|
origin = centre;
|
||||||
|
theta = heading * DCL_DEGREES_TO_RADIANS;
|
||||||
|
correction_factor = cos(origin.lat() * DCL_DEGREES_TO_RADIANS);
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3D FGATCAlignedProjection::ConvertToLocal(Point3D pt) {
|
||||||
|
// convert from lat/lon to orthogonal
|
||||||
|
double delta_lat = pt.lat() - origin.lat();
|
||||||
|
double delta_lon = pt.lon() - origin.lon();
|
||||||
|
double y = sin(delta_lat * DCL_DEGREES_TO_RADIANS) * SG_EQUATORIAL_RADIUS_M;
|
||||||
|
double x = sin(delta_lon * DCL_DEGREES_TO_RADIANS) * SG_EQUATORIAL_RADIUS_M * correction_factor;
|
||||||
|
//cout << "Before alignment, x = " << x << " y = " << y << '\n';
|
||||||
|
|
||||||
|
// Align
|
||||||
|
double xbar = x;
|
||||||
|
x = x*cos(theta) - y*sin(theta);
|
||||||
|
y = (xbar*sin(theta)) + (y*cos(theta));
|
||||||
|
//cout << "After alignment, x = " << x << " y = " << y << '\n';
|
||||||
|
|
||||||
|
return(Point3D(x,y,0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
Point3D FGATCAlignedProjection::ConvertFromLocal(Point3D pt) {
|
||||||
|
return(Point3D(0,0,0));
|
||||||
|
}
|
51
src/ATC/ATCProjection.hxx
Normal file
51
src/ATC/ATCProjection.hxx
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#ifndef _FG_ATC_PROJECTION_HXX
|
||||||
|
#define _FG_ATC_PROJECTION_HXX
|
||||||
|
|
||||||
|
#include <simgear/math/point3d.hxx>
|
||||||
|
|
||||||
|
// FGATCProjection - a class to project an area local to an airport onto an orthogonal co-ordinate system
|
||||||
|
class FGATCProjection {
|
||||||
|
|
||||||
|
public:
|
||||||
|
FGATCProjection();
|
||||||
|
~FGATCProjection();
|
||||||
|
|
||||||
|
void Init(Point3D centre);
|
||||||
|
|
||||||
|
// Convert a lat/lon co-ordinate to the local projection
|
||||||
|
Point3D ConvertToLocal(Point3D pt);
|
||||||
|
|
||||||
|
// Convert a local projection co-ordinate to lat/lon
|
||||||
|
Point3D ConvertFromLocal(Point3D pt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Point3D origin; // lat/lon of local area origin
|
||||||
|
double correction_factor; // Reduction in surface distance per degree of longitude due to latitude. Saves having to do a cos() every call.
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// FGATCAlignedProjection - a class to project an area local to a runway onto an orthogonal co-ordinate system
|
||||||
|
// with the origin at the threshold and the runway aligned with the y axis.
|
||||||
|
class FGATCAlignedProjection {
|
||||||
|
|
||||||
|
public:
|
||||||
|
FGATCAlignedProjection();
|
||||||
|
~FGATCAlignedProjection();
|
||||||
|
|
||||||
|
void Init(Point3D centre, double heading);
|
||||||
|
|
||||||
|
// Convert a lat/lon co-ordinate to the local projection
|
||||||
|
Point3D ConvertToLocal(Point3D pt);
|
||||||
|
|
||||||
|
// Convert a local projection co-ordinate to lat/lon
|
||||||
|
Point3D ConvertFromLocal(Point3D pt);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Point3D origin; // lat/lon of local area origin (the threshold)
|
||||||
|
double theta; // the rotation angle for alignment in radians
|
||||||
|
double correction_factor; // Reduction in surface distance per degree of longitude due to latitude. Saves having to do a cos() every call.
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _FG_ATC_PROJECTION_HXX
|
|
@ -146,6 +146,22 @@ void FGATCMgr::RemoveFromList(const char* id, atc_type tp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//DCL - this routine untested so far.
|
||||||
|
// Find in list - return a currently active ATC pointer given ICAO code and type
|
||||||
|
FGATC* FGATCMgr::FindInList(const char* id, atc_type tp) {
|
||||||
|
atc_list_itr = atc_list.begin();
|
||||||
|
while(atc_list_itr != atc_list.end()) {
|
||||||
|
if( (!strcmp((*atc_list_itr)->GetIdent(), id))
|
||||||
|
&& ((*atc_list_itr)->GetType() == tp) ) {
|
||||||
|
return(*atc_list_itr);
|
||||||
|
} // Note that that can upset where we are in the list but that shouldn't really matter
|
||||||
|
++atc_list_itr;
|
||||||
|
}
|
||||||
|
// We need a fallback position
|
||||||
|
cout << "*** Failed to find FGATC* in FGATCMgr::FindInList - this should not happen!" << endl;
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns true if the airport is found in the map
|
// Returns true if the airport is found in the map
|
||||||
bool FGATCMgr::GetAirportATCDetails(string icao, AirportATC* a) {
|
bool FGATCMgr::GetAirportATCDetails(string icao, AirportATC* a) {
|
||||||
if(airport_atc_map.find(icao) != airport_atc_map.end()) {
|
if(airport_atc_map.find(icao) != airport_atc_map.end()) {
|
||||||
|
@ -168,6 +184,7 @@ FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) {
|
||||||
case TOWER:
|
case TOWER:
|
||||||
if(a->tower_active) {
|
if(a->tower_active) {
|
||||||
// Get the pointer from the list
|
// Get the pointer from the list
|
||||||
|
return(FindInList(icao.c_str(), type)); // DCL - this untested so far.
|
||||||
} else {
|
} else {
|
||||||
FGTower* t = new FGTower;
|
FGTower* t = new FGTower;
|
||||||
if(current_towerlist->query(a->lon, a->lat, a->elev, a->tower_freq, &tower)) {
|
if(current_towerlist->query(a->lon, a->lat, a->elev, a->tower_freq, &tower)) {
|
||||||
|
@ -199,7 +216,7 @@ FGATC* FGATCMgr::GetATCPointer(string icao, atc_type type) {
|
||||||
|
|
||||||
cout << "ERROR IN FGATCMgr - reached end of GetATCPointer\n";
|
cout << "ERROR IN FGATCMgr - reached end of GetATCPointer\n";
|
||||||
|
|
||||||
return NULL;
|
return(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,9 @@ private:
|
||||||
// Remove a class from the atc_list and delete it from memory
|
// Remove a class from the atc_list and delete it from memory
|
||||||
void RemoveFromList(const char* id, atc_type tp);
|
void RemoveFromList(const char* id, atc_type tp);
|
||||||
|
|
||||||
|
// Return a pointer to a class in the list (external interface to this is through GetATCPointer)
|
||||||
|
FGATC* FGATCMgr::FindInList(const char* id, atc_type tp);
|
||||||
|
|
||||||
// Search a specified freq for matching stations
|
// Search a specified freq for matching stations
|
||||||
void Search();
|
void Search();
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,88 @@
|
||||||
// Utility functions for the ATC / AI system
|
// ATCutils.cxx - Utility functions for the ATC / AI system
|
||||||
|
//
|
||||||
|
// 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 <math.h>
|
#include <math.h>
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
#include <simgear/constants.h>
|
#include <simgear/constants.h>
|
||||||
#include <plib/sg.h>
|
#include <plib/sg.h>
|
||||||
|
#include <iomanip.h>
|
||||||
|
|
||||||
|
#include "ATCutils.hxx"
|
||||||
|
|
||||||
|
// Convert a 2 digit rwy number to a spoken-style string
|
||||||
|
string convertNumToSpokenString(int n) {
|
||||||
|
string nums[10] = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
|
||||||
|
// Basic error/sanity checking
|
||||||
|
while(n < 0) {
|
||||||
|
n += 36;
|
||||||
|
}
|
||||||
|
while(n > 36) {
|
||||||
|
n -= 36;
|
||||||
|
}
|
||||||
|
if(n == 0) {
|
||||||
|
n = 36; // Is this right?
|
||||||
|
}
|
||||||
|
|
||||||
|
string str = "";
|
||||||
|
int index = n/10;
|
||||||
|
str += nums[index];
|
||||||
|
n -= (index * 10);
|
||||||
|
str += "-";
|
||||||
|
str += nums[n];
|
||||||
|
return(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the phonetic letter of a letter represented as an integer 1->26
|
||||||
|
string GetPhoneticIdent(int i) {
|
||||||
|
// TODO - Check i is between 1 and 26 and wrap if necessary
|
||||||
|
switch(i) {
|
||||||
|
case 1 : return("Alpha");
|
||||||
|
case 2 : return("Bravo");
|
||||||
|
case 3 : return("Charlie");
|
||||||
|
case 4 : return("Delta");
|
||||||
|
case 5 : return("Echo");
|
||||||
|
case 6 : return("Foxtrot");
|
||||||
|
case 7 : return("Golf");
|
||||||
|
case 8 : return("Hotel");
|
||||||
|
case 9 : return("Indigo");
|
||||||
|
case 10 : return("Juliet");
|
||||||
|
case 11 : return("Kilo");
|
||||||
|
case 12 : return("Lima");
|
||||||
|
case 13 : return("Mike");
|
||||||
|
case 14 : return("November");
|
||||||
|
case 15 : return("Oscar");
|
||||||
|
case 16 : return("Papa");
|
||||||
|
case 17 : return("Quebec");
|
||||||
|
case 18 : return("Romeo");
|
||||||
|
case 19 : return("Sierra");
|
||||||
|
case 20 : return("Tango");
|
||||||
|
case 21 : return("Uniform");
|
||||||
|
case 22 : return("Victor");
|
||||||
|
case 23 : return("Whiskey");
|
||||||
|
case 24 : return("X-ray");
|
||||||
|
case 25 : return("Yankee");
|
||||||
|
case 26 : return("Zulu");
|
||||||
|
}
|
||||||
|
// We shouldn't get here
|
||||||
|
return("Error");
|
||||||
|
}
|
||||||
|
|
||||||
// Given two positions, get the HORIZONTAL separation (in meters)
|
// Given two positions, get the HORIZONTAL separation (in meters)
|
||||||
double dclGetHorizontalSeparation(Point3D pos1, Point3D pos2) {
|
double dclGetHorizontalSeparation(Point3D pos1, Point3D pos2) {
|
||||||
|
@ -23,12 +102,34 @@ double dclGetHorizontalSeparation(Point3D pos1, Point3D pos2) {
|
||||||
return(z);
|
return(z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given a point and a line, get the HORIZONTAL shortest distance from the point to a point on the line.
|
||||||
|
// Expects to be fed orthogonal co-ordinates, NOT lat & lon !
|
||||||
|
double dclGetLinePointSeparation(double px, double py, double x1, double y1, double x2, double y2) {
|
||||||
|
double vecx = x2-x1;
|
||||||
|
double vecy = y2-y1;
|
||||||
|
double magline = sqrt(vecx*vecx + vecy*vecy);
|
||||||
|
double u = ((px-x1)*(x2-x1) + (py-y1)*(y2-y1)) / (magline * magline);
|
||||||
|
double x0 = x1 + u*(x2-x1);
|
||||||
|
double y0 = y1 + u*(y2-y1);
|
||||||
|
vecx = px - x0;
|
||||||
|
vecy = py - y0;
|
||||||
|
double d = sqrt(vecx*vecx + vecy*vecy);
|
||||||
|
if(d < 0) {
|
||||||
|
d *= -1;
|
||||||
|
}
|
||||||
|
return(d);
|
||||||
|
}
|
||||||
|
|
||||||
// Given a position (lat/lon/elev), heading, vertical angle, and distance, calculate the new position.
|
// Given a position (lat/lon/elev), heading, vertical angle, and distance, calculate the new position.
|
||||||
// Assumes that the ground is not hit!!! Expects heading and angle in degrees, distance in meters.
|
// Assumes that the ground is not hit!!! Expects heading and angle in degrees, distance in meters.
|
||||||
Point3D dclUpdatePosition(Point3D pos, double heading, double angle, double distance) {
|
Point3D dclUpdatePosition(Point3D pos, double heading, double angle, double distance) {
|
||||||
double lat = pos.lat() * SG_DEGREES_TO_RADIANS;
|
//cout << setprecision(10) << pos.lon() << ' ' << pos.lat() << '\n';
|
||||||
double lon = pos.lon() * SG_DEGREES_TO_RADIANS;
|
heading *= DCL_DEGREES_TO_RADIANS;
|
||||||
|
angle *= DCL_DEGREES_TO_RADIANS;
|
||||||
|
double lat = pos.lat() * DCL_DEGREES_TO_RADIANS;
|
||||||
|
double lon = pos.lon() * DCL_DEGREES_TO_RADIANS;
|
||||||
double elev = pos.elev();
|
double elev = pos.elev();
|
||||||
|
//cout << setprecision(10) << lon*DCL_RADIANS_TO_DEGREES << ' ' << lat*DCL_RADIANS_TO_DEGREES << '\n';
|
||||||
|
|
||||||
double horiz_dist = distance * cos(angle);
|
double horiz_dist = distance * cos(angle);
|
||||||
double vert_dist = distance * sin(angle);
|
double vert_dist = distance * sin(angle);
|
||||||
|
@ -36,11 +137,19 @@ Point3D dclUpdatePosition(Point3D pos, double heading, double angle, double dist
|
||||||
double north_dist = horiz_dist * cos(heading);
|
double north_dist = horiz_dist * cos(heading);
|
||||||
double east_dist = horiz_dist * sin(heading);
|
double east_dist = horiz_dist * sin(heading);
|
||||||
|
|
||||||
lat += asin(north_dist / SG_EQUATORIAL_RADIUS_M);
|
//cout << distance << ' ' << horiz_dist << ' ' << vert_dist << ' ' << north_dist << ' ' << east_dist << '\n';
|
||||||
lon += asin(east_dist / SG_EQUATORIAL_RADIUS_M) * (1.0 / cos(lat)); // I suppose really we should use the average of the original and new lat but we'll assume that this will be good enough.
|
|
||||||
elev += vert_dist;
|
|
||||||
|
|
||||||
return(Point3D(lon*SG_RADIANS_TO_DEGREES, lat*SG_RADIANS_TO_DEGREES, elev));
|
double delta_lat = asin(north_dist / (double)SG_EQUATORIAL_RADIUS_M);
|
||||||
|
double delta_lon = asin(east_dist / (double)SG_EQUATORIAL_RADIUS_M) * (1.0 / cos(lat)); // I suppose really we should use the average of the original and new lat but we'll assume that this will be good enough.
|
||||||
|
//cout << delta_lon*DCL_RADIANS_TO_DEGREES << ' ' << delta_lat*DCL_RADIANS_TO_DEGREES << '\n';
|
||||||
|
lat += delta_lat;
|
||||||
|
lon += delta_lon;
|
||||||
|
elev += vert_dist;
|
||||||
|
//cout << setprecision(10) << lon*DCL_RADIANS_TO_DEGREES << ' ' << lat*DCL_RADIANS_TO_DEGREES << '\n';
|
||||||
|
|
||||||
|
//cout << setprecision(15) << DCL_DEGREES_TO_RADIANS * DCL_RADIANS_TO_DEGREES << '\n';
|
||||||
|
|
||||||
|
return(Point3D(lon*DCL_RADIANS_TO_DEGREES, lat*DCL_RADIANS_TO_DEGREES, elev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,59 @@
|
||||||
// Utility functions for the ATC / AI subsytem declarations
|
// ATCutils.hxx - Utility functions for the ATC / AI subsytem
|
||||||
|
//
|
||||||
|
// 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 <math.h>
|
#include <math.h>
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
|
#include <string>
|
||||||
|
SG_USING_STD(string);
|
||||||
|
|
||||||
|
// These are defined here because I had a problem with SG_DEGREES_TO_RADIANS
|
||||||
|
#define DCL_PI 3.1415926535f
|
||||||
|
#define DCL_DEGREES_TO_RADIANS (DCL_PI/180.0)
|
||||||
|
#define DCL_RADIANS_TO_DEGREES (180.0/DCL_PI)
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
*
|
||||||
|
* Communication functions
|
||||||
|
*
|
||||||
|
********************************/
|
||||||
|
|
||||||
|
// Convert a 2 digit rwy number to a spoken-style string
|
||||||
|
string convertNumToSpokenString(int n);
|
||||||
|
|
||||||
|
// Return the phonetic letter of a letter represented as an integer 1->26
|
||||||
|
string GetPhoneticIdent(int i);
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************
|
||||||
|
*
|
||||||
|
* Positional functions
|
||||||
|
*
|
||||||
|
********************************/
|
||||||
|
|
||||||
// Given two positions, get the HORIZONTAL separation
|
// Given two positions, get the HORIZONTAL separation
|
||||||
double dclGetHorizontalSeparation(Point3D pos1, Point3D pos2);
|
double dclGetHorizontalSeparation(Point3D pos1, Point3D pos2);
|
||||||
|
|
||||||
|
// Given a point and a line, get the HORIZONTAL shortest distance from the point to a point on the line.
|
||||||
|
// Expects to be fed orthogonal co-ordinates, NOT lat & lon !
|
||||||
|
double dclGetLinePointSeparation(double px, double py, double x1, double y1, double x2, double y2);
|
||||||
|
|
||||||
// Given a position (lat/lon/elev), heading, vertical angle, and distance, calculate the new position.
|
// Given a position (lat/lon/elev), heading, vertical angle, and distance, calculate the new position.
|
||||||
// Assumes that the ground is not hit!!! Expects heading and angle in degrees, distance in meters.
|
// Assumes that the ground is not hit!!! Expects heading and angle in degrees, distance in meters.
|
||||||
Point3D dclUpdatePosition(Point3D pos, double heading, double angle, double distance);
|
Point3D dclUpdatePosition(Point3D pos, double heading, double angle, double distance);
|
||||||
|
|
|
@ -8,8 +8,10 @@ libATC_a_SOURCES = \
|
||||||
ATCdisplay.hxx ATCdisplay.cxx \
|
ATCdisplay.hxx ATCdisplay.cxx \
|
||||||
ATCmgr.hxx ATCmgr.cxx \
|
ATCmgr.hxx ATCmgr.cxx \
|
||||||
ATCutils.hxx ATCutils.cxx \
|
ATCutils.hxx ATCutils.cxx \
|
||||||
|
ATCProjection.hxx ATCProjection.cxx \
|
||||||
AIMgr.hxx AIMgr.cxx \
|
AIMgr.hxx AIMgr.cxx \
|
||||||
AIEntity.hxx AIEntity.cxx \
|
AIEntity.hxx AIEntity.cxx \
|
||||||
|
AIPlane.hxx AIPlane.cxx \
|
||||||
AILocalTraffic.hxx AILocalTraffic.cxx
|
AILocalTraffic.hxx AILocalTraffic.cxx
|
||||||
|
|
||||||
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
|
||||||
|
|
|
@ -86,7 +86,7 @@ bool FGApproachList::init( SGPath path ) {
|
||||||
//cout << " Name = " << a.get_name() << endl;
|
//cout << " Name = " << a.get_name() << endl;
|
||||||
|
|
||||||
approachlist_freq[a.get_freq()].push_back(a);
|
approachlist_freq[a.get_freq()].push_back(a);
|
||||||
approachlist_bck[a.get_bucket()].push_back(a);
|
approachlist_bck[int(a.get_bucket())].push_back(a);
|
||||||
in >> skipcomment;
|
in >> skipcomment;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,40 +54,7 @@ SG_USING_STD(cout);
|
||||||
#include "atis.hxx"
|
#include "atis.hxx"
|
||||||
#include "atislist.hxx"
|
#include "atislist.hxx"
|
||||||
#include "ATCdisplay.hxx"
|
#include "ATCdisplay.hxx"
|
||||||
|
#include "ATCutils.hxx"
|
||||||
string GetPhoneticIdent(int i) {
|
|
||||||
// TODO - Check i is between 1 and 26 and wrap if necessary
|
|
||||||
switch(i) {
|
|
||||||
case 1 : return("Alpha");
|
|
||||||
case 2 : return("Bravo");
|
|
||||||
case 3 : return("Charlie");
|
|
||||||
case 4 : return("Delta");
|
|
||||||
case 5 : return("Echo");
|
|
||||||
case 6 : return("Foxtrot");
|
|
||||||
case 7 : return("Golf");
|
|
||||||
case 8 : return("Hotel");
|
|
||||||
case 9 : return("Indigo");
|
|
||||||
case 10 : return("Juliet");
|
|
||||||
case 11 : return("Kilo");
|
|
||||||
case 12 : return("Lima");
|
|
||||||
case 13 : return("Mike");
|
|
||||||
case 14 : return("November");
|
|
||||||
case 15 : return("Oscar");
|
|
||||||
case 16 : return("Papa");
|
|
||||||
case 17 : return("Quebec");
|
|
||||||
case 18 : return("Romeo");
|
|
||||||
case 19 : return("Sierra");
|
|
||||||
case 20 : return("Tango");
|
|
||||||
case 21 : return("Uniform");
|
|
||||||
case 22 : return("Victor");
|
|
||||||
case 23 : return("Whiskey");
|
|
||||||
case 24 : return("X-ray");
|
|
||||||
case 25 : return("Yankee");
|
|
||||||
case 26 : return("Zulu");
|
|
||||||
}
|
|
||||||
// We shouldn't get here
|
|
||||||
return("Error");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
FGATIS::FGATIS()
|
FGATIS::FGATIS()
|
||||||
|
|
|
@ -76,6 +76,7 @@ public:
|
||||||
inline int get_range() const { return range; }
|
inline int get_range() const { return range; }
|
||||||
inline const char* GetIdent() { return ident.c_str(); }
|
inline const char* GetIdent() { return ident.c_str(); }
|
||||||
inline string get_trans_ident() { return trans_ident; }
|
inline string get_trans_ident() { return trans_ident; }
|
||||||
|
inline string get_name() { return name; }
|
||||||
inline atc_type GetType() { return TOWER; }
|
inline atc_type GetType() { return TOWER; }
|
||||||
|
|
||||||
// Make a request of tower control
|
// Make a request of tower control
|
||||||
|
|
Loading…
Add table
Reference in a new issue