10 _base[0] = _base[1] = _base[2] = 0;
46 for(i=0; i<_surfs.size(); i++) {
47 SurfRec* s = (SurfRec*)_surfs.get(i);
53 int Wing::numSurfaces()
58 Surface* Wing::getSurface(int n)
60 return ((SurfRec*)_surfs.get(n))->surface;
63 float Wing::getSurfaceWeight(int n)
65 return ((SurfRec*)_surfs.get(n))->weight;
68 void Wing::setMirror(bool mirror)
73 void Wing::setBase(float* base)
76 for(i=0; i<3; i++) _base[i] = base[i];
79 void Wing::setLength(float length)
84 void Wing::setChord(float chord)
89 void Wing::setTaper(float taper)
94 void Wing::setSweep(float sweep)
99 void Wing::setDihedral(float dihedral)
101 _dihedral = dihedral;
104 void Wing::setStall(float aoa)
109 void Wing::setStallWidth(float angle)
114 void Wing::setStallPeak(float fraction)
116 _stallPeak = fraction;
119 void Wing::setTwist(float angle)
124 void Wing::setCamber(float camber)
129 void Wing::setIncidence(float incidence)
131 _incidence = incidence;
133 for(i=0; i<_surfs.size(); i++)
134 ((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence);
137 void Wing::setFlap0(float start, float end, float lift, float drag)
145 void Wing::setFlap1(float start, float end, float lift, float drag)
153 void Wing::setSlat(float start, float end, float aoa, float drag)
161 void Wing::setSpoiler(float start, float end, float lift, float drag)
163 _spoilerStart = start;
169 void Wing::setFlap0(float lval, float rval)
171 lval = Math::clamp(lval, -1, 1);
172 rval = Math::clamp(rval, -1, 1);
174 for(i=0; i<_flap0Surfs.size(); i++) {
175 ((Surface*)_flap0Surfs.get(i))->setFlap(lval);
176 if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
180 void Wing::setFlap0Effectiveness(float lval)
182 lval = Math::clamp(lval, 1, 10);
184 for(i=0; i<_flap0Surfs.size(); i++) {
185 ((Surface*)_flap0Surfs.get(i))->setFlapEffectiveness(lval);
186 // if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlapEffectiveness(rval);
190 void Wing::setFlap1(float lval, float rval)
192 lval = Math::clamp(lval, -1, 1);
193 rval = Math::clamp(rval, -1, 1);
195 for(i=0; i<_flap1Surfs.size(); i++) {
196 ((Surface*)_flap1Surfs.get(i))->setFlap(lval);
197 if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
201 void Wing::setFlap1Effectiveness(float lval)
203 lval = Math::clamp(lval, 1, 10);
205 for(i=0; i<_flap1Surfs.size(); i++) {
206 ((Surface*)_flap1Surfs.get(i))->setFlapEffectiveness(lval);
207 // if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
211 void Wing::setSpoiler(float lval, float rval)
213 lval = Math::clamp(lval, 0, 1);
214 rval = Math::clamp(rval, 0, 1);
216 for(i=0; i<_spoilerSurfs.size(); i++) {
217 ((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
218 if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
222 void Wing::setSlat(float val)
224 val = Math::clamp(val, 0, 1);
226 for(i=0; i<_slatSurfs.size(); i++)
227 ((Surface*)_slatSurfs.get(i))->setSlat(val);
230 float Wing::getGroundEffect(float* posOut)
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]));
239 void Wing::getTip(float* tip)
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);
249 bool Wing::isMirrored()
256 // Have we already been compiled?
257 if(_surfs.size() != 0) return;
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
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;
271 // Sort in increasing order
273 for(i=0; i<10; i++) {
275 float minVal = bounds[i];
277 for(j=i+1; j<10; j++) {
278 if(bounds[j] < minVal) {
283 float tmp = bounds[i];
284 bounds[i] = minVal; bounds[minIdx] = tmp;
288 float last = bounds[0];
290 for(i=1; i<10; i++) {
291 if(bounds[i] != last)
292 bounds[nbounds++] = bounds[i];
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;
300 // Generating a unit vector pointing out the left wing.
302 left[0] = -Math::tan(_sweep);
303 left[1] = Math::cos(_dihedral);
304 left[2] = Math::sin(_dihedral);
305 Math::unit3(left, left);
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);
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
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;
323 Math::cross3(x, y, z);
325 Math::cross3(y, z, x);
328 // Derive the right side orientation matrix from this one.
330 for(i=0; i<9; i++) rightOrient[i] = orient[i];
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];
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];
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;
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;
353 // FIXME: Should probably detect an error here if both flap0
354 // and flap1 are set. Right now flap1 overrides.
356 int nSegs = (int)Math::ceil((end-start)/segLen);
357 if (_twist != 0 && nSegs < 8) // more segments if twisted
359 float segWid = _length * (end - start)/nSegs;
362 for(j=0; j<nSegs; j++) {
363 float frac = start + (j+0.5f) * (end-start)/nSegs;
365 interp(root, tip, frac, pos);
367 float chord = _chord * (1 - (1-_taper)*frac);
369 Surface *s = newSurface(pos, orient, chord,
370 flap0, flap1, slat, spoiler);
372 SurfRec *sr = new SurfRec();
374 sr->weight = chord * segWid;
375 s->setTotalDrag(sr->weight);
376 s->setTwist(_twist * frac);
381 s = newSurface(pos, rightOrient, chord,
382 flap0, flap1, slat, spoiler);
385 sr->weight = chord * segWid;
386 s->setTotalDrag(sr->weight);
387 s->setTwist(_twist * frac);
393 // Last of all, re-set the incidence in case setIncidence() was
394 // called before we were compiled.
395 setIncidence(_incidence);
398 float Wing::getDragScale()
403 void Wing::setDragScale(float scale)
407 for(i=0; i<_surfs.size(); i++) {
408 SurfRec* s = (SurfRec*)_surfs.get(i);
409 s->surface->setTotalDrag(scale * s->weight);
413 void Wing::setLiftRatio(float ratio)
417 for(i=0; i<_surfs.size(); i++)
418 ((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio);
421 float Wing::getLiftRatio()
426 Surface* Wing::newSurface(float* pos, float* orient, float chord,
427 bool flap0, bool flap1, bool slat, bool spoiler)
429 Surface* s = new Surface();
432 s->setOrientation(orient);
435 // Camber is expressed as a fraction of stall peak, so convert.
436 s->setBaseZDrag(_camber*_stallPeak);
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);
444 // The negative AoA stall is the same if we're using an uncambered
445 // airfoil, otherwise a "little badder".
447 s->setStall(1, stallAoA * 0.8f);
448 s->setStallWidth(1, _stallWidth * 0.5f);
450 s->setStall(1, stallAoA);
451 s->setStall(1, _stallWidth);
454 // The "reverse" stalls are unmeasurable junk. Just use 13deg and
456 s->setStallPeak(1, 1);
459 s->setStall(i, 0.2267f);
460 s->setStallWidth(i, 0.01);
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);
468 if(flap0) _flap0Surfs.add(s);
469 if(flap1) _flap1Surfs.add(s);
470 if(slat) _slatSurfs.add(s);
471 if(spoiler) _spoilerSurfs.add(s);
473 s->setInducedDrag(_inducedDrag);
478 void Wing::interp(float* v1, float* v2, float frac, float* out)
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]);
485 }; // namespace yasim