]> git.mxchange.org Git - flightgear.git/blob - src/FDM/YASim/Wing.cpp
Fix for bug 1304 - crash loading XML route
[flightgear.git] / src / FDM / YASim / Wing.cpp
1 #include "Math.hpp"
2 #include "Surface.hpp"
3 #include "Wing.hpp"
4
5 namespace yasim {
6
7 Wing::Wing()
8 {
9     _mirror = false;
10     _base[0] = _base[1] = _base[2] = 0;
11     _length = 0;
12     _chord = 0;
13     _taper = 0;
14     _sweep = 0;
15     _dihedral = 0;
16     _stall = 0;
17     _stallWidth = 0;
18     _stallPeak = 0;
19     _twist = 0;
20     _camber = 0;
21     _incidence = 0;
22     _inducedDrag = 1;
23     _dragScale = 1;
24     _liftRatio = 1;
25     _flap0Start = 0;
26     _flap0End = 0;
27     _flap0Lift = 0;
28     _flap0Drag = 0;
29     _flap1Start = 0;
30     _flap1End = 0;
31     _flap1Lift = 0;
32     _flap1Drag = 0;
33     _spoilerStart = 0;
34     _spoilerEnd = 0;
35     _spoilerLift = 0;
36     _spoilerDrag = 0;
37     _slatStart = 0;
38     _slatEnd = 0;
39     _slatAoA = 0;
40     _slatDrag = 0;
41 }
42
43 Wing::~Wing()
44 {
45     int i;
46     for(i=0; i<_surfs.size(); i++) {
47         SurfRec* s = (SurfRec*)_surfs.get(i);
48         delete s->surface;
49         delete s;
50     }
51 }
52
53 int Wing::numSurfaces()
54 {
55     return _surfs.size();
56 }
57
58 Surface* Wing::getSurface(int n)
59 {
60     return ((SurfRec*)_surfs.get(n))->surface;
61 }
62
63 float Wing::getSurfaceWeight(int n)
64 {
65     return ((SurfRec*)_surfs.get(n))->weight;
66 }
67
68 void Wing::setMirror(bool mirror)
69 {
70     _mirror = mirror;
71 }
72
73 void Wing::setBase(float* base)
74 {
75     int i;
76     for(i=0; i<3; i++) _base[i] = base[i];
77 }
78
79 void Wing::setLength(float length)
80 {
81     _length = length;
82 }
83
84 void Wing::setChord(float chord)
85 {
86     _chord = chord;
87 }
88
89 void Wing::setTaper(float taper)
90 {
91     _taper = taper;
92 }
93
94 void Wing::setSweep(float sweep)
95 {
96     _sweep = sweep;
97 }
98
99 void Wing::setDihedral(float dihedral)
100 {
101     _dihedral = dihedral;
102 }
103
104 void Wing::setStall(float aoa)
105 {
106     _stall = aoa;
107 }
108
109 void Wing::setStallWidth(float angle)
110 {
111     _stallWidth = angle;
112 }
113
114 void Wing::setStallPeak(float fraction)
115 {
116     _stallPeak = fraction;
117 }
118
119 void Wing::setTwist(float angle)
120 {
121     _twist = angle;
122 }
123
124 void Wing::setCamber(float camber)
125 {
126     _camber = camber;
127 }
128
129 void Wing::setIncidence(float incidence)
130 {
131     _incidence = incidence;
132     int i;
133     for(i=0; i<_surfs.size(); i++)
134         ((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence);
135 }
136
137 void Wing::setFlap0(float start, float end, float lift, float drag)
138 {
139     _flap0Start = start;
140     _flap0End = end;
141     _flap0Lift = lift;
142     _flap0Drag = drag;
143 }
144
145 void Wing::setFlap1(float start, float end, float lift, float drag)
146 {
147     _flap1Start = start;
148     _flap1End = end;
149     _flap1Lift = lift;
150     _flap1Drag = drag;
151 }
152
153 void Wing::setSlat(float start, float end, float aoa, float drag)
154 {
155     _slatStart = start;
156     _slatEnd = end;
157     _slatAoA = aoa;
158     _slatDrag = drag;
159 }
160
161 void Wing::setSpoiler(float start, float end, float lift, float drag)
162 {
163     _spoilerStart = start;
164     _spoilerEnd = end;
165     _spoilerLift = lift;
166     _spoilerDrag = drag;
167 }
168
169 void Wing::setFlap0(float lval, float rval)
170 {
171     lval = Math::clamp(lval, -1, 1);
172     rval = Math::clamp(rval, -1, 1);
173     int i;
174     for(i=0; i<_flap0Surfs.size(); i++) {
175         ((Surface*)_flap0Surfs.get(i))->setFlap(lval);
176         if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
177     }
178 }
179
180 void Wing::setFlap0Effectiveness(float lval)
181 {
182     lval = Math::clamp(lval, 1, 10);
183     int i;
184     for(i=0; i<_flap0Surfs.size(); i++) {
185         ((Surface*)_flap0Surfs.get(i))->setFlapEffectiveness(lval);
186 //      if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlapEffectiveness(rval);
187     }
188 }
189
190 void Wing::setFlap1(float lval, float rval)
191 {
192     lval = Math::clamp(lval, -1, 1);
193     rval = Math::clamp(rval, -1, 1);
194     int i;
195     for(i=0; i<_flap1Surfs.size(); i++) {
196         ((Surface*)_flap1Surfs.get(i))->setFlap(lval);
197         if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
198     }
199 }
200
201 void Wing::setFlap1Effectiveness(float lval)
202 {
203     lval = Math::clamp(lval, 1, 10);
204     int i;
205     for(i=0; i<_flap1Surfs.size(); i++) {
206         ((Surface*)_flap1Surfs.get(i))->setFlapEffectiveness(lval);
207 //      if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
208     }
209 }
210
211 void Wing::setSpoiler(float lval, float rval)
212 {
213     lval = Math::clamp(lval, 0, 1);
214     rval = Math::clamp(rval, 0, 1);
215     int i;
216     for(i=0; i<_spoilerSurfs.size(); i++) {
217         ((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
218         if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
219     }
220 }
221
222 void Wing::setSlat(float val)
223 {
224     val = Math::clamp(val, 0, 1);
225     int i;
226     for(i=0; i<_slatSurfs.size(); i++)
227         ((Surface*)_slatSurfs.get(i))->setSlat(val);
228 }
229
230 float Wing::getGroundEffect(float* posOut)
231 {
232     int i;
233     for(i=0; i<3; i++) posOut[i] = _base[i];
234     float span = _length * Math::cos(_sweep) * Math::cos(_dihedral);
235     span = 2*(span + Math::abs(_base[2]));
236     return span;
237 }
238
239 void Wing::getTip(float* tip)
240 {
241     tip[0] = -Math::tan(_sweep);
242     tip[1] = Math::cos(_dihedral);
243     tip[2] = Math::sin(_dihedral);
244     Math::unit3(tip, tip);
245     Math::mul3(_length, tip, tip);
246     Math::add3(_base, tip, tip);
247 }
248
249 bool Wing::isMirrored()
250 {
251     return _mirror;
252 }
253
254 void Wing::compile()
255 {
256     // Have we already been compiled?
257     if(! _surfs.empty()) return;
258
259     // Assemble the start/end coordinates of all control surfaces
260     // and the wing itself into an array, sort them,
261     // and remove duplicates.  This gives us the boundaries of our
262     // segments.
263     float bounds[10];
264     bounds[0] = _flap0Start;   bounds[1] = _flap0End;
265     bounds[2] = _flap1Start;   bounds[3] = _flap1End;
266     bounds[4] = _spoilerStart; bounds[5] = _spoilerEnd;
267     bounds[6] = _slatStart;    bounds[7] = _slatEnd;
268     //and don't forget the root and the tip of the wing itself
269     bounds[8] = 0;             bounds[9] = 1;
270
271     // Sort in increasing order
272     int i;
273     for(i=0; i<10; i++) {
274         int minIdx = i;
275         float minVal = bounds[i];
276         int j;
277         for(j=i+1; j<10; j++) {
278             if(bounds[j] < minVal) {
279                 minIdx = j;
280                 minVal = bounds[j];
281             }
282         }
283         float tmp = bounds[i];
284         bounds[i] = minVal; bounds[minIdx] = tmp;
285     }
286
287     // Uniqify
288     float last = bounds[0];
289     int nbounds = 1;
290     for(i=1; i<10; i++) {
291         if(bounds[i] != last)
292             bounds[nbounds++] = bounds[i];
293         last = bounds[i];
294     }
295
296     // Calculate a "nominal" segment length equal to an average chord,
297     // normalized to lie within 0-1 over the length of the wing.
298     float segLen = _chord * (0.5f*(_taper+1)) / _length;
299
300     // Generating a unit vector pointing out the left wing.
301     float left[3];
302     left[0] = -Math::tan(_sweep);
303     left[1] = Math::cos(_dihedral);
304     left[2] = Math::sin(_dihedral);
305     Math::unit3(left, left);
306
307     // Calculate coordinates for the root and tip of the wing
308     float root[3], tip[3];
309     Math::set3(_base, root);
310     Math::set3(left, tip);
311     Math::mul3(_length, tip, tip);
312     Math::add3(root, tip, tip);
313
314     // The wing's Y axis will be the "left" vector.  The Z axis will
315     // be perpendicular to this and the local (!) X axis, because we
316     // want motion along the local X axis to be zero AoA (i.e. in the
317     // wing's XY plane) by definition.  Then the local X coordinate is
318     // just Y cross Z.
319     float orient[9], rightOrient[9];
320     float *x = orient, *y = orient+3, *z = orient+6;
321     x[0] = 1; x[1] = 0; x[2] = 0;
322     Math::set3(left, y);
323     Math::cross3(x, y, z);
324     Math::unit3(z, z);
325     Math::cross3(y, z, x);
326
327     if(_mirror) {
328         // Derive the right side orientation matrix from this one.
329         int i;
330         for(i=0; i<9; i++)  rightOrient[i] = orient[i];
331
332         // Negate all Y coordinates, this gets us a valid basis, but
333         // it's left handed!  So...
334         for(i=1; i<9; i+=3) rightOrient[i] = -rightOrient[i];
335
336         // Change the direction of the Y axis to get back to a
337         // right-handed system.
338         for(i=3; i<6; i++)  rightOrient[i] = -rightOrient[i];
339     }
340
341     // Now go through each boundary and make segments
342     for(i=0; i<(nbounds-1); i++) {
343         float start = bounds[i];
344         float end = bounds[i+1];
345         float mid = (start+end)/2;
346
347         bool flap0=0, flap1=0, slat=0, spoiler=0;
348         if(_flap0Start   < mid && mid < _flap0End)   flap0 = 1;
349         if(_flap1Start   < mid && mid < _flap1End)   flap1 = 1;
350         if(_slatStart    < mid && mid < _slatEnd)    slat = 1;
351         if(_spoilerStart < mid && mid < _spoilerEnd) spoiler = 1;
352
353         // FIXME: Should probably detect an error here if both flap0
354         // and flap1 are set.  Right now flap1 overrides.
355
356         int nSegs = (int)Math::ceil((end-start)/segLen);
357         if (_twist != 0 && nSegs < 8) // more segments if twisted
358             nSegs = 8;
359         float segWid = _length * (end - start)/nSegs;
360
361         int j;
362         for(j=0; j<nSegs; j++) {
363             float frac = start + (j+0.5f) * (end-start)/nSegs;
364             float pos[3];
365             interp(root, tip, frac, pos);
366
367             float chord = _chord * (1 - (1-_taper)*frac);
368
369             Surface *s = newSurface(pos, orient, chord,
370                                     flap0, flap1, slat, spoiler);
371
372             SurfRec *sr = new SurfRec();
373             sr->surface = s;
374             sr->weight = chord * segWid;
375             s->setTotalDrag(sr->weight);
376             s->setTwist(_twist * frac);
377             _surfs.add(sr);
378
379             if(_mirror) {
380                 pos[1] = -pos[1];
381                 s = newSurface(pos, rightOrient, chord,
382                                flap0, flap1, slat, spoiler);
383                 sr = new SurfRec();
384                 sr->surface = s;
385                 sr->weight = chord * segWid;
386                 s->setTotalDrag(sr->weight);
387                 s->setTwist(_twist * frac);
388                 _surfs.add(sr);
389             }
390         }
391     }
392
393     // Last of all, re-set the incidence in case setIncidence() was
394     // called before we were compiled.
395     setIncidence(_incidence);
396 }
397
398 float Wing::getDragScale()
399 {
400     return _dragScale;
401 }
402
403 void Wing::setDragScale(float scale)
404 {
405     _dragScale = scale;
406     int i;
407     for(i=0; i<_surfs.size(); i++) {
408         SurfRec* s = (SurfRec*)_surfs.get(i);
409         s->surface->setTotalDrag(scale * s->weight);
410     }
411 }
412
413 void Wing::setLiftRatio(float ratio)
414 {
415     _liftRatio = ratio;
416     int i;
417     for(i=0; i<_surfs.size(); i++)
418         ((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio);
419 }
420
421 float Wing::getLiftRatio()
422 {
423     return _liftRatio;
424 }
425
426 Surface* Wing::newSurface(float* pos, float* orient, float chord,
427                           bool flap0, bool flap1, bool slat, bool spoiler)
428 {
429     Surface* s = new Surface();
430
431     s->setPosition(pos);
432     s->setOrientation(orient);
433     s->setChord(chord);
434
435     // Camber is expressed as a fraction of stall peak, so convert.
436     s->setBaseZDrag(_camber*_stallPeak);
437
438     // The "main" (i.e. normal) stall angle
439     float stallAoA = _stall - _stallWidth/4;
440     s->setStall(0, stallAoA);
441     s->setStallWidth(0, _stallWidth);
442     s->setStallPeak(0, _stallPeak);
443
444     // The negative AoA stall is the same if we're using an uncambered
445     // airfoil, otherwise a "little badder".
446     if(_camber > 0) {
447         s->setStall(1, stallAoA * 0.8f);
448         s->setStallWidth(1, _stallWidth * 0.5f);
449     } else {
450         s->setStall(1, stallAoA);
451         s->setStall(1, _stallWidth);
452     }
453
454     // The "reverse" stalls are unmeasurable junk.  Just use 13deg and
455     // "sharp".
456     s->setStallPeak(1, 1);
457     int i;
458     for(i=2; i<4; i++) {
459         s->setStall(i, 0.2267f);
460         s->setStallWidth(i, 0.01);
461     }
462     
463     if(flap0)   s->setFlapParams(_flap0Lift, _flap0Drag);
464     if(flap1)   s->setFlapParams(_flap1Lift, _flap1Drag);
465     if(slat)    s->setSlatParams(_slatAoA, _slatDrag);
466     if(spoiler) s->setSpoilerParams(_spoilerLift, _spoilerDrag);    
467
468     if(flap0)   _flap0Surfs.add(s);
469     if(flap1)   _flap1Surfs.add(s);
470     if(slat)    _slatSurfs.add(s);
471     if(spoiler) _spoilerSurfs.add(s);
472
473     s->setInducedDrag(_inducedDrag);
474
475     return s;
476 }
477
478 void Wing::interp(float* v1, float* v2, float frac, float* out)
479 {
480     out[0] = v1[0] + frac*(v2[0]-v1[0]);
481     out[1] = v1[1] + frac*(v2[1]-v1[1]);
482     out[2] = v1[2] + frac*(v2[2]-v1[2]);
483 }
484
485 }; // namespace yasim