FlightGear next
Hitch.cpp
Go to the documentation of this file.
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include "Math.hpp"
6#include "BodyEnvironment.hpp"
7#include "RigidBody.hpp"
8#include <string.h>
9#include <sstream>
10#include <simgear/constants.h>
11
12
13
14#include "Hitch.hpp"
15
16using std::vector;
17
18namespace yasim {
19Hitch::Hitch(const char *name)
20{
21 if (fgGetNode("/sim/hitches", true))
22 _node = fgGetNode("/sim/hitches", true)->getNode(name, true);
23 else _node = 0;
24 int i;
25 for(i=0; i<3; i++)
26 _pos[i] = _force[i] = _winchPos[i] = _mp_lpos[i]=_towEndForce[i]=_mp_force[i]=0;
27 for(i=0; i<2; i++)
28 _global_ground[i] = 0;
29 _global_ground[2] = 1;
30 _global_ground[3] = -1e5;
31 _forceMagnitude=0;
32 _open=true;
33 _oldOpen=_open;
34 _towLength=60;
35 _autoReleaseAngle=0;
36 _towElasticConstant=1e5;
37 _towBreakForce=100000;
38 _towWeightPerM=1;
39 _winchMaxSpeed=40;
40 _winchRelSpeed=0;
41 _winchInitialTowLength=1000;
42 _winchPower=100000;
43 _winchMaxForce=10000;
44 _winchActualForce=0;
45 _winchMaxTowLength=1000;
46 _winchMinTowLength=0;
47 _dist=0;
48 _towEndIsConnectedToProperty=false;
49 _towEndNode=0;
50 _nodeIsMultiplayer=false;
51 _nodeIsAiAircraft=false;
52 _forceIsCalculatedByMaster=false;
53 _nodeID=0;
54 //_ai_MP_callsign=0;
55 _height_above_ground=0;
56 _winch_height_above_ground=0;
57 _loPosFrac=0;
58 _lowest_tow_height=0;
59 _state=new State;
60 _displayed_len_lower_dist_message=false;
61 _last_wish=true;
62 _isSlave=false;
63 _mpAutoConnectPeriod=0;
64 _timeToNextAutoConnectTry=0;
65 _timeToNextReConnectTry=10;
66 _speed_in_tow_direction=0;
67 _mp_time_lag=1;
68 _mp_last_reported_dist=0;
69 _mp_last_reported_v=0;
70 _mp_is_slave=false;
71 _mp_open_last_state=false;
72 _timeLagCorrectedDist=0;
73
74 if (_node)
75 {
76#define TIE(x,v) _tiedProperties.Tie(_node->getNode(x, true),v)
77 TIE("tow/length", SGRawValuePointer<float>(&_towLength));
78 TIE("automatic-release-angle-deg",SGRawValuePointer<float>(&_autoReleaseAngle));
79 TIE("tow/elastic-constant",SGRawValuePointer<float>(&_towElasticConstant));
80 TIE("tow/weight-per-m-kg-m",SGRawValuePointer<float>(&_towWeightPerM));
81 TIE("tow/break-force",SGRawValuePointer<float>(&_towBreakForce));
82 TIE("winch/max-speed-m-s",SGRawValuePointer<float>(&_winchMaxSpeed));
83 TIE("winch/rel-speed",SGRawValuePointer<float>(&_winchRelSpeed));
84 TIE("winch/initial-tow-length-m",SGRawValuePointer<float>(&_winchInitialTowLength));
85 TIE("winch/min-tow-length-m",SGRawValuePointer<float>(&_winchMinTowLength));
86 TIE("winch/max-tow-length-m",SGRawValuePointer<float>(&_winchMaxTowLength));
87 TIE("winch/global-pos-x",SGRawValuePointer<double>(&_winchPos[0]));
88 TIE("winch/global-pos-y",SGRawValuePointer<double>(&_winchPos[1]));
89 TIE("winch/global-pos-z",SGRawValuePointer<double>(&_winchPos[2]));
90 TIE("winch/max-power",SGRawValuePointer<float>(&_winchPower));
91 TIE("winch/max-force",SGRawValuePointer<float>(&_winchMaxForce));
92 TIE("winch/actual-force",SGRawValuePointer<float>(&_winchActualForce));
93 TIE("tow/end-force-x",SGRawValuePointer<float>(&_reportTowEndForce[0]));
94 TIE("tow/end-force-y",SGRawValuePointer<float>(&_reportTowEndForce[1]));
95 TIE("tow/end-force-z",SGRawValuePointer<float>(&_reportTowEndForce[2]));
96 TIE("force",SGRawValuePointer<float>(&_forceMagnitude));
97 TIE("open",SGRawValuePointer<bool>(&_open));
98 TIE("force-is-calculated-by-other",SGRawValuePointer<bool>(&_forceIsCalculatedByMaster));
99 TIE("local-pos-x",SGRawValuePointer<float>(&_pos[0]));
100 TIE("local-pos-y",SGRawValuePointer<float>(&_pos[1]));
101 TIE("local-pos-z",SGRawValuePointer<float>(&_pos[2]));
102 TIE("tow/dist",SGRawValuePointer<float>(&_dist));
103 TIE("tow/dist-time-lag-corrected",SGRawValuePointer<float>(&_timeLagCorrectedDist));
104 TIE("tow/connected-to-property-node",SGRawValuePointer<bool>(&_towEndIsConnectedToProperty));
105 TIE("tow/connected-to-mp-node",SGRawValuePointer<bool>(&_nodeIsMultiplayer));
106 TIE("tow/connected-to-ai-node",SGRawValuePointer<bool>(&_nodeIsAiAircraft));
107 TIE("tow/connected-to-ai-or-mp-id",SGRawValuePointer<int>(&_nodeID));
108 TIE("debug/hitch-height-above-ground",SGRawValuePointer<float>(&_height_above_ground));
109 TIE("debug/tow-end-height-above-ground",SGRawValuePointer<float>(&_winch_height_above_ground));
110 TIE("debug/tow-rel-lo-pos",SGRawValuePointer<float>(&_loPosFrac));
111 TIE("debug/tow-lowest-pos-height",SGRawValuePointer<float>(&_lowest_tow_height));
112 TIE("is-slave",SGRawValuePointer<bool>(&_isSlave));
113 TIE("speed-in-tow-direction",SGRawValuePointer<float>(&_speed_in_tow_direction));
114 TIE("mp-auto-connect-period",SGRawValuePointer<float>(&_mpAutoConnectPeriod));
115 TIE("mp-time-lag",SGRawValuePointer<float>(&_mp_time_lag));
116#undef TIE
117 _node->setStringValue("tow/node","");
118 _node->setStringValue("tow/connected-to-ai-or-mp-callsign");
119 _node->setBoolValue("broken",false);
120 }
121}
122
123Hitch::~Hitch()
124{
125 _tiedProperties.Untie();
126 delete _state;
127}
128
129void Hitch::setPosition(float* position)
130{
131 int i;
132 for(i=0; i<3; i++) _pos[i] = position[i];
133}
134
135void Hitch::setTowLength(float length)
136{
137 _towLength = length;
138}
139
140void Hitch::setOpen(bool isOpen)
141{
142 //test if we already processed this before
143 //without this test a binded property could
144 //try to close the Hitch every run
145 //it will close, if we are near the end
146 //e.g. if we are flying over the parked
147 //tow-aircraft....
148 if (isOpen==_last_wish)
149 return;
150 _last_wish=isOpen;
151 _open=isOpen;
152}
153
154void Hitch::setTowElasticConstant(float sc)
155{
156 _towElasticConstant=sc;
157}
158
159void Hitch::setTowBreakForce(float bf)
160{
161 _towBreakForce=bf;
162}
163
164void Hitch::setWinchMaxForce(float f)
165{
166 _winchMaxForce=f;
167}
168
169void Hitch::setTowWeightPerM(float rw)
170{
171 _towWeightPerM=rw;
172}
173
174void Hitch::setWinchMaxSpeed(float mws)
175{
176 _winchMaxSpeed=mws;
177}
178
179void Hitch::setWinchRelSpeed(float rws)
180{
181 _winchRelSpeed=rws;
182}
183
184void Hitch::setWinchPosition(double *winchPosition)//in global coordinates!
185{
186 for (int i=0; i<3;i++)
187 _winchPos[i]=winchPosition[i];
188}
189
190void Hitch::setMpAutoConnectPeriod(float dt)
191{
192 _mpAutoConnectPeriod=dt;
193}
194
195void Hitch::setForceIsCalculatedByOther(bool b)
196{
197 _forceIsCalculatedByMaster=b;
198}
199
200std::string Hitch::getConnectedPropertyNode() const
201{
202 if (_towEndNode)
203 return _towEndNode->getDisplayName();
204 else
205 return std::string("");
206}
207
208void Hitch::setConnectedPropertyNode(const char *nodename)
209{
210 _towEndNode=fgGetNode(nodename,false);
211}
212
213void Hitch::setWinchPositionAuto(bool doit)
214{
215 static bool lastState=false;
216 if(!_state)
217 return;
218 if (!doit)
219 {
220 lastState=false;
221 return;
222 }
223 if(lastState)
224 return;
225 lastState=true;
226 float lWinchPos[3];
227 // The ground plane transformed to the local frame.
228 float ground[4];
229 _state->planeGlobalToLocal(_global_ground, ground);
230
231 float help[3];
232 //find a normalized vector pointing forward parallel to the ground
233 help[0]=0;
234 help[1]=1;
235 help[2]=0;
236 Math::cross3(ground,help,help);
237 //multiplay by initial tow length;
238 //reduced by 1m to be able to close the
239 //hitch either if the glider slips backwards a bit
240 Math::mul3((_winchInitialTowLength-1.),help,help);
241 //add to the actual pos
242 Math::add3(_pos,help,lWinchPos);
243 //put it onto the ground plane
244 Math::mul3(ground[3],ground,help);
245 Math::add3(lWinchPos,help,lWinchPos);
246
247 _state->posLocalToGlobal(lWinchPos,_winchPos);
248 _towLength=_winchInitialTowLength;
249 fgSetString("/sim/messages/pilot", "Connected to winch!");
250 _open=false;
251
252 _node->setBoolValue("broken",false);
253
254 //set the dist value (if not, the hitch would open in the next calcforce run
255 float delta[3];
256 Math::sub3(lWinchPos,_pos,delta);
257 _dist=Math::mag3(delta);
258}
259
260void Hitch::findBestAIObject(bool doit,bool running_as_autoconnect)
261{
262 static bool lastState=false;
263 if(!_state)
264 return;
265 if (!running_as_autoconnect)
266 {
267 //if this function is binded to an input, it will be called every frame as long as the key is pressed.
268 //therefore wait for a key-release before running it again.
269 if (!doit)
270 {
271 lastState=false;
272 return;
273 }
274 if(lastState)
275 return;
276 lastState=true;
277 }
278 double gpos[3];
279 _state->posLocalToGlobal(_pos,gpos);
280 double bestdist=_towLength*_towLength;//squared!
281 _towEndIsConnectedToProperty=false;
282 SGPropertyNode * ainode = fgGetNode("/ai/models",false);
283 if(!ainode) return;
284 std::string myCallsign = "***********";
285 if (running_as_autoconnect)
286 {
287 //get own callsign
288 SGPropertyNode *cs=fgGetNode("/sim/multiplay/callsign",false);
289 if (cs)
290 {
291 myCallsign = cs->getStringValue();
292 }
293 //reset tow length for search radius. Lentgh will be later copied from master
294 _towLength=_winchInitialTowLength;
295 }
296 bool found=false;
297 vector <SGPropertyNode_ptr> nodes;//<SGPropertyNode_ptr>
298 for (int i=0;i<ainode->nChildren();i++)
299 {
300 SGPropertyNode * n=ainode->getChild(i);
301 _nodeIsMultiplayer = strncmp("multiplayer", n->getNameString().c_str(), 11) == 0;
302 _nodeIsAiAircraft = strncmp("aircraft", n->getNameString().c_str(), 8) == 0;
303 if (!(_nodeIsMultiplayer || _nodeIsAiAircraft))
304 continue;
305 if (running_as_autoconnect)
306 {
307 if (!_nodeIsMultiplayer)
308 continue;
309 if(n->getBoolValue("sim/hitches/aerotow/open",true)) continue;
310 if (myCallsign != n->getStringValue("sim/hitches/aerotow/tow/connected-to-ai-or-mp-callsign"))
311 continue;
312 }
313 double pos[3];
314 pos[0]=n->getDoubleValue("position/global-x",0);
315 pos[1]=n->getDoubleValue("position/global-y",0);
316 pos[2]=n->getDoubleValue("position/global-z",0);
317 double dist=0;
318 for (int j=0;j<3;j++)
319 dist+=(pos[j]-gpos[j])*(pos[j]-gpos[j]);
320 if (dist<bestdist)
321 {
322 bestdist=dist;
323 _towEndNode=n;
324 _towEndIsConnectedToProperty=true;
325 //_node->setStringValue("tow/node",n->getPath());
326 _node->setStringValue("tow/node",n->getDisplayName());
327 _nodeID=n->getIntValue("id",0);
328 _node->setStringValue("tow/connected-to-ai-or-mp-callsign",n->getStringValue("callsign"));
329 _open=false;
330 found = true;
331 }
332 }
333 if (found)
334 {
335 if (!running_as_autoconnect)
336 {
337 std::stringstream message;
338 message<<_node->getStringValue("tow/connected-to-ai-or-mp-callsign")
339 <<", I am on your hook, distance "<<Math::sqrt(bestdist)<<" meter.";
340 fgSetString("/sim/messages/pilot", message.str().c_str());
341 }
342 else
343 {
344 std::stringstream message;
345 message<<_node->getStringValue("tow/connected-to-ai-or-mp-callsign")
346 <<": I am on your hook, distance "<<Math::sqrt(bestdist)<<" meter.";
347 fgSetString("/sim/messages/ai-plane", message.str().c_str());
348 }
349 if (running_as_autoconnect)
350 _isSlave=true;
351 //set the dist value to some value below the tow lentgh (if not, the hitch
352 //would open in the next calc force run
353 _dist=_towLength*0.5;
354 _mp_open_last_state=true;
355 }
356 else
357 if (!running_as_autoconnect)
358 {
359 fgSetString("/sim/messages/atc", "Sorry, no aircraft for aerotow!");
360 }
361}
362
363void Hitch::setWinchInitialTowLength(float length)
364{
365 _winchInitialTowLength=length;
366}
367
368void Hitch::setWinchPower(float power)
369{
370 _winchPower=power;
371}
372
373void Hitch::setWinchMaxTowLength(float length)
374{
375 _winchMaxTowLength=length;
376}
377
378void Hitch::setWinchMinTowLength(float length)
379{
380 _winchMinTowLength=length;
381}
382
383void Hitch::setGlobalGround(double *global_ground, float *global_vel)
384{
385 int i;
386 for(i=0; i<4; i++) _global_ground[i] = global_ground[i];
387 for(i=0; i<3; i++) _global_vel[i] = global_vel[i];
388}
389
390void Hitch::getPosition(float* out)
391{
392 int i;
393 for(i=0; i<3; i++) out[i] = _pos[i];
394}
395
396float Hitch::getTowLength(void)
397{
398 return _towLength;
399}
400
401void Hitch::calcForce(Ground *g_cb, RigidBody* body, State* s)
402{
403 float lWinchPos[3],delta[3],deltaN[3];
404 *_state=*s;
405 s->posGlobalToLocal(_winchPos,lWinchPos);
406 Math::sub3(lWinchPos,_pos,delta);
407 if(!_towEndIsConnectedToProperty)
408 _dist=Math::mag3(delta);
409 else
410 _dist=Math::mag3(lWinchPos); //use the aircraft center as reference for distance calculation
411 //this position is transferred to the MP-Aircraft.
412 //With this trick, both player in aerotow get the same length
413 Math::unit3(delta,deltaN);
414 float lvel[3];
415 s->globalToLocal(s->v,lvel);
416 _speed_in_tow_direction=Math::dot3(lvel,deltaN);
417 if (_towEndIsConnectedToProperty && _nodeIsMultiplayer)
418 {
419 float mp_delta_dist_due_to_time_lag=0.5*_mp_time_lag*(-_mp_v+_speed_in_tow_direction);
420 _timeLagCorrectedDist=_dist+mp_delta_dist_due_to_time_lag;
421 if(_forceIsCalculatedByMaster && !_open)
422 {
423 s->globalToLocal(_mp_force,_force);
424 return;
425 }
426 }
427 else
428 _timeLagCorrectedDist=_dist;
429 if (_open)
430 {
431 _force[0]=_force[1]=_force[2]=0;
432 return;
433 }
434 if(_dist>_towLength)
435 if(_towLength>1e-3)
436 _forceMagnitude=(_dist-_towLength)/_towLength*_towElasticConstant;
437 else
438 _forceMagnitude=2*_towBreakForce;
439 else
440 _forceMagnitude=0;
441 if(_forceMagnitude>=_towBreakForce)
442 {
443 _forceMagnitude=0;
444 _open=true;
445 _node->setBoolValue("broken",true);
446 _force[0]=_force[1]=_force[2]=0;
447 _towEndForce[0]=_towEndForce[1]=_towEndForce[2]=0;
448 _reportTowEndForce[0]=_reportTowEndForce[1]=_reportTowEndForce[2]=0;
449 return;
450 }
451 Math::mul3(_forceMagnitude,deltaN,_force);
452 Math::mul3(-1.,_force,_towEndForce);
453 _winchActualForce=_forceMagnitude; //missing: gravity on this end and friction
454 //Add the gravitiy of the rope.
455 //calculate some numbers:
456 float grav_force=_towWeightPerM*_towLength*9.81;
457 //the length of the gravity-expanded row:
458 float leng=_towLength+grav_force*_towLength/_towElasticConstant;
459 // The ground plane transformed to the local frame.
460 float ground[4];
461 s->planeGlobalToLocal(_global_ground, ground);
462
463 // The velocity of the contact patch transformed to local coordinates.
464 //float glvel[3];
465 //s->velGlobalToLocal(_global_vel, glvel);
466
467 _height_above_ground = ground[3] - Math::dot3(_pos, ground);
468
469 //the same for the winch-pos (the pos of the tow end)
470 _winch_height_above_ground = ground[3] - Math::dot3(lWinchPos, ground);
471
472 //the frac of the grav force acting on _pos:
473 float grav_frac=0.5*(1+(_height_above_ground-_winch_height_above_ground)/leng);
474 grav_frac=Math::clamp(grav_frac,0,1);
475 float grav_frac_tow_end=1-grav_frac;
476 //reduce grav_frac, if the tow has ground contact.
477 if (_height_above_ground<leng) //if not, the tow can not be on ground
478 {
479 float fa[3],fb[3],fg[3];
480 //the grav force an the hitch position:
481 Math::mul3(-grav_frac*grav_force,ground,fg);
482 //the total force on hitch postion:
483 Math::add3(fg,_force,fa);
484 //the grav force an the tow end position:
485 Math::mul3(-(1-grav_frac)*grav_force,ground,fg);
486 //the total force on tow end postion:
487 //note: sub: _force on tow-end is negative of force on hitch postion
488 Math::sub3(fg,_force,fb);
489 float fa_=Math::mag3(fa);
490 float fb_=Math::mag3(fb);
491 float stretchedTowLen;
492 stretchedTowLen=_towLength*(1.+(fa_+fb_)/(2*_towElasticConstant));
493 //the relative position of the lowest postion of the tow:
494 if ((fa_+fb_)>1e-3)
495 _loPosFrac=fa_/(fa_+fb_);
496 else
497 _loPosFrac=0.5;
498 //dist to tow-end parallel to ground
499 float ground_dist;
500 float help[3];
501 //Math::cross3(delta,ground,help);//as long as we calculate the dist without _pos, od it with lWinchpos, the dist to our center....
502 Math::cross3(lWinchPos,ground,help);
503 ground_dist=Math::mag3(help);
504 //height of lowest tow pos (relative to _pos)
505 _lowest_tow_height=_loPosFrac*Math::sqrt(Math::abs(stretchedTowLen*stretchedTowLen-ground_dist*ground_dist));
506 if (_height_above_ground<_lowest_tow_height)
507 {
508 if (_height_above_ground>1e-3)
509 grav_frac*=_height_above_ground/_lowest_tow_height;
510 else
511 grav_frac=0;
512 }
513 if (_winch_height_above_ground<(_lowest_tow_height-_height_above_ground+_winch_height_above_ground))
514 {
515 if (_winch_height_above_ground>1e-3)
516 grav_frac_tow_end*=_winch_height_above_ground/
517 (_lowest_tow_height-_height_above_ground+_winch_height_above_ground);
518 else
519 grav_frac_tow_end=0;
520 }
521 }
522 else _lowest_tow_height=_loPosFrac=-1; //for debug output
523 float grav_force_v[3];
524 Math::mul3(grav_frac*grav_force,ground,grav_force_v);
525 Math::add3(grav_force_v,_force,_force);
526 _forceMagnitude=Math::mag3(_force);
527 //the same for the tow end:
528 Math::mul3(grav_frac_tow_end*grav_force,ground,grav_force_v);
529 Math::add3(grav_force_v,_towEndForce,_towEndForce);
530 s->localToGlobal(_towEndForce,_towEndForce);
531
532 if(_forceMagnitude>=_towBreakForce)
533 {
534 _forceMagnitude=0;
535 _open=true;
536 _node->setBoolValue("broken",true);
537 _force[0]=_force[1]=_force[2]=0;
538 _towEndForce[0]=_towEndForce[1]=_towEndForce[2]=0;
539 }
540
541
542}
543
544// Computed values: total force
545void Hitch::getForce(float* force, float* off)
546{
547 Math::set3(_force, force);
548 Math::set3(_pos, off);
549}
550
551float Hitch::getRopeAngleDeg()
552{
553 return -atan2(_force[2] , _force[0] ) * SG_RADIANS_TO_DEGREES;
554}
555
556void Hitch::integrate (float dt)
557{
558 //check if hitch has opened or closed, if yes: message
559 if (_open !=_oldOpen)
560 {
561 if (_oldOpen)
562 {
563 if (_dist>_towLength*1.00001)
564 {
565 std::stringstream message;
566 message<<"Could not lock hitch (tow length is insufficient) on hitch "
567 <<_node->getNameString()<<" "<<_node->getIndex()<<"!";
568 fgSetString("/sim/messages/pilot", message.str().c_str());
569 _open=true;
570 return;
571 }
572 _node->setBoolValue("broken",false);
573 }
574 std::stringstream message;
575 if (_node->getBoolValue("broken",false)&&_open)
576 message<<"Oh no, the tow is broken";
577 else
578 message<<(_open?"Opened hitch ":"Locked hitch ")<<_node->getNameString()<<" "<<_node->getIndex()<<"!";
579 fgSetString("/sim/messages/pilot", message.str().c_str());
580 _oldOpen=_open;
581 }
582
583 //check, if tow end should be searched in all MP-aircrafts
584 if(_open && _mpAutoConnectPeriod)
585 {
586 _isSlave=false;
587 _timeToNextAutoConnectTry-=dt;
588 if ((_timeToNextAutoConnectTry>_mpAutoConnectPeriod) || (_timeToNextAutoConnectTry<0))
589 {
590 _timeToNextAutoConnectTry=_mpAutoConnectPeriod;
591 //search for MP-Aircraft, which is towed with us
592 findBestAIObject(true,true);
593 }
594 }
595 //check, if tow end can be modified by property, if yes: update
596 if(_towEndIsConnectedToProperty)
597 {
598 if (_node)
599 {
600 //_towEndNode=fgGetNode(_node->getStringValue("tow/node"), false);
601 std::string towNode = _node->getStringValue("tow/node");
602 _towEndNode=fgGetNode("ai/models")->getNode(towNode, false);
603 //AI and multiplayer objects seem to change node?
604 //Check if we have the right one by callsign
605 if (_nodeIsMultiplayer || _nodeIsAiAircraft)
606 {
607 std::string MPcallsign = "";
608 std::string MPc =_node->getStringValue("tow/connected-to-ai-or-mp-callsign");
609 if (!MPc.empty())
610 {
611 MPcallsign = MPc;
612 }
613 if ((_towEndNode
614 && _towEndNode->getStringValue("callsign") != MPcallsign)
615 || !_towEndNode)
616 {
617 _timeToNextReConnectTry-=dt;
618 if((_timeToNextReConnectTry<0)||(_timeToNextReConnectTry>10))
619 {
620 _timeToNextReConnectTry=10;
621 SGPropertyNode * ainode = fgGetNode("/ai/models",false);
622 if(ainode)
623 {
624 for (int i=0;i<ainode->nChildren();i++)
625 {
626 SGPropertyNode * n=ainode->getChild(i);
627 if (_nodeIsMultiplayer
628 ? strncmp("multiplayer", n->getNameString().c_str(), 11) == 0
629 : strncmp("aircraft", n->getNameString().c_str(), 8)
630 ) {
631 if (n->getStringValue("callsign") == MPcallsign)//found
632 {
633 _towEndNode=n;
634 //_node->setStringValue("tow/node",n->getPath());
635 _node->setStringValue("tow/node",n->getDisplayName());
636 }
637 }
638 }
639 }
640 }
641 }
642 }
643 if(_towEndNode)
644 {
645 _winchPos[0]=_towEndNode->getDoubleValue("position/global-x",_winchPos[0]);
646 _winchPos[1]=_towEndNode->getDoubleValue("position/global-y",_winchPos[1]);
647 _winchPos[2]=_towEndNode->getDoubleValue("position/global-z",_winchPos[2]);
648 _mp_lpos[0]=_towEndNode->getFloatValue("sim/hitches/aerotow/local-pos-x",0);
649 _mp_lpos[1]=_towEndNode->getFloatValue("sim/hitches/aerotow/local-pos-y",0);
650 _mp_lpos[2]=_towEndNode->getFloatValue("sim/hitches/aerotow/local-pos-z",0);
651 _mp_dist=_towEndNode->getFloatValue("sim/hitches/aerotow/tow/dist");
652 _mp_v=_towEndNode->getFloatValue("sim/hitches/aerotow/speed-in-tow-direction");
653 _mp_force[0]=_towEndNode->getFloatValue("sim/hitches/aerotow/tow/end-force-x",0);
654 _mp_force[1]=_towEndNode->getFloatValue("sim/hitches/aerotow/tow/end-force-y",0);
655 _mp_force[2]=_towEndNode->getFloatValue("sim/hitches/aerotow/tow/end-force-z",0);
656
657 if(_isSlave)
658 {
659#define gf(a,b) a=_towEndNode->getFloatValue(b,a)
660#define gb(a,b) a=_towEndNode->getBoolValue(b,a)
661 gf(_towLength,"sim/hitches/aerotow/tow/length");
662 gf(_towElasticConstant,"sim/hitches/aerotow/tow/elastic-constant");
663 gf(_towWeightPerM,"sim/hitches/aerotow/tow/weight-per-m-kg-m");
664 gf(_towBreakForce,"sim/hitches/aerotow/break-force");
665 gb(_open,"sim/hitches/aerotow/open");
666 gb(_mp_is_slave,"sim/hitches/aerotow/is-slave");
667#undef gf
668#undef gb
669 if (_mp_is_slave) _isSlave=false; //someone should be master
670 }
671 else
672 {
673 //check if other has opened hitch, but is neccessary, that it was closed before
674 bool mp_open=_towEndNode->getBoolValue("sim/hitches/aerotow/open",_mp_open_last_state);
675 if (mp_open != _mp_open_last_state) //state has changed
676 {
677 _mp_open_last_state=mp_open; //store that value
678 if(!_open)
679 {
680 if(mp_open)
681 {
682 _oldOpen=_open=true;
683 std::stringstream message;
684 message<<_node->getStringValue("tow/connected-to-ai-or-mp-callsign")
685 <<": I have released the tow!";
686 fgSetString("/sim/messages/ai-plane", message.str().c_str());
687 }
688 }
689 }
690 }
691 //try to calculate the time lag
692 if ((_mp_last_reported_dist!=_mp_dist)||(_mp_last_reported_v!=_mp_v)) //new data;
693 {
694 _mp_last_reported_dist=_mp_dist;
695 _mp_last_reported_v=_mp_v;
696 float total_v=-_mp_v+_speed_in_tow_direction;//mp has opposite tow direction
697 float abs_v=Math::abs(total_v);
698 if (abs_v>0.1)
699 {
700 float actual_time_lag_guess=(_mp_dist-_dist)/total_v;
701 //check, if it sounds ok
702 if((actual_time_lag_guess>0)&&(actual_time_lag_guess<5))
703 {
704 float frac=abs_v*0.01;
705 if (frac>0.05) frac=0.05;
706 // if we are slow, the guess of the lag can be rather wrong. as faster we are
707 // the better the guess. Therefore frac is proportiona to the speed. Clamp it
708 // at 5m/s
709 _mp_time_lag=(1-frac)*_mp_time_lag+frac*actual_time_lag_guess;
710 }
711 }
712 }
713 }
714 }
715 }
716 //set the _reported_tow_end_force
717 Math::set3(_towEndForce,_reportTowEndForce);
718
719 if (_open) return;
720 if (_winchRelSpeed==0) return;
721
722 float forceMagnitude = Math::mag3(_towEndForce);
723 if (forceMagnitude > 100 && _autoReleaseAngle && (this->getRopeAngleDeg() > _autoReleaseAngle))
724 {
725 std::stringstream message;
726 message<<"Cable autoreleased";
727 fgSetString("/sim/messages/pilot", message.str().c_str());
728 _open=true;
729 return;
730 }
731
732 float factor=1,offset=0;
733 if (_winchActualForce>_winchMaxForce)
734 offset=-(_winchActualForce-_winchMaxForce)/_winchMaxForce*20;
735 if (_winchRelSpeed>0.01) // to avoit div by zero
736 {
737 float maxForcePowerLimit=_winchPower/(_winchRelSpeed*_winchMaxSpeed);
738 if (_winchActualForce>maxForcePowerLimit)
739 factor-=(_winchActualForce-maxForcePowerLimit)/maxForcePowerLimit;
740 }
741 _towLength-=dt*(factor*_winchRelSpeed+offset)*_winchMaxSpeed;
742 if (_towLength<=_winchMinTowLength)
743 {
744 if (_winchRelSpeed<0)
745 _winchRelSpeed=0;
746 _towLength=_winchMinTowLength;
747 return;
748 }
749 if (_towLength>=_winchMaxTowLength)
750 {
751 if (_winchRelSpeed<0)
752 _winchRelSpeed=0;
753 _towLength=_winchMaxTowLength;
754 return;
755 }
756}
757
758
759
760
761}; // namespace yasim
#define TIE(x, v)
#define gb(a, b)
#define gf(a, b)
#define i(x)
const char * name
State
Models an aircraft axis for purposes of trimming.
Definition FGTrimAxis.h:83
bool fgSetString(char const *name, char const *str)
Set a string value for a property.
Definition proptest.cpp:26
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27