]> git.mxchange.org Git - flightgear.git/blob - src/FDM/YASim/Gear.cpp
FGPUIDialog: fix reading from already free'd memory.
[flightgear.git] / src / FDM / YASim / Gear.cpp
1
2 #ifdef HAVE_CONFIG_H
3 #  include "config.h"
4 #endif
5
6 #include "Math.hpp"
7 #include "BodyEnvironment.hpp"
8 #include "RigidBody.hpp"
9
10 #include <cfloat>
11 #include <simgear/bvh/BVHMaterial.hxx>
12 #include <FDM/flight.hxx>
13 #include "Gear.hpp"
14 namespace yasim {
15 static const float YASIM_PI = 3.14159265358979323846;
16 static const float maxGroundBumpAmplitude=0.4;
17         //Amplitude can be positive and negative
18
19 Gear::Gear()
20 {
21     int i;
22     for(i=0; i<3; i++)
23         _pos[i] = _cmpr[i] = 0;
24     _spring = 1;
25     _damp = 0;
26     _sfric = 0.8f;
27     _dfric = 0.7f;
28     _brake = 0;
29     _rot = 0;
30     _initialLoad = 0;
31     _extension = 1;
32     _castering = false;
33     _frac = 0;
34     _ground_frictionFactor = 1;
35     _ground_rollingFriction = 0.02;
36     _ground_loadCapacity = 1e30;
37     _ground_loadResistance = 1e30;
38     _ground_isSolid = 1;
39     _ground_bumpiness = 0;
40     _onWater = 0;
41     _onSolid = 1;
42     _global_x = 0.0;
43     _global_y = 0.0;
44     _reduceFrictionByExtension = 0;
45     _spring_factor_not_planing = 1;
46     _speed_planing = 0;
47     _isContactPoint = 0;
48     _ignoreWhileSolving = 0;
49
50     for(i=0; i<3; i++)
51         _global_ground[i] = _global_vel[i] = 0;
52     _global_ground[2] = 1;
53     _global_ground[3] = -1e3;
54 }
55
56 void Gear::setPosition(float* position)
57 {
58     int i;
59     for(i=0; i<3; i++) _pos[i] = position[i];
60 }
61
62 void Gear::setCompression(float* compression)
63 {
64     int i;
65     for(i=0; i<3; i++) _cmpr[i] = compression[i];
66 }
67
68 void Gear::setSpring(float spring)
69 {
70     _spring = spring;
71 }
72
73 void Gear::setDamping(float damping)
74 {
75     _damp = damping;
76 }
77
78 void Gear::setStaticFriction(float sfric)
79 {
80     _sfric = sfric;
81 }
82
83 void Gear::setDynamicFriction(float dfric)
84 {
85     _dfric = dfric;
86 }
87
88 void Gear::setBrake(float brake)
89 {
90     _brake = Math::clamp(brake, 0, 1);
91 }
92
93 void Gear::setRotation(float rotation)
94 {
95     _rot = rotation;
96 }
97
98 void Gear::setExtension(float extension)
99 {
100     _extension = Math::clamp(extension, 0, 1);
101 }
102
103 void Gear::setCastering(bool c)
104 {
105     _castering = c;
106 }
107
108 void Gear::setContactPoint(bool c)
109 {
110     _isContactPoint=c;
111 }
112
113 void Gear::setOnWater(bool c)
114 {
115     _onWater = c;
116 }
117
118 void Gear::setOnSolid(bool c)
119 {
120     _onSolid = c;
121 }
122
123 void Gear::setIgnoreWhileSolving(bool c)
124 {
125     _ignoreWhileSolving = c;
126 }
127
128 void Gear::setSpringFactorNotPlaning(float f)
129 {
130     _spring_factor_not_planing = f;
131 }
132
133 void Gear::setSpeedPlaning(float s)
134 {
135     _speed_planing = s;
136 }
137
138 void Gear::setReduceFrictionByExtension(float s)
139 {
140     _reduceFrictionByExtension = s;
141 }
142
143 void Gear::setInitialLoad(float l)
144 {
145     _initialLoad = l;
146 }
147
148 void Gear::setGlobalGround(double *global_ground, float* global_vel,
149                            double globalX, double globalY,
150                            const simgear::BVHMaterial *material)
151 {
152     int i;
153     double frictionFactor,rollingFriction,loadCapacity,loadResistance,bumpiness;
154     bool isSolid;
155
156     for(i=0; i<4; i++) _global_ground[i] = global_ground[i];
157     for(i=0; i<3; i++) _global_vel[i] = global_vel[i];
158
159     if (material) {
160         loadCapacity = (*material).get_load_resistance();
161         frictionFactor =(*material).get_friction_factor();
162         rollingFriction = (*material).get_rolling_friction();
163         loadResistance = (*material).get_load_resistance();
164         bumpiness = (*material).get_bumpiness();
165         isSolid = (*material).get_solid();
166     } else {
167         // no material, assume solid
168         loadCapacity = DBL_MAX;
169         frictionFactor = 1.0;
170         rollingFriction = 0.02;
171         loadResistance = DBL_MAX;
172         bumpiness = 0.0;
173         isSolid = true;
174     }
175     _ground_frictionFactor = frictionFactor;
176     _ground_rollingFriction = rollingFriction;
177     _ground_loadCapacity = loadCapacity;
178     _ground_loadResistance = loadResistance;
179     _ground_bumpiness = bumpiness;
180     _ground_isSolid = isSolid;
181     _global_x = globalX;
182     _global_y = globalY;
183
184     }
185
186 void Gear::getPosition(float* out)
187 {
188     int i;
189     for(i=0; i<3; i++) out[i] = _pos[i];
190 }
191
192 void Gear::getCompression(float* out)
193 {
194     int i;
195     for(i=0; i<3; i++) out[i] = _cmpr[i];    
196 }
197
198 void Gear::getGlobalGround(double* global_ground)
199 {
200     int i;
201     for(i=0; i<4; i++) global_ground[i] = _global_ground[i];
202 }
203
204 float Gear::getSpring()
205 {
206     return _spring;
207 }
208
209 float Gear::getDamping()
210 {
211     return _damp;
212 }
213
214 float Gear::getStaticFriction()
215 {
216     return _sfric;
217 }
218
219 float Gear::getDynamicFriction()
220 {
221     return _dfric;
222 }
223
224 float Gear::getBrake()
225 {
226     return _brake;
227 }
228
229 float Gear::getRotation()
230 {
231     return _rot;
232 }
233
234 float Gear::getExtension()
235 {
236     return _extension;
237 }
238
239 void Gear::getForce(float* force, float* contact)
240 {
241     Math::set3(_force, force);
242     Math::set3(_contact, contact);
243 }
244
245 float Gear::getWoW()
246 {
247     return _wow;
248 }
249
250 float Gear::getCompressFraction()
251 {
252     return _frac;
253 }
254
255 bool Gear::getCastering()
256 {
257     return _castering;
258 }
259
260 bool Gear::getGroundIsSolid()
261 {
262     return _ground_isSolid;
263 }
264
265 float Gear::getBumpAltitude()
266 {
267     if (_ground_bumpiness<0.001) return 0.0;
268     double x = _global_x*0.1;
269     double y = _global_y*0.1;
270     x -= Math::floor(x);
271     y -= Math::floor(y);
272     x *= 2*YASIM_PI;
273     y *= 2*YASIM_PI;
274     //now x and y are in the range of 0..2pi
275     //we need a function, that is periodically on 2pi and gives some
276     //height. This is not very fast, but for a beginning.
277     //maybe this should be done by interpolating between some precalculated
278     //values
279     float h = Math::sin(x)+Math::sin(7*x)+Math::sin(8*x)+Math::sin(13*x);
280     h += Math::sin(2*y)+Math::sin(5*y)+Math::sin(9*y*x)+Math::sin(17*y);
281     
282     return h*(1/8.)*_ground_bumpiness*maxGroundBumpAmplitude;
283 }
284
285 void Gear::calcForce(RigidBody* body, State *s, float* v, float* rot)
286 {
287     // Init the return values
288     int i;
289     for(i=0; i<3; i++) _force[i] = _contact[i] = 0;
290
291     // Don't bother if it's not down
292     if(_extension < 1)
293     {
294         _wow = 0;
295         _frac = 0;
296         return;
297     }
298
299     // Dont bother if we are in the "wrong" ground
300     if (!((_onWater&&!_ground_isSolid)||(_onSolid&&_ground_isSolid)))  {
301          _wow = 0;
302          _frac = 0;
303         _compressDist = 0;
304         _rollSpeed = 0;
305         _casterAngle = 0;
306         return;
307     }
308
309     // The ground plane transformed to the local frame.
310     float ground[4];
311     s->planeGlobalToLocal(_global_ground, ground);
312         
313     // The velocity of the contact patch transformed to local coordinates.
314     float glvel[3];
315     s->velGlobalToLocal(_global_vel, glvel);
316
317     // First off, make sure that the gear "tip" is below the ground.
318     // If it's not, there's no force.
319     float a = ground[3] - Math::dot3(_pos, ground);
320     float BumpAltitude=0;
321     if (a<maxGroundBumpAmplitude)
322     {
323         BumpAltitude=getBumpAltitude();
324         a+=BumpAltitude;
325     }
326     _compressDist = -a;
327     if(a > 0) {
328         _wow = 0;
329         _frac = 0;
330         _compressDist = 0;
331         _rollSpeed = 0;
332         _casterAngle = 0;
333         return;
334     }
335
336     // Now a is the distance from the tip to ground, so make b the
337     // distance from the base to ground.  We can get the fraction
338     // (0-1) of compression from a/(a-b). Note the minus sign -- stuff
339     // above ground is negative.
340     float tmp[3];
341     Math::add3(_cmpr, _pos, tmp);
342     float b = ground[3] - Math::dot3(tmp, ground)+BumpAltitude;
343
344     // Calculate the point of ground _contact.
345     if(b < 0)
346         _frac = 1;
347     else
348         _frac = a/(a-b);
349     for(i=0; i<3; i++)
350         _contact[i] = _pos[i] + _frac*_cmpr[i];
351
352     // Turn _cmpr into a unit vector and a magnitude
353     float cmpr[3];
354     float clen = Math::mag3(_cmpr);
355     Math::mul3(1/clen, _cmpr, cmpr);
356
357     // Now get the velocity of the point of contact
358     float cv[3];
359     body->pointVelocity(_contact, rot, cv);
360     Math::add3(cv, v, cv);
361     Math::sub3(cv, glvel, cv);
362
363     // Finally, we can start adding up the forces.  First the spring
364     // compression.   (note the clamping of _frac to 1):
365     _frac = (_frac > 1) ? 1 : _frac;
366
367     // Add the initial load to frac, but with continous transistion around 0
368     float frac_with_initial_load;
369     if (_frac>0.2 || _initialLoad==0.0)
370         frac_with_initial_load = _frac+_initialLoad;
371     else
372         frac_with_initial_load = (_frac+_initialLoad)
373             *_frac*_frac*3*25-_frac*_frac*_frac*2*125;
374
375     float fmag = frac_with_initial_load*clen*_spring;
376     if (_speed_planing>0)
377     {
378         float v = Math::mag3(cv);
379         if (v < _speed_planing)
380         {
381             float frac = v/_speed_planing;
382             fmag = fmag*_spring_factor_not_planing*(1-frac)+fmag*frac;
383         }
384     }
385     // Then the damping.  Use the only the velocity into the ground
386     // (projection along "ground") projected along the compression
387     // axis.  So Vdamp = ground*(ground dot cv) dot cmpr
388     Math::mul3(Math::dot3(ground, cv), ground, tmp);
389     float dv = Math::dot3(cmpr, tmp);
390     float damp = _damp * dv;
391     if(damp > fmag) damp = fmag; // can't pull the plane down!
392     if(damp < -fmag) damp = -fmag; // sanity
393
394     // The actual force applied is only the component perpendicular to
395     // the ground.  Side forces come from velocity only.
396     _wow = (fmag - damp) * -Math::dot3(cmpr, ground);
397     Math::mul3(-_wow, ground, _force);
398
399     // Wheels are funky.  Split the velocity along the ground plane
400     // into rolling and skidding components.  Assuming small angles,
401     // we generate "forward" and "left" unit vectors (the compression
402     // goes "up") for the gear, make a "steer" direction from these,
403     // and then project it onto the ground plane.  Project the
404     // velocity onto the ground plane too, and extract the "steer"
405     // component.  The remainder is the skid velocity.
406
407     float gup[3]; // "up" unit vector from the ground
408     Math::set3(ground, gup);
409     Math::mul3(-1, gup, gup);
410
411     float xhat[] = {1,0,0};
412     float steer[3], skid[3];
413     Math::cross3(gup, xhat, skid);  // up cross xhat =~ skid
414     Math::unit3(skid, skid);        //               == skid
415
416     Math::cross3(skid, gup, steer); // skid cross up == steer
417
418     if(_rot != 0) {
419         // Correct for a rotation
420         float srot = Math::sin(_rot);
421         float crot = Math::cos(_rot);
422         float tx = steer[0];
423         float ty = steer[1];
424         steer[0] =  crot*tx + srot*ty;
425         steer[1] = -srot*tx + crot*ty;
426
427         tx = skid[0];
428         ty = skid[1];
429         skid[0] =  crot*tx + srot*ty;
430         skid[1] = -srot*tx + crot*ty;
431     }
432
433     float vsteer = Math::dot3(cv, steer);
434     float vskid  = Math::dot3(cv, skid);
435     float wgt = Math::dot3(_force, gup); // force into the ground
436
437     if(_castering) {
438         _rollSpeed = Math::sqrt(vsteer*vsteer + vskid*vskid);
439         // Don't modify caster angle when the wheel isn't moving,
440         // or else the angle will animate the "jitter" of a stopped
441         // gear.
442         if(_rollSpeed > 0.05)
443             _casterAngle = Math::atan2(vskid, vsteer);
444         return;
445     } else {
446         _rollSpeed = vsteer;
447         _casterAngle = _rot;
448     }
449     float fsteer,fskid;
450     if(_ground_isSolid)
451     {
452         fsteer = (_brake * _ground_frictionFactor
453                     +(1-_brake)*_ground_rollingFriction
454                  )*calcFriction(wgt, vsteer);
455         fskid  = calcFriction(wgt, vskid)*(_ground_frictionFactor);
456     }
457     else
458     {
459         fsteer = calcFrictionFluid(wgt, vsteer)*_ground_frictionFactor;
460         fskid  = 10*calcFrictionFluid(wgt, vskid)*_ground_frictionFactor;
461         //factor 10: floats have different drag in x and y.
462     }
463     if(vsteer > 0) fsteer = -fsteer;
464     if(vskid > 0) fskid = -fskid;
465     
466     //reduce friction if wanted by _reduceFrictionByExtension
467     float factor = (1-_frac)*(1-_reduceFrictionByExtension)+_frac*1;
468     factor = Math::clamp(factor,0,1);
469     fsteer *= factor;
470     fskid *= factor;
471
472     // Phoo!  All done.  Add it up and get out of here.
473     Math::mul3(fsteer, steer, tmp);
474     Math::add3(tmp, _force, _force);
475
476     Math::mul3(fskid, skid, tmp);
477     Math::add3(tmp, _force, _force);
478 }
479
480 float Gear::calcFriction(float wgt, float v) //used on solid ground
481 {
482     // How slow is stopped?  10 cm/second?
483     const float STOP = 0.1f;
484     const float iSTOP = 1.0f/STOP;
485     v = Math::abs(v);
486     if(v < STOP) return v*iSTOP * wgt * _sfric;
487     else         return wgt * _dfric;
488 }
489
490 float Gear::calcFrictionFluid(float wgt, float v) //used on fluid ground
491 {
492     // How slow is stopped?  1 cm/second?
493     const float STOP = 0.01f;
494     const float iSTOP = 1.0f/STOP;
495     v = Math::abs(v);
496     if(v < STOP) return v*iSTOP * wgt * _sfric;
497     else return wgt * _dfric*v*v*0.01;
498     //*0.01: to get _dfric of the same size than _dfric on solid
499 }
500 }; // namespace yasim
501