2011-04-03 15:39:35 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* atc_mgr.cxx
|
|
|
|
* Written by Durk Talsma, started August 1, 2010.
|
|
|
|
*
|
|
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
**************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include <simgear/math/SGMath.hxx>
|
2011-04-10 06:58:48 +00:00
|
|
|
#include <Airports/dynamics.hxx>
|
|
|
|
#include <Airports/simple.hxx>
|
2011-04-17 08:19:58 +00:00
|
|
|
#include <Scenery/scenery.hxx>
|
2011-04-03 15:39:35 +00:00
|
|
|
#include "atc_mgr.hxx"
|
|
|
|
|
|
|
|
|
|
|
|
FGATCManager::FGATCManager() {
|
2011-07-31 17:27:44 +00:00
|
|
|
controller = 0;
|
|
|
|
prevController = 0;
|
2011-07-24 10:48:13 +00:00
|
|
|
networkVisible = false;
|
2011-09-11 19:42:29 +00:00
|
|
|
initSucceeded = false;
|
2011-04-03 15:39:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
FGATCManager::~FGATCManager() {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGATCManager::init() {
|
|
|
|
SGSubsystem::init();
|
2011-04-05 16:13:11 +00:00
|
|
|
|
2011-04-10 10:46:00 +00:00
|
|
|
int leg = 0;
|
|
|
|
|
2011-04-10 06:58:48 +00:00
|
|
|
// find a reasonable controller for our user's aircraft..
|
|
|
|
// Let's start by working out the following three scenarios:
|
|
|
|
// Starting on ground at a parking position
|
|
|
|
// Starting on ground at the runway.
|
|
|
|
// Starting in the Air
|
|
|
|
bool onGround = fgGetBool("/sim/presets/onground");
|
|
|
|
string runway = fgGetString("/sim/atc/runway");
|
|
|
|
string airport = fgGetString("/sim/presets/airport-id");
|
|
|
|
string parking = fgGetString("/sim/presets/parkpos");
|
2011-04-10 10:46:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Create an (invisible) AIAircraft represenation of the current
|
|
|
|
// Users, aircraft, that mimicks the user aircraft's behavior.
|
|
|
|
string callsign= fgGetString("/sim/multiplay/callsign");
|
|
|
|
double longitude = fgGetDouble("/position/longitude-deg");
|
|
|
|
double latitude = fgGetDouble("/position/latitude-deg");
|
|
|
|
double altitude = fgGetDouble("/position/altitude-ft");
|
|
|
|
double heading = fgGetDouble("/orientation/heading-deg");
|
|
|
|
double speed = fgGetDouble("/velocities/groundspeed-kt");
|
|
|
|
double aircraftRadius = 40; // note that this is currently hardcoded to a one-size-fits all JumboJet value. Should change later;
|
|
|
|
|
|
|
|
|
|
|
|
ai_ac.setCallSign ( callsign );
|
|
|
|
ai_ac.setLongitude( longitude );
|
|
|
|
ai_ac.setLatitude ( latitude );
|
|
|
|
ai_ac.setAltitude ( altitude );
|
|
|
|
ai_ac.setPerformance("jet_transport");
|
|
|
|
|
2011-07-24 10:48:13 +00:00
|
|
|
// NEXT UP: Create a traffic Schedule and fill that with appropriate information. This we can use to flight planning.
|
|
|
|
// Note that these are currently only defaults.
|
2011-04-12 21:28:48 +00:00
|
|
|
FGAISchedule *trafficRef = new FGAISchedule;
|
|
|
|
trafficRef->setFlightType("gate");
|
|
|
|
|
|
|
|
FGScheduledFlight *flight = new FGScheduledFlight;
|
|
|
|
flight->setDepartureAirport(airport);
|
|
|
|
flight->setArrivalAirport(airport);
|
|
|
|
flight->initializeAirports();
|
|
|
|
flight->setFlightRules("IFR");
|
|
|
|
flight->setCallSign(callsign);
|
|
|
|
|
|
|
|
trafficRef->assign(flight);
|
2011-07-25 10:53:10 +00:00
|
|
|
FGAIFlightPlan *fp = 0;
|
2011-04-12 21:28:48 +00:00
|
|
|
ai_ac.setTrafficRef(trafficRef);
|
2011-04-10 10:46:00 +00:00
|
|
|
|
|
|
|
string flightPlanName = airport + "-" + airport + ".xml";
|
|
|
|
double cruiseAlt = 100; // Doesn't really matter right now.
|
|
|
|
double courseToDest = 180; // Just use something neutral; this value might affect the runway that is used though...
|
|
|
|
time_t deptime = 0; // just make sure how flightplan processing is affected by this...
|
|
|
|
|
2011-04-10 06:58:48 +00:00
|
|
|
|
|
|
|
FGAirport *apt = FGAirport::findByIdent(airport);
|
2011-07-27 09:01:37 +00:00
|
|
|
if (apt && onGround) {
|
2011-07-25 10:53:10 +00:00
|
|
|
FGAirportDynamics* dcs = apt->getDynamics();
|
|
|
|
int park_index = dcs->getNrOfParkings() - 1;
|
2011-07-27 09:01:37 +00:00
|
|
|
//cerr << "found information: " << runway << " " << airport << ": parking = " << parking << endl;
|
|
|
|
fp = new FGAIFlightPlan;
|
|
|
|
while (park_index >= 0 && dcs->getParkingName(park_index) != parking) park_index--;
|
|
|
|
if (park_index < 0) {
|
|
|
|
SG_LOG( SG_GENERAL, SG_ALERT,
|
|
|
|
"Failed to find parking position " << parking <<
|
Added a new startup option. By giving the command line option --parkpos=AVAILABLE you can -in principle- let FlightGear decide what the most optimal parking location is. This option does require a few properties to be set that are also needed for future ATC use. Hence, they are listed under /sim/ATC, but could move to a different location if desired.
/sim/ATC/radius should be a nummeric estimate of the size of your aircraft. A small aircraft fits into a large parking, but a large aircraft does not fit into a small parking space. Because the AI part of radius is also used for slightly different purposes (prioritizing gate assignmments, the given valuem may deviate slightly from the real aircraft size. See http:/wiki.flightgear.org/Aircraft.radii for an overview of currently used values for the redius property.
/sim/ATC/flight-type can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm can be any one of "ga", "cargo", "gate", "mil-fighter", "mil-cargo", or "vtol". See http://wiki.flightgear.org/Interactive_traffic#A_technical_perspective for more information.
optionally, the property /sim/ATC/airline can be set set to a three letter icao airline code. By way of illustration, I will commit a number of startup preset files setting these properties shortly.
Also did some more finetuning to the traffic mananger routing algorithm.
2011-09-17 14:51:00 +00:00
|
|
|
" at airport " << airport << "at " << SG_ORIGIN);
|
2011-07-27 09:01:37 +00:00
|
|
|
}
|
|
|
|
if (parking.empty() || (park_index < 0)) {
|
|
|
|
controller = apt->getDynamics()->getTowerController();
|
|
|
|
int stationFreq = apt->getDynamics()->getTowerFrequency(2);
|
|
|
|
//cerr << "Setting radio frequency to in airfrequency: " << stationFreq << endl;
|
|
|
|
fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
|
2011-07-31 17:27:44 +00:00
|
|
|
leg = 3;
|
2011-07-27 09:01:37 +00:00
|
|
|
string fltType = "ga";
|
|
|
|
fp->setRunway(runway);
|
|
|
|
fp->createTakeOff(&ai_ac, false, apt, 0, fltType);
|
2011-08-07 19:38:50 +00:00
|
|
|
ai_ac.setTakeOffStatus(2);
|
2011-07-27 09:01:37 +00:00
|
|
|
} else {
|
|
|
|
controller = apt->getDynamics()->getStartupController();
|
2011-07-31 17:27:44 +00:00
|
|
|
int stationFreq = apt->getDynamics()->getGroundFrequency(1);
|
2011-07-27 09:01:37 +00:00
|
|
|
//cerr << "Setting radio frequency to : " << stationFreq << endl;
|
|
|
|
fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
|
2011-07-31 17:27:44 +00:00
|
|
|
leg = 1;
|
2011-07-27 09:01:37 +00:00
|
|
|
//double, lat, lon, head; // Unused variables;
|
|
|
|
//int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head);
|
|
|
|
FGParking* parking = dcs->getParking(park_index);
|
|
|
|
aircraftRadius = parking->getRadius();
|
|
|
|
string fltType = parking->getType(); // gate / ramp, ga, etc etc.
|
|
|
|
string aircraftType; // Unused.
|
|
|
|
string airline; // Currently used for gate selection, but a fallback mechanism will apply when not specified.
|
|
|
|
fp->setGate(park_index);
|
2011-09-11 19:42:29 +00:00
|
|
|
if (!(fp->createPushBack(&ai_ac,
|
2011-07-27 09:01:37 +00:00
|
|
|
false,
|
|
|
|
apt,
|
|
|
|
latitude,
|
|
|
|
longitude,
|
|
|
|
aircraftRadius,
|
|
|
|
fltType,
|
|
|
|
aircraftType,
|
2011-09-11 19:42:29 +00:00
|
|
|
airline))) {
|
|
|
|
controller = 0;
|
|
|
|
return;
|
|
|
|
}
|
2011-07-31 17:27:44 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
fp->getLastWaypoint()->setName( fp->getLastWaypoint()->getName() + string("legend"));
|
2011-04-10 06:58:48 +00:00
|
|
|
} else {
|
|
|
|
controller = 0;
|
|
|
|
}
|
2011-04-10 10:46:00 +00:00
|
|
|
|
|
|
|
// Create an initial flightplan and assign it to the ai_ac. We won't use this flightplan, but it is necessary to
|
|
|
|
// keep the ATC code happy.
|
2011-07-25 10:53:10 +00:00
|
|
|
if (fp) {
|
|
|
|
fp->restart();
|
|
|
|
fp->setLeg(leg);
|
|
|
|
ai_ac.SetFlightPlan(fp);
|
|
|
|
}
|
2011-04-10 10:46:00 +00:00
|
|
|
if (controller) {
|
2011-07-31 17:27:44 +00:00
|
|
|
controller->announcePosition(ai_ac.getID(), fp, fp->getCurrentWaypoint()->getRouteIndex(),
|
2011-04-10 10:46:00 +00:00
|
|
|
ai_ac._getLatitude(), ai_ac._getLongitude(), heading, speed, altitude,
|
|
|
|
aircraftRadius, leg, &ai_ac);
|
2011-04-10 06:58:48 +00:00
|
|
|
|
2011-04-05 16:13:11 +00:00
|
|
|
//dialog.init();
|
2011-04-17 08:19:58 +00:00
|
|
|
|
2011-04-19 16:01:24 +00:00
|
|
|
//osg::Node* node = apt->getDynamics()->getGroundNetwork()->getRenderNode();
|
|
|
|
//cerr << "Adding groundnetWork to the scenegraph::init" << endl;
|
|
|
|
//globals->get_scenery()->get_scene_graph()->addChild(node);
|
2011-04-10 10:46:00 +00:00
|
|
|
}
|
2011-09-11 19:42:29 +00:00
|
|
|
initSucceeded = true;
|
2011-04-03 15:39:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FGATCManager::addController(FGATCController *controller) {
|
|
|
|
activeStations.push_back(controller);
|
|
|
|
}
|
|
|
|
|
|
|
|
void FGATCManager::update ( double time ) {
|
|
|
|
//cerr << "ATC update code is running at time: " << time << endl;
|
2011-05-07 08:03:27 +00:00
|
|
|
// Test code: let my virtual co-pilot handle ATC:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FGAIFlightPlan *fp = ai_ac.GetFlightPlan();
|
|
|
|
|
|
|
|
/* test code : find out how the routing develops */
|
2011-07-31 17:27:44 +00:00
|
|
|
if (fp) {
|
|
|
|
int size = fp->getNrOfWayPoints();
|
2011-07-27 09:01:37 +00:00
|
|
|
// //cerr << "Setting pos" << pos << " ";
|
|
|
|
// //cerr << "setting intentions " ;
|
2011-07-31 17:27:44 +00:00
|
|
|
for (int i = 0; i < size; i++) {
|
2011-07-27 09:01:37 +00:00
|
|
|
// int val = fp->getRouteIndex(i);
|
2011-08-03 19:23:42 +00:00
|
|
|
//cerr << fp->getWayPoint(i)->getName() << " ";
|
2011-07-25 10:53:10 +00:00
|
|
|
//if ((val) && (val != pos)) {
|
|
|
|
//intentions.push_back(val);
|
|
|
|
//cerr << "[done ] " << endl;
|
|
|
|
//}
|
2011-07-31 17:27:44 +00:00
|
|
|
}
|
|
|
|
}
|
2011-08-03 19:23:42 +00:00
|
|
|
//cerr << "[done ] " << endl;
|
2011-07-31 17:27:44 +00:00
|
|
|
if (fp) {
|
2011-08-03 19:23:42 +00:00
|
|
|
//cerr << "Currently at leg : " << fp->getLeg() << endl;
|
2011-07-31 17:27:44 +00:00
|
|
|
}
|
2011-05-07 08:03:27 +00:00
|
|
|
double longitude = fgGetDouble("/position/longitude-deg");
|
|
|
|
double latitude = fgGetDouble("/position/latitude-deg");
|
|
|
|
double heading = fgGetDouble("/orientation/heading-deg");
|
|
|
|
double speed = fgGetDouble("/velocities/groundspeed-kt");
|
|
|
|
double altitude = fgGetDouble("/position/altitude-ft");
|
|
|
|
ai_ac.setLatitude(latitude);
|
|
|
|
ai_ac.setLongitude(longitude);
|
|
|
|
ai_ac.setAltitude(altitude);
|
|
|
|
ai_ac.setHeading(heading);
|
|
|
|
ai_ac.setSpeed(speed);
|
2011-07-25 10:53:10 +00:00
|
|
|
ai_ac.update(time);
|
2011-07-27 09:01:37 +00:00
|
|
|
controller = ai_ac.getATCController();
|
2011-09-22 18:52:05 +00:00
|
|
|
FGATCDialogNew::instance()->update(time);
|
2011-04-11 20:23:53 +00:00
|
|
|
if (controller) {
|
2011-08-03 19:23:42 +00:00
|
|
|
//cerr << "name of previous waypoint : " << fp->getPreviousWaypoint()->getName() << endl;
|
2011-04-11 20:23:53 +00:00
|
|
|
|
2011-04-19 16:01:24 +00:00
|
|
|
//cerr << "Running FGATCManager::update()" << endl;
|
2011-08-03 19:23:42 +00:00
|
|
|
//cerr << "Currently under control of " << controller->getName() << endl;
|
2011-04-11 20:23:53 +00:00
|
|
|
controller->updateAircraftInformation(ai_ac.getID(),
|
|
|
|
latitude,
|
|
|
|
longitude,
|
|
|
|
heading,
|
|
|
|
speed,
|
|
|
|
altitude, time);
|
2011-04-26 17:18:28 +00:00
|
|
|
//string airport = fgGetString("/sim/presets/airport-id");
|
|
|
|
//FGAirport *apt = FGAirport::findByIdent(airport);
|
2011-04-29 18:44:05 +00:00
|
|
|
// AT this stage we should update the flightplan, so that waypoint incrementing is conducted as well as leg loading.
|
2011-07-24 10:48:13 +00:00
|
|
|
static SGPropertyNode_ptr trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
|
|
|
|
int n = trans_num->getIntValue();
|
|
|
|
if (n == 1) {
|
2011-07-27 09:01:37 +00:00
|
|
|
//cerr << "Toggling ground network visibility " << networkVisible << endl;
|
2011-07-24 10:48:13 +00:00
|
|
|
networkVisible = !networkVisible;
|
|
|
|
trans_num->setIntValue(-1);
|
|
|
|
}
|
2011-07-31 17:27:44 +00:00
|
|
|
if ((controller != prevController) && (prevController)) {
|
|
|
|
prevController->render(false);
|
|
|
|
}
|
2011-07-24 10:48:13 +00:00
|
|
|
controller->render(networkVisible);
|
2011-05-07 08:03:27 +00:00
|
|
|
|
2011-04-26 17:18:28 +00:00
|
|
|
//cerr << "Adding groundnetWork to the scenegraph::update" << endl;
|
2011-07-31 17:27:44 +00:00
|
|
|
prevController = controller;
|
2011-04-26 17:18:28 +00:00
|
|
|
}
|
|
|
|
//globals->get_scenery()->get_scene_graph()->addChild(node);
|
2011-04-03 15:39:35 +00:00
|
|
|
}
|