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