21#include <simgear/sg_inlines.h>
49 setName(scFileNode->getStringValue(
"name",
"groundvehicle"));
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));
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));
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",
86 SGRawValuePointer<double>(&_range_ft));
87 tie(
"hitch/x-offset-ft",
89 tie(
"hitch/y-offset-ft",
91 tie(
"hitch/z-offset-ft",
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));
121 props->setStringValue(
"controls/parent-name",
_parent.c_str());
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")
129 _hitch_y_offset_m =
_selected_ac->getDoubleValue(
"hitch/y-offset-ft")
131 _hitch_z_offset_m =
_selected_ac->getDoubleValue(
"hitch/z-offset-ft")
143 RunGroundVehicle(dt);
146void FGAIGroundVehicle::setNoRoll(
bool nr) {
150void FGAIGroundVehicle::setContactX1offset(
double x1) {
151 _contact_x1_offset = x1;
154void FGAIGroundVehicle::setContactX2offset(
double x2) {
155 _contact_x2_offset = x2;
158void FGAIGroundVehicle::setXOffset(
double x) {
162void FGAIGroundVehicle::setYOffset(
double y) {
166void FGAIGroundVehicle::setZOffset(
double z) {
170void FGAIGroundVehicle::setPitchCoeff(
double pc) {
174void FGAIGroundVehicle::setElevCoeff(
double ec) {
175 _elevation_coeff = ec;
178void FGAIGroundVehicle::setTowAngleGain(
double g) {
182void FGAIGroundVehicle::setTowAngleLimit(
double l) {
183 _tow_angle_limit = l;
186void FGAIGroundVehicle::setElevation(
double h,
double dt,
double coeff){
187 double c = dt / (coeff + dt);
191void FGAIGroundVehicle::setPitch(
double p,
double dt,
double coeff){
192 double c = dt / (coeff + dt);
193 _pitch_deg = (
p * c) + (_pitch_deg * (1 - c));
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;
205bool FGAIGroundVehicle::getPitch() {
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;
212 SGVec3d front(-contact_offset_x1_m, 0, 0);
213 SGVec3d rear(-contact_offset_x2_m, 0, 0);
217 SGGeod geodFront = SGGeod::fromCart(Front);
218 SGGeod geodRear = SGGeod::fromCart(Rear);
220 double front_elev_m = 0;
221 double rear_elev_m = 0;
222 double elev_front = 0;
223 double elev_rear = 0;
226 elev_front, NULL, 0)){
227 front_elev_m = elev_front + _z_offset_m;
232 elev_rear, NULL, 0)){
233 rear_elev_m = elev_rear;
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;
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;
251 if (
prev->getAltitude() == 0 ||
curr->getAltitude() == 0)
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;
263 double distance_to_go = SGGeodesy::distanceM(SGGeod::fromDeg(
pos.getLongitudeDeg(),
pos.getLatitudeDeg()),
264 SGGeod::fromDeg(
curr->getLongitude(),
curr->getLatitude()));
266 if (distance_to_go > _tunnel_distance)
267 _elevation = _tunnel_start_alt;
269 _elevation = _tunnel_end_alt - (tan(_pitch * SG_DEGREES_TO_RADIANS) * distance_to_go * SG_METER_TO_FEET);
275void FGAIGroundVehicle::setParent(){
277 double lat =
_selected_ac->getDoubleValue(
"position/latitude-deg");
278 double lon =
_selected_ac->getDoubleValue(
"position/longitude-deg");
281 _selectedpos.setLatitudeDeg(lat);
282 _selectedpos.setLongitudeDeg(lon);
285 _parent_speed =
_selected_ac->getDoubleValue(
"velocities/true-airspeed-kt");
287 SGVec3d rear_hitch(-_hitch_x_offset_m, _hitch_y_offset_m, 0);
288 SGVec3d RearHitch = getCartHitchPosAt(rear_hitch);
290 SGGeod rearpos = SGGeod::fromCart(RearHitch);
292 double user_lat = rearpos.getLatitudeDeg();
293 double user_lon = rearpos.getLongitudeDeg();
297 calcRangeBearing(
pos.getLatitudeDeg(),
pos.getLongitudeDeg(),
299 _range_ft =
range * 6076.11549;
303void FGAIGroundVehicle::calcRangeBearing(
double lat,
double lon,
double lat2,
double lon2,
304 double &range,
double &bearing)
const
307 double az2, distance;
308 geo_inverse_wgs_84(lat, lon, lat2, lon2, &
bearing, &az2, &distance);
309 range = distance * SG_METER_TO_NM;
313SGVec3d FGAIGroundVehicle::getCartHitchPosAt(
const SGVec3d& _off)
const {
314 double hdg =
_selected_ac->getDoubleValue(
"orientation/true-heading-deg");
319 SGQuatd hlTrans = SGQuatd::fromLonLat(_selectedpos);
323 hlTrans *= SGQuatd::fromYawPitchRollDeg(
hdg,
pitch,
roll);
327 SGVec3d off = hlTrans.backTransform(_off);
330 SGVec3d cartPos = SGVec3d::fromGeod(_selectedpos);
332 return cartPos + off;
335void FGAIGroundVehicle::AdvanceFP(){
338 string parent_next_name =
_selected_ac->getStringValue(
"waypoint/name-next");
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);
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());
351 fp->IncrementWaypoint(
false);
352 curr =
fp->getCurrentWaypoint();
353 next =
fp->getNextWaypoint();
355 if (
fp->getNextWaypoint()->getName() == parent_next_name){
356 SG_LOG(SG_AI, SG_DEBUG,
"AIGroundVeh1cle: " <<
_name
357 <<
" waypoint set to: " <<
fp->getNextWaypoint()->getName());
365 while(
fp->getPreviousWaypoint() != 0 &&
fp->getPreviousWaypoint()->getName() !=
"END"
367 SG_LOG(SG_AI, SG_DEBUG,
"AIGroundVeh1cle: " <<
_name
368 <<
" retreating waypoint to: " << parent_next_name
369 <<
" at: " <<
fp->getNextWaypoint()->getName());
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() );
378 fp->DecrementWaypoint();
379 curr =
fp->getCurrentWaypoint();
380 next =
fp->getNextWaypoint();
382 if (
fp->getNextWaypoint()->getName() == parent_next_name){
383 SG_LOG(SG_AI, SG_DEBUG,
"AIGroundVeh1cle: " <<
_name
384 <<
" waypoint set to: " <<
fp->getNextWaypoint()->getName());
393void FGAIGroundVehicle::setTowSpeed(){
400 if (_relbrg < -90 || _relbrg > 90) {
403 }
else if (_range_ft >
_x_offset + 0.25) {
407 }
else if (_range_ft <
_x_offset - 0.25) {
417void FGAIGroundVehicle::RunGroundVehicle(
double dt){
435 setElevation(_elevation,
_dt_count, _elevation_coeff);
437 setPitch(_pitch,
_dt_count, _pitch_coeff);
449 string parent_next_name =
_selected_ac->getStringValue(
"waypoint/name-next");
450 bool parent_waiting =
_selected_ac->getBoolValue(
"waypoint/waiting");
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 ");
461 }
else if (parent_waiting && !
_waiting){
462 SG_LOG(SG_AI, SG_DEBUG,
"AIGroundVeh1cle: " <<
_name
463 <<
" setting WAIT/WAITUNTIL: getting new waypoints ");
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 ");
472 fp->IncrementWaypoint(
false);
473 next =
fp->getNextWaypoint();
475 if (
next->getName() ==
"WAITUNTIL" ||
next->getName() ==
"WAIT"
476 ||
next->getName() ==
"END"){
479 fp->IncrementWaypoint(
false);
480 curr =
fp->getCurrentWaypoint();
481 next =
fp->getNextWaypoint();
485 }
else if (_range_ft > (
_x_offset +_parent_x_offset)* 4
487 SG_LOG(SG_AI, SG_ALERT,
"AIGroundVeh1cle: " <<
_name
488 <<
" rescue: reforming train " << _range_ft
491 setTowAngle(0, dt, 1);
494 }
else if (_parent_speed > 1){
497 setTowAngle(_relbrg, dt, 1);
499 }
else if (_parent_speed < -1){
504 setTowAngle(-(180 - (360 + _relbrg)), dt, 1);
506 setTowAngle(-(180 - _relbrg), dt, 1);
void setSpeed(double speed_KTAS)
void setName(const std::string &n)
void setParentName(const std::string &p)
SGVec3d getCartPosAt(const SGVec3d &off) const
SGPropertyNode_ptr _selected_ac
std::unique_ptr< FGAIFlightPlan > fp
double calcRelBearingDeg(double bearing, double heading)
void setYawoffset(double z_offset)
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
void readFromScenario(SGPropertyNode *scFileNode) override
bool init(ModelSearchOrder searchOrder) override
void readFromScenario(SGPropertyNode *scFileNode) override
void PitchTo(double angle)
void ClimbTo(double altitude)
void update(double dt) override
void AccelTo(double speed)
FGAIShip(object_type ot=object_type::otShip)
bool init(ModelSearchOrder searchOrder) override
void setInitialTunnel(bool t)
FGScenery * get_scenery() const
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 ...