FlightGear next
StartupController.cxx
Go to the documentation of this file.
1// Extracted from trafficrecord.cxx - Implementation of AIModels ATC code.
2//
3// Written by Durk Talsma, started September 2006.
4//
5// Copyright (C) 2006 Durk Talsma.
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License as
9// published by the Free Software Foundation; either version 2 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful, but
13// WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20//
21// $Id$
22
23#include <config.h>
24
25#include <algorithm>
26#include <cstdio>
27#include <random>
28
29#include <osg/Geode>
30#include <osg/Geometry>
31#include <osg/MatrixTransform>
32#include <osg/Shape>
33
34#include <simgear/scene/material/EffectGeode.hxx>
35#include <simgear/scene/material/matlib.hxx>
36#include <simgear/scene/material/mat.hxx>
37#include <simgear/scene/util/OsgMath.hxx>
38#include <simgear/timing/sg_time.hxx>
39
40#include <Scenery/scenery.hxx>
41
42#include "trafficcontrol.hxx"
43#include "atc_mgr.hxx"
49#include <Airports/dynamics.hxx>
50#include <Airports/airport.hxx>
51#include <Radio/radio.hxx>
52#include <signal.h>
53
54#include <ATC/atc_mgr.hxx>
56#include <ATC/ATCController.hxx>
58
59using std::sort;
60using std::string;
61
62/***************************************************************************
63 * class FGStartupController
64 * subclass of FGATCController
65 **************************************************************************/
71
75
77 FGAIFlightPlan * intendedRoute,
78 int currentPosition, double lat,
79 double lon, double heading,
80 double speed, double alt,
81 double radius, int leg,
82 FGAIAircraft * ref)
83{
84 init();
85 // Search activeTraffic for a record matching our id
87
88 // Add a new TrafficRecord if no one exists for this aircraft.
89 if (i == activeTraffic.end() || activeTraffic.empty()) {
91 rec->setId(id);
92
93 rec->setPositionAndHeading(lat, lon, heading, speed, alt, leg);
94 rec->setRunway(intendedRoute->getRunway());
95 rec->setLeg(leg);
96 rec->setPositionAndIntentions(currentPosition, intendedRoute);
97 rec->setCallsign(ref->getCallSign());
98 rec->setAircraft(ref);
99 rec->setHoldPosition(true);
100 SGSharedPtr<FGTrafficRecord> sharedRec = static_cast<FGTrafficRecord*>(rec);
101 activeTraffic.push_back(sharedRec);
102 SG_LOG(SG_ATC, SG_DEBUG,
103 "Added " << rec->getCallsign() << "(" << rec->getId() << ") " << rec << " to " << rec->getRunway());
104 airportGroundRadar->add(sharedRec);
105 } else {
106 bool moved = airportGroundRadar->move(SGRect<double>(lat, lon), *i);
107 if (!moved) {
108 SG_LOG(SG_ATC, SG_ALERT,
109 "Not moved " << (*i)->getCallsign() << "" );
110
111 }
112 (*i)->setRunway(intendedRoute->getRunway());
113 (*i)->setPositionAndIntentions(currentPosition, intendedRoute);
114 (*i)->setPositionAndHeading(lat, lon, heading, speed, alt, leg);
115 }
116}
117
118void FGStartupController::updateAircraftInformation(int id, SGGeod geod, double heading, double speed, double alt,
119 double dt)
120{
121 // Search activeTraffic for a record matching our id
123 TrafficVectorIterator current;
124
125 if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
126 SG_LOG(SG_ATC, SG_ALERT,
127 "AI error: updating aircraft without traffic record at " << SG_ORIGIN);
128 return;
129 } else {
130 (*i)->setPositionAndHeading(geod.getLatitudeDeg(), geod.getLongitudeDeg(), heading, speed, alt, AILeg::UNKNOWN);
131 current = i;
132 }
133 setDt(getDt() + dt);
134
135 int state = (*i)->getState();
136
137 // Sentry FLIGHTGEAR-2Q : don't crash on null TrafficRef
138 // Sentry FLIGHTGEAR-129: don't crash on null aircraft
139 if (!(*i)->getAircraft() || !(*i)->getAircraft()->getTrafficRef()) {
140 SG_LOG(SG_ATC, SG_ALERT, "AI traffic: updating aircraft without traffic ref");
141 return;
142 }
143
144 // The user controlled aircraft should have crashed here, because it doesn't have a traffic reference.
145 // NOTE: if we create a traffic schedule for the user aircraft, we can use this to plan a flight.
146 time_t startTime = (*i)->getAircraft()->getTrafficRef()->getDepartureTime();
147 time_t now = globals->get_time_params()->get_cur_time();
148
149
150 if (((startTime - now) > 60 && (startTime - now)%60 == 0) ||
151 ((startTime - now) < 60 && (startTime - now) > 0)) {
152 SG_LOG(SG_ATC, SG_BULK, (*i)->getAircraft()->getTrafficRef()->getCallSign() << " is scheduled to depart in " << startTime - now << " seconds. Available = " << available << " at parking " << getGateName((*i)->getAircraft()));
153 }
154
155 if ((now - lastTransmission) > 3 + (rand() % 15)) {
156 available = true;
157 }
158
159//FIXME These messages can become interleaved and shouldn't be
160 if (now >(startTime + 0)) {
162 }
163 if (now >(startTime + 60)) {
165 }
166 if (now >(startTime + 80)) {
168 }
169 if (now >(startTime + 100)) {
171 }
172 if (now >(startTime + 130)) {
174 }
175 if (now >(startTime + 140)) {
177 }
178 if (now >(startTime + 150)) {
180 }
181 if (now >(startTime + 180)) {
183 }
185 bool pushbackBlocked = airportGroundRadar->isBlockedForPushback(*i);
186 if (now > startTime + 200) {
187 if ((*i)->pushBackAllowed() && !pushbackBlocked) {
188 (*i)->allowRepeatedTransmissions();
190 ATC_GROUND_TO_AIR, true);
191 (*i)->updateState();
192 } else {
193 if ((*i)->allowTransmissions()) {
195 ATC_GROUND_TO_AIR, true);
196 (*i)->suppressRepeatedTransmissions();
197 }
198 }
199 lastTransmission = now;
200 available = false;
201 }
202 }
204 (*i)->setHoldPosition(false);
205 }
206}
207
208// Note that this function is copied from simgear. for maintenance purposes, it's probably better to make a general function out of that.
209static void WorldCoordinate(osg::Matrix& obj_pos, double lat,
210 double lon, double elev, double hdg, double slope)
211{
212 SGGeod geod = SGGeod::fromDegM(lon, lat, elev);
213 obj_pos = makeZUpFrame(geod);
214 // hdg is not a compass heading, but a counter-clockwise rotation
215 // around the Z axis
216 obj_pos.preMult(osg::Matrix::rotate(hdg * SGD_DEGREES_TO_RADIANS,
217 0.0, 0.0, 1.0));
218 obj_pos.preMult(osg::Matrix::rotate(slope * SGD_DEGREES_TO_RADIANS,
219 0.0, 1.0, 0.0));
220}
221
222
224{
225 SGMaterialLib *matlib = globals->get_matlib();
226 if (group) {
227 //int nr = ;
228 globals->get_scenery()->get_scene_graph()->removeChild(group);
229 //while (group->getNumChildren()) {
230 // SG_LOG(SG_ATC, SG_BULK, "Number of children: " << group->getNumChildren());
231 //simgear::EffectGeode* geode = (simgear::EffectGeode*) group->getChild(0);
232 //osg::MatrixTransform *obj_trans = (osg::MatrixTransform*) group->getChild(0);
233 //geode->releaseGLObjects();
234 //group->removeChild(geode);
235 //delete geode;
236 group = 0;
237 }
238 if (visible) {
239 SG_LOG(SG_ATC, SG_BULK, "Rendering startup controller");
240 group = new osg::Group;
241 FGScenery * local_scenery = globals->get_scenery();
242 //double elevation_meters = 0.0;
243 //double elevation_feet = 0.0;
244
245 FGGroundNetwork* groundNet = parent->parent()->groundNetwork();
246
247 //for ( FGTaxiSegmentVectorIterator i = segments.begin(); i != segments.end(); i++) {
248 double dx = 0;
249 time_t now = globals->get_time_params()->get_cur_time();
250
251 for (TrafficVectorIterator i = activeTraffic.begin(); i != activeTraffic.end(); ++i) {
252 if ((*i)->isActive(300)) {
253 // Handle start point
254 int pos = (*i)->getCurrentPosition();
255 SG_LOG(SG_ATC, SG_BULK, "rendering for " << (*i)->getAircraft()->getCallSign() << "pos = " << pos);
256 if (pos > 0) {
257 FGTaxiSegment *segment = groundNet->findSegment(pos);
258 SGGeod start = (*i)->getPos();
259 SGGeod end (segment->getEnd()->geod());
260
261 double length = SGGeodesy::distanceM(start, end);
262 //heading = SGGeodesy::headingDeg(start->geod(), end->geod());
263
264 double az2, heading; //, distanceM;
265 SGGeodesy::inverse(start, end, heading, az2, length);
266 double coveredDistance = length * 0.5;
267 SGGeod center;
268 SGGeodesy::direct(start, heading, coveredDistance, center, az2);
269 SG_LOG(SG_ATC, SG_BULK, "Active Aircraft : Centerpoint = (" << center.getLatitudeDeg() << ", " << center.getLongitudeDeg() << "). Heading = " << heading);
271 // Make a helper function out of this
272 osg::Matrix obj_pos;
273 osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
274 obj_trans->setDataVariance(osg::Object::STATIC);
275 // Experimental: Calculate slope here, based on length, and the individual elevations
276 double elevationStart;
277 if (isUserAircraft((*i)->getAircraft())) {
278 elevationStart = fgGetDouble("/position/ground-elev-m");
279 } else {
280 elevationStart = ((*i)->getAircraft()->_getAltitude() * SG_FEET_TO_METER);
281 }
282 double elevationEnd = segment->getEnd()->getElevationM();
283 if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
284 SGGeod center2 = end;
285 center2.setElevationM(SG_MAX_ELEVATION_M);
286 if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
287 //elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
288 //elevation_meters += 0.5;
289 }
290 else {
291 elevationEnd = parent->getElevation();
292 }
293 segment->getEnd()->setElevation(elevationEnd);
294 }
295
296 double elevationMean = (elevationStart + elevationEnd) / 2.0;
297 double elevDiff = elevationEnd - elevationStart;
298
299 double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
300
301 SG_LOG(SG_ATC, SG_BULK, "1. Using mean elevation : " << elevationMean << " and " << slope);
302
303 WorldCoordinate( obj_pos, center.getLatitudeDeg(), center.getLongitudeDeg(), elevationMean + 0.5 + dx, -(heading), slope );
304 ;
305
306 obj_trans->setMatrix( obj_pos );
307 //osg::Vec3 center(0, 0, 0)
308
309 float width = length /2.0;
310 osg::Vec3 corner(-width, 0, 0.25f);
311 osg::Vec3 widthVec(2*width + 1, 0, 0);
312 osg::Vec3 heightVec(0, 1, 0);
313 osg::Geometry* geometry;
314 geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
315 simgear::EffectGeode* geode = new simgear::EffectGeode;
316 geode->setName("test");
317 geode->addDrawable(geometry);
318 //osg::Node *custom_obj;
319 SGMaterial *mat;
320 if (segment->hasBlock(now)) {
321 mat = matlib->find("UnidirectionalTaperRed", center);
322 } else {
323 mat = matlib->find("UnidirectionalTaperGreen", center);
324 }
325 if (mat)
326 geode->setEffect(mat->get_effect());
327 obj_trans->addChild(geode);
328 // wire as much of the scene graph together as we can
329 //->addChild( obj_trans );
330 group->addChild( obj_trans );
332 } else {
333 SG_LOG(SG_ATC, SG_DEBUG, "BIG FAT WARNING: current position is here : " << pos);
334 }
335 for (intVecIterator j = (*i)->getIntentions().begin(); j != (*i)->getIntentions().end(); ++j) {
336 osg::Matrix obj_pos;
337 int k = (*j);
338 if (k > 0) {
339 SG_LOG(SG_ATC, SG_BULK, "rendering for " << (*i)->getAircraft()->getCallSign() << "intention = " << k);
340 osg::MatrixTransform *obj_trans = new osg::MatrixTransform;
341 obj_trans->setDataVariance(osg::Object::STATIC);
342 FGTaxiSegment *segment = groundNet->findSegment(k);
343
344 double elevationStart = segment->getStart()->getElevationM();
345 double elevationEnd = segment->getEnd ()->getElevationM();
346 if ((elevationStart == 0) || (elevationStart == parent->getElevation())) {
347 SGGeod center2 = segment->getStart()->geod();
348 center2.setElevationM(SG_MAX_ELEVATION_M);
349 if (local_scenery->get_elevation_m( center2, elevationStart, NULL )) {
350 //elevation_feet = elevationStart * SG_METER_TO_FEET + 0.5;
351 //elevation_meters += 0.5;
352 }
353 else {
354 elevationStart = parent->getElevation();
355 }
356 segment->getStart()->setElevation(elevationStart);
357 }
358 if ((elevationEnd == 0) || (elevationEnd == parent->getElevation())) {
359 SGGeod center2 = segment->getEnd()->geod();
360 center2.setElevationM(SG_MAX_ELEVATION_M);
361 if (local_scenery->get_elevation_m( center2, elevationEnd, NULL )) {
362 //elevation_feet = elevationEnd * SG_METER_TO_FEET + 0.5;
363 //elevation_meters += 0.5;
364 }
365 else {
366 elevationEnd = parent->getElevation();
367 }
368 segment->getEnd()->setElevation(elevationEnd);
369 }
370
371 double elevationMean = (elevationStart + elevationEnd) / 2.0;
372 double elevDiff = elevationEnd - elevationStart;
373 double length = segment->getLength();
374 double slope = atan2(elevDiff, length) * SGD_RADIANS_TO_DEGREES;
375
376 SG_LOG(SG_ATC, SG_BULK, "2. Using mean elevation : " << elevationMean << " and " << slope);
377
378 SGGeod segCenter(segment->getCenter());
379 WorldCoordinate( obj_pos, segCenter.getLatitudeDeg(),
380 segCenter.getLongitudeDeg(), elevationMean + 0.5 + dx, -(segment->getHeading()), slope );
381
382 //WorldCoordinate( obj_pos, segment->getLatitude(), segment->getLongitude(), parent->getElevation()+8+dx, -(segment->getHeading()) );
383
384 obj_trans->setMatrix( obj_pos );
385 //osg::Vec3 center(0, 0, 0)
386
387 float width = segment->getLength() /2.0;
388 osg::Vec3 corner(-width, 0, 0.25f);
389 osg::Vec3 widthVec(2*width + 1, 0, 0);
390 osg::Vec3 heightVec(0, 1, 0);
391 osg::Geometry* geometry;
392 geometry = osg::createTexturedQuadGeometry(corner, widthVec, heightVec);
393 simgear::EffectGeode* geode = new simgear::EffectGeode;
394 geode->setName("test");
395 geode->addDrawable(geometry);
396 //osg::Node *custom_obj;
397 SGMaterial *mat;
398 if (segment->hasBlock(now)) {
399 mat = matlib->find("UnidirectionalTaperRed", segCenter);
400 } else {
401 mat = matlib->find("UnidirectionalTaperGreen", segCenter);
402 }
403 if (mat)
404 geode->setEffect(mat->get_effect());
405 obj_trans->addChild(geode);
406 // wire as much of the scene graph together as we can
407 //->addChild( obj_trans );
408 group->addChild( obj_trans );
409 } else {
410 SG_LOG(SG_ATC, SG_DEBUG, "BIG FAT WARNING: k is here : " << pos);
411 }
412 }
413 dx += 0.2;
414 }
415 }
416 globals->get_scenery()->get_scene_graph()->addChild(group);
417 }
418}
419
421 return string(parent->parent()->getName() + "-Startup");
422}
423
428
429int FGStartupController::getFrequency() {
430 int groundFreq = parent->getGroundFrequency(2);
431 int towerFreq = parent->getTowerFrequency(2);
432 return groundFreq>0?groundFreq:towerFreq;
433}
434
const double rec
static void WorldCoordinate(osg::Matrix &obj_pos, double lat, double lon, double elev, double hdg, double slope)
#define i(x)
static void WorldCoordinate(osg::Matrix &obj_pos, double lat, double lon, double elev, double hdg, double slope)
const std::string & getCallSign() const
Definition AIBase.hxx:367
const std::string & getRunway() const
TrafficVectorIterator searchActiveTraffic(int id) const
Search activeTraffic vector to find matching id.
bool isUserAircraft(FGAIAircraft *)
FGAirportDynamics * parent
SGSharedPtr< AirportGroundRadar > airportGroundRadar
TrafficVector activeTraffic
void setDt(double dt)
osg::Group * group
void transmit(FGTrafficRecord *rec, FGAirportDynamics *parent, AtcMsgId msgId, AtcMsgDir msgDir, bool audible)
@ MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY
bool checkTransmissionState(int minState, int MaxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, AtcMsgDir msgDir)
std::string getGateName(FGAIAircraft *aircraft)
int getGroundFrequency(unsigned leg)
Definition dynamics.cxx:920
int getTowerFrequency(unsigned nr)
Definition dynamics.cxx:950
FGTaxiSegment * findSegment(const FGTaxiNode *from, const FGTaxiNode *to) const
Find the taxiway segment joining two (ground-net) nodes.
bool get_elevation_m(const SGGeod &geod, double &alt, const simgear::BVHMaterial **material, const osg::Node *butNotFrom=0)
Compute the elevation of the scenery at geodetic latitude lat, geodetic longitude lon and not higher ...
Definition scenery.cxx:527
virtual void updateAircraftInformation(int id, SGGeod geod, double heading, double speed, double alt, double dt)
FGStartupController(FGAirportDynamics *parent)
virtual void update(double dt)
virtual void render(bool)
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute, double lat, double lon, double hdg, double spd, double alt, double radius, int leg, FGAIAircraft *aircraft)
virtual std::string getName() const
FGTaxiNodeRef getEnd() const
double getLength() const
bool hasBlock(time_t now)
FGTaxiNodeRef getStart() const
double getHeading() const
SGGeod getCenter() const
FGGlobals * globals
Definition globals.cxx:142
std::vector< int >::iterator intVecIterator
double fgGetDouble(const char *name, double defaultValue)
Get a double value for a property.
Definition proptest.cpp:30
std::list< SGSharedPtr< FGTrafficRecord > >::const_iterator TrafficVectorIterator