24#include <simgear/sg_inlines.h>
53 setAzimuth(scFileNode->getDoubleValue(
"azimuth", 0.0));
54 setElevation(scFileNode->getDoubleValue(
"elevation", 0.0));
55 setLife(scFileNode->getDoubleValue(
"life", -1));
56 setNoRoll(scFileNode->getBoolValue(
"no-roll",
false));
57 setName(scFileNode->getStringValue(
"name",
"Wingman"));
59 setSubID(scFileNode->getIntValue(
"SubID", 0));
60 setXoffset(scFileNode->getDoubleValue(
"x-offset", 0.0));
61 setYoffset(scFileNode->getDoubleValue(
"y-offset", 0.0));
62 setZoffset(scFileNode->getDoubleValue(
"z-offset", 0.0));
64 setRolloffset(scFileNode->getDoubleValue(
"roll-offset", 0.0));
65 setYawoffset(scFileNode->getDoubleValue(
"yaw-offset", 0.0));
67 setFormate(scFileNode->getBoolValue(
"formate",
true));
68 setMaxSpeed(scFileNode->getDoubleValue(
"max-speed-kts", 300.0));
69 setCoeffHdg(scFileNode->getDoubleValue(
"coefficients/heading", 5.0));
70 setCoeffPch(scFileNode->getDoubleValue(
"coefficients/pitch", 5.0));
71 setCoeffBnk(scFileNode->getDoubleValue(
"coefficients/bank", 4.0));
72 setCoeffSpd(scFileNode->getDoubleValue(
"coefficients/speed", 2.0));
80 props->untie(
"controls/slave-to-ac");
82 tie(
"id", SGRawValueMethods<FGAIBase,int>(*
this,
84 tie(
"subID", SGRawValueMethods<FGAIBase,int>(*
this,
86 tie(
"position/altitude-ft",
87 SGRawValueMethods<FGAIBase,double>(*
this,
90 tie(
"position/latitude-deg",
91 SGRawValueMethods<FGAIBase,double>(*
this,
94 tie(
"position/longitude-deg",
95 SGRawValueMethods<FGAIBase,double>(*
this,
99 tie(
"controls/break", SGRawValuePointer<bool>(&_break));
100 tie(
"controls/join", SGRawValuePointer<bool>(&_join));
102 tie(
"controls/formate-to-ac",
103 SGRawValueMethods<FGAIWingman,bool>
104 (*
this, &FGAIWingman::getFormate, &FGAIWingman::setFormate));
105 tie(
"controls/tgt-heading-deg",
106 SGRawValueMethods<FGAIWingman,double>
107 (*
this, &FGAIWingman::getTgtHdg, &FGAIWingman::setTgtHdg));
108 tie(
"controls/tgt-speed-kt",
109 SGRawValueMethods<FGAIWingman,double>
110 (*
this, &FGAIWingman::getTgtSpd, &FGAIWingman::setTgtSpd));
111 tie(
"controls/break-deg-rel",
112 SGRawValueMethods<FGAIWingman,double>
113 (*
this, &FGAIWingman::getBrkAng, &FGAIWingman::setBrkAng));
114 tie(
"controls/coefficients/heading",
115 SGRawValuePointer<double>(&_coeff_hdg));
116 tie(
"controls/coefficients/pitch",
117 SGRawValuePointer<double>(&_coeff_pch));
118 tie(
"controls/coefficients/bank",
119 SGRawValuePointer<double>(&_coeff_bnk));
120 tie(
"controls/coefficients/speed",
121 SGRawValuePointer<double>(&_coeff_spd));
123 tie(
"orientation/pitch-deg", SGRawValuePointer<double>(&
pitch));
124 tie(
"orientation/roll-deg", SGRawValuePointer<double>(&
roll));
125 tie(
"orientation/true-heading-deg", SGRawValuePointer<double>(&
hdg));
127 tie(
"submodels/serviceable", SGRawValuePointer<bool>(&
serviceable));
129 tie(
"load/rel-brg-to-user-deg",
130 SGRawValueMethods<FGAIBallistic,double>
132 tie(
"load/elev-to-user-deg",
133 SGRawValueMethods<FGAIBallistic,double>
136 tie(
"velocities/vertical-speed-fps",
138 tie(
"velocities/true-airspeed-kt",
139 SGRawValuePointer<double>(&
speed));
140 tie(
"velocities/speed-east-fps",
142 tie(
"velocities/speed-north-fps",
145 tie(
"position/x-offset",
147 tie(
"position/y-offset",
149 tie(
"position/z-offset",
151 tie(
"position/tgt-x-offset",
153 tie(
"position/tgt-y-offset",
155 tie(
"position/tgt-z-offset",
185 props->setStringValue(
"submodels/path",
_path.c_str());
186 user_WoW_node =
fgGetNode(
"gear/gear[1]/wow",
true);
198 setBrkHdg(_break_angle);
214double FGAIWingman::calcDistanceM(SGGeod pos1, SGGeod pos2)
const {
216 SGVec3d cartPos1 = SGVec3d::fromGeod(pos1);
217 SGVec3d cartPos2 = SGVec3d::fromGeod(pos2);
219 SGVec3d diff = cartPos1 - cartPos2;
220 double distance = norm(diff);
224double FGAIWingman::calcAngle(
double range, SGGeod pos1, SGGeod pos2){
227 double distance = calcDistanceM(pos1, pos2);
228 double daltM = pos1.getElevationM() - pos2.getElevationM();
230 if (fabs(distance) < SGLimits<float>::min()) {
233 double sAngle = daltM/
range;
234 sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle));
235 angle = SGMiscd::rad2deg(asin(sAngle));
241void FGAIWingman::formateToAC(
double dt){
243 double p_hdg, p_pch, p_rll, p_agl, p_ht, p_wow = 0;
256 p_hdg =
manager->get_user_heading();
257 p_pch =
manager->get_user_pitch();
258 p_rll =
manager->get_user_roll();
271 double r_angle = 5 * factor;
272 double p_angle = 2.5 * factor;
273 double h_angle = 5 * factor;
274 double h_feet = 3 * factor;
276 p_agl =
manager->get_user_agl();
277 p_wow = user_WoW_node->getDoubleValue();
279 if(p_agl <= 10 || p_wow == 1) {
281 }
else if (p_agl <= 150 ) {
282 setHt(p_ht, dt, 1.0);
283 }
else if (p_agl <= 250) {
295 if(
speed >= 10 && p_wow != 1) {
296 setHdg(p_hdg + h_angle, dt, 0.9);
313void FGAIWingman::Break(
double dt) {
319 int turn = SGMiscd::sign(rel_brg);
323 setPch(0, dt, _coeff_pch);
326 setBnk(45 * turn , dt, _coeff_bnk);
328 setBnk(0, dt, _coeff_bnk);
332void FGAIWingman::Join(
double dt) {
335 double parent_hdg, parent_spd = 0;
336 double p_hdg, p_pch, p_rll = 0;
349 p_hdg =
manager->get_user_heading();
350 p_pch =
manager->get_user_pitch();
351 p_rll =
manager->get_user_roll();
353 parent_hdg =
manager->get_user_heading();
354 parent_spd =
manager->get_user_speed();
360 double daltM =
_offsetpos.getElevationM() -
pos.getElevationM();
362 double hdg_l_lim = parent_hdg - limit;
363 SG_NORMALIZE_RANGE(hdg_l_lim, 0.0, 360.0);
364 double hdg_r_lim = parent_hdg + limit;
365 SG_NORMALIZE_RANGE(hdg_r_lim, 0.0, 360.0);
367 if (distance <= 2 && fabs(daltM) <= 2 &&
368 (
hdg >= hdg_l_lim ||
hdg <= hdg_r_lim)){
370 _formate_to_ac =
true;
373 SG_LOG(SG_AI, SG_ALERT,
_name <<
" joined " <<
" RANGE " << distance
374 <<
" SPEED " <<
speed );
386 double join_rnge = 1000.0;
388 int turn = SGMiscd::sign(rel_brg);
390 if (
range <= join_rnge && (
hdg >= hdg_l_lim ||
hdg <= hdg_r_lim)){
394 if ((rel_brg <= -175 || rel_brg >= 175) &&
range <=10 ){
397 setHdg(recip_brg, dt, _coeff_hdg);
398 setPch(angle, dt, _coeff_pch);
401 }
else if (rel_brg >= -5 && rel_brg <= 5) {
406 setPch(angle, dt, _coeff_pch);
409 }
else if (
range <=10 ){
411 setSpd(parent_spd , dt, 2.0);
413 setHdg(parent_hdg + (5 * turn), dt, _coeff_hdg);
418 setSpd(parent_spd , dt, 2.0);
420 setHdg(recip_brg, dt, _coeff_hdg);
425 }
else if (
range <= join_rnge) {
427 setSpd(parent_spd , dt, 2.0);
429 setHdg(recip_brg , dt, _coeff_hdg);
434 }
else if (
range > join_rnge &&
range <= 2000 ){
438 setSpd(parent_spd + frm_spd, dt, 2.0);
441 setPch(angle, dt, _coeff_pch);
449 setPch(angle, dt, _coeff_pch);
457 setBnk(45 * turn , dt, _coeff_bnk);
459 setBnk(0, dt, _coeff_bnk);
463void FGAIWingman::Run(
double dt) {
481 double speed_north_fps = cos(
hdg / SG_RADIANS_TO_DEGREES) *
hs;
482 double speed_east_fps = sin(
hdg / SG_RADIANS_TO_DEGREES) *
hs;
497 hs = sqrt(((speed_north_fps) * (speed_north_fps))
498 + ((speed_east_fps)* (speed_east_fps )));
508 pos.setLatitudeDeg(
pos.getLatitudeDeg()
510 pos.setLongitudeDeg(
pos.getLongitudeDeg()
524 hdg = atan2((speed_east_fps),(speed_north_fps))* SG_RADIANS_TO_DEGREES;
527 SG_NORMALIZE_RANGE(
hdg, 0.0, 360.0);
bool init(ModelSearchOrder searchOrder) override
void setTgtXOffset(double x)
void setTgtZOffset(double z)
void setOffsetVelocity(double dt, SGGeod pos)
double getTgtYOffset() const
SGPropertyNode_ptr _p_rll_node
void setParentNodes(const SGPropertyNode_ptr)
SGPropertyNode_ptr _p_spd_node
double getTgtXOffset() const
void setBnk(double r, double dt, double c)
void setSpd(double s, double dt, double c)
int setHdg(double az, double dt, double c)
void setTgtYOffset(double y)
void setLife(double seconds)
void setOffsetPos(SGGeod pos, double heading, double pitch, double roll)
void setPch(double e, double dt, double c)
double getElevHitchToUser() const
void setHt(double h, double dt, double c)
double getTgtZOffset() const
double getRelBrgHitchToUser() const
SGPropertyNode_ptr _p_pch_node
void setTgtOffsets(double dt, double c)
void setAzimuth(double az)
void setElevation(double el)
void setGroundOffset(double g)
SGPropertyNode_ptr _p_hdg_node
SGPropertyNode_ptr _p_alt_node
SGPropertyNode_ptr _pnode
FGAIBallistic(object_type ot=object_type::otBallistic)
void setSpeed(double speed_KTAS)
void setName(const std::string &n)
void setMaxSpeed(double kts)
double _getZOffset() const
virtual void readFromScenario(SGPropertyNode *scFileNode)
double _getElevationFt() const
double _getYOffset() const
void setParentName(const std::string &p)
double _getLatitude() const
void _setAltitude(double _alt)
void setYoffset(double y_offset)
SGPropertyNode_ptr _selected_ac
virtual void update(double dt)
double _getXOffset() const
void setZoffset(double z_offset)
double _getLongitude() const
void _setLatitude(double latitude)
double speed_east_deg_sec
double calcRecipBearingDeg(double bearing)
double calcRelBearingDeg(double bearing, double heading)
void setXoffset(double x_offset)
void setYawoffset(double z_offset)
void _setVS_fps(double _vs)
void _setLongitude(double longitude)
double speed_north_deg_sec
double _getVS_fps() const
void tie(const char *aRelPath, const SGRawValue< T > &aRawValue)
Tied-properties helper, record nodes which are tied for easy un-tie-ing.
void setPitchoffset(double x_offset)
void setRolloffset(double y_offset)
void update(double dt) override
bool init(ModelSearchOrder searchOrder) override
void readFromScenario(SGPropertyNode *scFileNode) override
SGGeod get_aircraft_position() const
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.