1
0
Fork 0

Add the AIModel based air traffic subsystem from Durk Talsma.

This commit is contained in:
ehofman 2004-06-03 17:59:14 +00:00
parent 9227d02aa3
commit b3e9697262
19 changed files with 1203 additions and 41 deletions

2
Thanks
View file

@ -145,7 +145,7 @@ Bruce Finney <bfinney@gte.net>
Melchior Franz <a8603365@unet.univie.ac.at> Melchior Franz <a8603365@unet.univie.ac.at>
Made that joystick high/low support for joystick hats. Made that joystick high/low support for joystick hats.
Nasal-ified the Saitek Cyborg Gold 3D (USB) joystick which now forms Nasal-ified the Saitek Cyborg Gold 3D (USB) joystick which now forms
the basis of a lot of porgrammable joysticks. the basis of a lot of programmable joysticks.
Created the led.txf font. Created the led.txf font.
Ruthlessly hunted down memory leaks in FlightGear, SimGear, and JSBSim. Ruthlessly hunted down memory leaks in FlightGear, SimGear, and JSBSim.
Maintains the only fully working helicopter model in FlightGear (Bolkow 105). Maintains the only fully working helicopter model in FlightGear (Bolkow 105).

View file

@ -120,7 +120,7 @@ case "${host}" in
if test -d /opt/X11R6 ; then if test -d /opt/X11R6 ; then
EXTRA_DIR2="/opt/X11R6" EXTRA_DIR2="/opt/X11R6"
fi fi
EXTRA_DIRS="${EXTRA_DIRS} $EXTRA_DIR1 $EXTRA_DIR2" EXTRA_DIRS="${EXTRA_DIRS} $EXTRA_DIR1 $EXTRA_DIR2 /usr/local/"
;; ;;
esac esac
@ -564,6 +564,7 @@ AC_CONFIG_FILES([ \
src/Sound/Makefile \ src/Sound/Makefile \
src/Systems/Makefile \ src/Systems/Makefile \
src/Time/Makefile \ src/Time/Makefile \
src/Traffic/Makefile \
tests/Makefile \ tests/Makefile \
utils/Makefile \ utils/Makefile \
utils/TerraSync/Makefile \ utils/TerraSync/Makefile \

View file

@ -163,6 +163,7 @@ inline void FGAIBase::setAltitude( double altitude_ft ) {
inline void FGAIBase::setBank( double bank ) { inline void FGAIBase::setBank( double bank ) {
roll = tgt_roll = bank; roll = tgt_roll = bank;
no_roll = false;
} }
inline void FGAIBase::setLongitude( double longitude ) { inline void FGAIBase::setLongitude( double longitude ) {

View file

@ -20,6 +20,7 @@
#include "AIFlightPlan.hxx" #include "AIFlightPlan.hxx"
#include <simgear/misc/sg_path.hxx> #include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx> #include <simgear/debug/logstream.hxx>
#include <simgear/route/waypoint.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <simgear/constants.h> #include <simgear/constants.h>
#ifdef __BORLANDC__ #ifdef __BORLANDC__
@ -72,6 +73,124 @@ FGAIFlightPlan::FGAIFlightPlan(string filename)
} }
// This is a modified version of the constructor,
// Which not only reads the waypoints from a
// Flight plan file, but also adds the current
// Position computed by the traffic manager, as well
// as setting speeds and altitude computed by the
// traffic manager.
FGAIFlightPlan::FGAIFlightPlan(string filename,
double lat,
double lon,
double alt,
double speed,
double course)
{
int i;
bool useInitialWayPoint = true;
SGPath path( globals->get_fg_root() );
path.append( ("/Data/AI/FlightPlans/" + filename).c_str() );
SGPropertyNode root;
try {
readProperties(path.str(), &root);
} catch (const sg_exception &e) {
SG_LOG(SG_GENERAL, SG_ALERT,
"Error reading AI flight plan: ");
cout << path.str() << endl;
return;
}
SGPropertyNode * node = root.getNode("flightplan");
// First waypoint is current position of the aircraft as
// dictated by the traffic manager.
waypoint* init_waypoint = new waypoint;
init_waypoint->name = string("initial position");
init_waypoint->latitude = lat;
init_waypoint->longitude = lon;
init_waypoint->altitude = alt;
init_waypoint->speed = speed;
init_waypoint->crossat = - 10000;
init_waypoint->gear_down = false;
init_waypoint->flaps_down = false;
waypoints.push_back( init_waypoint );
for (i = 0; i < node->nChildren(); i++) {
//cout << "Reading waypoint " << i << endl;
waypoint* wpt = new waypoint;
SGPropertyNode * wpt_node = node->getChild(i);
wpt->name = wpt_node->getStringValue("name", "END");
wpt->latitude = wpt_node->getDoubleValue("lat", 0);
wpt->longitude = wpt_node->getDoubleValue("lon", 0);
wpt->altitude = wpt_node->getDoubleValue("alt", 0);
wpt->speed = wpt_node->getDoubleValue("ktas", 0);
//wpt->speed = speed;
wpt->crossat = wpt_node->getDoubleValue("crossat", -10000);
wpt->gear_down = wpt_node->getBoolValue("gear-down", false);
wpt->flaps_down= wpt_node->getBoolValue("flaps-down", false);
if (wpt->name == "END") wpt->finished = true;
else wpt->finished = false;
// discard this waypoint if it's bearing differs more than
// 90 degrees from the course we should fly according to the
// Traffic manager. Those are considered "behind" us.
SGWayPoint first(init_waypoint->longitude,
init_waypoint->latitude,
init_waypoint->altitude);
SGWayPoint curr (wpt->longitude,
wpt->latitude,
wpt->altitude);
double crse, crsDiff;
double dist;
first.CourseAndDistance(curr, &crse, &dist);
dist *= SG_METER_TO_NM;
// We're only interested in the absolute value of crsDiff
// wich should fall in the 0-180 deg range.
crsDiff = fabs(crse-course);
if (crsDiff > 180)
crsDiff -= 180;
// These are the threee conditions that we consder including
// in our flight plan:
// 1) current waypoint is less then 100 miles away OR
// 2) curren waypoint is ahead of us, at any distance
bool useWpt = false;
if ((dist > 100.0) && (crsDiff > 90.0) && (wpt->name != string ("EOF")))
{
//useWpt = false;
// Once we start including waypoints, we have to continue, even though
// one of the following way point would suffice.
// so once is the useWpt flag is set to true, we cannot reset it to false.
// cerr << "Discarding waypoint: " << wpt->name
// << ": Course difference = " << crsDiff << endl;
}
else
useWpt = true;
if (useWpt)
{
if ((dist > 100.0) && (useInitialWayPoint))
{
waypoints.push_back(init_waypoint);
//cerr << "Using waypoint : " << init_waypoint->name << endl;
}
waypoints.push_back( wpt );
//cerr << "Using waypoint : " << wpt->name
// << ": course diff : " << crsDiff
// << "distance : " << dist << endl;
useInitialWayPoint = false;
}
else
delete wpt;
}
wpt_iterator = waypoints.begin();
//cout << waypoints.size() << " waypoints read." << endl;
}
FGAIFlightPlan::~FGAIFlightPlan() FGAIFlightPlan::~FGAIFlightPlan()
{ {
waypoints.clear(); waypoints.clear();
@ -144,32 +263,41 @@ double FGAIFlightPlan::getBearing(waypoint* first, waypoint* second){
double FGAIFlightPlan::getBearing(double lat, double lon, waypoint* wp){ double FGAIFlightPlan::getBearing(double lat, double lon, waypoint* wp){
double latd = lat; double course, distance;
double lond = lon; // double latd = lat;
double latt = wp->latitude; // double lond = lon;
double lont = wp->longitude; // double latt = wp->latitude;
double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat/SG_RADIANS_TO_DEGREES); // double lont = wp->longitude;
double ft_per_deg_lon = 365228.16 * cos(lat/SG_RADIANS_TO_DEGREES); // double ft_per_deg_lat = 366468.96 - 3717.12 * cos(lat/SG_RADIANS_TO_DEGREES);
// double ft_per_deg_lon = 365228.16 * cos(lat/SG_RADIANS_TO_DEGREES);
if (lond < 0.0) lond+=360.0; // if (lond < 0.0) {
if (lont < 0.0) lont+=360.0; // lond+=360.0;
latd+=90.0; // lont+=360;
latt+=90.0; // }
// if (lont < 0.0) {
// lond+=360.0;
// lont+=360.0;
// }
// latd+=90.0;
// latt+=90.0;
double lat_diff = (latt - latd) * ft_per_deg_lat; // double lat_diff = (latt - latd) * ft_per_deg_lat;
double lon_diff = (lont - lond) * ft_per_deg_lon; // double lon_diff = (lont - lond) * ft_per_deg_lon;
double angle = atan(fabs(lat_diff / lon_diff)) * SG_RADIANS_TO_DEGREES; // double angle = atan(fabs(lat_diff / lon_diff)) * SG_RADIANS_TO_DEGREES;
bool southerly = true;
if (latt > latd) southerly = false;
bool easterly = false;
if (lont > lond) easterly = true;
if (southerly && easterly) return 90.0 + angle;
if (!southerly && easterly) return 90.0 - angle;
if (southerly && !easterly) return 270.0 - angle;
if (!southerly && !easterly) return 270.0 + angle;
// bool southerly = true;
// if (latt > latd) southerly = false;
// bool easterly = false;
// if (lont > lond) easterly = true;
// if (southerly && easterly) return 90.0 + angle;
// if (!southerly && easterly) return 90.0 - angle;
// if (southerly && !easterly) return 270.0 - angle;
// if (!southerly && !easterly) return 270.0 + angle;
SGWayPoint sgWp(wp->longitude,wp->latitude, wp->altitude, SGWayPoint::WGS84, string("temp"));
sgWp.CourseAndDistance(lon, lat, wp->altitude, &course, &distance);
return course;
// Omit a compiler warning. // Omit a compiler warning.
return 0;
} }

View file

@ -44,6 +44,12 @@ public:
} waypoint; } waypoint;
FGAIFlightPlan(string filename); FGAIFlightPlan(string filename);
FGAIFlightPlan(string filename,
double lat,
double lon,
double alt,
double speed,
double course);
~FGAIFlightPlan(); ~FGAIFlightPlan();
waypoint* getPreviousWaypoint( void ); waypoint* getPreviousWaypoint( void );

View file

@ -123,7 +123,7 @@ int FGAIManager::assignID() {
int maxint = 30000; int maxint = 30000;
int x; int x;
bool used; bool used;
for (x=0; x<maxint; x++) { for (x=1; x<maxint; x++) {
used = false; used = false;
id_itr = ids.begin(); id_itr = ids.begin();
while( id_itr != ids.end() ) { while( id_itr != ids.end() ) {

View file

@ -67,8 +67,8 @@ FGAIScenario::FGAIScenario(string filename)
en->azimuth = entry_node->getDoubleValue("azimuth", 0.0); en->azimuth = entry_node->getDoubleValue("azimuth", 0.0);
en->elevation = entry_node->getDoubleValue("elevation", 0.0); en->elevation = entry_node->getDoubleValue("elevation", 0.0);
en->rudder = entry_node->getDoubleValue("rudder", 0.0); en->rudder = entry_node->getDoubleValue("rudder", 0.0);
en->strength = entry_node->getDoubleValue("strength", 0.0); en->strength = entry_node->getDoubleValue("strength-fps", 0.0);
en->diameter = entry_node->getDoubleValue("diameter", 0.0); en->diameter = entry_node->getDoubleValue("diameter-ft", 0.0);
} }
entry_iterator = entries.begin(); entry_iterator = entries.begin();

View file

@ -291,6 +291,7 @@ void FGTrimAxis::SetThetaOnGround(double ff) {
bool FGTrimAxis::initTheta(void) { bool FGTrimAxis::initTheta(void) {
int i,N,iAft, iForward; int i,N,iAft, iForward;
double zAft,zForward,zDiff,theta; double zAft,zForward,zDiff,theta;
double xAft,xForward,xDiff;
bool level; bool level;
double saveAlt; double saveAlt;
@ -317,17 +318,25 @@ bool FGTrimAxis::initTheta(void) {
} }
// now adjust theta till the wheels are the same distance from the ground // now adjust theta till the wheels are the same distance from the ground
zAft=fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear(3); xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(1);
zForward=fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear(3); xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(1);
zDiff = zForward - zAft; xDiff = xForward - xAft;
level=false; zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
theta=fgic->GetPitchAngleDegIC(); zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
while(!level && (i < 100)) { zDiff = zForward - zAft;
theta+=2.0*zDiff; level=false;
fgic->SetPitchAngleDegIC(theta); theta=fgic->GetPitchAngleDegIC();
fdmex->RunIC(); while(!level && (i < 100)) {
zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3); theta+=180.0/M_PI*zDiff/fabs(xDiff);
zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3); fgic->SetPitchAngleDegIC(theta);
fdmex->RunIC();
xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(1);
xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(1);
xDiff = xForward - xAft;
zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
zDiff = zForward - zAft;
zDiff = zForward - zAft; zDiff = zForward - zAft;
//cout << endl << theta << " " << zDiff << endl; //cout << endl << theta << " " << zDiff << endl;
//cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl; //cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;

View file

@ -83,6 +83,7 @@ fgfs_LDADD = \
$(top_builddir)/src/Replay/libReplay.a \ $(top_builddir)/src/Replay/libReplay.a \
$(top_builddir)/src/Systems/libSystems.a \ $(top_builddir)/src/Systems/libSystems.a \
$(top_builddir)/src/Time/libTime.a \ $(top_builddir)/src/Time/libTime.a \
$(top_builddir)/src/Traffic/libTraffic.a \
$(top_builddir)/src/Environment/libEnvironment.a \ $(top_builddir)/src/Environment/libEnvironment.a \
$(CLOUD3D_LIBS) \ $(CLOUD3D_LIBS) \
-lsgroute -lsgsky -lsgsound -lsgephem -lsgmaterial -lsgtgdb -lsgmodel \ -lsgroute -lsgsky -lsgsound -lsgephem -lsgmaterial -lsgtgdb -lsgmodel \

View file

@ -111,6 +111,7 @@
#include <Time/sunpos.hxx> #include <Time/sunpos.hxx>
#include <Time/sunsolver.hxx> #include <Time/sunsolver.hxx>
#include <Time/tmp.hxx> #include <Time/tmp.hxx>
#include <Traffic/TrafficMgr.hxx>
#ifdef FG_MPLAYER_AS #ifdef FG_MPLAYER_AS
#include <MultiPlayer/multiplaytxmgr.hxx> #include <MultiPlayer/multiplaytxmgr.hxx>
@ -1684,14 +1685,26 @@ bool fgInitSubsystems() {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Initialise the AI Model Manager // Initialise the AI Model Manager
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
SG_LOG(SG_GENERAL, SG_INFO, " AI Model Manager"); SG_LOG(SG_GENERAL, SG_INFO, " AI Model Manager");
globals->add_subsystem("ai_model", new FGAIManager); globals->add_subsystem("ai_model", new FGAIManager);
// It's probably a good idea to initialize the top level traffic manager
// After the AI and ATC systems have been initialized properly.
// AI Traffic manager
globals->add_subsystem("Traffic Manager", new FGTrafficManager);
FGTrafficManager *dispatcher =
(FGTrafficManager*) globals->get_subsystem("Traffic Manager");
readXML(string(globals->get_fg_root() + string("/Traffic/fgtraffic.xml")),
*dispatcher);
globals->get_subsystem("Traffic Manager")->init();
globals->add_subsystem("instrumentation", new FGInstrumentMgr); globals->add_subsystem("instrumentation", new FGInstrumentMgr);
globals->add_subsystem("systems", new FGSystemMgr); globals->add_subsystem("systems", new FGSystemMgr);
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Initialize the radio stack subsystem. // Initialize the radio stack subsystem.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View file

@ -62,6 +62,7 @@ class SGPropertyNode;
class SGTime; class SGTime;
class SGSoundMgr; class SGSoundMgr;
class FGAirportList; class FGAirportList;
class FGRunwayList; class FGRunwayList;
class FGAIMgr; class FGAIMgr;
@ -69,6 +70,7 @@ class FGATCMgr;
class FGATCDisplay; class FGATCDisplay;
class FGAircraftModel; class FGAircraftModel;
class FGControls; class FGControls;
class FGFlightPlanDispatcher;
class FGIO; class FGIO;
class FGNavList; class FGNavList;
class FGFixList; class FGFixList;
@ -173,6 +175,8 @@ private:
SGModelLib *model_lib; SGModelLib *model_lib;
//FGFlightPlanDispatcher *fpDispatcher;
FGAircraftModel *acmodel; FGAircraftModel *acmodel;
FGModelMgr * model_mgr; FGModelMgr * model_mgr;

View file

@ -29,4 +29,5 @@ SUBDIRS = \
Sound \ Sound \
Systems \ Systems \
Time \ Time \
Traffic \
Main Main

9
src/Traffic/Makefile.am Normal file
View file

@ -0,0 +1,9 @@
noinst_LIBRARIES = libTraffic.a
libTraffic_a_SOURCES = \
SchedFlight.cxx SchedFlight.hxx \
Schedule.cxx Schedule.hxx \
TrafficMgr.cxx TrafficMgr.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

257
src/Traffic/SchedFlight.cxx Normal file
View file

@ -0,0 +1,257 @@
/******************************************************************************
* SchedFlight.cxx
* Written by Durk Talsma, started May 5, 2004.
*
* 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.
*
*
**************************************************************************/
/* This a prototype version of a top-level flight plan manager for Flightgear.
* It parses the fgtraffic.txt file and determine for a specific time/date,
* where each aircraft listed in this file is at the current time.
*
* I'm currently assuming the following simplifications:
* 1) The earth is a perfect sphere
* 2) Each aircraft flies a perfect great circle route.
* 3) Each aircraft flies at a constant speed (with infinite accelerations and
* decelerations)
* 4) Each aircraft leaves at exactly the departure time.
* 5) Each aircraft arrives at exactly the specified arrival time.
*
* TODO:
* - Check the code for known portability issues
* - Find an alternative for the depricated Point3D class
*
*****************************************************************************/
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <plib/sg.h>
#include <simgear/compiler.h>
#include <simgear/math/polar3d.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/props/props.hxx>
#include <simgear/route/waypoint.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/timing/sg_time.hxx>
#include <simgear/xml/easyxml.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include <AIModel/AIManager.hxx>
#include <Airports/simple.hxx>
#include <Main/fg_init.hxx> // That's pretty ugly, but I need fgFindAirportID
#include <Main/globals.hxx>
#include "SchedFlight.hxx"
/******************************************************************************
* FGScheduledFlight stuff
*****************************************************************************/
FGScheduledFlight::FGScheduledFlight()
{
}
FGScheduledFlight::FGScheduledFlight(const FGScheduledFlight &other)
{
callsign = other.callsign;
fltRules = other.fltRules;
departurePort = other.departurePort;
departureTime = other.departureTime;
cruiseAltitude = other.cruiseAltitude;
arrivalPort = other.arrivalPort;
arrivalTime = other.arrivalTime;
repeatPeriod = other.repeatPeriod;
initialized = other.initialized;
}
FGScheduledFlight::FGScheduledFlight(string cs,
string fr,
string depPrt,
string arrPrt,
int cruiseAlt,
string deptime,
string arrtime,
string rep)
{
callsign = cs;
fltRules = fr;
departurePort.id = depPrt;
arrivalPort.id = arrPrt;
//departureTime = processTimeString(deptime);
//arrivalTime = processTimeString(arrtime);
cruiseAltitude = cruiseAlt;
// Process the repeat period string
if (rep.find("WEEK",0) != string::npos)
{
repeatPeriod = 7*24*60*60; // in seconds
}
else if (rep.find("Hr", 0) != string::npos)
{
repeatPeriod = 60*60*atoi(rep.substr(0,2).c_str());
}
else
{
cerr << "Unknown repeat period" << endl;
exit(1);
}
// What we still need to do is preprocess the departure and
// arrival times.
departureTime = processTimeString(deptime);
arrivalTime = processTimeString(arrtime);
if (departureTime > arrivalTime)
{
departureTime -= repeatPeriod;
}
initialized = false;
}
FGScheduledFlight:: ~FGScheduledFlight()
{
}
time_t FGScheduledFlight::processTimeString(string theTime)
{
int weekday;
int timeOffsetInDays;
int targetDate;
int targetHour;
int targetMinute;
int targetSecond;
tm targetTimeDate;
SGTime* currTimeDate = globals->get_time_params();
string timeCopy = theTime;
// okay first split theTime string into
// weekday, hour, minute, second;
// Check if a week day is specified
if (timeCopy.find("/",0) != string::npos)
{
weekday = atoi(timeCopy.substr(0,1).c_str());
timeOffsetInDays = weekday - currTimeDate->getGmt()->tm_wday;
timeCopy = timeCopy.substr(2,timeCopy.length());
}
else
{
timeOffsetInDays = 0;
}
targetHour = atoi(timeCopy.substr(0,2).c_str());
targetMinute = atoi(timeCopy.substr(3,5).c_str());
targetSecond = atoi(timeCopy.substr(6,8).c_str());
targetTimeDate.tm_year = currTimeDate->getGmt()->tm_year;
targetTimeDate.tm_mon = currTimeDate->getGmt()->tm_mon;
targetTimeDate.tm_mday = currTimeDate->getGmt()->tm_mday;
targetTimeDate.tm_hour = targetHour;
targetTimeDate.tm_min = targetMinute;
targetTimeDate.tm_sec = targetSecond;
time_t processedTime = sgTimeGetGMT(&targetTimeDate);
processedTime += timeOffsetInDays*24*60*60;
if (processedTime < currTimeDate->get_cur_time())
{
processedTime += repeatPeriod;
}
//tm *temp = currTimeDate->getGmt();
//char buffer[512];
//sgTimeFormatTime(&targetTimeDate, buffer);
//cout << "Scheduled Time " << buffer << endl;
//cout << "Time :" << time(NULL) << " SGTime : " << sgTimeGetGMT(temp) << endl;
return processedTime;
}
void FGScheduledFlight::update()
{
departureTime += repeatPeriod;
arrivalTime += repeatPeriod;
}
void FGScheduledFlight::adjustTime(time_t now)
{
//cerr << "1: Adjusting schedule please wait: " << now
// << " " << arrivalTime << " " << arrivalTime+repeatPeriod << endl;
// Make sure that the arrival time is in between
// the current time and the next repeat period.
while ((arrivalTime < now) || (arrivalTime > now+repeatPeriod))
{
if (arrivalTime < now)
{
departureTime += repeatPeriod;
arrivalTime += repeatPeriod;
}
else if (arrivalTime > now+repeatPeriod)
{
departureTime -= repeatPeriod;
arrivalTime -= repeatPeriod;
}
// cerr << "2: Adjusting schedule please wait: " << now
// << " " << arrivalTime << " " << arrivalTime+repeatPeriod << endl;
}
}
FGAirport *FGScheduledFlight::getDepartureAirport()
{
if (!(initialized))
{
initializeAirports();
}
return &departurePort;
}
FGAirport * FGScheduledFlight::getArrivalAirport ()
{
if (!(initialized))
{
initializeAirports();
}
return &arrivalPort;
}
// Upon the first time of requesting airport information
// for this scheduled flight, these data need to be
// looked up in the main FlightGear database.
// Missing or bogus Airport codes are currently ignored,
// but we should improve that. The best idea is probably to cancel
// this flight entirely by removing it from the schedule, if one
// of the airports cannot be found.
void FGScheduledFlight::initializeAirports()
{
if(!(fgFindAirportID(arrivalPort.id, &arrivalPort )))
{
//cerr << ": Could not find " << arrivalPort.id << endl;
}
if(!(fgFindAirportID(departurePort.id, &departurePort)))
{
//cerr << ": Could not find " << departurePort.id << endl;
}
initialized = true;
}

104
src/Traffic/SchedFlight.hxx Normal file
View file

@ -0,0 +1,104 @@
/* -*- Mode: C++ -*- *****************************************************
* SchedFlight.hxx
* Written by Durk Talsma. Started May 5, 2004
*
* 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.
*
*
**************************************************************************/
/**************************************************************************
* ScheduledFlight is a class that is used by FlightGear's Traffic Manager
* A scheduled flight can be assigned to a schedule, which can be assigned
* to an aircraft. The traffic manager decides for each schedule which
* scheduled flight (if any) is currently active. I no scheduled flights
* are found active, it tries to position the aircraft associated with this
* schedule at departure airport of the next scheduled flight.
* The class ScheduledFlight is a software implimentation of this.
* In summary, this class stores arrival and departure information, as well
* as some administrative data, such as the callsign of this particular
* flight (used in future ATC scenarios), under which flight rules the
* flight is taking place, as well as a requested initial cruise altitude.
* Finally, the class contains a repeat period, wich indicates after how
* many seconds a flight should repeat in this schedule (which is usually
* after either a day or a week). If this value is zero, this flight won't
* repeat.
**************************************************************************/
#ifndef _FGSCHEDFLIGHT_HXX_
#define _FGSCHEDFLIGHT_HXX_
using namespace std;
SG_USING_STD(vector);
class FGScheduledFlight
{
private:
string callsign;
string fltRules;
FGAirport departurePort;
FGAirport arrivalPort;
time_t departureTime;
time_t arrivalTime;
time_t repeatPeriod;
int cruiseAltitude;
bool initialized;
void initializeAirports();
public:
FGScheduledFlight();
FGScheduledFlight(const FGScheduledFlight &other);
// FGScheduledFlight(const string);
FGScheduledFlight::FGScheduledFlight(string cs,
string fr,
string depPrt,
string arrPrt,
int cruiseAlt,
string deptime,
string arrtime,
string rep
);
~FGScheduledFlight();
void update();
void adjustTime(time_t now);
time_t getDepartureTime() { return departureTime; };
time_t getArrivalTime () { return arrivalTime; };
FGAirport *getDepartureAirport();
FGAirport *getArrivalAirport ();
int getCruiseAlt() { return cruiseAltitude; };
bool operator<(const FGScheduledFlight &other) const
{
return (departureTime < other.departureTime);
};
time_t processTimeString(string time);
};
typedef vector<FGScheduledFlight> FGScheduledFlightVec;
typedef vector<FGScheduledFlight>::iterator FGScheduledFlightVecIterator;
#endif

290
src/Traffic/Schedule.cxx Normal file
View file

@ -0,0 +1,290 @@
/******************************************************************************
* Schedule.cxx
* Written by Durk Talsma, started May 5, 2004.
*
* 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 <stdlib.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <plib/sg.h>
#include <simgear/compiler.h>
#include <simgear/math/polar3d.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/props/props.hxx>
#include <simgear/route/waypoint.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/xml/easyxml.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include <AIModel/AIManager.hxx>
#include <Airports/simple.hxx>
#include <Main/fg_init.hxx> // That's pretty ugly, but I need fgFindAirportID
#include "SchedFlight.hxx"
#include "TrafficMgr.hxx"
/******************************************************************************
* the FGAISchedule class contains data members and code to maintain a
* schedule of Flights for an articically controlled aircraft.
*****************************************************************************/
FGAISchedule::FGAISchedule()
{
firstRun = true;
AIManagerRef = 0;
}
FGAISchedule::FGAISchedule(string mdl,
string liv,
string reg,
bool hvy,
FGScheduledFlightVec flt)
{
modelPath = mdl;
livery = liv;
registration = reg;
heavy = hvy;
for (FGScheduledFlightVecIterator i = flt.begin();
i != flt.end();
i++)
flights.push_back(FGScheduledFlight((*i)));
AIManagerRef = 0;
firstRun = true;
}
FGAISchedule::FGAISchedule(const FGAISchedule &other)
{
modelPath = other.modelPath;
livery = other.livery;
registration = other.registration;
heavy = other.heavy;
flights = other.flights;
lat = other.lat;
lon = other.lon;
AIManagerRef = other.AIManagerRef;
firstRun = other.firstRun;
}
FGAISchedule::~FGAISchedule()
{
}
void FGAISchedule::update(time_t now)
{
FGAirport *dep;
FGAirport *arr;
sgdVec3 a, b, cross;
sgdVec3 newPos;
sgdMat4 matrix;
double angle;
FGAIManager *aimgr;
string airport;
double courseToUser, courseToDest;
double distanceToUser, distanceToDest;
double speed;
Point3D temp;
time_t
totalTimeEnroute,
elapsedTimeEnroute,
remainingTimeEnroute;
double
userLatitude,
userLongitude;
if (fgGetBool("/sim/ai/enabled") == false)
return;
aimgr = (FGAIManager *) globals-> get_subsystem("ai_model");
// Before the flight status of this traffic entity is updated
// for the first time, we need to roll back it's flight schedule so
// so that all the flights are centered around this simulated week's time
// table. This is to avoid the situation where the first scheduled flight is
// in the future, causing the traffic manager to not generate traffic until
// simulated time has caught up with the real world time at initialization.
// This is to counter a more general initialization bug, caused by the fact
// that warp is not yet set when the schedule is initialized. This is
// especially a problem when using a negative time offset.
// i.e let's say we specify FlightGear to run with --time-offset=-24:00:00.
// Then the schedule will initialize using today, but we will fly yesterday.
// Thus, it would take a whole day of simulation before the traffic manager
// finally kicks in.
if (firstRun)
{
for (FGScheduledFlightVecIterator i = flights.begin();
i != flights.end();
i++)
{
i->adjustTime(now);
}
firstRun = false;
}
// Sort all the scheduled flights according to scheduled departure time.
// Because this is done at every update, we only need to check the status
// of the first listed flight.
sort(flights.begin(), flights.end());
FGScheduledFlightVecIterator i = flights.begin();
if (!AIManagerRef)
{
userLatitude = fgGetDouble("/position/latitude-deg");
userLongitude = fgGetDouble("/position/longitude-deg");
// This flight entry is entirely in the past, do we need to
// push it forward in time to the next scheduled departure.
if ((i->getDepartureTime() < now) && (i->getArrivalTime() < now))
{
i->update();
return;
}
// Departure time in the past and arrival time in the future.
// This flight is in progress, so we need to calculate it's
// approximate position and -if in range- create an AIAircraft
// object for it.
if ((i->getDepartureTime() < now) && (i->getArrivalTime() > now))
{
dep = i->getDepartureAirport();
arr = i->getArrivalAirport ();
temp = sgPolarToCart3d(Point3D(dep->longitude *
SG_DEGREES_TO_RADIANS,
dep->latitude *
SG_DEGREES_TO_RADIANS,
1.0));
a[0] = temp.x();
a[1] = temp.y();
a[2] = temp.z();
temp = sgPolarToCart3d(Point3D(arr->longitude *
SG_DEGREES_TO_RADIANS,
arr->latitude *
SG_DEGREES_TO_RADIANS,
1.0));
b[0] = temp.x();
b[1] = temp.y();
b[2] = temp.z();
sgdNormaliseVec3(a);
sgdNormaliseVec3(b);
sgdVectorProductVec3(cross,b,a);
angle = sgACos(sgdScalarProductVec3(a,b));
// Okay, at this point we have the angle between departure and
// arrival airport, in degrees. From here we can interpolate the
// position of the aircraft by calculating the ratio between
// total time enroute and elapsed time enroute.
totalTimeEnroute = i->getArrivalTime() - i->getDepartureTime();
elapsedTimeEnroute = now - i->getDepartureTime();
remainingTimeEnroute = i->getArrivalTime() - now;
angle *= ( (double) elapsedTimeEnroute/ (double) totalTimeEnroute);
//cout << "a = " << a[0] << " " << a[1] << " " << a[2]
// << "b = " << b[0] << " " << b[1] << " " << b[2] << endl;
sgdMakeRotMat4(matrix, angle, cross);
for(int j = 0; j < 3; j++)
{
newPos[j] =0.0;
for (int k = 0; k<3; k++)
{
newPos[j] += matrix[j][k]*a[k];
}
}
temp = sgCartToPolar3d(Point3D(newPos[0], newPos[1],newPos[2]));
lat = temp.lat() * SG_RADIANS_TO_DEGREES;
lon = temp.lon() * SG_RADIANS_TO_DEGREES;
SGWayPoint current (lon,
lat,
i->getCruiseAlt());
SGWayPoint user ( userLongitude,
userLatitude,
i->getCruiseAlt());
SGWayPoint dest ( arr->longitude,
arr->latitude,
i->getCruiseAlt());
// We really only need distance to user
// and course to destination
current.CourseAndDistance(user, &courseToUser, &distanceToUser);
current.CourseAndDistance(dest, &courseToDest, &distanceToDest);
speed = (distanceToDest*SG_METER_TO_NM) /
((double) remainingTimeEnroute/3600.0);
// If distance between user and simulated aircaft is less
// then 500nm, create this flight. At jet speeds 500 nm is roughly
// one hour flight time, so that would be a good approximate point
// to start a more detailed simulation of this aircraft.
//cerr << registration << " is currently enroute from "
// << dep->id << " to " << arr->id << "distance : " << distanceToUser*SG_METER_TO_NM << endl;
if ((distanceToUser*SG_METER_TO_NM) < 500.0)
{
string flightPlanName = dep->id + string("-") + arr->id + string(".xml");
FGAIFlightPlan* f;
// If we're less then 10 minutes behind schedule, do a normal
// full flight plan initialization, otherwise, do a modified
// in-air initializition, at the location where this flight is
// according to the Traffic Manager
if (elapsedTimeEnroute < 600)
f = new FGAIFlightPlan(flightPlanName);
else
f = new FGAIFlightPlan(flightPlanName,
lat,
lon,
i->getCruiseAlt() * 1000, // convert from FL to feet
speed,
courseToDest);
// Fixme: A non-existent model path results in an
// abort, due to an unhandled exeption, in fg main loop.
AIManagerRef = aimgr->createAircraft("jet_transport",
modelPath, f);
//cerr << "Created: " << AIManagerRef << endl;
}
return;
}
// Both departure and arrival time are in the future, so this
// the aircraft is parked at the departure airport.
// Currently this status is mostly ignored, but in furture
// versions, code should go here that -if within user range-
// positions these aircraft at parking locations at the airport.
if ((i->getDepartureTime() > now) && (i->getArrivalTime() > now))
{
dep = i->getDepartureAirport();
return;
}
}
}

62
src/Traffic/Schedule.hxx Normal file
View file

@ -0,0 +1,62 @@
/* -*- Mode: C++ -*- *****************************************************
* Schedule.hxx
* Written by Durk Talsma. Started May 5, 2004
*
* 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.
*
*
**************************************************************************/
/**************************************************************************
* This file contains the definition of the class Shedule.
*
* A schedule is basically a number of scheduled flights, wich can be
* assigned to an AI aircraft.
**************************************************************************/
#ifndef _FGSCHEDULE_HXX_
#define _FGSCHEDULE_HXX_
class FGAISchedule
{
private:
string modelPath;
string livery;
string registration;
bool heavy;
FGScheduledFlightVec flights;
float lat;
float lon;
int AIManagerRef;
bool firstRun;
public:
FGAISchedule(); // constructor
FGAISchedule(string, string, string, bool, FGScheduledFlightVec); // construct & init
FGAISchedule(const FGAISchedule &other); // copy constructor
~FGAISchedule(); //destructor
void update(time_t now);
// More member functions follow later
};
typedef vector<FGAISchedule> ScheduleVector;
typedef vector<FGAISchedule>::iterator ScheduleVectorIterator;
#endif

207
src/Traffic/TrafficMgr.cxx Normal file
View file

@ -0,0 +1,207 @@
/******************************************************************************
* TrafficMGr.cxx
* Written by Durk Talsma, started May 5, 2004.
*
* 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.
*
*
**************************************************************************/
/* This a prototype version of a top-level flight plan manager for Flightgear.
* It parses the fgtraffic.txt file and determine for a specific time/date,
* where each aircraft listed in this file is at the current time.
*
* I'm currently assuming the following simplifications:
* 1) The earth is a perfect sphere
* 2) Each aircraft flies a perfect great circle route.
* 3) Each aircraft flies at a constant speed (with infinite accelerations and
* decelerations)
* 4) Each aircraft leaves at exactly the departure time.
* 5) Each aircraft arrives at exactly the specified arrival time.
*
*
*****************************************************************************/
#include <stdlib.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <plib/sg.h>
#include <simgear/compiler.h>
#include <simgear/math/polar3d.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/props/props.hxx>
#include <simgear/route/waypoint.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/xml/easyxml.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include <AIModel/AIManager.hxx>
#include <Airports/simple.hxx>
#include <Main/fg_init.hxx> // That's pretty ugly, but I need fgFindAirportID
#include "TrafficMgr.hxx"
/******************************************************************************
* TrafficManager
*****************************************************************************/
FGTrafficManager::FGTrafficManager()
{
}
void FGTrafficManager::init()
{
currAircraft = scheduledAircraft.begin();
}
void FGTrafficManager::update(double something)
{
//static const SGPropertyNode *warp = globals->get_props()->getNode("/sim/time/warp");
//time_t now = time(NULL) + globals->get_warp();
time_t now = time(NULL) + fgGetLong("/sim/time/warp");
// cerr << "TrafficManager update" << globals->get_warp() << endl;
if(currAircraft == scheduledAircraft.end())
currAircraft = scheduledAircraft.begin();
currAircraft->update(now);
currAircraft++;
}
void FGTrafficManager::startXML () {
//cout << "Start XML" << endl;
}
void FGTrafficManager::endXML () {
//cout << "End XML" << endl;
}
void FGTrafficManager::startElement (const char * name, const XMLAttributes &atts) {
const char * attval;
//cout << "Start element " << name << endl;
//FGTrafficManager temp;
//for (int i = 0; i < atts.size(); i++)
// if (string(atts.getName(i)) == string("include"))
attval = atts.getValue("include");
if (attval != 0)
{
//cout << "including " << attval << endl;
string path =
globals->get_fg_root() +
string("/Traffic/") +
string(attval);
readXML(path, *this);
}
// cout << " " << atts.getName(i) << '=' << atts.getValue(i) << endl;
}
void FGTrafficManager::endElement (const char * name) {
//cout << "End element " << name << endl;
string element(name);
if (element == string("model"))
mdl = value;
else if (element == string("livery"))
livery = value;
else if (element == string("registration"))
registration = value;
else if (element == string("heavy"))
{
if(value == string("true"))
heavy = true;
else
heavy = false;
}
else if (element == string("callsign"))
callsign = value;
else if (element == string("fltrules"))
fltrules = value;
else if (element == string("port"))
port = value;
else if (element == string("time"))
timeString = value;
else if (element == string("departure"))
{
departurePort = port;
departureTime = timeString;
}
else if (element == string("cruise-alt"))
cruiseAlt = atoi(value.c_str());
else if (element == string("arrival"))
{
arrivalPort = port;
arrivalTime = timeString;
}
else if (element == string("repeat"))
repeat = value;
else if (element == string("flight"))
{
// We have loaded and parsed all the information belonging to this flight
// so we temporarily store it.
//cerr << "Pusing back flight " << callsign << endl;
//cerr << callsign << " " << fltrules << " "<< departurePort << " " << arrivalPort << " "
// << cruiseAlt << " " << departureTime<< " "<< arrivalTime << " " << repeat << endl;
flights.push_back(FGScheduledFlight(callsign,
fltrules,
departurePort,
arrivalPort,
cruiseAlt,
departureTime,
arrivalTime,
repeat));
}
else if (element == string("aircraft"))
{
//cerr << "Pushing back aircraft " << registration << endl;
scheduledAircraft.push_back(FGAISchedule(mdl,
livery,
registration,
heavy,
flights));
while(flights.begin() != flights.end())
flights.pop_back();
}
}
void FGTrafficManager::data (const char * s, int len) {
string token = string(s,len);
//cout << "Character data " << string(s,len) << endl;
if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
value += token;
else
value = string("");
}
void FGTrafficManager::pi (const char * target, const char * data) {
//cout << "Processing instruction " << target << ' ' << data << endl;
}
void FGTrafficManager::warning (const char * message, int line, int column) {
cout << "Warning: " << message << " (" << line << ',' << column << ')'
<< endl;
}
void FGTrafficManager::error (const char * message, int line, int column) {
cout << "Error: " << message << " (" << line << ',' << column << ')'
<< endl;
}

View file

@ -0,0 +1,69 @@
/* -*- Mode: C++ -*- *****************************************************
* TrafficMgr.hxx
* Written by Durk Talsma. Started May 5, 2004
*
* 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.
*
*
**************************************************************************/
/**************************************************************************
* This file contains the class definitions for a (Top Level) traffic
* manager for FlightGear.
**************************************************************************/
#ifndef _TRAFFICMGR_HXX_
#define _TRAFFICMGR_HXX_
#include <simgear/structure/subsystem_mgr.hxx>
#include <simgear/xml/easyxml.hxx>
#include "SchedFlight.hxx"
#include "Schedule.hxx"
class FGTrafficManager : public SGSubsystem, public XMLVisitor
{
private:
ScheduleVector scheduledAircraft;
ScheduleVectorIterator currAircraft;
string value;
string mdl, livery, registration, callsign, fltrules,
port, timeString, departurePort, departureTime, arrivalPort, arrivalTime,
repeat;
int cruiseAlt;
bool heavy;
FGScheduledFlightVec flights;
public:
FGTrafficManager();
void init();
void update(double time);
// Some overloaded virtual XMLVisitor members
virtual void startXML ();
virtual void endXML ();
virtual void startElement (const char * name, const XMLAttributes &atts);
virtual void endElement (const char * name);
virtual void data (const char * s, int len);
virtual void pi (const char * target, const char * data);
virtual void warning (const char * message, int line, int column);
virtual void error (const char * message, int line, int column);
};
#endif