1 /******************************************************************************
3 * Written by Durk Talsma, started August 1, 2010.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 **************************************************************************/
29 #include <Airports/dynamics.hxx>
30 #include <Airports/airportdynamicsmanager.hxx>
31 #include <Airports/airport.hxx>
32 #include <Scenery/scenery.hxx>
33 #include <Main/globals.hxx>
34 #include <Main/fg_props.hxx>
35 #include <AIModel/AIAircraft.hxx>
36 #include <Traffic/Schedule.hxx>
37 #include <Traffic/SchedFlight.hxx>
38 #include <AIModel/AIFlightPlan.hxx>
40 #include "atc_mgr.hxx"
45 FGATCManager::FGATCManager() :
48 networkVisible(false),
53 FGATCManager::~FGATCManager() {
56 void FGATCManager::init() {
61 trans_num = globals->get_props()->getNode("/sim/atc/transmission-num", true);
63 // find a reasonable controller for our user's aircraft..
64 // Let's start by working out the following three scenarios:
65 // Starting on ground at a parking position
66 // Starting on ground at the runway.
67 // Starting in the Air
68 bool onGround = fgGetBool("/sim/presets/onground");
69 string runway = fgGetString("/sim/atc/runway");
70 string airport = fgGetString("/sim/presets/airport-id");
71 string parking = fgGetString("/sim/presets/parkpos");
74 // Create an (invisible) AIAircraft represenation of the current
75 // Users, aircraft, that mimicks the user aircraft's behavior.
76 string callsign= fgGetString("/sim/multiplay/callsign");
77 double longitude = fgGetDouble("/position/longitude-deg");
78 double latitude = fgGetDouble("/position/latitude-deg");
79 double altitude = fgGetDouble("/position/altitude-ft");
80 double heading = fgGetDouble("/orientation/heading-deg");
81 double speed = fgGetDouble("/velocities/groundspeed-kt");
82 double aircraftRadius = 40; // note that this is currently hardcoded to a one-size-fits all JumboJet value. Should change later;
84 ai_ac = new FGAIAircraft;
85 ai_ac->setCallSign ( callsign );
86 ai_ac->setLongitude( longitude );
87 ai_ac->setLatitude ( latitude );
88 ai_ac->setAltitude ( altitude );
89 ai_ac->setPerformance("", "jet_transport");
91 // NEXT UP: Create a traffic Schedule and fill that with appropriate information. This we can use to flight planning.
92 // Note that these are currently only defaults.
93 FGAISchedule *trafficRef = new FGAISchedule;
94 trafficRef->setFlightType("gate");
96 FGScheduledFlight *flight = new FGScheduledFlight;
97 flight->setDepartureAirport(airport);
98 flight->setArrivalAirport(airport);
99 flight->initializeAirports();
100 flight->setFlightRules("IFR");
101 flight->setCallSign(callsign);
103 trafficRef->assign(flight);
104 FGAIFlightPlan *fp = 0;
105 ai_ac->setTrafficRef(trafficRef);
107 string flightPlanName = airport + "-" + airport + ".xml";
108 //double cruiseAlt = 100; // Doesn't really matter right now.
109 //double courseToDest = 180; // Just use something neutral; this value might affect the runway that is used though...
110 //time_t deptime = 0; // just make sure how flightplan processing is affected by this...
113 FGAirportDynamicsRef dcs(flightgear::AirportDynamicsManager::find(airport));
114 if (dcs && onGround) {// && !runway.empty()) {
116 ParkingAssignment pk(dcs->getParkingByName(parking));
118 // No valid parking location, so either at the runway or at a random location.
120 dcs->setParkingAvailable(pk.parking(), false);
121 fp = new FGAIFlightPlan;
122 controller = dcs->getStartupController();
123 int stationFreq = dcs->getGroundFrequency(1);
126 //cerr << "Setting radio frequency to : " << stationFreq << endl;
127 fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
130 //double, lat, lon, head; // Unused variables;
131 //int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head);
132 aircraftRadius = pk.parking()->getRadius();
133 string fltType = pk.parking()->getType(); // gate / ramp, ga, etc etc.
134 string aircraftType; // Unused.
135 string airline; // Currently used for gate selection, but a fallback mechanism will apply when not specified.
137 if (!(fp->createPushBack(ai_ac,
150 } else if (!runway.empty()) {
151 controller = dcs->getTowerController();
152 int stationFreq = dcs->getTowerFrequency(2);
155 //cerr << "Setting radio frequency to in airfrequency: " << stationFreq << endl;
156 fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
158 fp = new FGAIFlightPlan;
160 string fltType = "ga";
161 fp->setRunway(runway);
162 fp->createTakeOff(ai_ac, false, dcs->parent(), 0, fltType);
163 ai_ac->setTakeOffStatus(2);
165 // We're on the ground somewhere. Handle this case later.
169 fp->getLastWaypoint()->setName( fp->getLastWaypoint()->getName() + string("legend"));
175 // Create an initial flightplan and assign it to the ai_ac. We won't use this flightplan, but it is necessary to
176 // keep the ATC code happy.
180 ai_ac->SetFlightPlan(fp);
183 controller->announcePosition(ai_ac->getID(), fp, fp->getCurrentWaypoint()->getRouteIndex(),
184 ai_ac->_getLatitude(), ai_ac->_getLongitude(), heading, speed, altitude,
185 aircraftRadius, leg, ai_ac);
189 //osg::Node* node = apt->getDynamics()->getGroundNetwork()->getRenderNode();
190 //cerr << "Adding groundnetWork to the scenegraph::init" << endl;
191 //globals->get_scenery()->get_scene_graph()->addChild(node);
193 initSucceeded = true;
196 void FGATCManager::shutdown()
199 activeStations.clear();
202 void FGATCManager::addController(FGATCController *controller) {
203 activeStations.push_back(controller);
206 void FGATCManager::removeController(FGATCController *controller)
209 it = std::find(activeStations.begin(), activeStations.end(), controller);
210 if (it != activeStations.end()) {
211 activeStations.erase(it);
215 void FGATCManager::update ( double time ) {
216 //cerr << "ATC update code is running at time: " << time << endl;
217 // Test code: let my virtual co-pilot handle ATC:
221 FGAIFlightPlan *fp = ai_ac->GetFlightPlan();
223 /* test code : find out how the routing develops */
225 int size = fp->getNrOfWayPoints();
226 //cerr << "Setting pos" << pos << " ";
227 //cerr << "setting intentions " ;
228 // This indicates that we have run out of waypoints: Im future versions, the
229 // user should be able to select a new route, but for now just shut down the
232 //cerr << "Shutting down the atc_mgr" << endl;
236 // Test code: Print how far we're progressing along the taxi route.
237 //std::cerr << "Size of waypoint cue " << size << " ";
238 for (int i = 0; i < size; i++) {
239 int val = fp->getRouteIndex(i);
240 //std::cerr << fp->getWayPoint(i)->getName() << " ";
241 //if ((val) && (val != pos)) {
242 // intentions.push_back(val);
243 // std::cerr << "[done ] " << std::endl;
246 //std::cerr << "[done ] " << std::endl;
250 //cerr << "Currently at leg : " << fp->getLeg() << endl;
252 double longitude = fgGetDouble("/position/longitude-deg");
253 double latitude = fgGetDouble("/position/latitude-deg");
254 double heading = fgGetDouble("/orientation/heading-deg");
255 double speed = fgGetDouble("/velocities/groundspeed-kt");
256 double altitude = fgGetDouble("/position/altitude-ft");
259 SGGeod me(SGGeod::fromDegM(longitude,
262 SGGeod wpt1(SGGeod::fromDegM(fp->getWayPoint(1)->getLongitude(),
263 fp->getWayPoint(1)->getLatitude(),
264 fp->getWayPoint(1)->getAltitude()));
265 SGGeod wpt2(SGGeod::fromDegM(fp->getWayPoint(1)->getLongitude(),
266 fp->getWayPoint(1)->getLatitude(),
267 fp->getWayPoint(1)->getAltitude()));
269 double course1, az1, dist1;
270 double course2, az2, dist2;
271 SGGeodesy::inverse(me, wpt1, course1, az1, dist1);
273 cerr << "Bearing to nearest waypoint : " << course1 << " " << dist1 << ". (course " << course2 << ")." << endl;
275 ai_ac->setLatitude(latitude);
276 ai_ac->setLongitude(longitude);
277 ai_ac->setAltitude(altitude);
278 ai_ac->setHeading(heading);
279 ai_ac->setSpeed(speed);
281 controller = ai_ac->getATCController();
282 FGATCDialogNew::instance()->update(time);
284 //cerr << "name of previous waypoint : " << fp->getPreviousWaypoint()->getName() << endl;
286 //cerr << "Running FGATCManager::update()" << endl;
287 //cerr << "Currently under control of " << controller->getName() << endl;
288 controller->updateAircraftInformation(ai_ac->getID(),
294 //string airport = fgGetString("/sim/presets/airport-id");
295 //FGAirport *apt = FGAirport::findByIdent(airport);
296 // AT this stage we should update the flightplan, so that waypoint incrementing is conducted as well as leg loading.
297 int n = trans_num->getIntValue();
299 //cerr << "Toggling ground network visibility " << networkVisible << endl;
300 networkVisible = !networkVisible;
301 trans_num->setIntValue(-1);
303 if ((controller != prevController) && (prevController)) {
304 prevController->render(false);
306 controller->render(networkVisible);
308 //cerr << "Adding groundnetWork to the scenegraph::update" << endl;
309 prevController = controller;
311 for (AtcVecIterator atc = activeStations.begin(); atc != activeStations.end(); atc++) {
312 (*atc)->update(time);