FlightGear next
AIGroundVehicle.cxx
Go to the documentation of this file.
1// FGAIGroundVehicle - FGAIShip-derived class creates an AI Ground Vehicle
2// by adding a ground following utility
3//
4// Written by Vivian Meazza, started August 2009.
5// - vivian.meazza at lineone.net
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#include <simgear/sg_inlines.h>
22
23#include <Viewer/view.hxx>
24#include <Scenery/scenery.hxx>
25#include <Airports/dynamics.hxx>
26#include <Main/globals.hxx>
27
28#include "AIGroundVehicle.hxx"
29
30using std::string;
31
33{
34 _dt_count = 0.0;
35 _next_run = 0.0;
36 _x_offset = 0.0;
37 _y_offset = 0.0;
38
39 invisible = false;
40 _parent = "";
41}
42
43void FGAIGroundVehicle::readFromScenario(SGPropertyNode* scFileNode) {
44 if (!scFileNode)
45 return;
46
48
49 setName(scFileNode->getStringValue("name", "groundvehicle"));
50 setParentName(scFileNode->getStringValue("parent", ""));
51 setNoRoll(scFileNode->getBoolValue("no-roll", true));
52 setContactX1offset(scFileNode->getDoubleValue("contact-x1-offset", 0.0));
53 setContactX2offset(scFileNode->getDoubleValue("contact-x2-offset", 0.0));
54 setXOffset(scFileNode->getDoubleValue("hitch-x-offset", 35.0));
55 setYOffset(scFileNode->getDoubleValue("hitch-y-offset", 0.0));
56 setZOffset(scFileNode->getDoubleValue("hitch-z-offset", 0.0));
57 setPitchoffset(scFileNode->getDoubleValue("pitch-offset", 0.0));
58 setRolloffset(scFileNode->getDoubleValue("roll-offset", 0.0));
59 setYawoffset(scFileNode->getDoubleValue("yaw-offset", 0.0));
60 setPitchCoeff(scFileNode->getDoubleValue("pitch-coefficient", 0.1));
61 setElevCoeff(scFileNode->getDoubleValue("elevation-coefficient", 0.25));
62 setTowAngleGain(scFileNode->getDoubleValue("tow-angle-gain", 1.0));
63 setTowAngleLimit(scFileNode->getDoubleValue("tow-angle-limit-deg", 2.0));
64 setInitialTunnel(scFileNode->getBoolValue("tunnel", false));
65
66 //we may need these later for towed vehicles
67 // setSubID(scFileNode->getIntValue("SubID", 0));
68 // setGroundOffset(scFileNode->getDoubleValue("ground-offset", 0.0));
69 // setFormate(scFileNode->getBoolValue("formate", true));
70}
71
74
75 tie("controls/constants/elevation-coeff",
76 SGRawValuePointer<double>(&_elevation_coeff));
77 tie("controls/constants/pitch-coeff",
78 SGRawValuePointer<double>(&_pitch_coeff));
79 tie("position/ht-AGL-ft",
80 SGRawValuePointer<double>(&_ht_agl_ft));
81 tie("hitch/rel-bearing-deg",
82 SGRawValuePointer<double>(&_relbrg));
83 tie("hitch/tow-angle-deg",
84 SGRawValuePointer<double>(&_tow_angle));
85 tie("hitch/range-ft",
86 SGRawValuePointer<double>(&_range_ft));
87 tie("hitch/x-offset-ft",
88 SGRawValuePointer<double>(&_x_offset));
89 tie("hitch/y-offset-ft",
90 SGRawValuePointer<double>(&_y_offset));
91 tie("hitch/z-offset-ft",
92 SGRawValuePointer<double>(&_z_offset));
93 tie("hitch/parent-x-offset-ft",
94 SGRawValuePointer<double>(&_parent_x_offset));
95 tie("hitch/parent-y-offset-ft",
96 SGRawValuePointer<double>(&_parent_y_offset));
97 tie("hitch/parent-z-offset-ft",
98 SGRawValuePointer<double>(&_parent_z_offset));
99 tie("controls/constants/tow-angle/gain",
100 SGRawValuePointer<double>(&_tow_angle_gain));
101 tie("controls/constants/tow-angle/limit-deg",
102 SGRawValuePointer<double>(&_tow_angle_limit));
103 tie("controls/contact-x1-offset-ft",
104 SGRawValuePointer<double>(&_contact_x1_offset));
105 tie("controls/contact-x2-offset-ft",
106 SGRawValuePointer<double>(&_contact_x2_offset));
107}
108
110 if (!FGAIShip::init(searchOrder))
111 return false;
112 reinit();
113 return true;
114}
115
117 invisible = false;
118 _limit = 200;
119 no_roll = true;
120
121 props->setStringValue("controls/parent-name", _parent.c_str());
122
123 if (setParentNode()){
124 _parent_x_offset = _selected_ac->getDoubleValue("hitch/x-offset-ft");
125 _parent_y_offset = _selected_ac->getDoubleValue("hitch/y-offset-ft");
126 _parent_z_offset = _selected_ac->getDoubleValue("hitch/z-offset-ft");
127 _hitch_x_offset_m = _selected_ac->getDoubleValue("hitch/x-offset-ft")
128 * SG_FEET_TO_METER;
129 _hitch_y_offset_m = _selected_ac->getDoubleValue("hitch/y-offset-ft")
130 * SG_FEET_TO_METER;
131 _hitch_z_offset_m = _selected_ac->getDoubleValue("hitch/z-offset-ft")
132 * SG_FEET_TO_METER;
133 setParent();
134 }
135
137}
138
140 // SG_LOG(SG_AI, SG_ALERT, "updating GroundVehicle: " << _name );
142
143 RunGroundVehicle(dt);
144}
145
146void FGAIGroundVehicle::setNoRoll(bool nr) {
147 no_roll = nr;
148}
149
150void FGAIGroundVehicle::setContactX1offset(double x1) {
151 _contact_x1_offset = x1;
152}
153
154void FGAIGroundVehicle::setContactX2offset(double x2) {
155 _contact_x2_offset = x2;
156}
157
158void FGAIGroundVehicle::setXOffset(double x) {
159 _x_offset = x;
160}
161
162void FGAIGroundVehicle::setYOffset(double y) {
163 _y_offset = y;
164}
165
166void FGAIGroundVehicle::setZOffset(double z) {
167 _z_offset = z;
168}
169
170void FGAIGroundVehicle::setPitchCoeff(double pc) {
171 _pitch_coeff = pc;
172}
173
174void FGAIGroundVehicle::setElevCoeff(double ec) {
175 _elevation_coeff = ec;
176}
177
178void FGAIGroundVehicle::setTowAngleGain(double g) {
179 _tow_angle_gain = g;
180}
181
182void FGAIGroundVehicle::setTowAngleLimit(double l) {
183 _tow_angle_limit = l;
184}
185
186void FGAIGroundVehicle::setElevation(double h, double dt, double coeff){
187 double c = dt / (coeff + dt);
188 _elevation_ft = (h * c) + (_elevation_ft * (1 - c));
189}
190
191void FGAIGroundVehicle::setPitch(double p, double dt, double coeff){
192 double c = dt / (coeff + dt);
193 _pitch_deg = (p * c) + (_pitch_deg * (1 - c));
194}
195
196void FGAIGroundVehicle::setTowAngle(double ta, double dt, double coeff){
197 ta *= _tow_angle_gain;
198 double factor = -0.0045 * speed + 1;
199 double limit = _tow_angle_limit * factor;
200// cout << "speed "<< speed << " _factor " << _factor<<" " <<_tow_angle_limit<< endl;
201 _tow_angle = pow(ta,2) * sign(ta) * factor;
202 SG_CLAMP_RANGE(_tow_angle, -limit, limit);
203}
204
205bool FGAIGroundVehicle::getPitch() {
206 if (!_tunnel){
207 double vel = props->getDoubleValue("velocities/true-airspeed-kt", 0);
208 double contact_offset_x1_m = _contact_x1_offset * SG_FEET_TO_METER;
209 double contact_offset_x2_m = _contact_x2_offset * SG_FEET_TO_METER;
210 double _z_offset_m = _parent_z_offset * SG_FEET_TO_METER;
211
212 SGVec3d front(-contact_offset_x1_m, 0, 0);
213 SGVec3d rear(-contact_offset_x2_m, 0, 0);
214 SGVec3d Front = getCartPosAt(front);
215 SGVec3d Rear = getCartPosAt(rear);
216
217 SGGeod geodFront = SGGeod::fromCart(Front);
218 SGGeod geodRear = SGGeod::fromCart(Rear);
219
220 double front_elev_m = 0;
221 double rear_elev_m = 0;
222 double elev_front = 0;
223 double elev_rear = 0;
224
225 if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(geodFront, 3000),
226 elev_front, NULL, 0)){
227 front_elev_m = elev_front + _z_offset_m;
228 } else
229 return false;
230
231 if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(geodRear, 3000),
232 elev_rear, NULL, 0)){
233 rear_elev_m = elev_rear;
234 } else
235 return false;
236
237 if (vel >= 0){
238 double diff = front_elev_m - rear_elev_m;
239 _pitch = atan2 (diff,
240 fabs(contact_offset_x1_m) + fabs(contact_offset_x2_m)) * SG_RADIANS_TO_DEGREES;
241 _elevation = (rear_elev_m + diff/2) * SG_METER_TO_FEET;
242 } else {
243 double diff = rear_elev_m - front_elev_m;
244 _pitch = atan2 (diff,
245 fabs(contact_offset_x1_m) + fabs(contact_offset_x2_m)) * SG_RADIANS_TO_DEGREES;
246 _elevation = (front_elev_m + diff/2) * SG_METER_TO_FEET;
247 _pitch = -_pitch;
248 }
249
250 } else {
251 if (prev->getAltitude() == 0 || curr->getAltitude() == 0)
252 return false;
253
254 if (_new_waypoint){
255 _tunnel_start_alt = prev->getAltitude();
256 _tunnel_end_alt = curr->getAltitude();
257 _tunnel_distance = SGGeodesy::distanceM(SGGeod::fromDeg(prev->getLongitude(), prev->getLatitude()),
258 SGGeod::fromDeg(curr->getLongitude(), curr->getLatitude()));
259 double d_alt = (_tunnel_end_alt - _tunnel_start_alt) * SG_METER_TO_FEET;
260 _pitch = atan2(d_alt, _tunnel_distance * SG_METER_TO_FEET) * SG_RADIANS_TO_DEGREES;
261 }
262
263 double distance_to_go = SGGeodesy::distanceM(SGGeod::fromDeg(pos.getLongitudeDeg(), pos.getLatitudeDeg()),
264 SGGeod::fromDeg(curr->getLongitude(), curr->getLatitude()));
265
266 if (distance_to_go > _tunnel_distance)
267 _elevation = _tunnel_start_alt;
268 else
269 _elevation = _tunnel_end_alt - (tan(_pitch * SG_DEGREES_TO_RADIANS) * distance_to_go * SG_METER_TO_FEET);
270 }
271
272 return true;
273}
274
275void FGAIGroundVehicle::setParent(){
276
277 double lat = _selected_ac->getDoubleValue("position/latitude-deg");
278 double lon = _selected_ac->getDoubleValue("position/longitude-deg");
279 double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
280
281 _selectedpos.setLatitudeDeg(lat);
282 _selectedpos.setLongitudeDeg(lon);
283 _selectedpos.setElevationFt(elevation);
284
285 _parent_speed = _selected_ac->getDoubleValue("velocities/true-airspeed-kt");
286
287 SGVec3d rear_hitch(-_hitch_x_offset_m, _hitch_y_offset_m, 0);
288 SGVec3d RearHitch = getCartHitchPosAt(rear_hitch);
289
290 SGGeod rearpos = SGGeod::fromCart(RearHitch);
291
292 double user_lat = rearpos.getLatitudeDeg();
293 double user_lon = rearpos.getLongitudeDeg();
294
295 double range, bearing;
296
297 calcRangeBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
298 user_lat, user_lon, range, bearing);
299 _range_ft = range * 6076.11549;
300 _relbrg = calcRelBearingDeg(bearing, hdg);
301}
302
303void FGAIGroundVehicle::calcRangeBearing(double lat, double lon, double lat2, double lon2,
304 double &range, double &bearing) const
305{
306 // calculate the bearing and range of the second pos from the first
307 double az2, distance;
308 geo_inverse_wgs_84(lat, lon, lat2, lon2, &bearing, &az2, &distance);
309 range = distance * SG_METER_TO_NM;
310}
311
312
313SGVec3d FGAIGroundVehicle::getCartHitchPosAt(const SGVec3d& _off) const {
314 double hdg = _selected_ac->getDoubleValue("orientation/true-heading-deg");
315 double pitch = _selected_ac->getDoubleValue("orientation/pitch-deg");
316 double roll = _selected_ac->getDoubleValue("orientation/roll-deg");
317
318 // Transform that one to the horizontal local coordinate system.
319 SGQuatd hlTrans = SGQuatd::fromLonLat(_selectedpos);
320
321 // and postrotate the orientation of the AIModel wrt the horizontal
322 // local frame
323 hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
324
325 // The offset converted to the usual body fixed coordinate system
326 // rotated to the earth fiexed coordinates axis
327 SGVec3d off = hlTrans.backTransform(_off);
328
329 // Add the position offset of the AIModel to gain the earth centered position
330 SGVec3d cartPos = SGVec3d::fromGeod(_selectedpos);
331
332 return cartPos + off;
333}
334
335void FGAIGroundVehicle::AdvanceFP(){
336
337 double count = 0;
338 string parent_next_name =_selected_ac->getStringValue("waypoint/name-next");
339
340 while(fp->getNextWaypoint() != 0 && fp->getNextWaypoint()->getName() != "END" && count < 5){
341 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
342 <<" advancing waypoint to: " << parent_next_name);
343
344 if (fp->getNextWaypoint()->getName() == parent_next_name){
345 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
346 << " not setting waypoint already at: " << fp->getNextWaypoint()->getName());
347 return;
348 }
349
350 prev = curr;
351 fp->IncrementWaypoint(false);
352 curr = fp->getCurrentWaypoint();
353 next = fp->getNextWaypoint();
354
355 if (fp->getNextWaypoint()->getName() == parent_next_name){
356 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
357 << " waypoint set to: " << fp->getNextWaypoint()->getName());
358 return;
359 }
360
361 count++;
362
363 }// end while loop
364
365 while(fp->getPreviousWaypoint() != 0 && fp->getPreviousWaypoint()->getName() != "END"
366 && count > -10){
367 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
368 << " retreating waypoint to: " << parent_next_name
369 << " at: " << fp->getNextWaypoint()->getName());
370
371 if (fp->getNextWaypoint()->getName() == parent_next_name){
372 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
373 << " not setting waypoint already at:" << fp->getNextWaypoint()->getName() );
374 return;
375 }
376
377 prev = curr;
378 fp->DecrementWaypoint();
379 curr = fp->getCurrentWaypoint();
380 next = fp->getNextWaypoint();
381
382 if (fp->getNextWaypoint()->getName() == parent_next_name){
383 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
384 << " waypoint set to: " << fp->getNextWaypoint()->getName());
385 return;
386 }
387
388 count--;
389
390 }// end while loop
391}
392
393void FGAIGroundVehicle::setTowSpeed(){
394
395 //double diff = _range_ft - _x_offset;
396 double x = 0;
397
398 if (_range_ft > _x_offset * 3) x = 50;
399
400 if (_relbrg < -90 || _relbrg > 90) {
401 setSpeed(_parent_speed - 5 - x);
402 //cout << _name << " case 1r _relbrg spd - 5 " << _relbrg << " " << diff << endl;
403 } else if (_range_ft > _x_offset + 0.25) {
404 setSpeed(_parent_speed + 1 + x);
405 //cout << _name << " case 2r _relbrg spd + 1 " << _relbrg << " "
406 // << diff << " range " << _range_ft << endl;
407 } else if (_range_ft < _x_offset - 0.25) {
408 setSpeed(_parent_speed - 1 - x);
409 //cout << _name << " case 3r _relbrg spd - 2 " << _relbrg << " "
410 // << diff << " " << _range_ft << endl;
411 } else {
412 setSpeed(_parent_speed);
413 //cout << _name << " else r _relbrg " << _relbrg << " " << diff << endl;
414 }
415}
416
417void FGAIGroundVehicle::RunGroundVehicle(double dt){
418
419 _dt_count += dt;
420
422 // Check execution time (currently once every 0.05 sec or 20 fps)
423 // Add a bit of randomization to prevent the execution of all flight plans
424 // in synchrony, which can add significant periodic framerate flutter.
425 // Randomization removed to get better appearance
427
428 //cout << "_start_sec " << _start_sec << " time_sec " << time_sec << endl;
429 if (_dt_count < _next_run)
430 return;
431
432 _next_run = 0.05 /*+ (0.015 * sg_random())*/;
433
434 if (getPitch()){
435 setElevation(_elevation, _dt_count, _elevation_coeff);
437 setPitch(_pitch, _dt_count, _pitch_coeff);
438 PitchTo(_pitch_deg);
439 }
440
441 if(_parent == ""){
442 AccelTo(prev->getSpeed());
443 _dt_count = 0;
444 return;
445 }
446
447 setParent();
448
449 string parent_next_name = _selected_ac->getStringValue("waypoint/name-next");
450 bool parent_waiting = _selected_ac->getBoolValue("waypoint/waiting");
451 //bool parent_restart = _selected_ac->getBoolValue("controls/restart");
452
453 if (parent_next_name == "END" && fp->getNextWaypoint()->getName() != "END" ){
454 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
455 << " setting END: getting new waypoints ");
456 AdvanceFP();
457 setWPNames();
459 if(_restart) _missed_count = 200;
460 /*} else if (parent_next_name == "WAIT" && fp->getNextWaypoint()->name != "WAIT" ){*/
461 } else if (parent_waiting && !_waiting){
462 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
463 << " setting WAIT/WAITUNTIL: getting new waypoints ");
464 AdvanceFP();
465 setWPNames();
466 _waiting = true;
467 } else if (parent_next_name != "WAIT" && fp->getNextWaypoint()->getName() == "WAIT"){
468 SG_LOG(SG_AI, SG_DEBUG, "AIGroundVeh1cle: " << _name
469 << " wait done: getting new waypoints ");
470 _waiting = false;
471 _wait_count = 0;
472 fp->IncrementWaypoint(false);
473 next = fp->getNextWaypoint();
474
475 if (next->getName() == "WAITUNTIL" || next->getName() == "WAIT"
476 || next->getName() == "END"){
477 } else {
478 prev = curr;
479 fp->IncrementWaypoint(false);
480 curr = fp->getCurrentWaypoint();
481 next = fp->getNextWaypoint();
482 }
483
484 setWPNames();
485 } else if (_range_ft > (_x_offset +_parent_x_offset)* 4
486 ){
487 SG_LOG(SG_AI, SG_ALERT, "AIGroundVeh1cle: " << _name
488 << " rescue: reforming train " << _range_ft
489 );
490
491 setTowAngle(0, dt, 1);
492 setSpeed(_parent_speed + (10 * sign(_parent_speed)));
493
494 } else if (_parent_speed > 1){
495
496 setTowSpeed();
497 setTowAngle(_relbrg, dt, 1);
498
499 } else if (_parent_speed < -1){
500
501 setTowSpeed();
502
503 if (_relbrg < 0)
504 setTowAngle(-(180 - (360 + _relbrg)), dt, 1);
505 else
506 setTowAngle(-(180 - _relbrg), dt, 1);
507
508 } else
509 setSpeed(_parent_speed);
510
511// FGAIShip::update(_dt_count);
512 _dt_count = 0;
513
514}
515
516// end AIGroundvehicle
#define p(x)
std::string _parent
Definition AIBase.hxx:191
void setSpeed(double speed_KTAS)
Definition AIBase.hxx:404
void setName(const std::string &n)
Definition AIBase.hxx:491
SGGeod pos
Definition AIBase.hxx:212
void setParentName(const std::string &p)
Definition AIBase.hxx:486
SGVec3d getCartPosAt(const SGVec3d &off) const
Definition AIBase.cxx:881
std::string _name
Definition AIBase.hxx:190
bool invisible
Definition AIBase.hxx:256
SGPropertyNode_ptr _selected_ac
Definition AIBase.hxx:204
double _x_offset
Definition AIBase.hxx:174
double speed
Definition AIBase.hxx:216
double bearing
Definition AIBase.hxx:239
std::unique_ptr< FGAIFlightPlan > fp
Definition AIBase.hxx:264
double range
Definition AIBase.hxx:241
bool setParentNode()
Definition AIBase.cxx:953
double hdg
Definition AIBase.hxx:213
double elevation
Definition AIBase.hxx:240
double _z_offset
Definition AIBase.hxx:176
double pitch
Definition AIBase.hxx:215
ModelSearchOrder
Definition AIBase.hxx:63
double _y_offset
Definition AIBase.hxx:175
double calcRelBearingDeg(double bearing, double heading)
Definition AIBase.hxx:521
void setYawoffset(double z_offset)
Definition AIBase.hxx:481
double roll
Definition AIBase.hxx:214
void tie(const char *aRelPath, const SGRawValue< T > &aRawValue)
Tied-properties helper, record nodes which are tied for easy un-tie-ing.
Definition AIBase.hxx:198
SGPropertyNode_ptr props
Definition AIBase.hxx:205
void setPitchoffset(double x_offset)
Definition AIBase.hxx:471
void setRolloffset(double y_offset)
Definition AIBase.hxx:476
bool no_roll
Definition AIBase.hxx:257
void bind() override
void update(double dt) override
void reinit() override
void readFromScenario(SGPropertyNode *scFileNode) override
bool init(ModelSearchOrder searchOrder) override
void readFromScenario(SGPropertyNode *scFileNode) override
Definition AIShip.cxx:63
double _tow_angle
Definition AIShip.hxx:80
void PitchTo(double angle)
Definition AIShip.cxx:436
FGAIWaypoint * next
Definition AIShip.hxx:87
bool _waiting
Definition AIShip.hxx:70
double _next_run
Definition AIShip.hxx:83
FGAIWaypoint * curr
Definition AIShip.hxx:86
void ClimbTo(double altitude)
Definition AIShip.cxx:451
void setWPNames()
Definition AIShip.cxx:573
bool _tunnel
Definition AIShip.hxx:72
bool _new_waypoint
Definition AIShip.hxx:71
void update(double dt) override
Definition AIShip.cxx:199
void bind() override
Definition AIShip.cxx:124
void AccelTo(double speed)
Definition AIShip.cxx:431
double _dt_count
Definition AIShip.hxx:83
bool _initial_tunnel
Definition AIShip.hxx:72
bool _restart
Definition AIShip.hxx:73
FGAIShip(object_type ot=object_type::otShip)
Definition AIShip.cxx:30
double sign(double x)
Definition AIShip.cxx:464
double _missed_count
Definition AIShip.hxx:82
double _elevation_ft
Definition AIShip.hxx:78
bool init(ModelSearchOrder searchOrder) override
Definition AIShip.cxx:92
void setTunnel(bool t)
Definition AIShip.cxx:568
double _wait_count
Definition AIShip.hxx:81
double _limit
Definition AIShip.hxx:77
void setInitialTunnel(bool t)
Definition AIShip.cxx:562
void reinit() override
Definition AIShip.cxx:98
FGAIWaypoint * prev
Definition AIShip.hxx:85
FGScenery * get_scenery() const
Definition globals.cxx:950
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
FGGlobals * globals
Definition globals.cxx:142
const double g(9.80665)