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