FlightGear next
AIBallistic.cxx
Go to the documentation of this file.
1/*
2 * SPDX-FileName: AIBallistic.cxx
3 * SPDX-FileComment: GAIBase-derived class creates a ballistic object
4 * SPDX-FileCopyrightText: Copyright (C) 2003 David P. Culp - davidculp2@comcast.net
5 * SPDX-FileContributor: With major additions by Mathias Froehlich & Vivian Meazza 2004-2008
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9#include <config.h>
10
11#include <simgear/math/sg_random.hxx>
12#include <simgear/math/sg_geodesy.hxx>
13#include <simgear/scene/model/modellib.hxx>
14
15#include <Scenery/scenery.hxx>
16
17#include "AIBallistic.hxx"
18
19#include <Main/util.hxx>
22#include <Main/fg_props.hxx>
23
24using namespace simgear;
25using std::string;
26
27const double FGAIBallistic::slugs_to_kgs = 14.5939029372;
28const double FGAIBallistic::slugs_to_lbs = 32.1740485564;
29
31FGAIBase(ot, false),
32_height(0.0),
33_speed(0),
34_ht_agl_ft(0.0),
35_azimuth(0.0),
36_elevation(0.0),
37_rotation(0.0),
38hs(0),
40_az_random_error(0.0),
41_el_random_error(0.0),
42_aero_stabilised(false),
43_drag_area(0.007),
44_cd(0.029),
45_init_cd(0.029),
46_cd_randomness(0.0),
47_buoyancy(0),
48_life_timer(0.0),
49_wind(true),
50_mass(0),
51_random(false),
52_life_randomness(0.0),
53_load_resistance(0),
54_solid(false),
55_force_stabilised(false),
56_slave_to_ac(false),
57_slave_load_to_ac(false),
58_contents_lb(0),
59_report_collision(false),
60_report_impact(false),
61_external_force(false),
62_report_expiry(false),
63_impact_report_node(fgGetNode("/ai/models/model-impact", true))
64
65{
66 no_roll = false;
67}
68
69
70void FGAIBallistic::readFromScenario(SGPropertyNode* scFileNode) {
71 if (!scFileNode){
72 return;
73 }
74
76
77 //setPath(scFileNode->getStringValue("model", "Models/Geometry/rocket.ac"));
78 setRandom(scFileNode->getBoolValue("random", false));
79 setAzimuth(scFileNode->getDoubleValue("azimuth", 0.0));
80 setElevation(scFileNode->getDoubleValue("elevation", 0));
81 setDragArea(scFileNode->getDoubleValue("eda", 0.007));
82 setLife(scFileNode->getDoubleValue("life", 900.0));
83 setBuoyancy(scFileNode->getDoubleValue("buoyancy", 0));
84 //setWind_from_east(scFileNode->getDoubleValue("wind_from_east", 0));
85 //setWind_from_north(scFileNode->getDoubleValue("wind_from_north", 0));
86 setWind(scFileNode->getBoolValue("wind", false));
87 setRoll(scFileNode->getDoubleValue("roll", 0.0));
88 setCd(scFileNode->getDoubleValue("cd", 0.029));
89 //setMass(scFileNode->getDoubleValue("mass", 0.007));
90 setWeight(scFileNode->getDoubleValue("weight", 0.25));
91 setStabilisation(scFileNode->getBoolValue("aero-stabilised", false));
92 setNoRoll(scFileNode->getBoolValue("no-roll", false));
93 setImpact(scFileNode->getBoolValue("impact", false));
94 setExpiry(scFileNode->getBoolValue("expiry", false));
95 setCollision(scFileNode->getBoolValue("collision", false));
96 setImpactReportNode(scFileNode->getStringValue("impact-reports"));
97 setName(scFileNode->getStringValue("name", "Rocket"));
98 setFuseRange(scFileNode->getDoubleValue("fuse-range", 0.0));
99 setSMPath(scFileNode->getStringValue("submodel-path", ""));
100 setSubID(scFileNode->getIntValue("SubID", 0));
101 setExternalForce(scFileNode->getBoolValue("external-force", false));
102 setForcePath(scFileNode->getStringValue("force-path", ""));
103 setForceStabilisation(scFileNode->getBoolValue("force-stabilised", false));
104 setXoffset(scFileNode->getDoubleValue("x-offset", 0.0));
105 setYoffset(scFileNode->getDoubleValue("y-offset", 0.0));
106 setZoffset(scFileNode->getDoubleValue("z-offset", 0.0));
107 setPitchoffset(scFileNode->getDoubleValue("pitch-offset", 0.0));
108 setRolloffset(scFileNode->getDoubleValue("roll-offset", 0.0));
109 setYawoffset(scFileNode->getDoubleValue("yaw-offset", 0.0));
110 setGroundOffset(scFileNode->getDoubleValue("ground-offset", 0.0));
111 setLoadOffset(scFileNode->getDoubleValue("load-offset", 0.0));
112 setSlaved(scFileNode->getBoolValue("slaved", false));
113 setSlavedLoad(scFileNode->getBoolValue("slaved-load", false));
114 setContentsPath(scFileNode->getStringValue("contents"));
115 setParentName(scFileNode->getStringValue("parent"));
116}
117
119{
120 FGAIBase::init(searchOrder);
121 reinit();
122 return true;
123}
124
126 _impact_reported = false;
127 _collision_reported = false;
128 _expiry_reported = false;
129
130 _impact_lat = 0;
131 _impact_lon = 0;
132 _impact_elev = 0;
133 _impact_hdg = 0;
134 _impact_pitch = 0;
135 _impact_roll = 0;
136 _impact_speed = 0;
137
138 invisible = false;
139
140 _elapsed_time += (sg_random() * 100);
141
142 _life_timer = 0;
143
144 props->setStringValue("material/name", "");
145 props->setStringValue("name", _name.c_str());
146 props->setStringValue("submodels/path", _path.c_str());
147
148 if (_slave_to_ac) {
149 props->setStringValue("force/path", _force_path.c_str());
150 props->setStringValue("contents/path", _contents_path.c_str());
151 }
152
153 //cout << "init: name " << _name.c_str() << " _life_timer " << _life_timer
154 // << endl;
155
156 //if(_parent != ""){
157 // setParentNode();
158 //}
159
160 //setParentNodes(_selected_ac);
161
162 //props->setStringValue("vector/path", _vector_path.c_str());
163
164 // start with high value so that animations don't trigger yet
165 _ht_agl_ft = 1e10;
166 hdg = _azimuth;
168 roll = _rotation;
169
170 Transform();
171
172 if (_parent != "") {
174 }
175
177
179}
180
182 // FGAIBase::bind();
183
184 _tiedProperties.setRoot(props);
185 tie("sim/time/elapsed-sec",
186 SGRawValueMethods<FGAIBallistic,double>(*this,
188 //tie("mass-slug",
189 // SGRawValueMethods<FGAIBallistic,double>(*this,
190 // &FGAIBallistic::getMass));
191
192 tie("material/solid",
193 SGRawValuePointer<bool>(&_solid));
194 tie("altitude-agl-ft",
195 SGRawValuePointer<double>(&_ht_agl_ft));
196 tie("controls/slave-to-ac",
197 SGRawValueMethods<FGAIBallistic,bool>
199 tie("controls/invisible",
200 SGRawValuePointer<bool>(&invisible));
201
202 if (_external_force || _slave_to_ac) {
203 tie("controls/force_stabilized",
204 SGRawValuePointer<bool>(&_force_stabilised));
205 tie("position/global-x",
206 SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getCartPosX, 0));
207 tie("position/global-y",
208 SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getCartPosY, 0));
209 tie("position/global-z",
210 SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getCartPosZ, 0));
211 tie("velocities/vertical-speed-fps",
212 SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getVS_fps, &FGAIBase::_setVS_fps));
213 tie("velocities/true-airspeed-kt",
214 SGRawValuePointer<double>(&speed));
215 tie("velocities/horizontal-speed-fps",
216 SGRawValuePointer<double>(&hs));
217 tie("position/altitude-ft",
218 SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getElevationFt, &FGAIBase::_setAltitude));
219 tie("position/latitude-deg",
220 SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getLatitude, &FGAIBase::_setLatitude));
221 tie("position/longitude-deg",
222 SGRawValueMethods<FGAIBase,double>(*this, &FGAIBase::_getLongitude, &FGAIBase::_setLongitude));
223 tie("orientation/hdg-deg",
224 SGRawValuePointer<double>(&hdg));
225 tie("orientation/pitch-deg",
226 SGRawValuePointer<double>(&pitch));
227 tie("orientation/roll-deg",
228 SGRawValuePointer<double>(&roll));
229 tie("controls/slave-load-to-ac",
230 SGRawValueMethods<FGAIBallistic,bool>
232 tie("position/load-offset",
233 SGRawValueMethods<FGAIBallistic,double>
235 tie("load/distance-to-hitch-ft",
236 SGRawValueMethods<FGAIBallistic,double>
238 tie("load/elevation-to-hitch-deg",
239 SGRawValueMethods<FGAIBallistic,double>
241 tie("load/bearing-to-hitch-deg",
242 SGRawValueMethods<FGAIBallistic,double>
244 tie("material/load-resistance",
245 SGRawValuePointer<double>(&_load_resistance));
246 }
247}
248
250{
252
253 if (_slave_to_ac) {
254 slaveToAC(dt);
255 Transform();
256 }
257 else if (!invisible) {
258 Run(dt);
259 Transform();
260 }
261
262}
263
265 if (_random)
266 hdg = _azimuth = az - _az_random_error + 2 * _az_random_error * sg_random();
267 else
268 hdg = _azimuth = az;
269}
270
272 _az_random_error = error;
273}
274
276 _el_random_error = error;
277}
278
280 if (_random)
281 pitch = _elevation = el - _el_random_error + 2 * _el_random_error * sg_random();
282 else
283 pitch = _elevation = el;
284}
285
286void FGAIBallistic::setRoll(double rl) {
287 roll = _rotation = rl;
288}
289
291 _aero_stabilised = val;
292}
293
295 _force_stabilised = val;
296}
297
299 no_roll = nr;
300}
301
303 _drag_area = a;
304}
305
306void FGAIBallistic::setLife(double seconds) {
307 if (_random)
308 life = seconds * _life_randomness + (seconds * (1 -_life_randomness) * sg_random());
309 else
310 life = seconds;
311}
312
313void FGAIBallistic::setBuoyancy(double fpss) {
314 _buoyancy = fpss;
315}
316
318 _wind_from_east = fps;
319}
320
322 _wind_from_north = fps;
323}
324
326 _wind = val;
327}
328
329void FGAIBallistic::setCd(double cd) {
330 _cd = cd;
331 _init_cd = cd;
332}
333
334void FGAIBallistic::setCdRandomness(double randomness) {
335 _cd_randomness = randomness;
336}
337
339 _mass = m;
340}
341
343 _weight_lb = w;
344}
345
346void FGAIBallistic::setLifeRandomness(double randomness) {
347 _life_randomness = randomness;
348}
349
351 _random = r;
352}
353
355 _report_impact = i;
356}
357
359 _report_collision = c;
360}
361
363 _report_expiry = e;
364}
365
367 _external_force = f;
368}
369
370void FGAIBallistic::setImpactReportNode(const string& path) {
371 if (!path.empty())
372 _impact_report_node = fgGetNode(path.c_str(), true);
373}
374
375void FGAIBallistic::setSMPath(const string& s) {
376 _path = s;
377 //cout << "submodel path " << _path << endl;
378}
379
381 _fuse_range = f;
382}
383
385 _subID = i;
386}
387
388void FGAIBallistic::setSubmodel(const string& s) {
389 _submodel = s;
390}
391
393 _ground_offset = g;
394}
395
397 _load_offset = l;
398}
399
401 return _load_offset;
402}
403
405 _slave_to_ac = s;
406}
407
408void FGAIBallistic::setContentsPath(const string& path) {
409 _contents_path = path;
410
411 if (!path.empty()) {
412 _contents_node = fgGetNode(path.c_str(), true);
413 }
414}
415
416void FGAIBallistic::setContentsNode(SGPropertyNode_ptr node) {
417 if (node != 0) {
418 _contents_node = node;
419 _contents_path = _contents_node->getDisplayName();
420 }
421}
422
423void FGAIBallistic::setParentNodes(SGPropertyNode_ptr node) {
424 if (node != 0) {
425 _pnode = node;
426 _p_pos_node = _pnode->getChild("position", 0, true);
427 _p_lat_node = _p_pos_node->getChild("latitude-deg", 0, true);
428 _p_lon_node = _p_pos_node->getChild("longitude-deg", 0, true);
429 _p_alt_node = _p_pos_node->getChild("altitude-ft", 0, true);
430 _p_agl_node = _p_pos_node->getChild("altitude-agl-ft", 0, true);
431
432
433 _p_ori_node = _pnode->getChild("orientation", 0, true);
434 _p_pch_node = _p_ori_node->getChild("pitch-deg", 0, true);
435 _p_rll_node = _p_ori_node->getChild("roll-deg", 0, true);
436 _p_hdg_node = _p_ori_node->getChild("true-heading-deg",0, true);
437
438 _p_vel_node = _pnode->getChild("velocities", 0, true);
439 _p_spd_node = _p_vel_node->getChild("true-airspeed-kt", 0, true);
440 }
441}
442
444 if (_pnode != 0) {
445 double lat = _p_lat_node->getDoubleValue();
446 double lon = _p_lon_node->getDoubleValue();
447 double alt = _p_alt_node->getDoubleValue();
448
449 _parentpos.setLongitudeDeg(lon);
450 _parentpos.setLatitudeDeg(lat);
451 _parentpos.setElevationFt(alt);
452 }
453}
454
456 return _slave_to_ac;
457}
458
459double FGAIBallistic::getMass() const {
460 return _mass;
461}
462
464 if (_contents_node) {
465 _contents_lb = _contents_node->getChild("level-lbs", 0, 1)->getDoubleValue();
466 }
467 return _contents_lb;
468}
469
470void FGAIBallistic::setContents(double c) {
471 if (_contents_node)
472 _contents_lb = _contents_node->getChild("level-gal_us", 0, 1)->setDoubleValue(c);
473}
474
476 _slave_load_to_ac = l;
477}
478
480 return _slave_load_to_ac;
481}
482
483void FGAIBallistic::setForcePath(const string& p) {
484 _force_path = p;
485 if (!_force_path.empty()) {
486 SGPropertyNode *fnode = fgGetNode(_force_path.c_str(), 0, true );
487 _force_node = fnode->getChild("force-lb", 0, true);
488 _force_azimuth_node = fnode->getChild("force-azimuth-deg", 0, true);
489 _force_elevation_node = fnode->getChild("force-elevation-deg", 0, true);
490 }
491}
492
493bool FGAIBallistic::getHtAGL(double start) {
494 const simgear::BVHMaterial* mat = 0;
495 if (getGroundElevationM(SGGeod::fromGeodM(pos, start),
496 _elevation_m, &mat)) {
497 const SGMaterial* material = dynamic_cast<const SGMaterial*>(mat);
498 _ht_agl_ft = pos.getElevationFt() - _elevation_m * SG_METER_TO_FEET;
499
500 if (material) {
501 const std::vector<string>& names = material->get_names();
502 _solid = material->get_solid();
503 _load_resistance = material->get_load_resistance();
504 _frictionFactor = material->get_friction_factor();
505
506 if (!names.empty())
507 props->setStringValue("material/name", names[0].c_str());
508 else
509 props->setStringValue("material/name", "");
510
511 _mat_name = names[0];
512
513 //cout << "material " << _mat_name
514 //<< " solid " << _solid
515 //<< " load " << _load_resistance
516 //<< " frictionFactor " << _frictionFactor
517 //<< endl;
518 }
519
520 return true;
521 }
522 else {
523 return false;
524 }
525}
526
527double FGAIBallistic::getRecip(double az) {
528 // calculate the reciprocal of the input azimuth
529 if (az - 180 < 0) {
530 return az + 180;
531 }
532 else {
533 return az - 180;
534 }
535}
536
537void FGAIBallistic::setPch(double e, double dt, double coeff) {
538 double c = dt / (coeff + dt);
539 pitch = (e * c) + (pitch * (1 - c));
540}
541
542void FGAIBallistic::setBnk(double r, double dt, double coeff) {
543 double c = dt / (coeff + dt);
544 roll = (r * c) + (roll * (1 - c));
545}
546
547void FGAIBallistic::setSpd(double s, double dt, double coeff) {
548 double c = dt / (coeff + dt);
549 _speed = (s * c) + (_speed * (1 - c));
550}
551
552void FGAIBallistic::setHt(double h, double dt, double coeff) {
553 double c = dt / (coeff + dt);
554 _height = (h * c) + (_height * (1 - c));
555}
556
557int FGAIBallistic::setHdg(double tgt_hdg, double dt, double coeff) {
558 double recip = getRecip(hdg);
559 double c = dt / (coeff + dt);
560 //cout << "set heading " << tgt_hdg << endl;
561 //we need to ensure that we turn the short way to the new hdg
562 if (tgt_hdg < recip && tgt_hdg < hdg && hdg > 180) {
563 hdg = ((tgt_hdg + 360) * c) + (hdg * (1 - c));
564// cout << "case 1: right turn" << endl;
565 } else if (tgt_hdg > recip && tgt_hdg > hdg && hdg <= 180){
566 hdg = ((tgt_hdg - 360) * c) + (hdg * (1 - c));
567// cout << "case 2: left turn" << endl;
568 } else {
569 hdg = (tgt_hdg * c) + (hdg * (1 - c));
570// cout << "case 4: left turn" << endl;
571 }
572 return -1;
573}
574
576 return _tgt_x_offset;
577}
578
580 return _tgt_y_offset;
581}
582
584 return _tgt_z_offset;
585}
586
588 _tgt_x_offset = x;
589}
590
592 _tgt_y_offset = y;
593}
594
596 _tgt_z_offset = z;
597}
598
599void FGAIBallistic::slaveToAC(double dt) {
600 if (invisible)
601 return;
602
603 double hdg, pch, rll;//, agl = 0;
604
605 if (_pnode != 0) {
606 setParentPos();
607 hdg = _p_hdg_node->getDoubleValue();
608 pch = _p_pch_node->getDoubleValue();
609 rll = _p_rll_node->getDoubleValue();
610// agl = _p_agl_node->getDoubleValue();
611 setOffsetPos(_parentpos, hdg, pch, rll);
612 setSpeed(_p_spd_node->getDoubleValue());
613 }
614 else {
615 hdg = manager->get_user_heading();
616 pch = manager->get_user_pitch();
617 rll = manager->get_user_roll();
618// agl = manager->get_user_agl();
620 setSpeed(manager->get_user_speed());
621 }
622
623 pos.setLatitudeDeg(_offsetpos.getLatitudeDeg());
624 pos.setLongitudeDeg(_offsetpos.getLongitudeDeg());
625 pos.setElevationFt(_offsetpos.getElevationFt());
627 setPitch(pch + _pitch_offset);
628 setBank(rll + _roll_offset);
630 setTime(0);
631
632 //update the mass (slugs)
633 _mass = (_weight_lb + getContents()) / slugs_to_lbs;
634
635 _impact_reported = false;
636
637 //cout << _name << " _mass "<<_mass <<" " << getContents()
638 //<< " " << getContents() / slugs_to_lbs << " weight " << _weight_lb << endl;
639 // cout << _name << " update hs " << hs << " vs " << vs << endl;
640}
641
642void FGAIBallistic::Run(double dt) {
643 _life_timer += dt;
644
645 //_pass += 1;
646 //cout<<"AIBallistic run: name " << _name.c_str()
647 // << " dt " << dt << " _life_timer " << _life_timer << " pass " << _pass << endl;
648
649 // if life = -1 the object does not die
650 if (_life_timer > life && life != -1) {
651 if (_report_expiry && !_expiry_reported && !_impact_reported && !_collision_reported) {
652 //cout<<"AIBallistic run: name " << _name.c_str() << " expiry "
653 //<< " _life_timer " << _life_timer<< endl;
654 handle_expiry();
655 }
656 else {
657 //cout<<"AIBallistic run: name " << _name.c_str()
658 // << " die " << " _life_timer " << _life_timer << endl;
659 setDie(true);
660 }
661
662 setTime(0);
663 }
664
665 // Set the contents in the appropriate tank or other property in the parent to zero
666 setContents(0);
667
668 if (_random) {
669 // Keep the new Cd within +- 10% of the current Cd to avoid a fluctuating value
670 double cd_min = _cd * 0.9;
671 double cd_max = _cd * 1.1;
672
673 // Randomize Cd by +- a certain percentage of the initial Cd
674 _cd = _init_cd * (1 - _cd_randomness + 2 * _cd_randomness * sg_random());
675
676 if (_cd < cd_min) _cd = cd_min;
677 if (_cd > cd_max) _cd = cd_max;
678 }
679
680 // Adjust Cd by Mach number. The equations are based on curves
681 // for a conventional shell/bullet (no boat-tail).
682 double Cdm;
683
685 const double rhoKgM3 = FGAtmo::densityAtAltitudeFt(altitude_ft);
686 const double rho = rhoKgM3 / SG_SLUGFT3_TO_KGPM3;
687
688 if (Mach < 0.7)
689 Cdm = 0.0125 * Mach + _cd;
690 else if (Mach < 1.2)
691 Cdm = 0.3742 * pow(Mach, 2) - 0.252 * Mach + 0.0021 + _cd;
692 else
693 Cdm = 0.2965 * pow(Mach, -1.1506) + _cd;
694
695 //cout <<_name << " Mach " << Mach << " Cdm " << Cdm
696 // << " ballistic speed kts "<< speed << endl;
697
698 // drag = Cd * 0.5 * rho * speed * speed * drag_area;
699 // rho is adjusted for altitude in void FGAIBase::update,
700 // using Standard Atmosphere (sealevel temperature 15C)
701 // acceleration = drag/mass;
702 // adjust speed by drag
703 //
704 // speed is in kt, rest is in ft and sec, so we convert speed^2 to fps (* SG_KT_TO_FPS^2)
705 // then the result back to kt (/ SG_KT_TO_FPS), which is the same as just * SG_KT_TO_FPS.
706 speed -= (Cdm * 0.5 * rho * speed * speed * _drag_area/_mass) * dt * SG_KT_TO_FPS;
707
708 // don't let speed become negative
709 if (speed < 0.0)
710 speed = 0.0;
711
712// double speed_fps = speed * SG_KT_TO_FPS;
713
714 // calculate vertical and horizontal speed components
715 calcVSHS();
716
717 //resolve horizontal speed into north and east components:
718 //and convert horizontal speed (fps) to degrees per second
719 calcNE();
720
721 // If wind not required, set to zero
722 if (!_wind) {
724 _wind_from_east = 0;
725 }
726 else {
727 _wind_from_north = manager->get_wind_from_north();
728 _wind_from_east = manager->get_wind_from_east();
729 }
730
731 // Calculate velocity due to external force
732 double force_speed_north_deg_sec = 0.0;
733 double force_speed_east_deg_sec = 0.0;
734 double v_force_acc_fpss = 0.0;
735 double force_speed_north_fps = 0.0;
736 double force_speed_east_fps = 0.0;
737 double h_force_lbs = 0.0;
738 double normal_force_fpss = 0.0;
739 double friction_force_speed_north_fps = 0.0;
740 double friction_force_speed_east_fps = 0.0;
741 double friction_force_speed_north_deg_sec = 0.0;
742 double friction_force_speed_east_deg_sec = 0.0;
743 double force_elevation_deg = 0.0;
744
745 if (_external_force) {
746 //cout << _name << " external force " << hdg << " az " << _azimuth << endl;
747
748 SGPropertyNode *n = fgGetNode(_force_path.c_str(), true);
749 double force_lbs = n->getChild("force-lb", 0, true)->getDoubleValue();
750 force_elevation_deg = n->getChild("force-elevation-deg", 0, true)->getDoubleValue();
751 double force_azimuth_deg = n->getChild("force-azimuth-deg", 0, true)->getDoubleValue();
752
753 // Resolve force into vertical and horizontal components:
754 double v_force_lbs = force_lbs * sin( force_elevation_deg * SG_DEGREES_TO_RADIANS );
755 h_force_lbs = force_lbs * cos( force_elevation_deg * SG_DEGREES_TO_RADIANS );
756
757 double normal_force_lbs = 0.0;
758 double dynamic_friction_force_lbs = 0.0;
759
760 // Perform ground interaction if impacts are not calculated
761 if (!_report_impact && getHtAGL(10000)) {
762 double deadzone = 0.1;
763
764 if (_ht_agl_ft <= (_ground_offset + deadzone) && _solid) {
765 normal_force_lbs = (_mass * slugs_to_lbs) - v_force_lbs;
766
767 if (normal_force_lbs < 0.0)
768 normal_force_lbs = 0.0;
769
770 pos.setElevationFt(0 + _ground_offset);
771 if (vs_fps < 0.0)
772 vs_fps *= -0.5;
773
774 // Calculate friction. We assume a static coefficient of
775 // friction (mu) of 0.62 (wood on concrete)
776 double mu = 0.62;
777
778 double static_friction_force_lbs = mu * normal_force_lbs * _frictionFactor;
779
780 // Adjust horizontal force. We assume that a speed of <= 5 fps is static
781 if (h_force_lbs <= static_friction_force_lbs && hs <= 5) {
782 h_force_lbs = hs = 0;
784 }
785 else
786 dynamic_friction_force_lbs = static_friction_force_lbs * 0.95;
787
788 // Ignore wind when on the ground for now
789 // TODO: fix this
791 _wind_from_east = 0;
792 }
793 }
794
795 //acceleration = (force(lbsf)/mass(slugs))
796 v_force_acc_fpss = v_force_lbs / _mass;
797 normal_force_fpss = normal_force_lbs / _mass;
798 double h_force_acc_fpss = h_force_lbs / _mass;
799 double dynamic_friction_acc_fpss = dynamic_friction_force_lbs / _mass;
800
801 // velocity = acceleration * dt
802 double hs_force_fps = h_force_acc_fpss * dt;
803 double friction_force_fps = dynamic_friction_acc_fpss * dt;
804
805 //resolve horizontal speeds into north and east components:
806 force_speed_north_fps = cos(force_azimuth_deg * SG_DEGREES_TO_RADIANS) * hs_force_fps;
807 force_speed_east_fps = sin(force_azimuth_deg * SG_DEGREES_TO_RADIANS) * hs_force_fps;
808
809 friction_force_speed_north_fps = cos(getRecip(hdg) * SG_DEGREES_TO_RADIANS) * friction_force_fps;
810 friction_force_speed_east_fps = sin(getRecip(hdg) * SG_DEGREES_TO_RADIANS) * friction_force_fps;
811
812 // convert horizontal speed (fps) to degrees per second
813 force_speed_north_deg_sec = force_speed_north_fps / ft_per_deg_lat;
814 force_speed_east_deg_sec = force_speed_east_fps / ft_per_deg_lon;
815
816 friction_force_speed_north_deg_sec = friction_force_speed_north_fps / ft_per_deg_lat;
817 friction_force_speed_east_deg_sec = friction_force_speed_east_fps / ft_per_deg_lon;
818 }
819
820 // convert wind speed (fps) to degrees lat/lon per second
821 double wind_speed_from_north_deg_sec = _wind_from_north / ft_per_deg_lat;
822 double wind_speed_from_east_deg_sec = _wind_from_east / ft_per_deg_lon;
823
824 //recombine the horizontal velocity components
825 hs = sqrt(((_speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps)
826 * (_speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps))
827 + ((_speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps)
828 * (_speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps)));
829
830 if (hs <= 0.00001)
831 hs = 0;
832
833 // adjust vertical speed for acceleration of gravity, buoyancy, and vertical force
834 double gravity = SG_METER_TO_FEET * (Environment::Gravity::instance()->getGravity(pos));
835 vs_fps -= (gravity - _buoyancy - v_force_acc_fpss - normal_force_fpss) * dt;
836
837 if (vs_fps <= 0.00001 && vs_fps >= -0.00001)
838 vs_fps = 0;
839
840 // set new position
841 if (_slave_load_to_ac) {
843 manager->get_user_heading(),
844 manager->get_user_pitch(),
845 manager->get_user_roll());
846 pos.setLatitudeDeg(_offsetpos.getLatitudeDeg());
847 pos.setLongitudeDeg(_offsetpos.getLongitudeDeg());
848 pos.setElevationFt(_offsetpos.getElevationFt());
849
850 if (getHtAGL(10000.0)) {
851 double deadzone = 0.1;
852
853 if (_ht_agl_ft <= (0 + _ground_offset + deadzone) && _solid) {
854 pos.setElevationFt(0 + _ground_offset);
855 }
856 else {
857 pos.setElevationFt(_offsetpos.getElevationFt() + _load_offset);
858 }
859 }
860 }
861 else {
862 pos.setLatitudeDeg( pos.getLatitudeDeg()
863 + (speed_north_deg_sec - wind_speed_from_north_deg_sec
864 + force_speed_north_deg_sec + friction_force_speed_north_deg_sec) * dt );
865 pos.setLongitudeDeg( pos.getLongitudeDeg()
866 + (speed_east_deg_sec - wind_speed_from_east_deg_sec
867 + force_speed_east_deg_sec + friction_force_speed_east_deg_sec) * dt );
868 pos.setElevationFt(pos.getElevationFt() + vs_fps * dt);
869 }
870
871// cout << _name << " run hs " << hs << " vs " << vs << endl;
872
873 // recalculate total speed
874 if ( vs_fps == 0 && hs == 0)
875 speed = 0;
876 else
877 speed = sqrt( vs_fps * vs_fps + hs * hs) / SG_KT_TO_FPS;
878
879 // recalculate elevation and azimuth (velocity vectors)
880 _elevation = atan2( vs_fps, hs ) * SG_RADIANS_TO_DEGREES;
881 _azimuth = atan2((_speed_east_fps + force_speed_east_fps + friction_force_speed_east_fps),
882 (_speed_north_fps + force_speed_north_fps + friction_force_speed_north_fps))
883 * SG_RADIANS_TO_DEGREES;
884
885 // rationalise azimuth
886 if (_azimuth < 0)
887 _azimuth += 360;
888
889 if (_aero_stabilised) { // we simulate rotational moment of inertia by using a filter
890 //cout<< "_aero_stabilised " << hdg << " az " << _azimuth << endl;
891 const double coeff = 0.9;
892
893 // we assume a symmetrical MI about the pitch and yaw axis
894 setPch(_elevation, dt, coeff);
895 setHdg(_azimuth, dt, coeff);
896 }
897 else if (_force_stabilised) { // we simulate rotational moment of inertia by using a filter
898 //cout<< "_force_stabilised "<< endl;
899
900 const double coeff = 0.9;
901 double ratio = h_force_lbs/(_mass * slugs_to_lbs);
902
903 if (ratio > 1) ratio = 1;
904 if (ratio < -1) ratio = -1;
905
906 double force_pitch = acos(ratio) * SG_RADIANS_TO_DEGREES;
907
908 if (force_pitch <= force_elevation_deg)
909 force_pitch = force_elevation_deg;
910
911 // we assume a symmetrical MI about the pitch and yaw axis
912 setPch(force_pitch,dt, coeff);
913 setHdg(_azimuth, dt, coeff);
914 }
915
916 // Do impacts and collisions
917 if (_report_impact && !_impact_reported)
918 handle_impact();
919
920 if (_report_collision && !_collision_reported)
921 handle_collision();
922
923 // Set destruction flag if altitude less than sea level -1000
924 if (altitude_ft < -1000.0 && life != -1)
925 setDie(true);
926}
927
929 return _life_timer;
930}
931
933 _life_timer = s;
934}
935
936void FGAIBallistic::handleEndOfLife(double elevation) {
937 report_impact(elevation);
938
939 // Make the submodel invisible if the submodel is immortal, otherwise kill it if it has no subsubmodels
940 if (life == -1) {
941 invisible = true;
942 }
943 else if (_subID == 0) {
944 // Kill the AIObject if there is no subsubmodel
945 setDie(true);
946 }
947}
948
949void FGAIBallistic::handle_impact() {
950 // Try terrain intersection
951 double start = pos.getElevationM() + 100;
952
953 if (!getHtAGL(start))
954 return;
955
956 if (_ht_agl_ft <= 0) {
957 SG_LOG(SG_AI, SG_DEBUG, "AIBallistic: terrain impact material" << _mat_name);
958 _impact_reported = true;
959 handleEndOfLife(_elevation_m);
960 }
961}
962
963void FGAIBallistic::handle_expiry() {
964 _expiry_reported = true;
965 handleEndOfLife(pos.getElevationM());
966}
967
968void FGAIBallistic::handle_collision()
969{
970 const FGAIBase *object = manager->calcCollision(pos.getElevationFt(),
971 pos.getLatitudeDeg(),pos.getLongitudeDeg(), _fuse_range);
972
973 if (object) {
974 report_impact(pos.getElevationM(), object);
975 _collision_reported = true;
976 }
977}
978
979void FGAIBallistic::report_impact(double elevation, const FGAIBase *object)
980{
981 _impact_lat = pos.getLatitudeDeg();
982 _impact_lon = pos.getLongitudeDeg();
984 _impact_speed = speed * SG_KT_TO_MPS;
988
989 SGPropertyNode *n = props->getNode("impact", true);
990
991 if (object)
992 n->setStringValue("type", static_cast<std::string>(object->getTypeString()));
993 else
994 n->setStringValue("type", "terrain");
995
996 SG_LOG(SG_AI, SG_DEBUG, "AIBallistic: object impact " << _name
997 << " lon " <<_impact_lon << " lat " <<_impact_lat << " sec " << _life_timer);
998
999 n->setDoubleValue("longitude-deg", _impact_lon);
1000 n->setDoubleValue("latitude-deg", _impact_lat);
1001 n->setDoubleValue("elevation-m", _impact_elev);
1002 n->setDoubleValue("heading-deg", _impact_hdg);
1003 n->setDoubleValue("pitch-deg", _impact_pitch);
1004 n->setDoubleValue("roll-deg", _impact_roll);
1005 n->setDoubleValue("speed-mps", _impact_speed);
1006
1007 _impact_report_node->setStringValue(props->getPath());
1008}
1009
1011 // convert geodetic positions to geocentered
1012 SGVec3d cartuserPos = globals->get_aircraft_position_cart();
1013
1014 //SGVec3d cartPos = getCartPos();
1015
1016 // Transform to the right coordinate frame, configuration is done in
1017 // the x-forward, y-right, z-up coordinates (feet), computation
1018 // in the simulation usual body x-forward, y-right, z-down coordinates
1019 // (meters) )
1020 SGVec3d _off(_x_offset * SG_FEET_TO_METER,
1021 _y_offset * SG_FEET_TO_METER,
1022 -_z_offset * SG_FEET_TO_METER);
1023
1024 // Transform the user position to the horizontal local coordinate system.
1025 SGQuatd hlTrans = SGQuatd::fromLonLat(globals->get_aircraft_position());
1026
1027 // and postrotate the orientation of the user model wrt the horizontal
1028 // local frame
1029 hlTrans *= SGQuatd::fromYawPitchRollDeg(
1030 manager->get_user_heading(),
1031 manager->get_user_pitch(),
1032 manager->get_user_roll());
1033
1034 // The offset converted to the usual body fixed coordinate system
1035 // rotated to the earth-fixed coordinates axis
1036 SGVec3d off = hlTrans.backTransform(_off);
1037
1038 // Add the position offset of the user model to get the geocentered position
1039 SGVec3d offsetPos = cartuserPos + off;
1040 return offsetPos;
1041}
1042
1043void FGAIBallistic::setOffsetPos(SGGeod inpos, double heading, double pitch, double roll) {
1044 // Convert the hitch geocentered position to geodetic
1045 SGVec3d cartoffsetPos = getCartOffsetPos(inpos, heading, pitch, roll);
1046 SGGeodesy::SGCartToGeod(cartoffsetPos, _offsetpos);
1047}
1048
1050 //calculate the distance load to hitch
1051 SGVec3d carthitchPos = getCartHitchPos();
1052 SGVec3d cartPos = getCartPos();
1053
1054 SGVec3d diff = carthitchPos - cartPos;
1055 double distance = norm(diff);
1056 return distance * SG_METER_TO_FEET;
1057}
1058
1060 // now the angle, positive angles are upwards
1061 double distance = getDistanceToHitch() * SG_FEET_TO_METER;
1062 double angle = 0;
1063 double daltM = _offsetpos.getElevationM() - pos.getElevationM();
1064
1065 if (fabs(distance) < SGLimits<float>::min()) {
1066 angle = 0;
1067 } else {
1068 double sAngle = daltM/distance;
1069 sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle));
1070 angle = SGMiscd::rad2deg(asin(sAngle));
1071 }
1072
1073 return angle;
1074}
1075
1077 //calculate the bearing and range of the second pos from the first
1078 double distance = getDistanceToHitch() * SG_FEET_TO_METER;
1079 double az1, az2;
1080
1081 geo_inverse_wgs_84(pos, _offsetpos, &az1, &az2, &distance);
1082
1083 return az1;
1084}
1085
1087 //calculate the relative bearing
1088 double az1, az2, distance;
1089
1090 geo_inverse_wgs_84(_offsetpos, globals->get_aircraft_position(), &az1, &az2, &distance);
1091
1092 double rel_brg = az1 - hdg;
1093
1094 SG_NORMALIZE_RANGE(rel_brg, -180.0, 180.0);
1095
1096 return rel_brg;
1097}
1098
1100 // Calculate the distance from the user position
1101 SGVec3d carthitchPos = getCartHitchPos();
1102 SGVec3d cartuserPos = globals->get_aircraft_position_cart();
1103
1104 SGVec3d diff = cartuserPos - carthitchPos;
1105
1106 double distance = norm(diff);
1107 double angle = 0;
1108
1109 double daltM = globals->get_aircraft_position().getElevationM() - _offsetpos.getElevationM();
1110
1111 // Now the angle, positive angles are upwards
1112 if (fabs(distance) < SGLimits<float>::min()) {
1113 angle = 0;
1114 }
1115 else {
1116 double sAngle = daltM/distance;
1117 sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle));
1118 angle = SGMiscd::rad2deg(asin(sAngle));
1119 }
1120
1121 return angle;
1122}
1123
1124void FGAIBallistic::setTgtOffsets(double dt, double coeff) {
1125 double c = dt / (coeff + dt);
1126
1127 _x_offset = (_tgt_x_offset * c) + (_x_offset * (1 - c));
1128 _y_offset = (_tgt_y_offset * c) + (_y_offset * (1 - c));
1129 _z_offset = (_tgt_z_offset * c) + (_z_offset * (1 - c));
1130}
1131
1132void FGAIBallistic::calcVSHS() {
1133 // Calculate vertical and horizontal speed components
1134 double speed_fps = speed * SG_KT_TO_FPS;
1135
1136 if (speed == 0.0) {
1137 hs = vs_fps = 0.0;
1138 }
1139 else {
1140 vs_fps = sin( _elevation * SG_DEGREES_TO_RADIANS ) * speed_fps;
1141 hs = cos( _elevation * SG_DEGREES_TO_RADIANS ) * speed_fps;
1142 }
1143}
1144
1145void FGAIBallistic::calcNE() {
1146 // Resolve horizontal speed into north and east components:
1147 _speed_north_fps = cos(_azimuth / SG_RADIANS_TO_DEGREES) * hs;
1148 _speed_east_fps = sin(_azimuth / SG_RADIANS_TO_DEGREES) * hs;
1149
1150 // Convert horizontal speed (fps) to degrees per second
1153}
1154
1155SGVec3d FGAIBallistic::getCartOffsetPos(SGGeod inpos, double user_heading,
1156 double user_pitch, double user_roll
1157 ) const {
1158 // Convert geodetic positions to geocentered
1159 SGVec3d cartuserPos = SGVec3d::fromGeod(inpos);
1160
1161 // Transform to the right coordinate frame, configuration is done in
1162 // the x-forward, y-right, z-up coordinates (feet), computation
1163 // in the simulation usual body x-forward, y-right, z-down coordinates
1164 // (meters) )
1165 SGVec3d _off(_x_offset * SG_FEET_TO_METER,
1166 _y_offset * SG_FEET_TO_METER,
1167 -_z_offset * SG_FEET_TO_METER);
1168
1169 // Transform the user position to the horizontal local coordinate system.
1170 SGQuatd hlTrans = SGQuatd::fromLonLat(inpos);
1171
1172 // And postrotate the orientation of the user model wrt the horizontal
1173 // local frame
1174 hlTrans *= SGQuatd::fromYawPitchRollDeg(
1175 user_heading,
1176 user_pitch,
1177 user_roll);
1178
1179 // The offset converted to the usual body fixed coordinate system
1180 // rotated to the earth-fixed coordinates axis
1181 SGVec3d off = hlTrans.backTransform(_off);
1182
1183 // Add the position offset of the user model to get the geocentered position
1184 SGVec3d offsetPos = cartuserPos + off;
1185
1186 return offsetPos;
1187}
1188
1189void FGAIBallistic::setOffsetVelocity(double dt, SGGeod offsetpos) {
1190 // Calculate the distance from the previous offset position
1191 SGVec3d cartoffsetPos = SGVec3d::fromGeod(offsetpos);
1192 SGVec3d diff = cartoffsetPos - _oldcartoffsetPos;
1193
1194 double distance = norm(diff);
1195 // Calculate speed knots
1196 speed = (distance / dt) * SG_MPS_TO_KT;
1197
1198 // Now calulate the angle between the old and current postion positions (degrees)
1199 double angle = 0;
1200 double daltM = offsetpos.getElevationM() - _oldoffsetpos.getElevationM();
1201
1202 if (fabs(distance) < SGLimits<float>::min()) {
1203 angle = 0;
1204 }
1205 else {
1206 double sAngle = daltM / distance;
1207 sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle));
1208 angle = SGMiscd::rad2deg(asin(sAngle));
1209 }
1210
1211 _elevation = angle;
1212
1213 // Calculate vertical and horizontal speed components
1214 calcVSHS();
1215
1216 // Calculate the bearing of the new offset position from the old
1217 // Don't do this if speed is low
1218 //cout << "speed " << speed << endl;
1219 if (speed > 0.1) {
1220 double az1, az2, dist;
1221 geo_inverse_wgs_84(_oldoffsetpos, offsetpos, &az1, &az2, &dist);
1222 _azimuth = az1;
1223 //cout << "offset az " << _azimuth << endl;
1224 }
1225 else {
1226 _azimuth = hdg;
1227 //cout << " slow offset az " << _azimuth << endl;
1228 }
1229
1230 // Resolve horizontal speed into north and east components
1231 calcNE();
1232
1233 // And finally store the new values
1234 _oldcartoffsetPos = cartoffsetPos;
1235 _oldoffsetpos = offsetpos;
1236}
#define p(x)
#define i(x)
static const Gravity * instance()
Definition gravity.cxx:80
virtual double getGravity(const SGGeod &position) const =0
void update(double dt) override
SGPropertyNode_ptr _p_lat_node
void setMass(double m)
bool init(ModelSearchOrder searchOrder) override
bool getSlavedLoad() const
void setTgtXOffset(double x)
void setTime(double sec)
void setSlavedLoad(bool s)
double getLoadOffset() const
SGPropertyNode_ptr _force_elevation_node
void setTgtZOffset(double z)
void readFromScenario(SGPropertyNode *scFileNode) override
void setOffsetVelocity(double dt, SGGeod pos)
double getTgtYOffset() const
SGPropertyNode_ptr _p_rll_node
void setSlaved(bool s)
SGPropertyNode_ptr _p_vel_node
double _speed_east_fps
void setImpactReportNode(const std::string &)
void setNoRoll(bool nr)
void setSubmodel(const std::string &)
SGPropertyNode_ptr _p_lon_node
void setParentNodes(const SGPropertyNode_ptr)
SGPropertyNode_ptr _p_spd_node
bool getHtAGL(double start)
void setFuseRange(double f)
double getTgtXOffset() const
void setDragArea(double a)
void setExpiry(bool e)
void setBnk(double r, double dt, double c)
void setStabilisation(bool val)
static const double slugs_to_kgs
void setLifeRandomness(double randomness)
void setSpd(double s, double dt, double c)
double _wind_from_north
SGVec3d getCartHitchPos() const
double _wind_from_east
double _speed_north_fps
int setHdg(double az, double dt, double c)
void setWind_from_east(double fps)
void setTgtYOffset(double y)
void setForcePath(const std::string &)
void setLife(double seconds)
SGPropertyNode_ptr _p_ori_node
SGPropertyNode_ptr _force_node
void setOffsetPos(SGGeod pos, double heading, double pitch, double roll)
void setPch(double e, double dt, double c)
double getBearingToHitch() const
void setWeight(double w)
double getElevHitchToUser() const
SGPropertyNode_ptr _p_pos_node
void setSubID(int i)
void setHt(double h, double dt, double c)
void setContentsNode(const SGPropertyNode_ptr)
double getTgtZOffset() const
void setCollision(bool c)
double getRelBrgHitchToUser() const
static const double slugs_to_lbs
double _getTime() const
void setRandom(bool r)
bool getSlaved() const
void Run(double dt)
void reinit() override
SGPropertyNode_ptr _p_pch_node
double getElevToHitch() const
void setSMPath(const std::string &)
void setTgtOffsets(double dt, double c)
void setAzimuth(double az)
void setLoadOffset(double l)
double getDistanceToHitch() const
void setForceStabilisation(bool val)
void setElevation(double el)
void setCd(double cd)
double getContents()
void setGroundOffset(double g)
void setContentsPath(const std::string &)
SGPropertyNode_ptr _p_hdg_node
void setCdRandomness(double randomness)
void setWind(bool val)
void setAzimuthRandomError(double error)
SGPropertyNode_ptr _force_azimuth_node
void setWind_from_north(double fps)
void setExternalForce(bool f)
SGPropertyNode_ptr _p_alt_node
SGPropertyNode_ptr _pnode
void setImpact(bool i)
void setElevationRandomError(double error)
SGPropertyNode_ptr _p_agl_node
void setRoll(double rl)
FGAIBallistic(object_type ot=object_type::otBallistic)
void setBuoyancy(double fpss)
void bind() override
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
int _subID
Definition AIBase.hxx:260
double speed_fps
Definition AIBase.hxx:217
simgear::TiedPropertyList _tiedProperties
Definition AIBase.hxx:203
double altitude_ft
Definition AIBase.hxx:218
SGGeod pos
Definition AIBase.hxx:212
virtual void readFromScenario(SGPropertyNode *scFileNode)
Definition AIBase.cxx:249
double _getElevationFt() const
Definition AIBase.cxx:1002
void setDie(bool die)
Definition AIBase.hxx:506
SGVec3d getCartPos() const
Definition AIBase.cxx:899
void setParentName(const std::string &p)
Definition AIBase.hxx:486
double _getLatitude() const
Definition AIBase.cxx:998
void _setAltitude(double _alt)
Definition AIBase.cxx:1044
void setYoffset(double y_offset)
Definition AIBase.hxx:461
std::string _name
Definition AIBase.hxx:190
double _getCartPosX() const
Definition AIBase.cxx:926
bool invisible
Definition AIBase.hxx:256
double _impact_elev
Definition AIBase.hxx:272
bool _impact_reported
Definition AIBase.hxx:266
FGAIBase(object_type ot, bool enableHot)
Definition AIBase.cxx:146
bool _expiry_reported
Definition AIBase.hxx:268
double _pitch_offset
Definition AIBase.hxx:178
double _impact_pitch
Definition AIBase.hxx:274
bool getGroundElevationM(const SGGeod &pos, double &elev, const simgear::BVHMaterial **material) const
Definition AIBase.cxx:904
void setBank(double bank)
Definition AIBase.hxx:430
SGPropertyNode_ptr _selected_ac
Definition AIBase.hxx:204
double _x_offset
Definition AIBase.hxx:174
double _getCartPosY() const
Definition AIBase.cxx:931
virtual bool init(ModelSearchOrder searchOrder)
Definition AIBase.cxx:633
virtual void update(double dt)
Definition AIBase.cxx:294
double speed
Definition AIBase.hxx:216
double _impact_speed
Definition AIBase.hxx:276
bool _collision_reported
Definition AIBase.hxx:267
void setZoffset(double z_offset)
Definition AIBase.hxx:466
double _impact_roll
Definition AIBase.hxx:275
double _getCartPosZ() const
Definition AIBase.cxx:936
double _getLongitude() const
Definition AIBase.cxx:994
void _setLatitude(double latitude)
Definition AIBase.cxx:945
bool setParentNode()
Definition AIBase.cxx:953
double vs_fps
Definition AIBase.hxx:219
double hdg
Definition AIBase.hxx:213
double elevation
Definition AIBase.hxx:240
void Transform()
Definition AIBase.cxx:518
double _impact_lat
Definition AIBase.hxx:270
double _impact_lon
Definition AIBase.hxx:271
static const double e
Definition AIBase.hxx:359
double _z_offset
Definition AIBase.hxx:176
double pitch
Definition AIBase.hxx:215
std::string _path
Definition AIBase.hxx:187
double ft_per_deg_lon
Definition AIBase.hxx:225
double speed_east_deg_sec
Definition AIBase.hxx:221
ModelSearchOrder
Definition AIBase.hxx:63
std::string _submodel
Definition AIBase.hxx:189
virtual std::string_view getTypeString(void) const
Definition AIBase.hxx:301
double _y_offset
Definition AIBase.hxx:175
double ft_per_deg_lat
Definition AIBase.hxx:226
void setXoffset(double x_offset)
Definition AIBase.hxx:456
double _elevation_m
Definition AIBase.hxx:172
double life
Definition AIBase.hxx:262
void setYawoffset(double z_offset)
Definition AIBase.hxx:481
double _impact_hdg
Definition AIBase.hxx:273
void _setVS_fps(double _vs)
Definition AIBase.cxx:1022
void setHeading(double heading)
Definition AIBase.hxx:414
void _setLongitude(double longitude)
Definition AIBase.cxx:941
double speed_north_deg_sec
Definition AIBase.hxx:220
double _getVS_fps() const
Definition AIBase.cxx:1010
void setPitch(double newpitch)
Definition AIBase.hxx:436
double _roll_offset
Definition AIBase.hxx:179
virtual void reinit()
Definition AIBase.hxx:74
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
FGAIManager * manager
Definition AIBase.hxx:209
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
static double densityAtAltitudeFt(const double alt, const double Tsl=atmodel::ISA::T0)
static double machFromKnotsAtAltitudeFt(const double knots, const double altFt, const double Tsl=atmodel::ISA::T0)
SGGeod get_aircraft_position() const
Definition globals.cxx:611
FGGlobals * globals
Definition globals.cxx:142
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27