Melchior Franz <a8603365@unet.univie.ac.at>
Made that joystick high/low support for joystick hats.
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.
Ruthlessly hunted down memory leaks in FlightGear, SimGear, and JSBSim.
Maintains the only fully working helicopter model in FlightGear (Bolkow 105).
if test -d /opt/X11R6 ; then
EXTRA_DIR2="/opt/X11R6"
fi
- EXTRA_DIRS="${EXTRA_DIRS} $EXTRA_DIR1 $EXTRA_DIR2"
+ EXTRA_DIRS="${EXTRA_DIRS} $EXTRA_DIR1 $EXTRA_DIR2 /usr/local/"
;;
esac
src/Sound/Makefile \
src/Systems/Makefile \
src/Time/Makefile \
+ src/Traffic/Makefile \
tests/Makefile \
utils/Makefile \
utils/TerraSync/Makefile \
inline void FGAIBase::setBank( double bank ) {
roll = tgt_roll = bank;
+ no_roll = false;
}
inline void FGAIBase::setLongitude( double longitude ) {
#include "AIFlightPlan.hxx"
#include <simgear/misc/sg_path.hxx>
#include <simgear/debug/logstream.hxx>
+#include <simgear/route/waypoint.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/constants.h>
#ifdef __BORLANDC__
}
+// 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()
{
waypoints.clear();
double FGAIFlightPlan::getBearing(double lat, double lon, waypoint* wp){
- double latd = lat;
- double lond = lon;
- double latt = wp->latitude;
- double lont = wp->longitude;
- 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 (lont < 0.0) lont+=360.0;
- latd+=90.0;
- latt+=90.0;
-
- double lat_diff = (latt - latd) * ft_per_deg_lat;
- double lon_diff = (lont - lond) * ft_per_deg_lon;
- 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;
+ double course, distance;
+ // double latd = lat;
+// double lond = lon;
+// double latt = wp->latitude;
+// double lont = wp->longitude;
+// 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;
+// lont+=360;
+// }
+// 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 lon_diff = (lont - lond) * ft_per_deg_lon;
+// 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;
+ 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.
- return 0;
+
}
} waypoint;
FGAIFlightPlan(string filename);
+ FGAIFlightPlan(string filename,
+ double lat,
+ double lon,
+ double alt,
+ double speed,
+ double course);
~FGAIFlightPlan();
waypoint* getPreviousWaypoint( void );
int maxint = 30000;
int x;
bool used;
- for (x=0; x<maxint; x++) {
+ for (x=1; x<maxint; x++) {
used = false;
id_itr = ids.begin();
while( id_itr != ids.end() ) {
en->azimuth = entry_node->getDoubleValue("azimuth", 0.0);
en->elevation = entry_node->getDoubleValue("elevation", 0.0);
en->rudder = entry_node->getDoubleValue("rudder", 0.0);
- en->strength = entry_node->getDoubleValue("strength", 0.0);
- en->diameter = entry_node->getDoubleValue("diameter", 0.0);
+ en->strength = entry_node->getDoubleValue("strength-fps", 0.0);
+ en->diameter = entry_node->getDoubleValue("diameter-ft", 0.0);
}
entry_iterator = entries.begin();
bool FGTrimAxis::initTheta(void) {
int i,N,iAft, iForward;
- double zAft,zForward,zDiff,theta;
+ double zAft,zForward,zDiff,theta;
+ double xAft,xForward,xDiff;
bool level;
double saveAlt;
}
// now adjust theta till the wheels are the same distance from the ground
- zAft=fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear(3);
- zForward=fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear(3);
- zDiff = zForward - zAft;
- level=false;
- theta=fgic->GetPitchAngleDegIC();
- while(!level && (i < 100)) {
- theta+=2.0*zDiff;
- fgic->SetPitchAngleDegIC(theta);
- fdmex->RunIC();
- zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
- zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
+ 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;
+ level=false;
+ theta=fgic->GetPitchAngleDegIC();
+ while(!level && (i < 100)) {
+ theta+=180.0/M_PI*zDiff/fabs(xDiff);
+ 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;
//cout << endl << theta << " " << zDiff << endl;
//cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;
$(top_builddir)/src/Replay/libReplay.a \
$(top_builddir)/src/Systems/libSystems.a \
$(top_builddir)/src/Time/libTime.a \
+ $(top_builddir)/src/Traffic/libTraffic.a \
$(top_builddir)/src/Environment/libEnvironment.a \
$(CLOUD3D_LIBS) \
-lsgroute -lsgsky -lsgsound -lsgephem -lsgmaterial -lsgtgdb -lsgmodel \
#include <Time/sunpos.hxx>
#include <Time/sunsolver.hxx>
#include <Time/tmp.hxx>
+#include <Traffic/TrafficMgr.hxx>
#ifdef FG_MPLAYER_AS
#include <MultiPlayer/multiplaytxmgr.hxx>
////////////////////////////////////////////////////////////////////
// Initialise the AI Model Manager
////////////////////////////////////////////////////////////////////
-
SG_LOG(SG_GENERAL, SG_INFO, " AI Model Manager");
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("systems", new FGSystemMgr);
+
+
////////////////////////////////////////////////////////////////////
// Initialize the radio stack subsystem.
////////////////////////////////////////////////////////////////////
class SGTime;
class SGSoundMgr;
+
class FGAirportList;
class FGRunwayList;
class FGAIMgr;
class FGATCDisplay;
class FGAircraftModel;
class FGControls;
+class FGFlightPlanDispatcher;
class FGIO;
class FGNavList;
class FGFixList;
SGModelLib *model_lib;
+ //FGFlightPlanDispatcher *fpDispatcher;
+
FGAircraftModel *acmodel;
FGModelMgr * model_mgr;
Sound \
Systems \
Time \
+ Traffic \
Main
--- /dev/null
+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
--- /dev/null
+/******************************************************************************
+ * 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;
+}
--- /dev/null
+/* -*- 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
--- /dev/null
+/******************************************************************************
+ * 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;
+ }
+ }
+}
--- /dev/null
+/* -*- 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
+
--- /dev/null
+/******************************************************************************
+ * 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;
+}
--- /dev/null
+/* -*- 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