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