9 _base[0] = _base[1] = _base[2] = 0;
42 for(int i=0; i<_surfs.size(); i++) {
43 SurfRec* s = (SurfRec*)_surfs.get(i);
49 int Wing::numSurfaces()
54 Surface* Wing::getSurface(int n)
56 return ((SurfRec*)_surfs.get(n))->surface;
59 float Wing::getSurfaceWeight(int n)
61 return ((SurfRec*)_surfs.get(n))->weight;
64 void Wing::setMirror(bool mirror)
69 void Wing::setBase(float* base)
71 for(int i=0; i<3; i++) _base[i] = base[i];
74 void Wing::setLength(float length)
79 void Wing::setChord(float chord)
84 void Wing::setTaper(float taper)
89 void Wing::setSweep(float sweep)
94 void Wing::setDihedral(float dihedral)
99 void Wing::setStall(float aoa)
104 void Wing::setStallWidth(float angle)
109 void Wing::setStallPeak(float fraction)
111 _stallPeak = fraction;
114 void Wing::setCamber(float camber)
119 void Wing::setIncidence(float incidence)
121 _incidence = incidence;
122 for(int i=0; i<_surfs.size(); i++)
123 ((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence);
126 void Wing::setFlap0(float start, float end, float lift, float drag)
134 void Wing::setFlap1(float start, float end, float lift, float drag)
142 void Wing::setSlat(float start, float end, float aoa, float drag)
150 void Wing::setSpoiler(float start, float end, float lift, float drag)
152 _spoilerStart = start;
158 void Wing::setFlap0(float lval, float rval)
160 for(int i=0; i<_flap0Surfs.size(); i++) {
161 ((Surface*)_flap0Surfs.get(i))->setFlap(lval);
162 if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
166 void Wing::setFlap1(float lval, float rval)
168 for(int i=0; i<_flap1Surfs.size(); i++) {
169 ((Surface*)_flap1Surfs.get(i))->setFlap(lval);
170 if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
174 void Wing::setSpoiler(float lval, float rval)
176 for(int i=0; i<_spoilerSurfs.size(); i++) {
177 ((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
178 if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
182 void Wing::setSlat(float val)
184 for(int i=0; i<_slatSurfs.size(); i++)
185 ((Surface*)_slatSurfs.get(i))->setSlat(val);
190 // Have we already been compiled?
191 if(_surfs.size() != 0) return;
193 // Assemble the start/end coordinates into an array, sort them,
194 // and remove duplicates. This gives us the boundaries of our
197 bounds[0] = _flap0Start; bounds[1] = _flap0End;
198 bounds[2] = _flap1Start; bounds[3] = _flap1End;
199 bounds[4] = _spoilerStart; bounds[5] = _spoilerEnd;
200 bounds[6] = _slatStart; bounds[7] = _slatEnd;
202 // Sort in increasing order
203 for(int i=0; i<8; i++) {
205 float minVal = bounds[i];
206 for(int j=i+1; j<8; j++) {
207 if(bounds[j] < minVal) {
212 float tmp = bounds[i];
213 bounds[i] = minVal; bounds[minIdx] = tmp;
217 float last = bounds[0];
219 for(int i=1; i<8; i++) {
220 if(bounds[i] != last)
221 bounds[nbounds++] = bounds[i];
225 // Calculate a "nominal" segment length equal to an average chord,
226 // normalized to lie within 0-1 over the length of the wing.
227 float segLen = _chord * (0.5*(_taper+1)) / _length;
229 // Generating a unit vector pointing out the left wing.
231 left[0] = -Math::tan(_sweep);
232 left[1] = Math::cos(_dihedral);
233 left[2] = Math::sin(_dihedral);
234 Math::unit3(left, left);
236 // Calculate coordinates for the root and tip of the wing
237 float root[3], tip[3];
238 Math::set3(_base, root);
239 Math::set3(left, tip);
240 Math::mul3(_length, tip, tip);
241 Math::add3(root, tip, tip);
243 // The wing's Y axis will be the "left" vector. The Z axis will
244 // be perpendicular to this and the local (!) X axis, because we
245 // want motion along the local X axis to be zero AoA (i.e. in the
246 // wing's XY plane) by definition. Then the local X coordinate is
248 float orient[9], rightOrient[9];
249 float *x = orient, *y = orient+3, *z = orient+6;
250 x[0] = 1; x[1] = 0; x[2] = 0;
252 Math::cross3(x, y, z);
254 Math::cross3(y, z, x);
257 // Derive the right side orientation matrix from this one.
258 for(int i=0; i<9; i++) rightOrient[i] = orient[i];
260 // Negate all Y coordinates, this gets us a valid basis, but
261 // it's left handed! So...
262 for(int i=1; i<9; i+=3) rightOrient[i] = -rightOrient[i];
264 // Change the direction of the Y axis to get back to a
265 // right-handed system.
266 for(int i=3; i<6; i++) rightOrient[i] = -rightOrient[i];
269 // Now go through each boundary and make segments
270 for(int i=0; i<(nbounds-1); i++) {
271 float start = bounds[i];
272 float end = bounds[i+1];
273 float mid = (start+end)/2;
275 bool flap0=0, flap1=0, slat=0, spoiler=0;
276 if(_flap0Start < mid && mid < _flap0End) flap0 = 1;
277 if(_flap1Start < mid && mid < _flap1End) flap1 = 1;
278 if(_slatStart < mid && mid < _slatEnd) slat = 1;
279 if(_spoilerStart < mid && mid < _spoilerEnd) spoiler = 1;
281 // FIXME: Should probably detect an error here if both flap0
282 // and flap1 are set. Right now flap1 overrides.
284 int nSegs = (int)Math::ceil((end-start)/segLen);
285 float segWid = _length * (end - start)/nSegs;
287 for(int j=0; j<nSegs; j++) {
288 float frac = start + (j+0.5) * (end-start)/nSegs;
290 interp(root, tip, frac, pos);
292 float chord = _chord * (1 - (1-_taper)*frac);
294 Surface *s = newSurface(pos, orient, chord,
295 flap0, flap1, slat, spoiler);
297 SurfRec *sr = new SurfRec();
299 sr->weight = chord * segWid;
300 s->setTotalDrag(sr->weight);
305 s = newSurface(pos, rightOrient, chord,
306 flap0, flap1, slat, spoiler);
309 sr->weight = chord * segWid;
310 s->setTotalDrag(sr->weight);
317 float Wing::getDragScale()
322 void Wing::setDragScale(float scale)
325 for(int i=0; i<_surfs.size(); i++) {
326 SurfRec* s = (SurfRec*)_surfs.get(i);
327 s->surface->setTotalDrag(scale * s->weight);
331 void Wing::setLiftRatio(float ratio)
334 for(int i=0; i<_surfs.size(); i++)
335 ((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio);
338 float Wing::getLiftRatio()
343 Surface* Wing::newSurface(float* pos, float* orient, float chord,
344 bool flap0, bool flap1, bool slat, bool spoiler)
346 Surface* s = new Surface();
349 s->setOrientation(orient);
352 // Camber is expressed as a fraction of stall peak, so convert.
353 s->setBaseZDrag(_camber*_stallPeak);
355 // The "main" (i.e. normal) stall angle
356 float stallAoA = _stall - _stallWidth/4;
357 s->setStall(0, stallAoA);
358 s->setStallWidth(0, _stallWidth);
359 s->setStallPeak(0, _stallPeak);
361 // The negative AoA stall is the same if we're using an uncambered
362 // airfoil, otherwise a "little badder".
364 s->setStall(1, stallAoA * 0.8);
365 s->setStallWidth(1, _stallWidth * 0.5);
367 s->setStall(1, stallAoA);
368 s->setStall(1, _stallWidth);
371 // The "reverse" stalls are unmeasurable junk. Just use 13deg and
373 s->setStallPeak(1, 1);
374 for(int i=2; i<4; i++) {
375 s->setStall(i, 0.2267);
376 s->setStallWidth(i, 1);
379 if(flap0) s->setFlapParams(_flap0Lift, _flap0Drag);
380 if(flap1) s->setFlapParams(_flap1Lift, _flap1Drag);
381 if(slat) s->setSlatParams(_slatAoA, _slatDrag);
382 if(spoiler) s->setSpoilerParams(_spoilerLift, _spoilerDrag);
384 if(flap0) _flap0Surfs.add(s);
385 if(flap1) _flap1Surfs.add(s);
386 if(slat) _slatSurfs.add(s);
387 if(spoiler) _spoilerSurfs.add(s);
392 void Wing::interp(float* v1, float* v2, float frac, float* out)
394 out[0] = v1[0] + frac*(v2[0]-v1[0]);
395 out[1] = v1[1] + frac*(v2[1]-v1[1]);
396 out[2] = v1[2] + frac*(v2[2]-v1[2]);
399 }; // namespace yasim