From ea8bfba98adbdfea204b5b109077cb38a5b079a6 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Fri, 5 May 2017 16:25:16 +0200 Subject: [PATCH 01/29] YASim: add method to Wing and clarify member name. --- src/FDM/YASim/Wing.cpp | 18 +++++++++++++++--- src/FDM/YASim/Wing.hpp | 7 +++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index 81aa4e3e9..e8c77be07 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -11,7 +11,7 @@ Wing::Wing(Version *ver, bool mirror, float* base, float chord, _chord(chord), _length(length), _taper(taper), - _sweep(sweep), + _sweepAngleCenterLine(sweep), _dihedral(dihedral), _twist(twist) { @@ -129,7 +129,7 @@ void Wing::calculateWingCoordinateSystem() { // (tail incidence is varied by the solver) // Generating a unit vector pointing out the left wing. float left[3]; - left[0] = -Math::tan(_sweep); + left[0] = -Math::tan(_sweepAngleCenterLine); left[1] = Math::cos(_dihedral); left[2] = Math::sin(_dihedral); Math::unit3(left, left); @@ -175,9 +175,21 @@ void Wing::calculateMAC() const float commonFactor = _chord*(0.5+_taper)/(3*_chord*(1+_taper)); _mac = _chord-(2*_chord*(1-_taper)*commonFactor); _macRootDistance = _netSpan*commonFactor; - _macX = _base[0]-Math::tan(_sweep) * _macRootDistance + _mac/2; + _macX = _base[0]-Math::tan(_sweepAngleCenterLine) * _macRootDistance + _mac/2; } +float Wing::calculateSweepAngleLeadingEdge() +{ + if (_length == 0) { + return 0; + } + return Math::atan( + (sin(_sweepAngleCenterLine)+(1-_taper)*_chord/(2*_length)) / + cos(_sweepAngleCenterLine) + ); +} + + void Wing::compile() { // Have we already been compiled? diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index e7496c61d..ac206bd4e 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -31,7 +31,7 @@ public: // fraction of chord at wing tip, 0..1 float getTaper() const { return _taper; }; // radians - float getSweep() const { return _sweep; }; + float getSweep() const { return _sweepAngleCenterLine; }; // radians, positive is "up" void setDihedral(float dihedral) { _dihedral = dihedral; } float getDihedral() const { return _dihedral; }; @@ -96,6 +96,7 @@ private: void calculateTip(); void calculateSpan(); void calculateMAC(); + float calculateSweepAngleLeadingEdge(); void addSurface(Surface* s, float weight, float twist); struct SurfRec { Surface * surface; float weight; }; @@ -110,9 +111,11 @@ private: bool _mirror {false}; float _base[3] {0,0,0}; float _chord {0}; + // length is distance from base to tip, not wing span float _length {0}; float _taper {1}; - float _sweep {0}; + // sweep of center line, not leading edge! + float _sweepAngleCenterLine {0}; float _dihedral {0}; // calculated from above From 3ac90ee866667671f49fabb0c34c9eabd4630558 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Tue, 13 Jun 2017 21:05:41 +0200 Subject: [PATCH 02/29] YASIM: minor corrections and safeguards. --- src/FDM/YASim/Atmosphere.cpp | 2 +- src/FDM/YASim/ControlMap.cpp | 9 +++++---- src/FDM/YASim/Vector.hpp | 5 +++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/FDM/YASim/Atmosphere.cpp b/src/FDM/YASim/Atmosphere.cpp index 5e751dbce..dd1649993 100644 --- a/src/FDM/YASim/Atmosphere.cpp +++ b/src/FDM/YASim/Atmosphere.cpp @@ -211,7 +211,7 @@ bool Atmosphere::test() { fprintf(stderr, "Columns = %d\n", numColumns); fprintf(stderr, "Rows = %d\n", rows); - for (int alt = 0; alt < maxTableIndex(); alt++) { + for (int alt = 0; alt <= maxTableIndex(); alt++) { float density = calcStdDensity(data[alt][PRESSURE], data[alt][TEMPERATURE]); float delta = data[alt][DENSITY] - density; fprintf(stderr, "%d : %f \n", alt, delta); diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp index bf56615f9..9fb6d0985 100644 --- a/src/FDM/YASim/ControlMap.cpp +++ b/src/FDM/YASim/ControlMap.cpp @@ -132,11 +132,12 @@ void ControlMap::setInput(int input, float val) int ControlMap::getOutputHandle(void* obj, int type) { for(int i=0; i<_outputs.size(); i++) { - OutRec* o = (OutRec*)_outputs.get(i); - if(o->object == obj && o->type == type) - return i; + OutRec* o = (OutRec*)_outputs.get(i); + if(o->object == obj && o->type == type) + return i; } - return 0; + fprintf(stderr, "ControlMap::getOutputHandle cannot find *%d, type %d \n", obj, type); + return -1; } void ControlMap::setTransitionTime(int handle, float time) diff --git a/src/FDM/YASim/Vector.hpp b/src/FDM/YASim/Vector.hpp index 33079558b..e1a493c80 100644 --- a/src/FDM/YASim/Vector.hpp +++ b/src/FDM/YASim/Vector.hpp @@ -1,6 +1,8 @@ #ifndef _VECTOR_HPP #define _VECTOR_HPP +#include +#include // // Excruciatingly simple vector-of-pointers class. Easy & useful. // No support for addition of elements anywhere but at the end of the @@ -46,11 +48,14 @@ inline int Vector::add(void* p) inline void* Vector::get(int i) const { + assert(i >= 0 and i < _sz); return _array[i]; + } inline void Vector::set(int i, void* p) { + assert(i >= 0 and i < _sz); _array[i] = p; } From 95ee37c9b996e945f5bd81d55f2169ecd73b0ca1 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Tue, 13 Jun 2017 21:15:46 +0200 Subject: [PATCH 03/29] YASIM refactoring of Wing class --- src/FDM/YASim/FGFDM.cpp | 65 ++++++++++++++++++++++++----------------- src/FDM/YASim/Wing.cpp | 59 ++++++++++++------------------------- src/FDM/YASim/Wing.hpp | 42 +++++++++++++------------- 3 files changed, 77 insertions(+), 89 deletions(-) diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index 7fe64908b..bd689d9e2 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -308,7 +308,8 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) #undef p2 r->setInUse(); } else if(eq(name, "wing")) { - _airplane.setWing(parseWing(a, name, &_airplane)); + Wing *wing = parseWing(a, name, &_airplane); + _airplane.setWing(wing); } else if(eq(name, "hstab")) { _airplane.setTail(parseWing(a, name, &_airplane)); } else if(eq(name, "vstab") || eq(name, "mstab")) { @@ -537,23 +538,30 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) w->setStall(attrf(a, "aoa") * DEG2RAD); w->setStallWidth(attrf(a, "width", 2) * DEG2RAD); w->setStallPeak(attrf(a, "peak", 1.5)); - } else if(eq(name, "flap0")) { - ((Wing*)_currObj)->setFlap0Params(attrf(a, "start"), attrf(a, "end"), - attrf(a, "lift"), attrf(a, "drag")); - } else if(eq(name, "flap1")) { - ((Wing*)_currObj)->setFlap1Params(attrf(a, "start"), attrf(a, "end"), - attrf(a, "lift"), attrf(a, "drag")); - } else if(eq(name, "slat")) { - ((Wing*)_currObj)->setSlatParams(attrf(a, "start"), attrf(a, "end"), - attrf(a, "aoa"), attrf(a, "drag")); - } else if(eq(name, "spoiler")) { - ((Wing*)_currObj)->setSpoilerParams(attrf(a, "start"), attrf(a, "end"), - attrf(a, "lift"), attrf(a, "drag")); - /* } else if(eq(name, "collective")) { - ((Rotor*)_currObj)->setcollective(attrf(a, "min"), attrf(a, "max")); - } else if(eq(name, "cyclic")) { - ((Rotor*)_currObj)->setcyclic(attrf(a, "ail"), attrf(a, "ele")); - */ + } else if(eq(name, "flap0") || eq(name, "flap1") || eq(name, "spoiler") || eq(name, "slat")) { + FlapParams fp; + fp.start = attrf(a, "start"); + fp.end = attrf(a, "end"); + if (eq(name, "slat")) { + fp.aoa = attrf(a, "aoa"); + } + else { + fp.lift = attrf(a, "lift"); + } + fp.drag = attrf(a, "drag"); + + if (eq(name, "flap0")) { + ((Wing*)_currObj)->setFlapParams(WING_FLAP0, fp); + } + if (eq(name, "flap1")) { + ((Wing*)_currObj)->setFlapParams(WING_FLAP1, fp); + } + if (eq(name, "spoiler")) { + ((Wing*)_currObj)->setFlapParams(WING_SPOILER, fp); + } + if (eq(name, "slat")) { + ((Wing*)_currObj)->setFlapParams(WING_SLAT, fp); + } } else if(eq(name, "actionpt")) { v[0] = attrf(a, "x"); v[1] = attrf(a, "y"); @@ -807,14 +815,19 @@ Wing* FGFDM::parseWing(XMLAttributes* a, const char* type, Version * version) defDihed = 90; mirror = false; } - - float base[3]; - base[0] = attrf(a, "x"); - base[1] = attrf(a, "y"); - base[2] = attrf(a, "z"); - + + float isSection = attrb(a, "section"); + float base[3] {0,0,0}; + float chord {0}; + if (!isSection) { + base[0] = attrf(a, "x"); + base[1] = attrf(a, "y"); + base[2] = attrf(a, "z"); + chord = attrf(a, "chord"); + } float length = attrf(a, "length"); - float chord = attrf(a, "chord"); + + // optional attributes (with defaults) float sweep = attrf(a, "sweep", 0) * DEG2RAD; float taper = attrf(a, "taper", 1); float dihedral = attrf(a, "dihedral", defDihed) * DEG2RAD; @@ -831,7 +844,7 @@ Wing* FGFDM::parseWing(XMLAttributes* a, const char* type, Version * version) } Wing* w = new Wing(version, mirror, base, chord, length, - taper, sweep, dihedral, twist); + taper, sweep, dihedral, twist); w->setIncidence(incidence); w->setCamber(camber); diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index e8c77be07..e39bb4d85 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -39,36 +39,9 @@ void Wing::setIncidence(float incidence) ((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence); } -void Wing::setFlap0Params(float start, float end, float lift, float drag) +void Wing::setFlapParams(WingFlaps i, FlapParams fp) { - _flap0Start = start; - _flap0End = end; - _flap0Lift = lift; - _flap0Drag = drag; -} - -void Wing::setFlap1Params(float start, float end, float lift, float drag) -{ - _flap1Start = start; - _flap1End = end; - _flap1Lift = lift; - _flap1Drag = drag; -} - -void Wing::setSlatParams(float start, float end, float aoa, float drag) -{ - _slatStart = start; - _slatEnd = end; - _slatAoA = aoa; - _slatDrag = drag; -} - -void Wing::setSpoilerParams(float start, float end, float lift, float drag) -{ - _spoilerStart = start; - _spoilerEnd = end; - _spoilerLift = lift; - _spoilerDrag = drag; + _flapParams[i] = fp; } void Wing::setFlap0Pos(float lval, float rval) @@ -201,10 +174,14 @@ void Wing::compile() // segments. const int NUM_BOUNDS {10}; float bounds[NUM_BOUNDS]; - bounds[0] = _flap0Start; bounds[1] = _flap0End; - bounds[2] = _flap1Start; bounds[3] = _flap1End; - bounds[4] = _spoilerStart; bounds[5] = _spoilerEnd; - bounds[6] = _slatStart; bounds[7] = _slatEnd; + bounds[0] = _flapParams[WING_FLAP0].start; + bounds[1] = _flapParams[WING_FLAP0].end; + bounds[2] = _flapParams[WING_FLAP1].start; + bounds[3] = _flapParams[WING_FLAP1].end; + bounds[4] = _flapParams[WING_SPOILER].start; + bounds[5] = _flapParams[WING_SPOILER].end; + bounds[6] = _flapParams[WING_SLAT].start; + bounds[7] = _flapParams[WING_SLAT].end; //and don't forget the root and the tip of the wing itself bounds[8] = 0; bounds[9] = 1; @@ -243,10 +220,10 @@ void Wing::compile() float mid = (start+end)/2; bool hasFlap0=0, hasFlap1=0, hasSlat=0, hasSpoiler=0; - if(_flap0Start < mid && mid < _flap0End) hasFlap0 = 1; - if(_flap1Start < mid && mid < _flap1End) hasFlap1 = 1; - if(_slatStart < mid && mid < _slatEnd) hasSlat = 1; - if(_spoilerStart < mid && mid < _spoilerEnd) hasSpoiler = 1; + if(_flapParams[WING_FLAP0].start < mid && mid < _flapParams[WING_FLAP0].end) hasFlap0 = 1; + if(_flapParams[WING_FLAP1].start < mid && mid < _flapParams[WING_FLAP1].end) hasFlap1 = 1; + if(_flapParams[WING_SLAT].start < mid && mid < _flapParams[WING_SLAT].end) hasSlat = 1; + if(_flapParams[WING_SPOILER].start < mid && mid < _flapParams[WING_SPOILER].end) hasSpoiler = 1; // FIXME: Should probably detect an error here if both flap0 // and flap1 are set. Right now flap1 overrides. @@ -353,10 +330,10 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord, s->setStallWidth(i, 0.01); } - if(hasFlap0) s->setFlapParams(_flap0Lift, _flap0Drag); - if(hasFlap1) s->setFlapParams(_flap1Lift, _flap1Drag); - if(hasSlat) s->setSlatParams(_slatAoA, _slatDrag); - if(hasSpoiler) s->setSpoilerParams(_spoilerLift, _spoilerDrag); + if(hasFlap0) s->setFlapParams(_flapParams[WING_FLAP0].lift, _flapParams[WING_FLAP0].drag); + if(hasFlap1) s->setFlapParams(_flapParams[WING_FLAP1].lift, _flapParams[WING_FLAP1].drag); + if(hasSlat) s->setSlatParams(_flapParams[WING_SLAT].aoa, _flapParams[WING_SLAT].drag); + if(hasSpoiler) s->setSpoilerParams(_flapParams[WING_SPOILER].lift, _flapParams[WING_SPOILER].drag); if(hasFlap0) _flap0Surfs.add(s); if(hasFlap1) _flap1Surfs.add(s); diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index ac206bd4e..3e913d43b 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -9,8 +9,24 @@ namespace yasim { class Surface; +struct FlapParams { + float start {0}; + float end {0}; + float lift {0}; + float drag {0}; + float aoa {0}; +}; + +enum WingFlaps { + WING_FLAP0, + WING_FLAP1, + WING_SLAT, + WING_SPOILER +}; + // FIXME: need to handle "inverted" controls for mirrored wings. class Wing { + public: Wing(Version *ver, bool mirror, float* base, float chord, float length, float taper = 1, float sweep = 0, float dihedral = 0, float twist = 0); @@ -47,10 +63,7 @@ public: void setInducedDrag(float drag) { _inducedDrag = drag; } - void setFlap0Params(float start, float end, float lift, float drag); - void setFlap1Params(float start, float end, float lift, float drag); - void setSpoilerParams(float start, float end, float lift, float drag); - void setSlatParams(float start, float end, float aoa, float drag); + void setFlapParams(WingFlaps i, FlapParams fp); // Set the control axes for the sub-surfaces void setFlap0Pos(float lval, float rval); @@ -88,6 +101,7 @@ public: void setLiftRatio(float ratio); float getLiftRatio() const { return _liftRatio; } + private: void interp(const float* v1, const float* v2, const float frac, float* out); Surface* newSurface(float* pos, float* orient, float chord, @@ -97,6 +111,7 @@ private: void calculateSpan(); void calculateMAC(); float calculateSweepAngleLeadingEdge(); + void addSurface(Surface* s, float weight, float twist); struct SurfRec { Surface * surface; float weight; }; @@ -141,25 +156,8 @@ private: float _dragScale {1}; float _liftRatio {1}; - float _flap0Start {0}; - float _flap0End {0}; - float _flap0Lift {0}; - float _flap0Drag {0}; + FlapParams _flapParams[sizeof(WingFlaps)]; - float _flap1Start {0}; - float _flap1End {0}; - float _flap1Lift {0}; - float _flap1Drag {0}; - - float _spoilerStart {0}; - float _spoilerEnd {0}; - float _spoilerLift {0}; - float _spoilerDrag {0}; - - float _slatStart {0}; - float _slatEnd {0}; - float _slatAoA {0}; - float _slatDrag {0}; }; }; // namespace yasim From 77a9cca6d52da19c03277ac5a6ffb1d8fa21d29b Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sat, 11 Nov 2017 15:06:08 +0100 Subject: [PATCH 04/29] YASIM refactoring Wing class (flaps) --- src/FDM/YASim/ControlMap.cpp | 12 +++--- src/FDM/YASim/Wing.cpp | 77 ++++++++++++++---------------------- src/FDM/YASim/Wing.hpp | 21 ++++------ 3 files changed, 43 insertions(+), 67 deletions(-) diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp index 9fb6d0985..4beef0fe0 100644 --- a/src/FDM/YASim/ControlMap.cpp +++ b/src/FDM/YASim/ControlMap.cpp @@ -219,12 +219,12 @@ void ControlMap::applyControls(float dt) case LEXTEND: ((Launchbar*)obj)->setExtension(lval); break; case LACCEL: ((Launchbar*)obj)->setAcceleration(lval); break; case CASTERING:((Gear*)obj)->setCastering(lval != 0); break; - case SLAT: ((Wing*)obj)->setSlatPos(lval); break; - case FLAP0: ((Wing*)obj)->setFlap0Pos(lval, rval); break; - case FLAP0EFFECTIVENESS: ((Wing*)obj)->setFlap0Effectiveness(lval); break; - case FLAP1: ((Wing*)obj)->setFlap1Pos(lval, rval); break; - case FLAP1EFFECTIVENESS: ((Wing*)obj)->setFlap1Effectiveness(lval); break; - case SPOILER: ((Wing*)obj)->setSpoilerPos(lval, rval); break; + case SLAT: ((Wing*)obj)->setFlapPos(WING_SLAT,lval); break; + case FLAP0: ((Wing*)obj)->setFlapPos(WING_FLAP0, lval, rval); break; + case FLAP0EFFECTIVENESS: ((Wing*)obj)->setFlapEffectiveness(WING_FLAP0,lval); break; + case FLAP1: ((Wing*)obj)->setFlapPos(WING_FLAP1,lval, rval); break; + case FLAP1EFFECTIVENESS: ((Wing*)obj)->setFlapEffectiveness(WING_FLAP1,lval); break; + case SPOILER: ((Wing*)obj)->setFlapPos(WING_SPOILER, lval, rval); break; case COLLECTIVE: ((Rotor*)obj)->setCollective(lval); break; case CYCLICAIL: ((Rotor*)obj)->setCyclicail(lval,rval); break; case CYCLICELE: ((Rotor*)obj)->setCyclicele(lval,rval); break; diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index e39bb4d85..f706c6d92 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -44,59 +44,40 @@ void Wing::setFlapParams(WingFlaps i, FlapParams fp) _flapParams[i] = fp; } -void Wing::setFlap0Pos(float lval, float rval) +void Wing::setFlapPos(WingFlaps f,float lval, float rval) { - lval = Math::clamp(lval, -1, 1); - rval = Math::clamp(rval, -1, 1); - for(int i=0; i<_flap0Surfs.size(); i++) { - ((Surface*)_flap0Surfs.get(i))->setFlapPos(lval); - if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlapPos(rval); + float min {-1}; + if (f == WING_SPOILER || f == WING_SLAT) { + min = 0; + } + lval = Math::clamp(lval, min, 1); + rval = Math::clamp(rval, min, 1); + for(int i=0; i<_flapSurfs[f].size(); i++) { + switch (f) { + case WING_FLAP0: + case WING_FLAP1: + ((Surface*)_flapSurfs[f].get(i))->setFlapPos(lval); + if(_mirror) ((Surface*)_flapSurfs[f].get(++i))->setFlapPos(rval); + break; + case WING_SLAT: + ((Surface*)_flapSurfs[f].get(i))->setSlatPos(lval); + break; + case WING_SPOILER: + ((Surface*)_flapSurfs[f].get(i))->setSpoilerPos(lval); + if(_mirror) ((Surface*)_flapSurfs[f].get(++i))->setSpoilerPos(rval); + break; + } } } -void Wing::setFlap0Effectiveness(float lval) +void Wing::setFlapEffectiveness(WingFlaps f, float lval) { lval = Math::clamp(lval, 1, 10); - for(int i=0; i<_flap0Surfs.size(); i++) { - ((Surface*)_flap0Surfs.get(i))->setFlapEffectiveness(lval); + for(int i=0; i<_flapSurfs[f].size(); i++) { + ((Surface*)_flapSurfs[f].get(i))->setFlapEffectiveness(lval); } } -void Wing::setFlap1Pos(float lval, float rval) -{ - lval = Math::clamp(lval, -1, 1); - rval = Math::clamp(rval, -1, 1); - for(int i=0; i<_flap1Surfs.size(); i++) { - ((Surface*)_flap1Surfs.get(i))->setFlapPos(lval); - if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlapPos(rval); - } -} - -void Wing::setFlap1Effectiveness(float lval) -{ - lval = Math::clamp(lval, 1, 10); - for(int i=0; i<_flap1Surfs.size(); i++) { - ((Surface*)_flap1Surfs.get(i))->setFlapEffectiveness(lval); - } -} - -void Wing::setSpoilerPos(float lval, float rval) -{ - lval = Math::clamp(lval, 0, 1); - rval = Math::clamp(rval, 0, 1); - for(int i=0; i<_spoilerSurfs.size(); i++) { - ((Surface*)_spoilerSurfs.get(i))->setSpoilerPos(lval); - if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoilerPos(rval); - } -} - -void Wing::setSlatPos(float val) -{ - val = Math::clamp(val, 0, 1); - for(int i=0; i<_slatSurfs.size(); i++) - ((Surface*)_slatSurfs.get(i))->setSlatPos(val); -} - void Wing::calculateWingCoordinateSystem() { // prepare wing coordinate system, ignoring incidence and twist for now // (tail incidence is varied by the solver) @@ -335,10 +316,10 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord, if(hasSlat) s->setSlatParams(_flapParams[WING_SLAT].aoa, _flapParams[WING_SLAT].drag); if(hasSpoiler) s->setSpoilerParams(_flapParams[WING_SPOILER].lift, _flapParams[WING_SPOILER].drag); - if(hasFlap0) _flap0Surfs.add(s); - if(hasFlap1) _flap1Surfs.add(s); - if(hasSlat) _slatSurfs.add(s); - if(hasSpoiler) _spoilerSurfs.add(s); + if(hasFlap0) _flapSurfs[WING_FLAP0].add(s); + if(hasFlap1) _flapSurfs[WING_FLAP1].add(s); + if(hasSlat) _flapSurfs[WING_SLAT].add(s); + if(hasSpoiler) _flapSurfs[WING_SPOILER].add(s); s->setInducedDrag(_inducedDrag); diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index 3e913d43b..d31d752c3 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -20,8 +20,8 @@ struct FlapParams { enum WingFlaps { WING_FLAP0, WING_FLAP1, + WING_SPOILER, WING_SLAT, - WING_SPOILER }; // FIXME: need to handle "inverted" controls for mirrored wings. @@ -65,13 +65,9 @@ public: void setFlapParams(WingFlaps i, FlapParams fp); - // Set the control axes for the sub-surfaces - void setFlap0Pos(float lval, float rval); - void setFlap1Pos(float lval, float rval); - void setSpoilerPos(float lval, float rval); - void setSlatPos(float val); - void setFlap0Effectiveness(float lval); - void setFlap1Effectiveness(float lval); + // propergate the control axes value for the sub-surfaces + void setFlapPos(WingFlaps i, float lval, float rval = 0); + void setFlapEffectiveness(WingFlaps f, float lval); // Compile the thing into a bunch of Surface objects void compile(); @@ -116,11 +112,10 @@ private: struct SurfRec { Surface * surface; float weight; }; - Vector _surfs; - Vector _flap0Surfs; - Vector _flap1Surfs; - Vector _slatSurfs; - Vector _spoilerSurfs; + // all surfaces of this wing + Vector _surfs; + // surfaces having a certain type of flap (flap, slat, spoiler) + Vector _flapSurfs[sizeof(WingFlaps)]; Version * _version; bool _mirror {false}; From 1f721fb6d8427f19806bd47157c7b693973a3c69 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sat, 11 Nov 2017 15:27:18 +0100 Subject: [PATCH 05/29] YASIM add new version tag for 2018.1 --- src/FDM/YASim/Version.cpp | 2 ++ src/FDM/YASim/Version.hpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/FDM/YASim/Version.cpp b/src/FDM/YASim/Version.cpp index c449db034..c54f207df 100644 --- a/src/FDM/YASim/Version.cpp +++ b/src/FDM/YASim/Version.cpp @@ -18,6 +18,8 @@ void Version::setVersion( const char * version ) _version = YASIM_VERSION_32; } else if( v == "2017.2" ) { _version = YASIM_VERSION_2017_2; + } else if( v == "2018.1" ) { + _version = YASIM_VERSION_2018_1; } else if( v == "YASIM_VERSION_CURRENT" ) { _version = YASIM_VERSION_CURRENT; } else { diff --git a/src/FDM/YASim/Version.hpp b/src/FDM/YASim/Version.hpp index 10e7e3e01..169379962 100644 --- a/src/FDM/YASim/Version.hpp +++ b/src/FDM/YASim/Version.hpp @@ -12,7 +12,8 @@ public: YASIM_VERSION_ORIGINAL = 0, YASIM_VERSION_32, YASIM_VERSION_2017_2, - YASIM_VERSION_CURRENT = YASIM_VERSION_2017_2 + YASIM_VERSION_2018_1, + YASIM_VERSION_CURRENT = YASIM_VERSION_2018_1 } YASIM_VERSION; void setVersion( const char * version ); From 1194b095250cb21ac97c8bb2289a410389b03e61 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sat, 18 Nov 2017 21:07:16 +0100 Subject: [PATCH 06/29] YASIM rename methods in class Surface --- src/FDM/YASim/Airplane.cpp | 16 ++++++++-------- src/FDM/YASim/Surface.hpp | 4 ++-- src/FDM/YASim/Wing.cpp | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index a419090f1..22fc093a1 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -240,7 +240,7 @@ int Airplane::addWeight(float* pos, float size) wr->surf = new Surface(this); wr->surf->setPosition(pos); - wr->surf->setTotalDrag(size*size); + wr->surf->setDragCoefficient(size*size); _model.addSurface(wr->surf); _surfs.add(wr->surf); @@ -329,7 +329,7 @@ float Airplane::compileWing(Wing* w) float dragSum = 0; for(int i=0; inumSurfaces(); i++) { Surface* s = (Surface*)w->getSurface(i); - float td = s->getTotalDrag(); + float td = s->getDragCoefficient(); int sid = s->getID(); _model.addSurface(s); @@ -437,9 +437,9 @@ float Airplane::compileFuselage(Fuselage* f) s->setYDrag(sideDrag*f->_cy); s->setZDrag(sideDrag*f->_cz); if( isVersionOrNewer( YASIM_VERSION_32 ) ) { - s->setTotalDrag(scale*segWgt); + s->setDragCoefficient(scale*segWgt); } else { - s->setTotalDrag(scale*segWgt*f->_cx); + s->setDragCoefficient(scale*segWgt*f->_cx); } s->setInducedDrag(f->_idrag); @@ -481,7 +481,7 @@ void Airplane::compileGear(GearRec* gr) Math::add3(pos, cmp, pos); s->setPosition(pos); - s->setTotalDrag(length*length); + s->setDragCoefficient(length*length); _model.addGear(g); _model.addSurface(s); @@ -826,17 +826,17 @@ void Airplane::applyDragFactor(float factor) } else { // Originally YASim applied the drag factor to all axes // for Fuselage Surfaces. - s->setTotalDrag(s->getTotalDrag() * applied); + s->setDragCoefficient(s->getDragCoefficient() * applied); } } } for(i=0; i<_weights.size(); i++) { WeightRec* wr = (WeightRec*)_weights.get(i); - wr->surf->setTotalDrag(wr->surf->getTotalDrag() * applied); + wr->surf->setDragCoefficient(wr->surf->getDragCoefficient() * applied); } for(i=0; i<_gears.size(); i++) { GearRec* gr = (GearRec*)_gears.get(i); - gr->surf->setTotalDrag(gr->surf->getTotalDrag() * applied); + gr->surf->setDragCoefficient(gr->surf->getDragCoefficient() * applied); } } diff --git a/src/FDM/YASim/Surface.hpp b/src/FDM/YASim/Surface.hpp index 278c05a83..4d5538ce1 100644 --- a/src/FDM/YASim/Surface.hpp +++ b/src/FDM/YASim/Surface.hpp @@ -59,8 +59,8 @@ public: // The offset from base incidence for this surface. void setTwist(float angle) { _twist = angle; } - void setTotalDrag(float c0) { _c0 = c0; } - float getTotalDrag() const { return _c0; } + void setDragCoefficient(float c0) { _c0 = c0; } + float getDragCoefficient() const { return _c0; } void setXDrag(float cx) { _cx = cx; } void setYDrag(float cy) { _cy = cy; } diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index f706c6d92..69eadb84f 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -247,7 +247,7 @@ void Wing::addSurface(Surface* s, float weight, float twist) SurfRec *sr = new SurfRec(); sr->surface = s; sr->weight = weight; - s->setTotalDrag(sr->weight); + s->setDragCoefficient(sr->weight); s->setTwist(twist); _surfs.add(sr); } @@ -257,7 +257,7 @@ void Wing::setDragScale(float scale) _dragScale = scale; for(int i=0; i<_surfs.size(); i++) { SurfRec* s = (SurfRec*)_surfs.get(i); - s->surface->setTotalDrag(scale * s->weight); + s->surface->setDragCoefficient(scale * s->weight); } } From 030403db5f15793b1c0d04d3f7c7d3f675347868 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sat, 18 Nov 2017 21:16:46 +0100 Subject: [PATCH 07/29] YASIM member initialization in class Vector --- src/FDM/YASim/Vector.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/FDM/YASim/Vector.hpp b/src/FDM/YASim/Vector.hpp index e1a493c80..f290f0ae0 100644 --- a/src/FDM/YASim/Vector.hpp +++ b/src/FDM/YASim/Vector.hpp @@ -21,9 +21,9 @@ public: private: void realloc(); - int _nelem; - int _sz; - void** _array; + int _nelem {0}; + int _sz {0}; + void** _array {nullptr}; }; inline Vector::Vector() From c3bfeb4ba0de9c73bc829ae121a40eb7254c85c3 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sat, 18 Nov 2017 21:22:55 +0100 Subject: [PATCH 08/29] YASIM only reformat for better readability --- src/FDM/YASim/ControlMap.hpp | 60 ++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/src/FDM/YASim/ControlMap.hpp b/src/FDM/YASim/ControlMap.hpp index dc7f75f79..41342f450 100644 --- a/src/FDM/YASim/ControlMap.hpp +++ b/src/FDM/YASim/ControlMap.hpp @@ -10,22 +10,56 @@ class ControlMap { public: ~ControlMap(); - enum OutputType { THROTTLE, MIXTURE, CONDLEVER, STARTER, MAGNETOS, - ADVANCE, REHEAT, PROP, - BRAKE, STEER, EXTEND, HEXTEND, LEXTEND, LACCEL, - INCIDENCE, FLAP0, FLAP1, SLAT, SPOILER, VECTOR, - FLAP0EFFECTIVENESS, FLAP1EFFECTIVENESS, - BOOST, CASTERING, PROPPITCH, PROPFEATHER, - COLLECTIVE, CYCLICAIL, CYCLICELE, ROTORENGINEON, - TILTYAW, TILTPITCH, TILTROLL, - ROTORBRAKE, ROTORENGINEMAXRELTORQUE, ROTORRELTARGET, - ROTORBALANCE, REVERSE_THRUST, WASTEGATE, - WINCHRELSPEED, HITCHOPEN, PLACEWINCH, FINDAITOW - }; + enum OutputType { + THROTTLE, + MIXTURE, + CONDLEVER, + STARTER, + MAGNETOS, + ADVANCE, + REHEAT, + PROP, + BRAKE, + STEER, + EXTEND, + HEXTEND, + LEXTEND, + LACCEL, + INCIDENCE, + FLAP0, + FLAP1, + SLAT, + SPOILER, + VECTOR, + FLAP0EFFECTIVENESS, + FLAP1EFFECTIVENESS, + BOOST, + CASTERING, + PROPPITCH, + PROPFEATHER, + COLLECTIVE, + CYCLICAIL, + CYCLICELE, + ROTORENGINEON, + TILTYAW, + TILTPITCH, + TILTROLL, + ROTORBRAKE, + ROTORENGINEMAXRELTORQUE, + ROTORRELTARGET, + ROTORBALANCE, + REVERSE_THRUST, + WASTEGATE, + WINCHRELSPEED, + HITCHOPEN, + PLACEWINCH, + FINDAITOW + }; enum { OPT_SPLIT = 0x01, OPT_INVERT = 0x02, - OPT_SQUARE = 0x04 }; + OPT_SQUARE = 0x04 + }; struct PropHandle { char* name; int handle; }; From 43af43508553e0f35deaba6ff0c2270c7d1003f1 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sun, 19 Nov 2017 11:20:46 +0100 Subject: [PATCH 09/29] YASIM: rename method getMAC to getMACLength --- src/FDM/YASim/Airplane.cpp | 8 ++++---- src/FDM/YASim/Wing.hpp | 2 +- src/FDM/YASim/yasim-test.cpp | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index 22fc093a1..f25338830 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -320,7 +320,7 @@ float Airplane::compileWing(Wing* w) _wingsN->getNode("wing-area", true)->setFloatValue(w->getArea()); _wingsN->getNode("aspect-ratio", true)->setFloatValue(w->getAspectRatio()); _wingsN->getNode("standard-mean-chord", true)->setFloatValue(w->getSMC()); - _wingsN->getNode("mac", true)->setFloatValue(w->getMAC()); + _wingsN->getNode("mac", true)->setFloatValue(w->getMACLength()); _wingsN->getNode("mac-x", true)->setFloatValue(w->getMACx()); _wingsN->getNode("mac-y", true)->setFloatValue(w->getMACy()); } @@ -547,8 +547,8 @@ void Airplane::compile() aeroWgt += compileWing(_wing); // convert % to absolute x coordinates - _cgDesiredFront = _wing->getMACx() - _wing->getMAC()*_cgDesiredMin; - _cgDesiredAft = _wing->getMACx() - _wing->getMAC()*_cgDesiredMax; + _cgDesiredFront = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMin; + _cgDesiredAft = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMax; if (baseN != 0) { SGPropertyNode_ptr n = fgGetNode("/fdm/yasim/model", true); n->getNode("cg-x-range-front", true)->setFloatValue(_cgDesiredFront); @@ -1034,7 +1034,7 @@ float Airplane::getCGMAC() if (_wing) { float cg[3]; _model.getBody()->getCG(cg); - return (_wing->getMACx() - cg[0]) / _wing->getMAC(); + return (_wing->getMACx() - cg[0]) / _wing->getMACLength(); } return 0; } diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index d31d752c3..4cb26b051 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -78,7 +78,7 @@ public: float getArea() const { return _wingspan*_meanChord; }; float getAspectRatio() const { return _aspectRatio; }; float getSMC() const { return _meanChord; }; - float getMAC() const { return _mac; }; // get length of MAC + float getMACLength() const { return _mac; }; // get length of MAC float getMACx() const { return _macX; }; // get x-coord of MAC leading edge float getMACy() const { return _base[1]+_macRootDistance; }; // get y-coord of MAC leading edge diff --git a/src/FDM/YASim/yasim-test.cpp b/src/FDM/YASim/yasim-test.cpp index 8c4f69d63..d4f9f1518 100644 --- a/src/FDM/YASim/yasim-test.cpp +++ b/src/FDM/YASim/yasim-test.cpp @@ -248,7 +248,7 @@ int main(int argc, char** argv) float MAC = 0, MACx = 0, MACy = 0; Wing* wing = a->getWing(); if (wing) { - MAC = a->getWing()->getMAC(); + MAC = a->getWing()->getMACLength(); MACx = a->getWing()->getMACx(); MACy = a->getWing()->getMACy(); } From 0e6552cddf10c25835ba3d51d7c2c245614f7b38 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sun, 19 Nov 2017 15:54:41 +0100 Subject: [PATCH 10/29] YASIM: move property export code into classes (Wing) --- src/FDM/YASim/Airplane.cpp | 37 ++++++++++++------------------------- src/FDM/YASim/Wing.cpp | 33 +++++++++++++++++++++++++++++++++ src/FDM/YASim/Wing.hpp | 7 +++++-- 3 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index f25338830..c5adde2f5 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -308,25 +308,8 @@ float Airplane::compileWing(Wing* w) addContactPoint(tip); tip[1] *= -1; //undo mirror } - if (_wingsN != 0) { - _wingsN->getNode("tip-x", true)->setFloatValue(tip[0]); - _wingsN->getNode("tip-y", true)->setFloatValue(tip[1]); - _wingsN->getNode("tip-z", true)->setFloatValue(tip[2]); - w->getBase(tip); - _wingsN->getNode("base-x", true)->setFloatValue(tip[0]); - _wingsN->getNode("base-y", true)->setFloatValue(tip[1]); - _wingsN->getNode("base-z", true)->setFloatValue(tip[2]); - _wingsN->getNode("wing-span", true)->setFloatValue(w->getSpan()); - _wingsN->getNode("wing-area", true)->setFloatValue(w->getArea()); - _wingsN->getNode("aspect-ratio", true)->setFloatValue(w->getAspectRatio()); - _wingsN->getNode("standard-mean-chord", true)->setFloatValue(w->getSMC()); - _wingsN->getNode("mac", true)->setFloatValue(w->getMACLength()); - _wingsN->getNode("mac-x", true)->setFloatValue(w->getMACx()); - _wingsN->getNode("mac-y", true)->setFloatValue(w->getMACy()); - } float wgt = 0; - float dragSum = 0; for(int i=0; inumSurfaces(); i++) { Surface* s = (Surface*)w->getSurface(i); float td = s->getDragCoefficient(); @@ -345,11 +328,6 @@ float Airplane::compileWing(Wing* w) n->getNode("mass-id", true)->setIntValue(mid); } wgt += mass; - dragSum += td; - } - if (_wingsN != 0) { - _wingsN->getNode("weight", true)->setFloatValue(wgt); - _wingsN->getNode("drag", true)->setFloatValue(dragSum); } return wgt; } @@ -543,7 +521,10 @@ void Airplane::compile() // The Wing objects if (_wing) { - if (baseN != 0) _wingsN = baseN->getChild("wing", 0, true); + if (baseN != 0) { + _wingsN = baseN->getChild("wing", 0, true); + _wing->setPropertyNode(_wingsN); + } aeroWgt += compileWing(_wing); // convert % to absolute x coordinates @@ -557,13 +538,19 @@ void Airplane::compile() } if (_tail) { - if (baseN != 0) _wingsN = baseN->getChild("tail", 0, true); + if (baseN != 0) { + _wingsN = baseN->getChild("tail", 0, true); + _tail->setPropertyNode(_wingsN); + } aeroWgt += compileWing(_tail); } int i; for(i=0; i<_vstabs.size(); i++) { - if (baseN != 0) _wingsN = baseN->getChild("stab", i, true); + if (baseN != 0) { + _wingsN = baseN->getChild("stab", i, true); + ((Wing*)_vstabs.get(i))->setPropertyNode(_wingsN); + } aeroWgt += compileWing((Wing*)_vstabs.get(i)); } diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index 69eadb84f..00ef265cb 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -240,6 +240,7 @@ void Wing::compile() // Last of all, re-set the incidence in case setIncidence() was // called before we were compiled. setIncidence(_incidence); + writeInfoToProptree(); } void Wing::addSurface(Surface* s, float weight, float twist) @@ -333,4 +334,36 @@ void Wing::interp(const float* v1, const float* v2, const float frac, float* out out[2] = v1[2] + frac*(v2[2]-v1[2]); } +void Wing::writeInfoToProptree() +{ + if (_wingN == nullptr) + return; + _wingN->getNode("tip-x", true)->setFloatValue(_tip[0]); + _wingN->getNode("tip-y", true)->setFloatValue(_tip[1]); + _wingN->getNode("tip-z", true)->setFloatValue(_tip[2]); + _wingN->getNode("base-x", true)->setFloatValue(_base[0]); + _wingN->getNode("base-y", true)->setFloatValue(_base[1]); + _wingN->getNode("base-z", true)->setFloatValue(_base[2]); + _wingN->getNode("wing-span", true)->setFloatValue(_wingspan); + _wingN->getNode("wing-area", true)->setFloatValue(_wingspan*_meanChord); + _wingN->getNode("aspect-ratio", true)->setFloatValue(_aspectRatio); + _wingN->getNode("standard-mean-chord", true)->setFloatValue(_meanChord); + _wingN->getNode("mac", true)->setFloatValue(_mac); + _wingN->getNode("mac-x", true)->setFloatValue(_macX); + _wingN->getNode("mac-y", true)->setFloatValue(_base[1]+_macRootDistance); + + float wgt = 0; + float dragSum = 0; + for(int surf=0; surf < numSurfaces(); surf++) { + Surface* s = (Surface*)getSurface(surf); + float td = s->getDragCoefficient(); + dragSum += td; + + float mass = getSurfaceWeight(surf); + mass = mass * Math::sqrt(mass); + wgt += mass; + } + _wingN->getNode("weight", true)->setFloatValue(wgt); + _wingN->getNode("drag", true)->setFloatValue(dragSum); +} }; // namespace yasim diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index 4cb26b051..09d3d8cff 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -4,6 +4,7 @@ #include "Vector.hpp" #include "Version.hpp" #include "Math.hpp" +#include namespace yasim { @@ -26,7 +27,7 @@ enum WingFlaps { // FIXME: need to handle "inverted" controls for mirrored wings. class Wing { - + SGPropertyNode_ptr _wingN {nullptr}; public: Wing(Version *ver, bool mirror, float* base, float chord, float length, float taper = 1, float sweep = 0, float dihedral = 0, float twist = 0); @@ -97,6 +98,7 @@ public: void setLiftRatio(float ratio); float getLiftRatio() const { return _liftRatio; } + void setPropertyNode(SGPropertyNode_ptr n) { _wingN = n; }; private: void interp(const float* v1, const float* v2, const float frac, float* out); @@ -109,9 +111,10 @@ private: float calculateSweepAngleLeadingEdge(); void addSurface(Surface* s, float weight, float twist); + void writeInfoToProptree(); + struct SurfRec { Surface * surface; float weight; }; - // all surfaces of this wing Vector _surfs; // surfaces having a certain type of flap (flap, slat, spoiler) From fb6f965db77c73b9b2f327218a0df575d32a085f Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sun, 19 Nov 2017 16:11:57 +0100 Subject: [PATCH 11/29] YASIM: method name clarification (and indention) --- src/FDM/YASim/Airplane.cpp | 48 +++++++++++++++++++------------------- src/FDM/YASim/FGFDM.cpp | 2 +- src/FDM/YASim/Wing.cpp | 7 +++++- src/FDM/YASim/Wing.hpp | 4 ++-- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index c5adde2f5..8941ef145 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -787,35 +787,35 @@ void Airplane::applyDragFactor(float factor) float applied = Math::pow(factor, SOLVE_TWEAK); _dragFactor *= applied; if(_wing) - _wing->setDragScale(_wing->getDragScale() * applied); + _wing->multiplyDragCoefficient(applied); if(_tail) - _tail->setDragScale(_tail->getDragScale() * applied); + _tail->multiplyDragCoefficient(applied); int i; for(i=0; i<_vstabs.size(); i++) { - Wing* w = (Wing*)_vstabs.get(i); - w->setDragScale(w->getDragScale() * applied); + Wing* w = (Wing*)_vstabs.get(i); + w->multiplyDragCoefficient(applied); } for(i=0; i<_fuselages.size(); i++) { - Fuselage* f = (Fuselage*)_fuselages.get(i); - int j; - for(j=0; jsurfs.size(); j++) { - Surface* s = (Surface*)f->surfs.get(j); - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { - // For new YASim, the solver drag factor is only applied to - // the X axis for Fuselage Surfaces. - // The solver is tuning the coefficient for longitudinal drag, - // along the direction of flight. A fuselage's lateral drag - // is completely independent and is normally much higher; - // it won't be affected by the streamlining done to reduce - // longitudinal drag. So the solver should only adjust the - // fuselage's longitudinal (X axis) drag coefficient. - s->setXDrag(s->getXDrag() * applied); - } else { - // Originally YASim applied the drag factor to all axes - // for Fuselage Surfaces. - s->setDragCoefficient(s->getDragCoefficient() * applied); - } - } + Fuselage* f = (Fuselage*)_fuselages.get(i); + int j; + for(j=0; jsurfs.size(); j++) { + Surface* s = (Surface*)f->surfs.get(j); + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + // For new YASim, the solver drag factor is only applied to + // the X axis for Fuselage Surfaces. + // The solver is tuning the coefficient for longitudinal drag, + // along the direction of flight. A fuselage's lateral drag + // is completely independent and is normally much higher; + // it won't be affected by the streamlining done to reduce + // longitudinal drag. So the solver should only adjust the + // fuselage's longitudinal (X axis) drag coefficient. + s->setXDrag(s->getXDrag() * applied); + } else { + // Originally YASim applied the drag factor to all axes + // for Fuselage Surfaces. + s->setDragCoefficient(s->getDragCoefficient() * applied); + } + } } for(i=0; i<_weights.size(); i++) { WeightRec* wr = (WeightRec*)_weights.get(i); diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index bd689d9e2..5bad06e85 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -853,7 +853,7 @@ Wing* FGFDM::parseWing(XMLAttributes* a, const char* type, Version * version) w->setInducedDrag(0.7*attrf(a, "idrag", 1)); float effect = attrf(a, "effectiveness", 1); - w->setDragScale(w->getDragScale()*effect); + w->multiplyDragCoefficient(effect); _currObj = w; return w; diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index 00ef265cb..e4be7666e 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -253,7 +253,7 @@ void Wing::addSurface(Surface* s, float weight, float twist) _surfs.add(sr); } -void Wing::setDragScale(float scale) +void Wing::setDragCoefficient(float scale) { _dragScale = scale; for(int i=0; i<_surfs.size(); i++) { @@ -262,6 +262,11 @@ void Wing::setDragScale(float scale) } } +void Wing::multiplyDragCoefficient(float factor) +{ + setDragCoefficient(_dragScale * factor); +} + void Wing::setLiftRatio(float ratio) { _liftRatio = ratio; diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index 09d3d8cff..2a0d45868 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -90,8 +90,8 @@ public: // The overall drag coefficient for the wing as a whole. Units are // arbitrary. - void setDragScale(float scale); - float getDragScale() const { return _dragScale; } + void setDragCoefficient(float scale); + void multiplyDragCoefficient(float factor); // The ratio of force along the Z (lift) direction of each wing // segment to that along the X (drag) direction. From 6b473fde68cdc5cd8433d5e631857423022f2b38 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sun, 19 Nov 2017 23:30:35 +0100 Subject: [PATCH 12/29] YASIM: move updating of model from Airplane to Wing --- src/FDM/YASim/Airplane.cpp | 20 +------------------- src/FDM/YASim/Wing.cpp | 29 +++++++++++++++++++++++++++-- src/FDM/YASim/Wing.hpp | 4 +++- 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index 8941ef145..bbc80f1f2 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -310,25 +310,7 @@ float Airplane::compileWing(Wing* w) } float wgt = 0; - for(int i=0; inumSurfaces(); i++) { - Surface* s = (Surface*)w->getSurface(i); - float td = s->getDragCoefficient(); - int sid = s->getID(); - - _model.addSurface(s); - - float mass = w->getSurfaceWeight(i); - mass = mass * Math::sqrt(mass); - float pos[3]; - s->getPosition(pos); - int mid = _model.getBody()->addMass(mass, pos, true); - if (_wingsN != 0) { - SGPropertyNode_ptr n = _wingsN->getNode("surfaces", true)->getChild("surface", sid, true); - n->getNode("drag", true)->setFloatValue(td); - n->getNode("mass-id", true)->setIntValue(mid); - } - wgt += mass; - } + wgt = w->updateModel(&_model); return wgt; } diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index e4be7666e..30bafe0bf 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -1,4 +1,5 @@ #include "yasim-common.hpp" +#include "Model.hpp" #include "Surface.hpp" #include "Wing.hpp" @@ -361,8 +362,8 @@ void Wing::writeInfoToProptree() float dragSum = 0; for(int surf=0; surf < numSurfaces(); surf++) { Surface* s = (Surface*)getSurface(surf); - float td = s->getDragCoefficient(); - dragSum += td; + float drag = s->getDragCoefficient(); + dragSum += drag; float mass = getSurfaceWeight(surf); mass = mass * Math::sqrt(mass); @@ -371,4 +372,28 @@ void Wing::writeInfoToProptree() _wingN->getNode("weight", true)->setFloatValue(wgt); _wingN->getNode("drag", true)->setFloatValue(dragSum); } + +float Wing::updateModel(Model* model) +{ + float wgt = 0; + for(int surf=0; surf < numSurfaces(); surf++) { + Surface* s = (Surface*)getSurface(surf); + model->addSurface(s); + + float mass = getSurfaceWeight(surf); + mass = mass * Math::sqrt(mass); + wgt += mass; + + float pos[3]; + s->getPosition(pos); + int mid = model->getBody()->addMass(mass, pos, true); + if (_wingN != nullptr) { + SGPropertyNode_ptr n = _wingN->getNode("surfaces", true)->getChild("surface", s->getID(), true); + n->getNode("drag", true)->setFloatValue(s->getDragCoefficient()); + n->getNode("mass-id", true)->setIntValue(mid); + } + } + return wgt; +} + }; // namespace yasim diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index 2a0d45868..4e64500ca 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -9,6 +9,7 @@ namespace yasim { class Surface; +class Model; struct FlapParams { float start {0}; @@ -99,6 +100,7 @@ public: float getLiftRatio() const { return _liftRatio; } void setPropertyNode(SGPropertyNode_ptr n) { _wingN = n; }; + float updateModel(Model* model); private: void interp(const float* v1, const float* v2, const float frac, float* out); @@ -112,7 +114,7 @@ private: void addSurface(Surface* s, float weight, float twist); void writeInfoToProptree(); - + struct SurfRec { Surface * surface; float weight; }; // all surfaces of this wing From b288ca3d9db8bd4835afb74bcf366f27bb205d73 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sun, 19 Nov 2017 23:33:07 +0100 Subject: [PATCH 13/29] YASIM: add struct Chord to Wing.hpp ; add static method calculateMAC to Wing --- src/FDM/YASim/Wing.cpp | 34 +++++++++++++++++++++++----------- src/FDM/YASim/Wing.hpp | 24 +++++++++++++++--------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index 30bafe0bf..f83c91c79 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -9,7 +9,7 @@ Wing::Wing(Version *ver, bool mirror, float* base, float chord, float length, float taper, float sweep, float dihedral, float twist) : _version(ver), _mirror(mirror), - _chord(chord), + _rootChordLength(chord), _length(length), _taper(taper), _sweepAngleCenterLine(sweep), @@ -17,7 +17,7 @@ Wing::Wing(Version *ver, bool mirror, float* base, float chord, _twist(twist) { Math::set3(base, _base); - _meanChord = _chord*(_taper+1)*0.5f; + _meanChord = _rootChordLength*(_taper+1)*0.5f; calculateWingCoordinateSystem(); calculateTip(); calculateSpan(); @@ -127,10 +127,22 @@ void Wing::calculateSpan() void Wing::calculateMAC() { // http://www.nasascale.org/p2/wp-content/uploads/mac-calculator.htm - const float commonFactor = _chord*(0.5+_taper)/(3*_chord*(1+_taper)); - _mac = _chord-(2*_chord*(1-_taper)*commonFactor); - _macRootDistance = _netSpan*commonFactor; - _macX = _base[0]-Math::tan(_sweepAngleCenterLine) * _macRootDistance + _mac/2; + const float commonFactor = _rootChordLength*(0.5+_taper)/(3*_rootChordLength*(1+_taper)); + _mac.length = _rootChordLength-(2*_rootChordLength*(1-_taper)*commonFactor); + _mac.y = _netSpan*commonFactor; + _mac.x = _base[0]-Math::tan(_sweepAngleCenterLine) * _mac.y + _mac.length/2; +} + +Chord Wing::calculateMAC(Chord root, Chord tip) +{ + assert(root.length > 0); + //const float taper = tip.length / root.length; + const float commonFactor = (root.length*0.5+tip.length)/(3*(root.length+tip.length)); + Chord m; + m.length = root.length-(2*(root.length - tip.length)*commonFactor); + m.y = Math::abs(2*(tip.y - root.y))*commonFactor; + m.x = root.x - (root.x - tip.x)*(root.y - m.y)/(root.y - tip.y); + return m; } float Wing::calculateSweepAngleLeadingEdge() @@ -139,7 +151,7 @@ float Wing::calculateSweepAngleLeadingEdge() return 0; } return Math::atan( - (sin(_sweepAngleCenterLine)+(1-_taper)*_chord/(2*_length)) / + (sin(_sweepAngleCenterLine)+(1-_taper)*_rootChordLength/(2*_length)) / cos(_sweepAngleCenterLine) ); } @@ -221,7 +233,7 @@ void Wing::compile() float pos[3]; interp(_base, _tip, frac, pos); - float chord = _chord * (1 - (1-_taper)*frac); + float chord = _rootChordLength * (1 - (1-_taper)*frac); float weight = chord * segWid; float twist = _twist * frac; @@ -354,9 +366,9 @@ void Wing::writeInfoToProptree() _wingN->getNode("wing-area", true)->setFloatValue(_wingspan*_meanChord); _wingN->getNode("aspect-ratio", true)->setFloatValue(_aspectRatio); _wingN->getNode("standard-mean-chord", true)->setFloatValue(_meanChord); - _wingN->getNode("mac", true)->setFloatValue(_mac); - _wingN->getNode("mac-x", true)->setFloatValue(_macX); - _wingN->getNode("mac-y", true)->setFloatValue(_base[1]+_macRootDistance); + _wingN->getNode("mac", true)->setFloatValue(_mac.length); + _wingN->getNode("mac-x", true)->setFloatValue(_mac.x); + _wingN->getNode("mac-y", true)->setFloatValue(_base[1]+_mac.y); float wgt = 0; float dragSum = 0; diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index 4e64500ca..8b7f10f64 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -19,6 +19,13 @@ struct FlapParams { float aoa {0}; }; +// position and length of a chord line +struct Chord { + float x {0}; + float y {0}; + float length {0}; +}; + enum WingFlaps { WING_FLAP0, WING_FLAP1, @@ -45,7 +52,7 @@ public: // dist. ALONG wing (not span!) float getLength() const { return _length; }; // at base, measured along X axis - float getChord() const { return _chord; }; + float getChord() const { return _rootChordLength; }; // fraction of chord at wing tip, 0..1 float getTaper() const { return _taper; }; // radians @@ -80,9 +87,10 @@ public: float getArea() const { return _wingspan*_meanChord; }; float getAspectRatio() const { return _aspectRatio; }; float getSMC() const { return _meanChord; }; - float getMACLength() const { return _mac; }; // get length of MAC - float getMACx() const { return _macX; }; // get x-coord of MAC leading edge - float getMACy() const { return _base[1]+_macRootDistance; }; // get y-coord of MAC leading edge + Chord getMAC() const { return _mac; }; + float getMACLength() const { return _mac.length; }; // get length of MAC + float getMACx() const { return _mac.x; }; // get x-coord of MAC + float getMACy() const { return _base[1]+_mac.y; }; // get y-coord of MAC int numSurfaces() const { return _surfs.size(); } @@ -110,12 +118,12 @@ private: void calculateTip(); void calculateSpan(); void calculateMAC(); + static Chord calculateMAC(Chord root, Chord tip); float calculateSweepAngleLeadingEdge(); void addSurface(Surface* s, float weight, float twist); void writeInfoToProptree(); - struct SurfRec { Surface * surface; float weight; }; // all surfaces of this wing Vector _surfs; @@ -125,7 +133,7 @@ private: Version * _version; bool _mirror {false}; float _base[3] {0,0,0}; - float _chord {0}; + float _rootChordLength {0}; // length is distance from base to tip, not wing span float _length {0}; float _taper {1}; @@ -138,9 +146,7 @@ private: float _rightOrient[9]; float _tip[3] {0,0,0}; float _meanChord {0}; // std. mean chord - float _mac {0}; // mean aerodynamic chord length - float _macRootDistance {0}; // y-distance of mac from root - float _macX {0}; // x-coordinate of mac (leading edge) + Chord _mac; // mean aerodynamic chord (x,y) leading edge float _netSpan {0}; float _wingspan {0}; float _aspectRatio {1}; From 6feca9206034cc3c786958502e0a67ae0c21c56a Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Wed, 22 Nov 2017 09:25:23 +0100 Subject: [PATCH 14/29] YASIM add struct StallParams to Wing --- src/FDM/YASim/FGFDM.cpp | 10 ++++++---- src/FDM/YASim/Wing.cpp | 14 +++++++------- src/FDM/YASim/Wing.hpp | 15 +++++++++------ 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index 5bad06e85..3e5df51d2 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -534,10 +534,12 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) } else if(eq(name, "weight")) { parseWeight(a); } else if(eq(name, "stall")) { - Wing* w = (Wing*)_currObj; - w->setStall(attrf(a, "aoa") * DEG2RAD); - w->setStallWidth(attrf(a, "width", 2) * DEG2RAD); - w->setStallPeak(attrf(a, "peak", 1.5)); + Wing* w = (Wing*)_currObj; + StallParams sp; + sp.aoa = attrf(a, "aoa") * DEG2RAD; + sp.width = attrf(a, "width", 2) * DEG2RAD; + sp.peak = attrf(a, "peak", 1.5); + w->setStallParams(sp); } else if(eq(name, "flap0") || eq(name, "flap1") || eq(name, "spoiler") || eq(name, "slat")) { FlapParams fp; fp.start = attrf(a, "start"); diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index f83c91c79..dc87a4aed 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -297,27 +297,27 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord, s->setChord(chord); // Camber is expressed as a fraction of stall peak, so convert. - s->setBaseZDrag(_camber*_stallPeak); + s->setBaseZDrag(_camber*_stallParams.peak); // The "main" (i.e. normal) stall angle - float stallAoA = _stall - _stallWidth/4; + float stallAoA = _stallParams.aoa - _stallParams.width/4; s->setStall(0, stallAoA); - s->setStallWidth(0, _stallWidth); - s->setStallPeak(0, _stallPeak); + s->setStallWidth(0, _stallParams.width); + s->setStallPeak(0, _stallParams.peak); // The negative AoA stall is the same if we're using an symmetric // airfoil, otherwise a "little worse". if(_camber > 0) { s->setStall(1, stallAoA * 0.8f); - s->setStallWidth(1, _stallWidth * 0.5f); + s->setStallWidth(1, _stallParams.width * 0.5f); } else { s->setStall(1, stallAoA); if( _version->isVersionOrNewer( Version::YASIM_VERSION_2017_2 )) { // what was presumably meant - s->setStallWidth(1, _stallWidth); + s->setStallWidth(1, _stallParams.width); } else { // old code; presumably a copy&paste error - s->setStall(1, _stallWidth); + s->setStall(1, _stallParams.width); } } diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index 8b7f10f64..447878627 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -19,6 +19,12 @@ struct FlapParams { float aoa {0}; }; +struct StallParams { + float aoa {0}; + float width {0}; + float peak {0}; +}; + // position and length of a chord line struct Chord { float x {0}; @@ -65,9 +71,7 @@ public: // parameters for stall curve - void setStall(float aoa) { _stall = aoa; } - void setStallWidth(float angle) { _stallWidth = angle; } - void setStallPeak(float fraction) { _stallPeak = fraction; } + void setStallParams(StallParams sp) { _stallParams = sp; } void setCamber(float camber) { _camber = camber; } void setInducedDrag(float drag) { _inducedDrag = drag; } @@ -151,9 +155,8 @@ private: float _wingspan {0}; float _aspectRatio {1}; - float _stall {0}; - float _stallWidth {0}; - float _stallPeak {0}; + StallParams _stallParams; + float _twist {0}; float _camber {0}; float _incidence {0}; From 3809137f7da19631e519286fe36799ed0501ad96 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sun, 26 Nov 2017 22:28:30 +0100 Subject: [PATCH 15/29] YASIM add method multiplyLiftRatio to class Wing --- src/FDM/YASim/Airplane.cpp | 6 +++--- src/FDM/YASim/Wing.cpp | 5 +++++ src/FDM/YASim/Wing.hpp | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index bbc80f1f2..2d6d2fe4a 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -815,13 +815,13 @@ void Airplane::applyLiftRatio(float factor) float applied = Math::pow(factor, SOLVE_TWEAK); _liftRatio *= applied; if(_wing) - _wing->setLiftRatio(_wing->getLiftRatio() * applied); + _wing->multiplyLiftRatio(applied); if(_tail) - _tail->setLiftRatio(_tail->getLiftRatio() * applied); + _tail->multiplyLiftRatio(applied); int i; for(i=0; i<_vstabs.size(); i++) { Wing* w = (Wing*)_vstabs.get(i); - w->setLiftRatio(w->getLiftRatio() * applied); + w->multiplyLiftRatio(applied); } } diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index dc87a4aed..3c3c3dc21 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -256,6 +256,11 @@ void Wing::compile() writeInfoToProptree(); } +void Wing::multiplyLiftRatio(float factor) +{ + setLiftRatio(_liftRatio * factor); +} + void Wing::addSurface(Surface* s, float weight, float twist) { SurfRec *sr = new SurfRec(); diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index 447878627..b4142612a 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -109,7 +109,7 @@ public: // The ratio of force along the Z (lift) direction of each wing // segment to that along the X (drag) direction. void setLiftRatio(float ratio); - float getLiftRatio() const { return _liftRatio; } + void multiplyLiftRatio(float factor); void setPropertyNode(SGPropertyNode_ptr n) { _wingN = n; }; float updateModel(Model* model); From 09c60ee40e92d7a2dc4bd36e3937a60903e02b9b Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Sun, 26 Nov 2017 23:05:42 +0100 Subject: [PATCH 16/29] YASIM add variable initialization --- src/FDM/YASim/FGFDM.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index 3e5df51d2..e93ed0354 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -221,9 +221,9 @@ void FGFDM::init() void FGFDM::startElement(const char* name, const XMLAttributes &atts) { XMLAttributes* a = (XMLAttributes*)&atts; - float v[3]; + float v[3] {0,0,0}; char buf[64]; - float f = 0; + float f {0}; if(eq(name, "airplane")) { if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; } From 5aead123fc7f9caabb2e02dfecabfd5e3b6b9c30 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Wed, 29 Nov 2017 09:17:51 +0100 Subject: [PATCH 17/29] YASIM refactoring of ControlMap --- src/FDM/YASim/ControlMap.cpp | 134 ++++++++++++++++++++++++----------- src/FDM/YASim/ControlMap.hpp | 53 +++++++++----- src/FDM/YASim/FGFDM.cpp | 74 +++---------------- src/FDM/YASim/FGFDM.hpp | 10 ++- 4 files changed, 146 insertions(+), 125 deletions(-) diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp index 4beef0fe0..e2560193a 100644 --- a/src/FDM/YASim/ControlMap.cpp +++ b/src/FDM/YASim/ControlMap.cpp @@ -44,10 +44,10 @@ ControlMap::~ControlMap() input : index to _inputs type: identifier (see enum OutputType) */ -void ControlMap::addMapping(int input, int type, void* object, int options, +void ControlMap::addMapping(int input, Control control, void* object, int options, float src0, float src1, float dst0, float dst1) { - addMapping(input, type, object, options); + addMapping(input, control, object, options); // The one we just added is last in the list (ugly, awful hack!) Vector* maps = (Vector*)_inputs.get(input); @@ -63,26 +63,25 @@ void ControlMap::addMapping(int input, int type, void* object, int options, input : index to _inputs type: identifier (see enum OutputType) */ -void ControlMap::addMapping(int input, int type, void* object, int options) +void ControlMap::addMapping(int input, Control control, void* object, int options) { // See if the output object already exists OutRec* out = 0; int i; for(i=0; i<_outputs.size(); i++) { - OutRec* o = (OutRec*)_outputs.get(i); - if(o->object == object && o->type == type) { - out = o; - break; - } + OutRec* o = (OutRec*)_outputs.get(i); + if(o->object == object && o->control == control) { + out = o; + break; + } } // Create one if it doesn't if(out == 0) { - out = new OutRec(); - out->type = type; - out->object = object; - out->oldL = out->oldR = out->time = 0; - _outputs.add(out); + out = new OutRec(); + out->control = control; + out->object = object; + _outputs.add(out); } // Make a new input record @@ -92,8 +91,8 @@ void ControlMap::addMapping(int input, int type, void* object, int options) map->idx = out->maps.add(map); // The default ranges differ depending on type! - map->src1 = map->dst1 = rangeMax(type); - map->src0 = map->dst0 = rangeMin(type); + map->src1 = map->dst1 = rangeMax(control); + map->src0 = map->dst0 = rangeMin(control); // And add it to the approproate vectors. Vector* maps = (Vector*)_inputs.get(input); @@ -129,14 +128,14 @@ void ControlMap::setInput(int input, float val) } } -int ControlMap::getOutputHandle(void* obj, int type) +int ControlMap::getOutputHandle(void* obj, Control control) { for(int i=0; i<_outputs.size(); i++) { OutRec* o = (OutRec*)_outputs.get(i); - if(o->object == obj && o->type == type) + if(o->object == obj && o->control == control) return i; } - fprintf(stderr, "ControlMap::getOutputHandle cannot find *%d, type %d \n", obj, type); + fprintf(stderr, "ControlMap::getOutputHandle cannot find *%d, control %d \n", obj, control); return -1; } @@ -188,7 +187,7 @@ void ControlMap::applyControls(float dt) float adl = Math::abs(dl); float adr = Math::abs(dr); - float max = (dt/o->time) * (rangeMax(o->type) - rangeMin(o->type)); + float max = (dt/o->time) * (rangeMax(o->control) - rangeMin(o->control)); if(adl > max) dl = dl*max/adl; if(adr > max) dr = dr*max/adr; @@ -200,7 +199,7 @@ void ControlMap::applyControls(float dt) o->oldR = rval; void* obj = o->object; - switch(o->type) { + switch(o->control) { case THROTTLE: ((Thruster*)obj)->setThrottle(lval); break; case MIXTURE: ((Thruster*)obj)->setMixture(lval); break; case CONDLEVER: ((TurbineEngine*)((PropEngine*) @@ -255,35 +254,35 @@ void ControlMap::applyControls(float dt) } } -float ControlMap::rangeMin(int type) +float ControlMap::rangeMin(Control control) { // The minimum of the range for each type of control - switch(type) { - case FLAP0: return -1; // [-1:1] - case FLAP1: return -1; - case STEER: return -1; - case CYCLICELE: return -1; - case CYCLICAIL: return -1; - case COLLECTIVE: return -1; - case WINCHRELSPEED: return -1; - case MAGNETOS: return 0; // [0:3] - case FLAP0EFFECTIVENESS: return 1; // [0:10] - case FLAP1EFFECTIVENESS: return 1; // [0:10] - default: return 0; // [0:1] + switch(control) { + case FLAP0: return -1; // [-1:1] + case FLAP1: return -1; + case STEER: return -1; + case CYCLICELE: return -1; + case CYCLICAIL: return -1; + case COLLECTIVE: return -1; + case WINCHRELSPEED: return -1; + case MAGNETOS: return 0; // [0:3] + case FLAP0EFFECTIVENESS: return 1; // [0:10] + case FLAP1EFFECTIVENESS: return 1; // [0:10] + default: return 0; // [0:1] } } -float ControlMap::rangeMax(int type) +float ControlMap::rangeMax(Control control) { // The maximum of the range for each type of control - switch(type) { - case FLAP0: return 1; // [-1:1] - case FLAP1: return 1; - case STEER: return 1; - case MAGNETOS: return 3; // [0:3] - case FLAP0EFFECTIVENESS: return 10;// [0:10] - case FLAP1EFFECTIVENESS: return 10;// [0:10] - default: return 1; // [0:1] + switch(control) { + case FLAP0: return 1; // [-1:1] + case FLAP1: return 1; + case STEER: return 1; + case MAGNETOS: return 3; // [0:3] + case FLAP0EFFECTIVENESS: return 10;// [0:10] + case FLAP1EFFECTIVENESS: return 10;// [0:10] + default: return 1; // [0:1] } } @@ -328,4 +327,55 @@ int ControlMap::propertyHandle(const char* name) return p->handle; } + +ControlMap::Control ControlMap::parseControl(const char* name) +{ + if(eq(name, "THROTTLE")) return THROTTLE; + if(eq(name, "MIXTURE")) return MIXTURE; + if(eq(name, "CONDLEVER")) return CONDLEVER; + if(eq(name, "STARTER")) return STARTER; + if(eq(name, "MAGNETOS")) return MAGNETOS; + if(eq(name, "ADVANCE")) return ADVANCE; + if(eq(name, "REHEAT")) return REHEAT; + if(eq(name, "BOOST")) return BOOST; + if(eq(name, "VECTOR")) return VECTOR; + if(eq(name, "PROP")) return PROP; + if(eq(name, "BRAKE")) return BRAKE; + if(eq(name, "STEER")) return STEER; + if(eq(name, "EXTEND")) return EXTEND; + if(eq(name, "HEXTEND")) return HEXTEND; + if(eq(name, "LEXTEND")) return LEXTEND; + if(eq(name, "LACCEL")) return LACCEL; + if(eq(name, "INCIDENCE")) return INCIDENCE; + if(eq(name, "FLAP0")) return FLAP0; + if(eq(name, "FLAP0EFFECTIVENESS")) return FLAP0EFFECTIVENESS; + if(eq(name, "FLAP1")) return FLAP1; + if(eq(name, "FLAP1EFFECTIVENESS")) return FLAP1EFFECTIVENESS; + if(eq(name, "SLAT")) return SLAT; + if(eq(name, "SPOILER")) return SPOILER; + if(eq(name, "CASTERING")) return CASTERING; + if(eq(name, "PROPPITCH")) return PROPPITCH; + if(eq(name, "PROPFEATHER")) return PROPFEATHER; + if(eq(name, "COLLECTIVE")) return COLLECTIVE; + if(eq(name, "CYCLICAIL")) return CYCLICAIL; + if(eq(name, "CYCLICELE")) return CYCLICELE; + if(eq(name, "TILTROLL")) return TILTROLL; + if(eq(name, "TILTPITCH")) return TILTPITCH; + if(eq(name, "TILTYAW")) return TILTYAW; + if(eq(name, "ROTORGEARENGINEON")) return ROTORENGINEON; + if(eq(name, "ROTORBRAKE")) return ROTORBRAKE; + if(eq(name, "ROTORENGINEMAXRELTORQUE")) return ROTORENGINEMAXRELTORQUE; + if(eq(name, "ROTORRELTARGET")) return ROTORRELTARGET; + if(eq(name, "ROTORBALANCE")) return ROTORBALANCE; + if(eq(name, "REVERSE_THRUST")) return REVERSE_THRUST; + if(eq(name, "WASTEGATE")) return WASTEGATE; + if(eq(name, "WINCHRELSPEED")) return WINCHRELSPEED; + if(eq(name, "HITCHOPEN")) return HITCHOPEN; + if(eq(name, "PLACEWINCH")) return PLACEWINCH; + if(eq(name, "FINDAITOW")) return FINDAITOW; + SG_LOG(SG_FLIGHT,SG_ALERT,"Unrecognized control type '" << name + << "' in YASim aircraft description."); + exit(1); +} + } // namespace yasim diff --git a/src/FDM/YASim/ControlMap.hpp b/src/FDM/YASim/ControlMap.hpp index 41342f450..3c135fa6d 100644 --- a/src/FDM/YASim/ControlMap.hpp +++ b/src/FDM/YASim/ControlMap.hpp @@ -10,7 +10,7 @@ class ControlMap { public: ~ControlMap(); - enum OutputType { + enum Control { THROTTLE, MIXTURE, CONDLEVER, @@ -56,22 +56,25 @@ public: FINDAITOW }; - enum { OPT_SPLIT = 0x01, - OPT_INVERT = 0x02, - OPT_SQUARE = 0x04 + enum { + OPT_SPLIT = 0x01, + OPT_INVERT = 0x02, + OPT_SQUARE = 0x04 }; struct PropHandle { char* name; int handle; }; - + + // map control name to int (enum) + Control parseControl(const char* name); // Adds a mapping to between input handle and a particular setting // on an output object. The value of output MUST match the type // of object! - void addMapping(int input, int output, void* object, int options=0); + void addMapping(int input, Control control, void* object, int options=0); // An additional form to specify a mapping range. Input values // outside of [src0:src1] are clamped, and are then mapped to // [dst0:dst1] before being set on the object. - void addMapping(int input, int output, void* object, int options, + void addMapping(int input, Control control, void* object, int options, float src0, float src1, float dst0, float dst1); // Resets our accumulated input values. Call before any @@ -89,12 +92,12 @@ public: // Returns the input/output range appropriate for the given // control. Ailerons go from -1 to 1, while throttles are never // lower than zero, etc... - static float rangeMin(int type); - static float rangeMax(int type); + static float rangeMin(Control control); + static float rangeMax(Control control); // Each output record is identified by both an object/type tuple // and a numeric handle. - int getOutputHandle(void* obj, int type); + int getOutputHandle(void* obj, Control control); // Sets the transition time for the control output to swing // through its full range. @@ -111,15 +114,25 @@ public: int numProperties() { return _properties.size(); } PropHandle* getProperty(const int i) { return ((PropHandle*)_properties.get(i)); } - // helper - char* dup(const char* s); - bool eq(const char* a, const char* b); - private: - struct OutRec { int type; void* object; Vector maps; - float oldL, oldR, time; }; - struct MapRec { OutRec* out; int idx; int opt; float val; - float src0; float src1; float dst0; float dst1; }; + struct OutRec { + Control control; + void* object; + Vector maps; + float oldL {0}; + float oldR {0}; + float time {0}; + }; + struct MapRec { + OutRec* out; + int idx {0}; + int opt {0}; + float val {0}; + float src0 {0}; + float src1 {0}; + float dst0 {0}; + float dst1 {0}; + }; // A list of (sub)Vectors containing a bunch of MapRec objects for // each input handle. @@ -129,6 +142,10 @@ private: Vector _outputs; // control properties Vector _properties; + + // helper + char* dup(const char* s); + bool eq(const char* a, const char* b); }; }; // namespace yasim diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index e93ed0354..ee13427a4 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -587,7 +587,7 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) ControlMap* cm = _airplane.getControlMap(); // A mapping of input property to a control int axis = cm->propertyHandle(a->getValue("axis")); - int control = parseOutput(a->getValue("control")); + ControlMap::Control control = cm->parseControl(a->getValue("control")); int opt = 0; opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0; opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0; @@ -602,23 +602,24 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) } else if(eq(name, "control-output")) { // A property output for a control on the current object ControlMap* cm = _airplane.getControlMap(); - int type = parseOutput(a->getValue("control")); - int handle = cm->getOutputHandle(_currObj, type); + ControlMap::Control control = cm->parseControl(a->getValue("control")); + + int handle = cm->getOutputHandle(_currObj, control); PropOut* p = new PropOut(); p->prop = fgGetNode(a->getValue("prop"), true); p->handle = handle; - p->type = type; + p->control = control; p->left = !(a->hasAttribute("side") && eq("right", a->getValue("side"))); - p->min = attrf(a, "min", cm->rangeMin(type)); - p->max = attrf(a, "max", cm->rangeMax(type)); + p->min = attrf(a, "min", cm->rangeMin(control)); + p->max = attrf(a, "max", cm->rangeMax(control)); _controlProps.add(p); } else if(eq(name, "control-speed")) { ControlMap* cm = _airplane.getControlMap(); - int type = parseOutput(a->getValue("control")); - int handle = cm->getOutputHandle(_currObj, type); + ControlMap::Control control = cm->parseControl(a->getValue("control")); + int handle = cm->getOutputHandle(_currObj, control); float time = attrf(a, "transition-time", 0); cm->setTransitionTime(handle, time); @@ -715,8 +716,8 @@ void FGFDM::setOutputProperties(float dt) float val = (p->left ? cm->getOutput(p->handle) : cm->getOutputR(p->handle)); - float rmin = cm->rangeMin(p->type); - float rmax = cm->rangeMax(p->type); + float rmin = cm->rangeMin(p->control); + float rmax = cm->rangeMax(p->control); float frac = (val - rmin) / (rmax - rmin); val = frac*(p->max - p->min) + p->min; p->prop->setFloatValue(val); @@ -1104,59 +1105,6 @@ void FGFDM::parsePropeller(XMLAttributes* a) _currObj = thruster; } -/// map identifier (string) to int (enum in ControlMap) -int FGFDM::parseOutput(const char* name) -{ - if(eq(name, "THROTTLE")) return ControlMap::THROTTLE; - if(eq(name, "MIXTURE")) return ControlMap::MIXTURE; - if(eq(name, "CONDLEVER")) return ControlMap::CONDLEVER; - if(eq(name, "STARTER")) return ControlMap::STARTER; - if(eq(name, "MAGNETOS")) return ControlMap::MAGNETOS; - if(eq(name, "ADVANCE")) return ControlMap::ADVANCE; - if(eq(name, "REHEAT")) return ControlMap::REHEAT; - if(eq(name, "BOOST")) return ControlMap::BOOST; - if(eq(name, "VECTOR")) return ControlMap::VECTOR; - if(eq(name, "PROP")) return ControlMap::PROP; - if(eq(name, "BRAKE")) return ControlMap::BRAKE; - if(eq(name, "STEER")) return ControlMap::STEER; - if(eq(name, "EXTEND")) return ControlMap::EXTEND; - if(eq(name, "HEXTEND")) return ControlMap::HEXTEND; - if(eq(name, "LEXTEND")) return ControlMap::LEXTEND; - if(eq(name, "LACCEL")) return ControlMap::LACCEL; - if(eq(name, "INCIDENCE")) return ControlMap::INCIDENCE; - if(eq(name, "FLAP0")) return ControlMap::FLAP0; - if(eq(name, "FLAP0EFFECTIVENESS")) return ControlMap::FLAP0EFFECTIVENESS; - if(eq(name, "FLAP1")) return ControlMap::FLAP1; - if(eq(name, "FLAP1EFFECTIVENESS")) return ControlMap::FLAP1EFFECTIVENESS; - if(eq(name, "SLAT")) return ControlMap::SLAT; - if(eq(name, "SPOILER")) return ControlMap::SPOILER; - if(eq(name, "CASTERING")) return ControlMap::CASTERING; - if(eq(name, "PROPPITCH")) return ControlMap::PROPPITCH; - if(eq(name, "PROPFEATHER")) return ControlMap::PROPFEATHER; - if(eq(name, "COLLECTIVE")) return ControlMap::COLLECTIVE; - if(eq(name, "CYCLICAIL")) return ControlMap::CYCLICAIL; - if(eq(name, "CYCLICELE")) return ControlMap::CYCLICELE; - if(eq(name, "TILTROLL")) return ControlMap::TILTROLL; - if(eq(name, "TILTPITCH")) return ControlMap::TILTPITCH; - if(eq(name, "TILTYAW")) return ControlMap::TILTYAW; - if(eq(name, "ROTORGEARENGINEON")) return ControlMap::ROTORENGINEON; - if(eq(name, "ROTORBRAKE")) return ControlMap::ROTORBRAKE; - if(eq(name, "ROTORENGINEMAXRELTORQUE")) - return ControlMap::ROTORENGINEMAXRELTORQUE; - if(eq(name, "ROTORRELTARGET")) return ControlMap::ROTORRELTARGET; - if(eq(name, "ROTORBALANCE")) return ControlMap::ROTORBALANCE; - if(eq(name, "REVERSE_THRUST")) return ControlMap::REVERSE_THRUST; - if(eq(name, "WASTEGATE")) return ControlMap::WASTEGATE; - if(eq(name, "WINCHRELSPEED")) return ControlMap::WINCHRELSPEED; - if(eq(name, "HITCHOPEN")) return ControlMap::HITCHOPEN; - if(eq(name, "PLACEWINCH")) return ControlMap::PLACEWINCH; - if(eq(name, "FINDAITOW")) return ControlMap::FINDAITOW; - - SG_LOG(SG_FLIGHT,SG_ALERT,"Unrecognized control type '" - << name << "' in YASim aircraft description."); - exit(1); - -} void FGFDM::parseWeight(XMLAttributes* a) { diff --git a/src/FDM/YASim/FGFDM.hpp b/src/FDM/YASim/FGFDM.hpp index 28eabba21..2d57090ac 100644 --- a/src/FDM/YASim/FGFDM.hpp +++ b/src/FDM/YASim/FGFDM.hpp @@ -34,8 +34,14 @@ public: private: struct EngRec { char* prefix; Thruster* eng; }; struct WeightRec { char* prop; float size; int handle; }; - struct PropOut { SGPropertyNode* prop; int handle, type; bool left; - float min, max; }; + struct PropOut { + SGPropertyNode* prop; + int handle {0}; + ControlMap::Control control; + bool left {false}; + float min {0}; + float max {0}; + }; void setOutputProperties(float dt); From b2000e1cca78b78f1d240deb7750d6daae50ce3e Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Wed, 29 Nov 2017 17:59:01 +0100 Subject: [PATCH 18/29] YASIM add a local var --- src/FDM/YASim/Airplane.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index 2d6d2fe4a..3aee54f0f 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -529,11 +529,12 @@ void Airplane::compile() int i; for(i=0; i<_vstabs.size(); i++) { + Wing* vs = (Wing*)_vstabs.get(i); if (baseN != 0) { _wingsN = baseN->getChild("stab", i, true); - ((Wing*)_vstabs.get(i))->setPropertyNode(_wingsN); + vs->setPropertyNode(_wingsN); } - aeroWgt += compileWing((Wing*)_vstabs.get(i)); + aeroWgt += compileWing(vs); } // The fuselage(s) From c63ded1c44a2d211237738a92fd8b8e3f3e86dcb Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Fri, 1 Dec 2017 13:03:36 +0100 Subject: [PATCH 19/29] YASIM add initialization use Math::clamp in ControlMap --- src/FDM/YASim/ControlMap.cpp | 37 ++++++++++----------- src/FDM/YASim/ControlMap.hpp | 6 ++-- src/FDM/YASim/FGFDM.cpp | 62 ++++++++++++++++-------------------- src/FDM/YASim/FGFDM.hpp | 25 +++++++++------ 4 files changed, 62 insertions(+), 68 deletions(-) diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp index e2560193a..5e6de0478 100644 --- a/src/FDM/YASim/ControlMap.cpp +++ b/src/FDM/YASim/ControlMap.cpp @@ -66,9 +66,8 @@ void ControlMap::addMapping(int input, Control control, void* object, int option void ControlMap::addMapping(int input, Control control, void* object, int options) { // See if the output object already exists - OutRec* out = 0; - int i; - for(i=0; i<_outputs.size(); i++) { + OutRec* out {nullptr}; + for(int i = 0; i < _outputs.size(); i++) { OutRec* o = (OutRec*)_outputs.get(i); if(o->object == object && o->control == control) { out = o; @@ -77,7 +76,7 @@ void ControlMap::addMapping(int input, Control control, void* object, int option } // Create one if it doesn't - if(out == 0) { + if(out == nullptr) { out = new OutRec(); out->control = control; out->object = object; @@ -102,29 +101,25 @@ void ControlMap::addMapping(int input, Control control, void* object, int option void ControlMap::reset() { // Set all the values to zero - for(int i=0; i<_outputs.size(); i++) { - OutRec* o = (OutRec*)_outputs.get(i); - for(int j=0; jmaps.size(); j++) - ((MapRec*)(o->maps.get(j)))->val = 0; + for(int i = 0; i < _outputs.size(); i++) { + OutRec* o = (OutRec*)_outputs.get(i); + for(int j = 0; j < o->maps.size(); j++) { + ((MapRec*)(o->maps.get(j)))->val = 0; + } } } void ControlMap::setInput(int input, float val) { Vector* maps = (Vector*)_inputs.get(input); - for(int i=0; isize(); i++) { - MapRec* m = (MapRec*)maps->get(i); - - float val2 = val; - - // Do the scaling operation. Clamp to [src0:src1], rescale to - // [0:1] within that range, then map to [dst0:dst1]. - if(val2 < m->src0) val2 = m->src0; - if(val2 > m->src1) val2 = m->src1; - val2 = (val2 - m->src0) / (m->src1 - m->src0); - val2 = m->dst0 + val2 * (m->dst1 - m->dst0); - - m->val = val2; + for(int i = 0; i < maps->size(); i++) { + MapRec* m = (MapRec*)maps->get(i); + float val2 = val; + // Do the scaling operation. Clamp to [src0:src1], rescale to + // [0:1] within that range, then map to [dst0:dst1]. + val2 = Math::clamp(val2, m->src0, m->src1); + val2 = (val2 - m->src0) / (m->src1 - m->src0); + m->val = m->dst0 + val2 * (m->dst1 - m->dst0); } } diff --git a/src/FDM/YASim/ControlMap.hpp b/src/FDM/YASim/ControlMap.hpp index 3c135fa6d..464676ac9 100644 --- a/src/FDM/YASim/ControlMap.hpp +++ b/src/FDM/YASim/ControlMap.hpp @@ -116,15 +116,15 @@ public: private: struct OutRec { - Control control; - void* object; + Control control; + void* object {nullptr}; Vector maps; float oldL {0}; float oldR {0}; float time {0}; }; struct MapRec { - OutRec* out; + OutRec* out {nullptr}; int idx {0}; int opt {0}; float val {0}; diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index ee13427a4..dba161335 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -35,10 +35,6 @@ namespace yasim { FGFDM::FGFDM() { - _vehicle_radius = 0.0f; - - _nextEngine = 0; - // Map /controls/flight/elevator to the approach elevator control. This // should probably be settable, but there are very few aircraft // who trim their approaches using things other than elevator. @@ -534,7 +530,7 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) } else if(eq(name, "weight")) { parseWeight(a); } else if(eq(name, "stall")) { - Wing* w = (Wing*)_currObj; + Wing* w = (Wing*)_currObj; StallParams sp; sp.aoa = attrf(a, "aoa") * DEG2RAD; sp.width = attrf(a, "width", 2) * DEG2RAD; @@ -583,38 +579,34 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) _airplane.addCruiseControl(cm->propertyHandle(axis), value); else _airplane.addApproachControl(cm->propertyHandle(axis), value); - } else if(eq(name, "control-input")) { - ControlMap* cm = _airplane.getControlMap(); - // A mapping of input property to a control - int axis = cm->propertyHandle(a->getValue("axis")); - ControlMap::Control control = cm->parseControl(a->getValue("control")); - int opt = 0; - opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0; - opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0; - opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0; - if(a->hasAttribute("src0")) { - cm->addMapping(axis, control, _currObj, opt, - attrf(a, "src0"), attrf(a, "src1"), - attrf(a, "dst0"), attrf(a, "dst1")); - } else { - cm->addMapping(axis, control, _currObj, opt); - } - } else if(eq(name, "control-output")) { + } else if(eq(name, "control-input")) { + ControlMap* cm = _airplane.getControlMap(); + // A mapping of input property to a control + int propHandle = cm->propertyHandle(a->getValue("axis")); + ControlMap::Control control = cm->parseControl(a->getValue("control")); + int opt = 0; + opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0; + opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0; + opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0; + if(a->hasAttribute("src0")) { + cm->addMapping(propHandle, control, _currObj, opt, attrf(a, "src0"), attrf(a, "src1"), attrf(a, "dst0"), attrf(a, "dst1")); + } else { + cm->addMapping(propHandle, control, _currObj, opt); + } + } else if(eq(name, "control-output")) { // A property output for a control on the current object ControlMap* cm = _airplane.getControlMap(); ControlMap::Control control = cm->parseControl(a->getValue("control")); - - int handle = cm->getOutputHandle(_currObj, control); - PropOut* p = new PropOut(); - p->prop = fgGetNode(a->getValue("prop"), true); - p->handle = handle; - p->control = control; - p->left = !(a->hasAttribute("side") && - eq("right", a->getValue("side"))); - p->min = attrf(a, "min", cm->rangeMin(control)); - p->max = attrf(a, "max", cm->rangeMax(control)); - _controlProps.add(p); + PropOut* p = new PropOut(); + p->prop = fgGetNode(a->getValue("prop"), true); + p->handle = cm->getOutputHandle(_currObj, control); + p->control = control; + p->left = !(a->hasAttribute("side") && + eq("right", a->getValue("side"))); + p->min = attrf(a, "min", cm->rangeMin(control)); + p->max = attrf(a, "max", cm->rangeMax(control)); + _controlProps.add(p); } else if(eq(name, "control-speed")) { ControlMap* cm = _airplane.getControlMap(); @@ -854,10 +846,10 @@ Wing* FGFDM::parseWing(XMLAttributes* a, const char* type, Version * version) // The 70% is a magic number that sorta kinda seems to match known // throttle settings to approach speed. w->setInducedDrag(0.7*attrf(a, "idrag", 1)); - + float effect = attrf(a, "effectiveness", 1); w->multiplyDragCoefficient(effect); - + _currObj = w; return w; } diff --git a/src/FDM/YASim/FGFDM.hpp b/src/FDM/YASim/FGFDM.hpp index 2d57090ac..333d0c1a2 100644 --- a/src/FDM/YASim/FGFDM.hpp +++ b/src/FDM/YASim/FGFDM.hpp @@ -32,12 +32,19 @@ public: float getVehicleRadius(void) const { return _vehicle_radius; } private: - struct EngRec { char* prefix; Thruster* eng; }; - struct WeightRec { char* prop; float size; int handle; }; - struct PropOut { - SGPropertyNode* prop; + struct EngRec { + char* prefix {nullptr}; + Thruster* eng {nullptr}; + }; + struct WeightRec { + char* prop {nullptr}; + float size {0}; int handle {0}; - ControlMap::Control control; + }; + struct PropOut { + SGPropertyNode* prop {nullptr}; + int handle {0}; + ControlMap::Control control; bool left {false}; float min {0}; float max {0}; @@ -79,12 +86,12 @@ private: Vector _controlProps; // Radius of the vehicle, for intersection testing. - float _vehicle_radius; + float _vehicle_radius {0}; // Parsing temporaries - void* _currObj; - bool _cruiseCurr; - int _nextEngine; + void* _currObj {nullptr}; + bool _cruiseCurr {false}; + int _nextEngine {0}; class FuelProps { From 78f7950fa66bbda7f086aebe24d1a88df536caf4 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Fri, 1 Dec 2017 22:59:07 +0100 Subject: [PATCH 20/29] YASim: move common helper functions to new yasim-common.cpp --- src/FDM/YASim/CMakeLists.txt | 1 + src/FDM/YASim/ControlMap.cpp | 21 +------------ src/FDM/YASim/ControlMap.hpp | 4 --- src/FDM/YASim/FGFDM.cpp | 18 ------------ src/FDM/YASim/FGFDM.hpp | 3 -- src/FDM/YASim/Vector.hpp | 4 ++- src/FDM/YASim/yasim-common.cpp | 23 +++++++++++++++ src/FDM/YASim/yasim-common.hpp | 54 +++++++++++++++++++--------------- 8 files changed, 58 insertions(+), 70 deletions(-) create mode 100644 src/FDM/YASim/yasim-common.cpp diff --git a/src/FDM/YASim/CMakeLists.txt b/src/FDM/YASim/CMakeLists.txt index 0d7efa881..3065af68a 100644 --- a/src/FDM/YASim/CMakeLists.txt +++ b/src/FDM/YASim/CMakeLists.txt @@ -26,6 +26,7 @@ set(COMMON Turbulence.cpp Wing.cpp Version.cpp + yasim-common.cpp ) set(SOURCES diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp index 5e6de0478..27dddc72c 100644 --- a/src/FDM/YASim/ControlMap.cpp +++ b/src/FDM/YASim/ControlMap.cpp @@ -2,6 +2,7 @@ # include "config.h" #endif +#include "yasim-common.hpp" #include "Jet.hpp" #include "Thruster.hpp" #include "PropEngine.hpp" @@ -281,26 +282,6 @@ float ControlMap::rangeMax(Control control) } } -/// duplicate null-terminated string -char* ControlMap::dup(const char* s) -{ - int len=0; - while(s[len++]); - char* s2 = new char[len+1]; - char* p = s2; - while((*p++ = *s++)); - s2[len] = 0; - return s2; -} - -/// compare null-terminated strings -bool ControlMap::eq(const char* a, const char* b) -{ - while(*a && *b && *a == *b) { a++; b++; } - // equal if both a and b points to null chars - return !(*a || *b); -} - /// register property name, return ID (int) int ControlMap::propertyHandle(const char* name) { diff --git a/src/FDM/YASim/ControlMap.hpp b/src/FDM/YASim/ControlMap.hpp index 464676ac9..b385187bb 100644 --- a/src/FDM/YASim/ControlMap.hpp +++ b/src/FDM/YASim/ControlMap.hpp @@ -142,10 +142,6 @@ private: Vector _outputs; // control properties Vector _properties; - - // helper - char* dup(const char* s); - bool eq(const char* a, const char* b); }; }; // namespace yasim diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index dba161335..f5545fc7e 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -1114,24 +1114,6 @@ void FGFDM::parseWeight(XMLAttributes* a) _weights.add(wr); } -bool FGFDM::eq(const char* a, const char* b) -{ - // Figure it out for yourself. :) - while(*a && *b && *a == *b) { a++; b++; } - return !(*a || *b); -} - -char* FGFDM::dup(const char* s) -{ - int len=0; - while(s[len++]); - char* s2 = new char[len+1]; - char* p = s2; - while((*p++ = *s++)); - s2[len] = 0; - return s2; -} - int FGFDM::attri(XMLAttributes* atts, const char* attr) { if(!atts->hasAttribute(attr)) { diff --git a/src/FDM/YASim/FGFDM.hpp b/src/FDM/YASim/FGFDM.hpp index 333d0c1a2..49644163f 100644 --- a/src/FDM/YASim/FGFDM.hpp +++ b/src/FDM/YASim/FGFDM.hpp @@ -59,9 +59,6 @@ private: void parseTurbineEngine(XMLAttributes* a); void parsePistonEngine(XMLAttributes* a); void parsePropeller(XMLAttributes* a); - bool eq(const char* a, const char* b); - bool caseeq(const char* a, const char* b); - char* dup(const char* s); int attri(XMLAttributes* atts, const char* attr); int attri(XMLAttributes* atts, const char* attr, int def); float attrf(XMLAttributes* atts, const char* attr); diff --git a/src/FDM/YASim/Vector.hpp b/src/FDM/YASim/Vector.hpp index f290f0ae0..5dbf8b42f 100644 --- a/src/FDM/YASim/Vector.hpp +++ b/src/FDM/YASim/Vector.hpp @@ -3,6 +3,8 @@ #include #include + +namespace yasim { // // Excruciatingly simple vector-of-pointers class. Easy & useful. // No support for addition of elements anywhere but at the end of the @@ -78,5 +80,5 @@ inline void Vector::realloc() delete[] _array; _array = array; } - +}; //namespace yasim #endif // _VECTOR_HPP diff --git a/src/FDM/YASim/yasim-common.cpp b/src/FDM/YASim/yasim-common.cpp new file mode 100644 index 000000000..23bbf7f6a --- /dev/null +++ b/src/FDM/YASim/yasim-common.cpp @@ -0,0 +1,23 @@ +#include "yasim-common.hpp" + +namespace yasim { + /// duplicate null-terminated string + char* dup(const char* s) + { + int len=0; + while(s[len++]); + char* s2 = new char[len+1]; + char* p = s2; + while((*p++ = *s++)); + s2[len] = 0; + return s2; + } + + /// compare null-terminated strings + bool eq(const char* a, const char* b) + { + while(*a && *b && *a == *b) { a++; b++; } + // equal if both a and b points to null chars + return !(*a || *b); + } +}; //namespace yasim diff --git a/src/FDM/YASim/yasim-common.hpp b/src/FDM/YASim/yasim-common.hpp index ed1c4f018..32097af7e 100644 --- a/src/FDM/YASim/yasim-common.hpp +++ b/src/FDM/YASim/yasim-common.hpp @@ -1,34 +1,40 @@ #ifndef _YASIM_COMMON_HPP #define _YASIM_COMMON_HPP +/* + common file for YASim wide constants and static helper functions + */ namespace yasim { - static const float YASIM_PI = 3.14159265358979323846f; - static const float PI2 = YASIM_PI*2; - static const float RAD2DEG = 180/YASIM_PI; - static const float DEG2RAD = YASIM_PI/180; - static const float RPM2RAD = YASIM_PI/30; + static const float YASIM_PI = 3.14159265358979323846f; + static const float PI2 = YASIM_PI*2; + static const float RAD2DEG = 180/YASIM_PI; + static const float DEG2RAD = YASIM_PI/180; + static const float RPM2RAD = YASIM_PI/30; - static const float KTS2MPS = 1852.0f/3600.0f; - static const float MPS2KTS = 3600.0f/1852.0f; - static const float KMH2MPS = 1/3.6f; + static const float KTS2MPS = 1852.0f/3600.0f; + static const float MPS2KTS = 3600.0f/1852.0f; + static const float KMH2MPS = 1/3.6f; - static const float FT2M = 0.3048f; - static const float M2FT = 1/FT2M; + static const float FT2M = 0.3048f; + static const float M2FT = 1/FT2M; - static const float LBS2N = 4.44822f; - static const float N2LB = 1/LBS2N; - static const float LBS2KG = 0.45359237f; - static const float KG2LBS = 1/LBS2KG; - static const float CM2GALS = 264.172037284f; - static const float HP2W = 745.700f; - static const float INHG2PA = 3386.389f; - static const float K2DEGF = 1.8f; - static const float K2DEGFOFFSET = -459.4f; - static const float CIN2CM = 1.6387064e-5f; - - static const float NM2FTLB = (1/(LBS2N*FT2M)); - static const float SLUG2KG = 14.59390f; + static const float LBS2N = 4.44822f; + static const float N2LB = 1/LBS2N; + static const float LBS2KG = 0.45359237f; + static const float KG2LBS = 1/LBS2KG; + static const float CM2GALS = 264.172037284f; + static const float HP2W = 745.700f; + static const float INHG2PA = 3386.389f; + static const float K2DEGF = 1.8f; + static const float K2DEGFOFFSET = -459.4f; + static const float CIN2CM = 1.6387064e-5f; -}; + static const float NM2FTLB = (1/(LBS2N*FT2M)); + static const float SLUG2KG = 14.59390f; + + char* dup(const char* s); + bool eq(const char* a, const char* b); + +}; //namespace yasim #endif // ifndef _YASIM_COMMON_HPP From abb451256dc4bfd8ce1552c03ef06c7d42863c08 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Fri, 1 Dec 2017 12:54:43 +0100 Subject: [PATCH 21/29] YASim CLI tool: add more CG outputs remove non-significant digits from inertia printf() --- src/FDM/YASim/yasim-test.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/FDM/YASim/yasim-test.cpp b/src/FDM/YASim/yasim-test.cpp index d4f9f1518..685164756 100644 --- a/src/FDM/YASim/yasim-test.cpp +++ b/src/FDM/YASim/yasim-test.cpp @@ -260,16 +260,18 @@ int main(int argc, char** argv) printf("Approach Elevator: %.3f\n\n", a->getApproachElevator()); printf(" CG: x:%.3f, y:%.3f, z:%.3f\n", cg[0], cg[1], cg[2]); if (wing) { - printf(" Wing MAC (*1): x:%.2f, y:%.2f, length:%.1f \n", MACx, MACy, MAC); - printf(" CG-x rel. MAC: %.3f\n", a->getCGMAC()); - printf(" CG-x desired: %.3f < %.3f < %.3f \n", a->getCGSoftLimitXMin(), cg[0], a->getCGSoftLimitXMax()); + printf(" Wing MAC: (x:%.2f, y:%.2f), length:%.1f \n", MACx, MACy, MAC); + printf(" hard limit CG-x: %.3f \n", a->getCGHardLimitXMax()); + printf(" soft limit CG-x: %.3f \n", a->getCGSoftLimitXMax()); + printf(" CG-x: %.3f \n", cg[0]); + printf(" CG-x rel. MAC: %3.0f%%\n", a->getCGMAC()*100); + printf(" soft limit CG-x: %.3f \n", a->getCGSoftLimitXMin()); + printf(" hard limit CG-x: %.3f \n", a->getCGHardLimitXMin()); } - printf("\nInertia tensor [kg*m^2], origo at CG:\n\n"); - printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]); - printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[3], SI_inertia[4], SI_inertia[5]); - printf(" %7.3f, %7.3f, %7.3f\n", SI_inertia[6], SI_inertia[7], SI_inertia[8]); - printf("\n(*1) MAC calculation works on only! Numbers will be wrong for segmented wings, e.g. +.\n"); + printf(" %7.0f, %7.0f, %7.0f\n", SI_inertia[0], SI_inertia[1], SI_inertia[2]); + printf(" %7.0f, %7.0f, %7.0f\n", SI_inertia[3], SI_inertia[4], SI_inertia[5]); + printf(" %7.0f, %7.0f, %7.0f\n", SI_inertia[6], SI_inertia[7], SI_inertia[8]); } delete fdm; return 0; From a199ca817cc99eabea9e3268be55e34175486ea2 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Mon, 11 Dec 2017 19:27:59 +0100 Subject: [PATCH 22/29] YASim: user Math functions in RigidBody --- src/FDM/YASim/Math.hpp | 2 + src/FDM/YASim/RigidBody.cpp | 150 +++++++++++++++++------------------- 2 files changed, 74 insertions(+), 78 deletions(-) diff --git a/src/FDM/YASim/Math.hpp b/src/FDM/YASim/Math.hpp index 1aca16478..d8610bd8b 100644 --- a/src/FDM/YASim/Math.hpp +++ b/src/FDM/YASim/Math.hpp @@ -50,6 +50,8 @@ public: out[2] = v[2]; } + static void zero3(float* out) { out[0] = out[1] = out[2] = 0; } + static inline float dot3(const float* a, const float* b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; } diff --git a/src/FDM/YASim/RigidBody.cpp b/src/FDM/YASim/RigidBody.cpp index 2824b5e9e..bf635ab16 100644 --- a/src/FDM/YASim/RigidBody.cpp +++ b/src/FDM/YASim/RigidBody.cpp @@ -69,9 +69,7 @@ void RigidBody::setMass(int handle, float mass, const float* pos, bool isStatic) void RigidBody::getMassPosition(int handle, float* out) const { - out[0] = _masses[handle].p[0]; - out[1] = _masses[handle].p[1]; - out[2] = _masses[handle].p[2]; + Math::set3(_masses[handle].p, out); } // Calcualtes the rotational velocity of a particular point. All @@ -84,56 +82,54 @@ void RigidBody::pointVelocity(const float* pos, const float* rot, float* out) void RigidBody::_recalcStatic() { - // aggregate all masses that do not change (e.g. fuselage, wings) into one point mass - _staticMass.m = 0; - _staticMass.p[0] = 0; - _staticMass.p[1] = 0; - _staticMass.p[2] = 0; - int i; - int s = 0; - for(i=0; i<_nMasses; i++) { - if (_masses[i].isStatic) { - s++; - float m = _masses[i].m; - _staticMass.m += m; - _staticMass.p[0] += m * _masses[i].p[0]; - _staticMass.p[1] += m * _masses[i].p[1]; - _staticMass.p[2] += m * _masses[i].p[2]; - } - } - Math::mul3(1/_staticMass.m, _staticMass.p, _staticMass.p); - if (_bodyN != 0) { - _bodyN->getNode("aggregated-mass", true)->setFloatValue(_staticMass.m); - _bodyN->getNode("aggregated-count", true)->setIntValue(s); - _bodyN->getNode("aggregated-pos-x", true)->setFloatValue(_staticMass.p[0]); - _bodyN->getNode("aggregated-pos-y", true)->setFloatValue(_staticMass.p[1]); - _bodyN->getNode("aggregated-pos-z", true)->setFloatValue(_staticMass.p[2]); - } - // Now the inertia tensor: - for(i=0; i<9; i++) - _tI_static[i] = 0; + // aggregate all masses that do not change (e.g. fuselage, wings) into one point mass + _staticMass.m = 0; + Math::zero3(_staticMass.p); + int i; + int s = 0; + for(i=0; i<_nMasses; i++) { + if (_masses[i].isStatic) { + s++; + float mass = _masses[i].m; + _staticMass.m += mass; + float momentum[3]; + Math::mul3(mass, _masses[i].p, momentum); + Math::add3(momentum, _staticMass.p, _staticMass.p); + } + } + Math::mul3(1/_staticMass.m, _staticMass.p, _staticMass.p); + if (_bodyN != 0) { + _bodyN->getNode("aggregated-mass", true)->setFloatValue(_staticMass.m); + _bodyN->getNode("aggregated-count", true)->setIntValue(s); + _bodyN->getNode("aggregated-pos-x", true)->setFloatValue(_staticMass.p[0]); + _bodyN->getNode("aggregated-pos-y", true)->setFloatValue(_staticMass.p[1]); + _bodyN->getNode("aggregated-pos-z", true)->setFloatValue(_staticMass.p[2]); + } + // Now the inertia tensor: + for(i=0; i<9; i++) + _tI_static[i] = 0; - for(i=0; i<_nMasses; i++) { - if (_masses[i].isStatic) { - float m = _masses[i].m; + for(i=0; i<_nMasses; i++) { + if (_masses[i].isStatic) { + float m = _masses[i].m; - float x = _masses[i].p[0] - _staticMass.p[0]; - float y = _masses[i].p[1] - _staticMass.p[1]; - float z = _masses[i].p[2] - _staticMass.p[2]; + float x = _masses[i].p[0] - _staticMass.p[0]; + float y = _masses[i].p[1] - _staticMass.p[1]; + float z = _masses[i].p[2] - _staticMass.p[2]; - float xy = m*x*y; float yz = m*y*z; float zx = m*z*x; - float x2 = m*x*x; float y2 = m*y*y; float z2 = m*z*z; + float xy = m*x*y; float yz = m*y*z; float zx = m*z*x; + float x2 = m*x*x; float y2 = m*y*y; float z2 = m*z*z; - // tensor is symmetric, so we can save some calculations in the loop - _tI_static[0] += y2+z2; _tI_static[1] -= xy; _tI_static[2] -= zx; - _tI_static[4] += x2+z2; _tI_static[5] -= yz; - _tI_static[8] += x2+y2; - } - } - // copy symmetric elements - _tI_static[3] = _tI_static[1]; - _tI_static[6] = _tI_static[2]; - _tI_static[7] = _tI_static[5]; + // tensor is symmetric, so we can save some calculations in the loop + _tI_static[0] += y2+z2; _tI_static[1] -= xy; _tI_static[2] -= zx; + _tI_static[4] += x2+z2; _tI_static[5] -= yz; + _tI_static[8] += x2+y2; + } + } + // copy symmetric elements + _tI_static[3] = _tI_static[1]; + _tI_static[6] = _tI_static[2]; + _tI_static[7] = _tI_static[5]; } /// calculate the total mass, centre of gravity and inertia tensor @@ -151,44 +147,42 @@ void RigidBody::recalc() // Calculate the c.g and total mass // init with pre-calculated static mass _totalMass = _staticMass.m; - _cg[0] = _staticMass.m * _staticMass.p[0]; - _cg[1] = _staticMass.m * _staticMass.p[1]; - _cg[2] = _staticMass.m * _staticMass.p[2]; + Math::mul3(_staticMass.m, _staticMass.p, _cg); int i; for(i=0; i<_nMasses; i++) { - // only masses we did not aggregate - if (!_masses[i].isStatic) { - float m = _masses[i].m; - _totalMass += m; - _cg[0] += m * _masses[i].p[0]; - _cg[1] += m * _masses[i].p[1]; - _cg[2] += m * _masses[i].p[2]; - } + // only masses we did not aggregate + if (!_masses[i].isStatic) { + float mass = _masses[i].m; + _totalMass += mass; + float momentum[3]; + Math::mul3(mass, _masses[i].p, momentum); + Math::add3(momentum, _cg, _cg); + } } Math::mul3(1/_totalMass, _cg, _cg); // Now the inertia tensor: for(i=0; i<9; i++) - _tI[i] = _tI_static[i]; + _tI[i] = _tI_static[i]; for(i=0; i<_nMasses; i++) { - if (!_masses[i].isStatic) { - float m = _masses[i].m; + if (!_masses[i].isStatic) { + float m = _masses[i].m; - float x = _masses[i].p[0] - _cg[0]; - float y = _masses[i].p[1] - _cg[1]; - float z = _masses[i].p[2] - _cg[2]; - float mx = m*x; - float my = m*y; - float mz = m*z; - - float xy = mx*y; float yz = my*z; float zx = mz*x; - float x2 = mx*x; float y2 = my*y; float z2 = mz*z; + float x = _masses[i].p[0] - _cg[0]; + float y = _masses[i].p[1] - _cg[1]; + float z = _masses[i].p[2] - _cg[2]; + float mx = m*x; + float my = m*y; + float mz = m*z; + + float xy = mx*y; float yz = my*z; float zx = mz*x; + float x2 = mx*x; float y2 = my*y; float z2 = mz*z; - _tI[0] += y2+z2; _tI[1] -= xy; _tI[2] -= zx; - _tI[4] += x2+z2; _tI[5] -= yz; - _tI[8] += x2+y2; - } + _tI[0] += y2+z2; _tI[1] -= xy; _tI[2] -= zx; + _tI[4] += x2+z2; _tI[5] -= yz; + _tI[8] += x2+y2; + } } // copy symmetric elements _tI[3] = _tI[1]; @@ -201,8 +195,8 @@ void RigidBody::recalc() void RigidBody::reset() { - _torque[0] = _torque[1] = _torque[2] = 0; - _force[0] = _force[1] = _force[2] = 0; + Math::zero3(_torque); + Math::zero3(_force); } void RigidBody::addForce(const float* pos, const float* force) From 13e00b275b40bbb010a6515175aca55949989061 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Mon, 11 Dec 2017 19:02:00 +0100 Subject: [PATCH 23/29] YASim: export more forces to prop tree for in flight debugging --- src/FDM/YASim/Model.cpp | 31 +++++++++++++++++++++---------- src/FDM/YASim/Model.hpp | 6 ++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/FDM/YASim/Model.cpp b/src/FDM/YASim/Model.cpp index a5d442fe4..5c4e50f9f 100644 --- a/src/FDM/YASim/Model.cpp +++ b/src/FDM/YASim/Model.cpp @@ -61,6 +61,12 @@ Model::Model() _fAeroXN = _modelN->getNode("f-x-drag", true); _fAeroYN = _modelN->getNode("f-y-side", true); _fAeroZN = _modelN->getNode("f-z-lift", true); + _fGravXN = _modelN->getNode("gravity-x", true); + _fGravYN = _modelN->getNode("gravity-y", true); + _fGravZN = _modelN->getNode("gravity-z", true); + _fSumXN = _modelN->getNode("f-sum-x", true); + _fSumYN = _modelN->getNode("f-sum-y", true); + _fSumZN = _modelN->getNode("f-sum-z", true); _gefxN = fgGetNode("/fdm/yasim/debug/ground-effect/ge-f-x", true); _gefyN = fgGetNode("/fdm/yasim/debug/ground-effect/ge-f-y", true); @@ -293,8 +299,7 @@ void Model::calcForces(State* s) // Do each surface, remembering that the local velocity at each // point is different due to rotation. - float faero[3]; - faero[0] = faero[1] = faero[2] = 0; + float faero[3] {0,0,0}; for(i=0; i<_surfaces.size(); i++) { Surface* sf = (Surface*)_surfaces.get(i); @@ -374,6 +379,12 @@ void Model::calcForces(State* s) _fAeroXN->setFloatValue(faero[0]); _fAeroYN->setFloatValue(faero[1]); _fAeroZN->setFloatValue(faero[2]); + _fGravXN->setFloatValue(grav[0]); + _fGravYN->setFloatValue(grav[1]); + _fGravZN->setFloatValue(grav[2]); + _fSumXN->setFloatValue(faero[0]+grav[0]); + _fSumYN->setFloatValue(faero[1]+grav[1]); + _fSumZN->setFloatValue(faero[2]+grav[2]); } // Convert the velocity and rotation vectors to local coordinates float lrot[3], lv[3]; @@ -382,18 +393,18 @@ void Model::calcForces(State* s) // The landing gear for(i=0; i<_gears.size(); i++) { - float force[3], contact[3]; - Gear* g = (Gear*)_gears.get(i); + float force[3], contact[3]; + Gear* g = (Gear*)_gears.get(i); - g->calcForce(&_body, s, lv, lrot); - g->getForce(force, contact); - _body.addForce(contact, force); + g->calcForce(&_body, s, lv, lrot); + g->getForce(force, contact); + _body.addForce(contact, force); } // The arrester hook if(_hook) { _hook->calcForce(_ground_cb, &_body, s, lv, lrot); - float force[3], contact[3]; + float force[3], contact[3]; _hook->getForce(force, contact); _body.addForce(contact, force); } @@ -401,13 +412,13 @@ void Model::calcForces(State* s) // The launchbar/holdback if(_launchbar) { _launchbar->calcForce(_ground_cb, &_body, s, lv, lrot); - float forcelb[3], contactlb[3], forcehb[3], contacthb[3]; + float forcelb[3], contactlb[3], forcehb[3], contacthb[3]; _launchbar->getForce(forcelb, contactlb, forcehb, contacthb); _body.addForce(contactlb, forcelb); _body.addForce(contacthb, forcehb); } -// The hitches + // The hitches for(i=0; i<_hitches.size(); i++) { float force[3], contact[3]; Hitch* h = (Hitch*)_hitches.get(i); diff --git a/src/FDM/YASim/Model.hpp b/src/FDM/YASim/Model.hpp index 75e2de16e..a455b9133 100644 --- a/src/FDM/YASim/Model.hpp +++ b/src/FDM/YASim/Model.hpp @@ -118,6 +118,12 @@ private: SGPropertyNode_ptr _fAeroXN; SGPropertyNode_ptr _fAeroYN; SGPropertyNode_ptr _fAeroZN; + SGPropertyNode_ptr _fSumXN; + SGPropertyNode_ptr _fSumYN; + SGPropertyNode_ptr _fSumZN; + SGPropertyNode_ptr _fGravXN; + SGPropertyNode_ptr _fGravYN; + SGPropertyNode_ptr _fGravZN; SGPropertyNode_ptr _gefxN; SGPropertyNode_ptr _gefyN; SGPropertyNode_ptr _gefzN; From e913e44aa051e1feb8480d95e24589cf98078fba Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Wed, 13 Dec 2017 19:15:49 +0100 Subject: [PATCH 24/29] YASIM type name clarification --- src/FDM/YASim/Airplane.cpp | 266 ++++++++++++++++++------------------- src/FDM/YASim/Airplane.hpp | 4 +- 2 files changed, 135 insertions(+), 135 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index 3aee54f0f..762fed9fa 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -60,9 +60,9 @@ Airplane::~Airplane() for(i=0; i<_solveWeights.size(); i++) delete (SolveWeight*)_solveWeights.get(i); for(i=0; i<_cruiseConfig.controls.size(); i++) - delete (Control*)_cruiseConfig.controls.get(i); + delete (ControlSetting*)_cruiseConfig.controls.get(i); for(i=0; i<_approachConfig.controls.size(); i++) { - Control* c = (Control*)_approachConfig.controls.get(i); + ControlSetting* c = (ControlSetting*)_approachConfig.controls.get(i); if(c != &_approachElevator) delete c; } @@ -152,19 +152,19 @@ void Airplane::setElevatorControl(int control) void Airplane::addApproachControl(int control, float val) { - Control* c = new Control(); + ControlSetting* c = new ControlSetting(); c->control = control; c->val = val; - _approachConfig.controls.add(c); + _approachConfig.controls.add(c); } void Airplane::addCruiseControl(int control, float val) { - Control* c = new Control(); + ControlSetting* c = new ControlSetting(); c->control = control; c->val = val; - _cruiseConfig.controls.add(c); -} + _cruiseConfig.controls.add(c); + } void Airplane::addSolutionWeight(bool approach, int idx, float wgt) { @@ -258,11 +258,11 @@ void Airplane::setWeight(int handle, float mass) // how we simulate droppable stores. if(mass == 0) { wr->surf->setXDrag(0); - wr->surf->setYDrag(0); + wr->surf->setYDrag(0); wr->surf->setZDrag(0); } else { wr->surf->setXDrag(1); - wr->surf->setYDrag(1); + wr->surf->setYDrag(1); wr->surf->setZDrag(1); } } @@ -331,7 +331,7 @@ float Airplane::compileFuselage(Fuselage* f) float len = Math::mag3(fwd); if (len == 0) { _failureMsg = "Zero length fuselage"; - return 0; + return 0; } float wid = f->width; int segs = (int)Math::ceil(len/wid); @@ -344,14 +344,14 @@ float Airplane::compileFuselage(Fuselage* f) if(frac < f->mid) scale = f->taper+(1-f->taper) * (frac / f->mid); else { - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { - // Correct calculation of width for fuselage taper. - scale = 1 - (1-f->taper) * (frac - f->mid) / (1 - f->mid); - } else { - // Original, incorrect calculation of width for fuselage taper. - scale = f->taper+(1-f->taper) * (frac - f->mid) / (1 - f->mid); - } - } + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + // Correct calculation of width for fuselage taper. + scale = 1 - (1-f->taper) * (frac - f->mid) / (1 - f->mid); + } else { + // Original, incorrect calculation of width for fuselage taper. + scale = f->taper+(1-f->taper) * (frac - f->mid) / (1 - f->mid); + } + } // Where are we? float pos[3]; @@ -367,40 +367,40 @@ float Airplane::compileFuselage(Fuselage* f) Surface* s = new Surface(this); s->setPosition(pos); - // The following is the original YASim value for sideDrag. - // Originally YASim calculated the fuselage's lateral drag - // coefficient as (solver drag factor) * (len/wid). - // However, this greatly underestimates a fuselage's lateral drag. - float sideDrag = len/wid; + // The following is the original YASim value for sideDrag. + // Originally YASim calculated the fuselage's lateral drag + // coefficient as (solver drag factor) * (len/wid). + // However, this greatly underestimates a fuselage's lateral drag. + float sideDrag = len/wid; - if ( isVersionOrNewer( YASIM_VERSION_32 ) ) { - // New YASim assumes a fixed lateral drag coefficient of 0.5. - // This will not be multiplied by the solver drag factor, because - // that factor is tuned to match the drag in the direction of - // flight, which is completely independent of lateral drag. - // The value of 0.5 is only a ballpark estimate, roughly matching - // the side-on drag for a long cylinder at the higher Reynolds - // numbers typical for an aircraft's lateral drag. - // This fits if the fuselage is long and has a round cross section. - // For flat-sided fuselages, the value should be increased, up to - // a limit of around 2 for a long rectangular prism. - // For very short fuselages, in which the end effects are strong, - // the value should be reduced. - // Such adjustments can be made using the fuselage's "cy" and "cz" - // XML parameters: "cy" for the sides, "cz" for top and bottom. - sideDrag = 0.5; - } + if ( isVersionOrNewer( YASIM_VERSION_32 ) ) { + // New YASim assumes a fixed lateral drag coefficient of 0.5. + // This will not be multiplied by the solver drag factor, because + // that factor is tuned to match the drag in the direction of + // flight, which is completely independent of lateral drag. + // The value of 0.5 is only a ballpark estimate, roughly matching + // the side-on drag for a long cylinder at the higher Reynolds + // numbers typical for an aircraft's lateral drag. + // This fits if the fuselage is long and has a round cross section. + // For flat-sided fuselages, the value should be increased, up to + // a limit of around 2 for a long rectangular prism. + // For very short fuselages, in which the end effects are strong, + // the value should be reduced. + // Such adjustments can be made using the fuselage's "cy" and "cz" + // XML parameters: "cy" for the sides, "cz" for top and bottom. + sideDrag = 0.5; + } - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { s->setXDrag(f->_cx); - } + } s->setYDrag(sideDrag*f->_cy); s->setZDrag(sideDrag*f->_cz); - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { s->setDragCoefficient(scale*segWgt); } else { s->setDragCoefficient(scale*segWgt*f->_cx); - } + } s->setInducedDrag(f->_idrag); // FIXME: fails for fuselages aligned along the Y axis @@ -409,8 +409,8 @@ float Airplane::compileFuselage(Fuselage* f) Math::unit3(fwd, x); y[0] = 0; y[1] = 1; y[2] = 0; Math::cross3(x, y, z); - Math::unit3(z, z); - Math::cross3(z, x, y); + Math::unit3(z, z); + Math::cross3(z, x, y); s->setOrientation(o); _model.addSurface(s); @@ -503,38 +503,38 @@ void Airplane::compile() // The Wing objects if (_wing) { - if (baseN != 0) { - _wingsN = baseN->getChild("wing", 0, true); - _wing->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(_wing); - - // convert % to absolute x coordinates - _cgDesiredFront = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMin; - _cgDesiredAft = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMax; - if (baseN != 0) { - SGPropertyNode_ptr n = fgGetNode("/fdm/yasim/model", true); - n->getNode("cg-x-range-front", true)->setFloatValue(_cgDesiredFront); - n->getNode("cg-x-range-aft", true)->setFloatValue(_cgDesiredAft); - } + if (baseN != 0) { + _wingsN = baseN->getChild("wing", 0, true); + _wing->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(_wing); + + // convert % to absolute x coordinates + _cgDesiredFront = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMin; + _cgDesiredAft = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMax; + if (baseN != 0) { + SGPropertyNode_ptr n = fgGetNode("/fdm/yasim/model", true); + n->getNode("cg-x-range-front", true)->setFloatValue(_cgDesiredFront); + n->getNode("cg-x-range-aft", true)->setFloatValue(_cgDesiredAft); + } } if (_tail) { - if (baseN != 0) { - _wingsN = baseN->getChild("tail", 0, true); - _tail->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(_tail); + if (baseN != 0) { + _wingsN = baseN->getChild("tail", 0, true); + _tail->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(_tail); } int i; for(i=0; i<_vstabs.size(); i++) { - Wing* vs = (Wing*)_vstabs.get(i); - if (baseN != 0) { - _wingsN = baseN->getChild("stab", i, true); - vs->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(vs); + Wing* vs = (Wing*)_vstabs.get(i); + if (baseN != 0) { + _wingsN = baseN->getChild("stab", i, true); + vs->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(vs); } // The fuselage(s) @@ -718,12 +718,12 @@ void Airplane::setupWeights(bool isApproach) /// load values for controls as defined in cruise configuration void Airplane::loadControls(const Vector& controls) { - _controls.reset(); - for(int i=0; i < controls.size(); i++) { - Control* c = (Control*)controls.get(i); + _controls.reset(); + for(int i=0; i < controls.size(); i++) { + ControlSetting* c = (ControlSetting*)controls.get(i); _controls.setInput(c->control, c->val); - } - _controls.applyControls(); + } + _controls.applyControls(); } /// Helper for solve() @@ -801,11 +801,11 @@ void Airplane::applyDragFactor(float factor) } } for(i=0; i<_weights.size(); i++) { - WeightRec* wr = (WeightRec*)_weights.get(i); + WeightRec* wr = (WeightRec*)_weights.get(i); wr->surf->setDragCoefficient(wr->surf->getDragCoefficient() * applied); } for(i=0; i<_gears.size(); i++) { - GearRec* gr = (GearRec*)_gears.get(i); + GearRec* gr = (GearRec*)_gears.get(i); gr->surf->setDragCoefficient(gr->surf->getDragCoefficient() * applied); } } @@ -848,57 +848,57 @@ void Airplane::solve() return; } - // Run an iteration at cruise, and extract the needed numbers: - runConfig(_cruiseConfig); + // Run an iteration at cruise, and extract the needed numbers: + runConfig(_cruiseConfig); - _model.getThrust(tmp); + _model.getThrust(tmp); float thrust = tmp[0] + _cruiseConfig.weight * Math::sin(_cruiseConfig.glideAngle) * 9.81; - _model.getBody()->getAccel(tmp); + _model.getBody()->getAccel(tmp); _cruiseConfig.state.localToGlobal(tmp, tmp); - float xforce = _cruiseConfig.weight * tmp[0]; - float clift0 = _cruiseConfig.weight * tmp[2]; + float xforce = _cruiseConfig.weight * tmp[0]; + float clift0 = _cruiseConfig.weight * tmp[2]; - _model.getBody()->getAngularAccel(tmp); + _model.getBody()->getAngularAccel(tmp); _cruiseConfig.state.localToGlobal(tmp, tmp); - float pitch0 = tmp[1]; + float pitch0 = tmp[1]; - // Run an approach iteration, and do likewise + // Run an approach iteration, and do likewise runConfig(_approachConfig); - _model.getBody()->getAngularAccel(tmp); + _model.getBody()->getAngularAccel(tmp); _approachConfig.state.localToGlobal(tmp, tmp); - double apitch0 = tmp[1]; + double apitch0 = tmp[1]; - _model.getBody()->getAccel(tmp); + _model.getBody()->getAccel(tmp); _approachConfig.state.localToGlobal(tmp, tmp); - float alift = _approachConfig.weight * tmp[2]; + float alift = _approachConfig.weight * tmp[2]; - // Modify the cruise AoA a bit to get a derivative - _cruiseConfig.aoa += ARCMIN; + // Modify the cruise AoA a bit to get a derivative + _cruiseConfig.aoa += ARCMIN; runConfig(_cruiseConfig); _cruiseConfig.aoa -= ARCMIN; - - _model.getBody()->getAccel(tmp); + + _model.getBody()->getAccel(tmp); _cruiseConfig.state.localToGlobal(tmp, tmp); - float clift1 = _cruiseConfig.weight * tmp[2]; + float clift1 = _cruiseConfig.weight * tmp[2]; - // Do the same with the tail incidence - _tail->setIncidence(_tailIncidence + ARCMIN); + // Do the same with the tail incidence + _tail->setIncidence(_tailIncidence + ARCMIN); runConfig(_cruiseConfig); _tail->setIncidence(_tailIncidence); - _model.getBody()->getAngularAccel(tmp); + _model.getBody()->getAngularAccel(tmp); _cruiseConfig.state.localToGlobal(tmp, tmp); - float pitch1 = tmp[1]; + float pitch1 = tmp[1]; - // Now calculate: - float awgt = 9.8f * _approachConfig.weight; + // Now calculate: + float awgt = 9.8f * _approachConfig.weight; - float dragFactor = thrust / (thrust-xforce); - float liftFactor = awgt / (awgt+alift); - float aoaDelta = -clift0 * (ARCMIN/(clift1-clift0)); - float tailDelta = -pitch0 * (ARCMIN/(pitch1-pitch0)); + float dragFactor = thrust / (thrust-xforce); + float liftFactor = awgt / (awgt+alift); + float aoaDelta = -clift0 * (ARCMIN/(clift1-clift0)); + float tailDelta = -pitch0 * (ARCMIN/(pitch1-pitch0)); // Sanity: if(dragFactor <= 0 || liftFactor <= 0) @@ -913,36 +913,36 @@ void Airplane::solve() runConfig(_approachConfig); _approachElevator.val -= ELEVDIDDLE; - _model.getBody()->getAngularAccel(tmp); + _model.getBody()->getAngularAccel(tmp); _approachConfig.state.localToGlobal(tmp, tmp); - double apitch1 = tmp[1]; + double apitch1 = tmp[1]; float elevDelta = -apitch0 * (ELEVDIDDLE/(apitch1-apitch0)); // Now apply the values we just computed. Note that the // "minor" variables are deferred until we get the lift/drag // numbers in the right ballpark. - applyDragFactor(dragFactor); - applyLiftRatio(liftFactor); + applyDragFactor(dragFactor); + applyLiftRatio(liftFactor); - // DON'T do the following until the above are sane - if(normFactor(dragFactor) > STHRESH*1.0001 - || normFactor(liftFactor) > STHRESH*1.0001) - { - continue; - } + // DON'T do the following until the above are sane + if(normFactor(dragFactor) > STHRESH*1.0001 + || normFactor(liftFactor) > STHRESH*1.0001) + { + continue; + } - // OK, now we can adjust the minor variables: - _cruiseConfig.aoa += SOLVE_TWEAK*aoaDelta; - _tailIncidence += SOLVE_TWEAK*tailDelta; - - _cruiseConfig.aoa = Math::clamp(_cruiseConfig.aoa, -0.175f, 0.175f); - _tailIncidence = Math::clamp(_tailIncidence, -0.175f, 0.175f); + // OK, now we can adjust the minor variables: + _cruiseConfig.aoa += SOLVE_TWEAK*aoaDelta; + _tailIncidence += SOLVE_TWEAK*tailDelta; + + _cruiseConfig.aoa = Math::clamp(_cruiseConfig.aoa, -0.175f, 0.175f); + _tailIncidence = Math::clamp(_tailIncidence, -0.175f, 0.175f); if(abs(xforce/_cruiseConfig.weight) < STHRESH*0.0001 && - abs(alift/_approachConfig.weight) < STHRESH*0.0001 && - abs(aoaDelta) < STHRESH*.000017 && - abs(tailDelta) < STHRESH*.000017) + abs(alift/_approachConfig.weight) < STHRESH*0.0001 && + abs(aoaDelta) < STHRESH*.000017 && + abs(tailDelta) < STHRESH*.000017) { // If this finaly value is OK, then we're all done if(abs(elevDelta) < STHRESH*0.0001) @@ -958,17 +958,17 @@ void Airplane::solve() } if(_dragFactor < 1e-06 || _dragFactor > 1e6) { - _failureMsg = "Drag factor beyond reasonable bounds."; - return; + _failureMsg = "Drag factor beyond reasonable bounds."; + return; } else if(_liftRatio < 1e-04 || _liftRatio > 1e4) { - _failureMsg = "Lift ratio beyond reasonable bounds."; - return; + _failureMsg = "Lift ratio beyond reasonable bounds."; + return; } else if(Math::abs(_cruiseConfig.aoa) >= .17453293) { - _failureMsg = "Cruise AoA > 10 degrees"; - return; + _failureMsg = "Cruise AoA > 10 degrees"; + return; } else if(Math::abs(_tailIncidence) >= .17453293) { - _failureMsg = "Tail incidence > 10 degrees"; - return; + _failureMsg = "Tail incidence > 10 degrees"; + return; } } diff --git a/src/FDM/YASim/Airplane.hpp b/src/FDM/YASim/Airplane.hpp index d985d6734..1a033357e 100644 --- a/src/FDM/YASim/Airplane.hpp +++ b/src/FDM/YASim/Airplane.hpp @@ -134,7 +134,7 @@ private: float cg[3]; float mass; }; - struct Control { + struct ControlSetting { int control; float val; }; @@ -210,7 +210,7 @@ private: float _dragFactor {1}; float _liftRatio {1}; float _tailIncidence {0}; - Control _approachElevator; + ControlSetting _approachElevator; const char* _failureMsg {0}; float _cgMax {-1e6}; // hard limits for cg from gear position From 408e645bb223c9e6e21fdec592f1431d6872c630 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Tue, 13 Jun 2017 21:15:46 +0200 Subject: [PATCH 25/29] YASIM add wing section support refactoring of FGFDM parser replace old helpers with lib functions from remove typecast that kills 'const' add some comments and clarify variable names --- src/FDM/YASim/Airplane.cpp | 178 +++--- src/FDM/YASim/Airplane.hpp | 14 +- src/FDM/YASim/ControlMap.cpp | 366 +++++++----- src/FDM/YASim/ControlMap.hpp | 34 +- src/FDM/YASim/FGFDM.cpp | 1002 +++++++++++++++++--------------- src/FDM/YASim/FGFDM.hpp | 55 +- src/FDM/YASim/Surface.cpp | 10 +- src/FDM/YASim/Wing.cpp | 526 ++++++++++------- src/FDM/YASim/Wing.hpp | 222 +++---- src/FDM/YASim/proptest.cpp | 1 + src/FDM/YASim/yasim-common.cpp | 18 - src/FDM/YASim/yasim-common.hpp | 4 - src/FDM/YASim/yasim-test.cpp | 11 +- 13 files changed, 1389 insertions(+), 1052 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index 762fed9fa..8a3fb9afd 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -111,6 +111,22 @@ void Airplane::getPilotAccel(float* out) // FIXME: rotational & centripetal acceleration needed } +Wing* Airplane::getWing() +{ + if (_wing == nullptr) { + _wing = new Wing((Version*)this, true); + } + return _wing; +} + +Wing* Airplane::getTail() +{ + if (_tail == nullptr) { + _tail = new Wing((Version*)this, true); + } + return _tail; +} + void Airplane::updateGearState() { for(int i=0; i<_gears.size(); i++) { @@ -143,28 +159,28 @@ void Airplane::setCruise(float speed, float altitude, float fuel, float gla) _cruiseConfig.glideAngle = gla; } -void Airplane::setElevatorControl(int control) +void Airplane::setElevatorControl(const char* prop) { - _approachElevator.control = control; + _approachElevator.propHandle = getControlMap()->getPropertyHandle(prop); _approachElevator.val = 0; _approachConfig.controls.add(&_approachElevator); } -void Airplane::addApproachControl(int control, float val) +void Airplane::addApproachControl(const char* prop, float val) { ControlSetting* c = new ControlSetting(); - c->control = control; + c->propHandle = getControlMap()->getPropertyHandle(prop); c->val = val; - _approachConfig.controls.add(c); + _approachConfig.controls.add(c); } -void Airplane::addCruiseControl(int control, float val) +void Airplane::addCruiseControl(const char* prop, float val) { ControlSetting* c = new ControlSetting(); - c->control = control; + c->propHandle = getControlMap()->getPropertyHandle(prop); c->val = val; - _cruiseConfig.controls.add(c); - } + _cruiseConfig.controls.add(c); +} void Airplane::addSolutionWeight(bool approach, int idx, float wgt) { @@ -258,11 +274,11 @@ void Airplane::setWeight(int handle, float mass) // how we simulate droppable stores. if(mass == 0) { wr->surf->setXDrag(0); - wr->surf->setYDrag(0); + wr->surf->setYDrag(0); wr->surf->setZDrag(0); } else { wr->surf->setXDrag(1); - wr->surf->setYDrag(1); + wr->surf->setYDrag(1); wr->surf->setZDrag(1); } } @@ -331,7 +347,7 @@ float Airplane::compileFuselage(Fuselage* f) float len = Math::mag3(fwd); if (len == 0) { _failureMsg = "Zero length fuselage"; - return 0; + return 0; } float wid = f->width; int segs = (int)Math::ceil(len/wid); @@ -344,14 +360,14 @@ float Airplane::compileFuselage(Fuselage* f) if(frac < f->mid) scale = f->taper+(1-f->taper) * (frac / f->mid); else { - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { - // Correct calculation of width for fuselage taper. - scale = 1 - (1-f->taper) * (frac - f->mid) / (1 - f->mid); - } else { - // Original, incorrect calculation of width for fuselage taper. - scale = f->taper+(1-f->taper) * (frac - f->mid) / (1 - f->mid); - } - } + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + // Correct calculation of width for fuselage taper. + scale = 1 - (1-f->taper) * (frac - f->mid) / (1 - f->mid); + } else { + // Original, incorrect calculation of width for fuselage taper. + scale = f->taper+(1-f->taper) * (frac - f->mid) / (1 - f->mid); + } + } // Where are we? float pos[3]; @@ -367,40 +383,40 @@ float Airplane::compileFuselage(Fuselage* f) Surface* s = new Surface(this); s->setPosition(pos); - // The following is the original YASim value for sideDrag. - // Originally YASim calculated the fuselage's lateral drag - // coefficient as (solver drag factor) * (len/wid). - // However, this greatly underestimates a fuselage's lateral drag. - float sideDrag = len/wid; + // The following is the original YASim value for sideDrag. + // Originally YASim calculated the fuselage's lateral drag + // coefficient as (solver drag factor) * (len/wid). + // However, this greatly underestimates a fuselage's lateral drag. + float sideDrag = len/wid; - if ( isVersionOrNewer( YASIM_VERSION_32 ) ) { - // New YASim assumes a fixed lateral drag coefficient of 0.5. - // This will not be multiplied by the solver drag factor, because - // that factor is tuned to match the drag in the direction of - // flight, which is completely independent of lateral drag. - // The value of 0.5 is only a ballpark estimate, roughly matching - // the side-on drag for a long cylinder at the higher Reynolds - // numbers typical for an aircraft's lateral drag. - // This fits if the fuselage is long and has a round cross section. - // For flat-sided fuselages, the value should be increased, up to - // a limit of around 2 for a long rectangular prism. - // For very short fuselages, in which the end effects are strong, - // the value should be reduced. - // Such adjustments can be made using the fuselage's "cy" and "cz" - // XML parameters: "cy" for the sides, "cz" for top and bottom. - sideDrag = 0.5; - } + if ( isVersionOrNewer( YASIM_VERSION_32 ) ) { + // New YASim assumes a fixed lateral drag coefficient of 0.5. + // This will not be multiplied by the solver drag factor, because + // that factor is tuned to match the drag in the direction of + // flight, which is completely independent of lateral drag. + // The value of 0.5 is only a ballpark estimate, roughly matching + // the side-on drag for a long cylinder at the higher Reynolds + // numbers typical for an aircraft's lateral drag. + // This fits if the fuselage is long and has a round cross section. + // For flat-sided fuselages, the value should be increased, up to + // a limit of around 2 for a long rectangular prism. + // For very short fuselages, in which the end effects are strong, + // the value should be reduced. + // Such adjustments can be made using the fuselage's "cy" and "cz" + // XML parameters: "cy" for the sides, "cz" for top and bottom. + sideDrag = 0.5; + } - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { s->setXDrag(f->_cx); - } + } s->setYDrag(sideDrag*f->_cy); s->setZDrag(sideDrag*f->_cz); - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { s->setDragCoefficient(scale*segWgt); } else { s->setDragCoefficient(scale*segWgt*f->_cx); - } + } s->setInducedDrag(f->_idrag); // FIXME: fails for fuselages aligned along the Y axis @@ -409,8 +425,8 @@ float Airplane::compileFuselage(Fuselage* f) Math::unit3(fwd, x); y[0] = 0; y[1] = 1; y[2] = 0; Math::cross3(x, y, z); - Math::unit3(z, z); - Math::cross3(z, x, y); + Math::unit3(z, z); + Math::cross3(z, x, y); s->setOrientation(o); _model.addSurface(s); @@ -503,38 +519,38 @@ void Airplane::compile() // The Wing objects if (_wing) { - if (baseN != 0) { - _wingsN = baseN->getChild("wing", 0, true); - _wing->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(_wing); - - // convert % to absolute x coordinates - _cgDesiredFront = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMin; - _cgDesiredAft = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMax; - if (baseN != 0) { - SGPropertyNode_ptr n = fgGetNode("/fdm/yasim/model", true); - n->getNode("cg-x-range-front", true)->setFloatValue(_cgDesiredFront); - n->getNode("cg-x-range-aft", true)->setFloatValue(_cgDesiredAft); - } + if (baseN != 0) { + _wingsN = baseN->getChild("wing", 0, true); + _wing->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(_wing); + + // convert % to absolute x coordinates + _cgDesiredFront = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMin; + _cgDesiredAft = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMax; + if (baseN != 0) { + SGPropertyNode_ptr n = fgGetNode("/fdm/yasim/model", true); + n->getNode("cg-x-range-front", true)->setFloatValue(_cgDesiredFront); + n->getNode("cg-x-range-aft", true)->setFloatValue(_cgDesiredAft); + } } if (_tail) { - if (baseN != 0) { - _wingsN = baseN->getChild("tail", 0, true); - _tail->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(_tail); + if (baseN != 0) { + _wingsN = baseN->getChild("tail", 0, true); + _tail->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(_tail); } int i; for(i=0; i<_vstabs.size(); i++) { - Wing* vs = (Wing*)_vstabs.get(i); - if (baseN != 0) { - _wingsN = baseN->getChild("stab", i, true); - vs->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(vs); + Wing* vs = (Wing*)_vstabs.get(i); + if (baseN != 0) { + _wingsN = baseN->getChild("stab", i, true); + vs->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(vs); } // The fuselage(s) @@ -715,15 +731,15 @@ void Airplane::setupWeights(bool isApproach) } } -/// load values for controls as defined in cruise configuration +/// load values for controls as defined in cruise/approach configuration void Airplane::loadControls(const Vector& controls) { - _controls.reset(); - for(int i=0; i < controls.size(); i++) { + _controls.reset(); + for(int i=0; i < controls.size(); i++) { ControlSetting* c = (ControlSetting*)controls.get(i); - _controls.setInput(c->control, c->val); - } - _controls.applyControls(); + _controls.setInput(c->propHandle, c->val); + } + _controls.applyControls(); } /// Helper for solve() @@ -801,11 +817,11 @@ void Airplane::applyDragFactor(float factor) } } for(i=0; i<_weights.size(); i++) { - WeightRec* wr = (WeightRec*)_weights.get(i); + WeightRec* wr = (WeightRec*)_weights.get(i); wr->surf->setDragCoefficient(wr->surf->getDragCoefficient() * applied); } for(i=0; i<_gears.size(); i++) { - GearRec* gr = (GearRec*)_gears.get(i); + GearRec* gr = (GearRec*)_gears.get(i); gr->surf->setDragCoefficient(gr->surf->getDragCoefficient() * applied); } } diff --git a/src/FDM/YASim/Airplane.hpp b/src/FDM/YASim/Airplane.hpp index 1a033357e..0f22cfc22 100644 --- a/src/FDM/YASim/Airplane.hpp +++ b/src/FDM/YASim/Airplane.hpp @@ -37,9 +37,9 @@ public: void setEmptyWeight(float weight) { _emptyWeight = weight; } - void setWing(Wing* wing) { _wing = wing; } - Wing* getWing() { return _wing; } - void setTail(Wing* tail) { _tail = tail; } + Wing* getWing(); + bool hasWing() const { return (_wing != nullptr); } + Wing* getTail(); void addVStab(Wing* vstab) { _vstabs.add(vstab); } void addFuselage(float* front, float* back, float width, @@ -59,9 +59,9 @@ public: void setApproach(float speed, float altitude, float aoa, float fuel, float gla); void setCruise(float speed, float altitude, float fuel, float gla); - void setElevatorControl(int control); - void addApproachControl(int control, float val); - void addCruiseControl(int control, float val); + void setElevatorControl(const char* prop); + void addApproachControl(const char* prop, float val); + void addCruiseControl(const char* prop, float val); void addSolutionWeight(bool approach, int idx, float wgt); @@ -135,7 +135,7 @@ private: float mass; }; struct ControlSetting { - int control; + int propHandle; float val; }; struct WeightRec { diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp index 27dddc72c..db644691d 100644 --- a/src/FDM/YASim/ControlMap.cpp +++ b/src/FDM/YASim/ControlMap.cpp @@ -2,7 +2,8 @@ # include "config.h" #endif -#include "yasim-common.hpp" +#include + #include "Jet.hpp" #include "Thruster.hpp" #include "PropEngine.hpp" @@ -42,16 +43,18 @@ ControlMap::~ControlMap() } /** - input : index to _inputs - type: identifier (see enum OutputType) +prop: name of input property +control: identifier (see enum OutputType) +object: object to which this input belongs to +options: bits OPT_INVERT, OPT_SPLIT, OPT_SQUARE */ -void ControlMap::addMapping(int input, Control control, void* object, int options, - float src0, float src1, float dst0, float dst1) +void ControlMap::addMapping(const char* prop, Control control, ObjectID id, int options, float src0, float src1, float dst0, float dst1) { - addMapping(input, control, object, options); + addMapping(prop, control, id, options); + int inputPropHandle = getPropertyHandle(prop); // The one we just added is last in the list (ugly, awful hack!) - Vector* maps = (Vector*)_inputs.get(input); + Vector* maps = (Vector*)_inputs.get(inputPropHandle); MapRec* m = (MapRec*)maps->get(maps->size() - 1); m->src0 = src0; @@ -61,16 +64,21 @@ void ControlMap::addMapping(int input, Control control, void* object, int option } /** - input : index to _inputs - type: identifier (see enum OutputType) +prop: name of input property +control: identifier (see enum OutputType) +object: object to which this input belongs to +options: bits OPT_INVERT, OPT_SPLIT, OPT_SQUARE */ -void ControlMap::addMapping(int input, Control control, void* object, int options) +void ControlMap::addMapping(const char* prop, Control control, ObjectID id, int options) { + int inputPropHandle = getPropertyHandle(prop); // See if the output object already exists OutRec* out {nullptr}; for(int i = 0; i < _outputs.size(); i++) { OutRec* o = (OutRec*)_outputs.get(i); - if(o->object == object && o->control == control) { + if(o->oid.object == id.object && o->oid.subObj == id.subObj + && o->control == control) + { out = o; break; } @@ -80,7 +88,7 @@ void ControlMap::addMapping(int input, Control control, void* object, int option if(out == nullptr) { out = new OutRec(); out->control = control; - out->object = object; + out->oid = id; _outputs.add(out); } @@ -95,7 +103,7 @@ void ControlMap::addMapping(int input, Control control, void* object, int option map->src0 = map->dst0 = rangeMin(control); // And add it to the approproate vectors. - Vector* maps = (Vector*)_inputs.get(input); + Vector* maps = (Vector*)_inputs.get(inputPropHandle); maps->add(map); } @@ -124,14 +132,15 @@ void ControlMap::setInput(int input, float val) } } -int ControlMap::getOutputHandle(void* obj, Control control) +int ControlMap::getOutputHandle(ObjectID id, Control control) { - for(int i=0; i<_outputs.size(); i++) { + for(int i = 0; i < _outputs.size(); i++) { OutRec* o = (OutRec*)_outputs.get(i); - if(o->object == obj && o->control == control) + if(o->oid.object == id.object && o->oid.subObj == id.subObj + && o->control == control) return i; } - fprintf(stderr, "ControlMap::getOutputHandle cannot find *%d, control %d \n", obj, control); + fprintf(stderr, "ControlMap::getOutputHandle cannot find *%ld, control %d \n", (long)id.object, control); return -1; } @@ -153,27 +162,28 @@ float ControlMap::getOutputR(int handle) void ControlMap::applyControls(float dt) { int outrec; - for(outrec=0; outrec<_outputs.size(); outrec++) { - OutRec* o = (OutRec*)_outputs.get(outrec); - - // Generate a summed value. Note the check for "split" - // control axes like ailerons. - float lval = 0, rval = 0; - int i; - for(i=0; imaps.size(); i++) { - MapRec* m = (MapRec*)o->maps.get(i); - float val = m->val; + for(outrec=0; outrec<_outputs.size(); outrec++) + { + OutRec* o = (OutRec*)_outputs.get(outrec); + + // Generate a summed value. Note the check for "split" + // control axes like ailerons. + float lval = 0, rval = 0; + int i; + for(i=0; imaps.size(); i++) { + MapRec* m = (MapRec*)o->maps.get(i); + float val = m->val; - if(m->opt & OPT_SQUARE) - val = val * Math::abs(val); - if(m->opt & OPT_INVERT) - val = -val; - lval += val; - if(m->opt & OPT_SPLIT) - rval -= val; - else - rval += val; - } + if(m->opt & OPT_SQUARE) + val = val * Math::abs(val); + if(m->opt & OPT_INVERT) + val = -val; + lval += val; + if(m->opt & OPT_SPLIT) + rval -= val; + else + rval += val; + } // If there is a finite transition time, clamp the values to // the maximum travel allowed in this dt. @@ -194,59 +204,135 @@ void ControlMap::applyControls(float dt) o->oldL = lval; o->oldR = rval; - void* obj = o->object; - switch(o->control) { - case THROTTLE: ((Thruster*)obj)->setThrottle(lval); break; - case MIXTURE: ((Thruster*)obj)->setMixture(lval); break; - case CONDLEVER: ((TurbineEngine*)((PropEngine*) - obj)->getEngine())->setCondLever(lval); break; - case STARTER: ((Thruster*)obj)->setStarter(lval != 0.0); break; - case MAGNETOS: ((PropEngine*)obj)->setMagnetos((int)lval); break; - case ADVANCE: ((PropEngine*)obj)->setAdvance(lval); break; - case PROPPITCH: ((PropEngine*)obj)->setPropPitch(lval); break; - case PROPFEATHER: ((PropEngine*)obj)->setPropFeather((int)lval); break; - case REHEAT: ((Jet*)obj)->setReheat(lval); break; - case VECTOR: ((Jet*)obj)->setRotation(lval); break; - case BRAKE: ((Gear*)obj)->setBrake(lval); break; - case STEER: ((Gear*)obj)->setRotation(lval); break; - case EXTEND: ((Gear*)obj)->setExtension(lval); break; - case HEXTEND: ((Hook*)obj)->setExtension(lval); break; - case LEXTEND: ((Launchbar*)obj)->setExtension(lval); break; - case LACCEL: ((Launchbar*)obj)->setAcceleration(lval); break; - case CASTERING:((Gear*)obj)->setCastering(lval != 0); break; - case SLAT: ((Wing*)obj)->setFlapPos(WING_SLAT,lval); break; - case FLAP0: ((Wing*)obj)->setFlapPos(WING_FLAP0, lval, rval); break; - case FLAP0EFFECTIVENESS: ((Wing*)obj)->setFlapEffectiveness(WING_FLAP0,lval); break; - case FLAP1: ((Wing*)obj)->setFlapPos(WING_FLAP1,lval, rval); break; - case FLAP1EFFECTIVENESS: ((Wing*)obj)->setFlapEffectiveness(WING_FLAP1,lval); break; - case SPOILER: ((Wing*)obj)->setFlapPos(WING_SPOILER, lval, rval); break; - case COLLECTIVE: ((Rotor*)obj)->setCollective(lval); break; - case CYCLICAIL: ((Rotor*)obj)->setCyclicail(lval,rval); break; - case CYCLICELE: ((Rotor*)obj)->setCyclicele(lval,rval); break; - case TILTPITCH: ((Rotor*)obj)->setTiltPitch(lval); break; - case TILTYAW: ((Rotor*)obj)->setTiltYaw(lval); break; - case TILTROLL: ((Rotor*)obj)->setTiltRoll(lval); break; - case ROTORBALANCE: - ((Rotor*)obj)->setRotorBalance(lval); break; - case ROTORBRAKE: ((Rotorgear*)obj)->setRotorBrake(lval); break; - case ROTORENGINEON: - ((Rotorgear*)obj)->setEngineOn((int)lval); break; - case ROTORENGINEMAXRELTORQUE: - ((Rotorgear*)obj)->setRotorEngineMaxRelTorque(lval); break; - case ROTORRELTARGET: - ((Rotorgear*)obj)->setRotorRelTarget(lval); break; - case REVERSE_THRUST: ((Jet*)obj)->setReverse(lval != 0); break; - case BOOST: - ((PistonEngine*)((Thruster*)obj)->getEngine())->setBoost(lval); - break; - case WASTEGATE: - ((PistonEngine*)((Thruster*)obj)->getEngine())->setWastegate(lval); - break; - case WINCHRELSPEED: ((Hitch*)obj)->setWinchRelSpeed(lval); break; - case HITCHOPEN: ((Hitch*)obj)->setOpen(lval!=0); break; - case PLACEWINCH: ((Hitch*)obj)->setWinchPositionAuto(lval!=0); break; - case FINDAITOW: ((Hitch*)obj)->findBestAIObject(lval!=0); break; - } + void* obj = o->oid.object; + switch(o->control) { + case THROTTLE: + ((Thruster*)obj)->setThrottle(lval); + break; + case MIXTURE: + ((Thruster*)obj)->setMixture(lval); + break; + case CONDLEVER: + ((TurbineEngine*)((PropEngine*)obj)->getEngine())->setCondLever(lval); + break; + case STARTER: + ((Thruster*)obj)->setStarter(lval != 0.0); + break; + case MAGNETOS: + ((PropEngine*)obj)->setMagnetos((int)lval); + break; + case ADVANCE: + ((PropEngine*)obj)->setAdvance(lval); + break; + case PROPPITCH: + ((PropEngine*)obj)->setPropPitch(lval); + break; + case PROPFEATHER: + ((PropEngine*)obj)->setPropFeather((int)lval); + break; + case REHEAT: + ((Jet*)obj)->setReheat(lval); + break; + case VECTOR: + ((Jet*)obj)->setRotation(lval); + break; + case BRAKE: + ((Gear*)obj)->setBrake(lval); + break; + case STEER: + ((Gear*)obj)->setRotation(lval); + break; + case EXTEND: + ((Gear*)obj)->setExtension(lval); + break; + case HEXTEND: + ((Hook*)obj)->setExtension(lval); + break; + case LEXTEND: + ((Launchbar*)obj)->setExtension(lval); + break; + case LACCEL: + ((Launchbar*)obj)->setAcceleration(lval); + break; + case CASTERING: + ((Gear*)obj)->setCastering(lval != 0); + break; + case SLAT: + ((Wing*)obj)->setFlapPos(WING_SLAT,lval); + break; + case FLAP0: + ((Wing*)obj)->setFlapPos(WING_FLAP0, lval, rval); + break; + case FLAP0EFFECTIVENESS: + ((Wing*)obj)->setFlapEffectiveness(WING_FLAP0,lval); + break; + case FLAP1: + ((Wing*)obj)->setFlapPos(WING_FLAP1,lval, rval); + break; + case FLAP1EFFECTIVENESS: + ((Wing*)obj)->setFlapEffectiveness(WING_FLAP1,lval); + break; + case SPOILER: + ((Wing*)obj)->setFlapPos(WING_SPOILER, lval, rval); + break; + case COLLECTIVE: + ((Rotor*)obj)->setCollective(lval); + break; + case CYCLICAIL: + ((Rotor*)obj)->setCyclicail(lval,rval); + break; + case CYCLICELE: + ((Rotor*)obj)->setCyclicele(lval,rval); + break; + case TILTPITCH: + ((Rotor*)obj)->setTiltPitch(lval); + break; + case TILTYAW: + ((Rotor*)obj)->setTiltYaw(lval); + break; + case TILTROLL: + ((Rotor*)obj)->setTiltRoll(lval); + break; + case ROTORBALANCE: + ((Rotor*)obj)->setRotorBalance(lval); + break; + case ROTORBRAKE: + ((Rotorgear*)obj)->setRotorBrake(lval); + break; + case ROTORENGINEON: + ((Rotorgear*)obj)->setEngineOn((int)lval); + break; + case ROTORENGINEMAXRELTORQUE: + ((Rotorgear*)obj)->setRotorEngineMaxRelTorque(lval); + break; + case ROTORRELTARGET: + ((Rotorgear*)obj)->setRotorRelTarget(lval); + break; + case REVERSE_THRUST: + ((Jet*)obj)->setReverse(lval != 0); + break; + case BOOST: + ((PistonEngine*)((Thruster*)obj)->getEngine())->setBoost(lval); + break; + case WASTEGATE: + ((PistonEngine*)((Thruster*)obj)->getEngine())->setWastegate(lval); + break; + case WINCHRELSPEED: + ((Hitch*)obj)->setWinchRelSpeed(lval); + break; + case HITCHOPEN: + ((Hitch*)obj)->setOpen(lval!=0); + break; + case PLACEWINCH: + ((Hitch*)obj)->setWinchPositionAuto(lval!=0); + break; + case FINDAITOW: + ((Hitch*)obj)->findBestAIObject(lval!=0); + break; + case PROP: + case INCIDENCE: + break; + } } } @@ -283,17 +369,17 @@ float ControlMap::rangeMax(Control control) } /// register property name, return ID (int) -int ControlMap::propertyHandle(const char* name) +int ControlMap::getPropertyHandle(const char* name) { for(int i=0; i < _properties.size(); i++) { PropHandle* p = (PropHandle*)_properties.get(i); - if(eq(p->name, name)) + if(!strcmp(p->name, name)) return p->handle; } // create new PropHandle* p = new PropHandle(); - p->name = dup(name); + p->name = strdup(name); fgGetNode(p->name, true); @@ -306,52 +392,60 @@ int ControlMap::propertyHandle(const char* name) ControlMap::Control ControlMap::parseControl(const char* name) { - if(eq(name, "THROTTLE")) return THROTTLE; - if(eq(name, "MIXTURE")) return MIXTURE; - if(eq(name, "CONDLEVER")) return CONDLEVER; - if(eq(name, "STARTER")) return STARTER; - if(eq(name, "MAGNETOS")) return MAGNETOS; - if(eq(name, "ADVANCE")) return ADVANCE; - if(eq(name, "REHEAT")) return REHEAT; - if(eq(name, "BOOST")) return BOOST; - if(eq(name, "VECTOR")) return VECTOR; - if(eq(name, "PROP")) return PROP; - if(eq(name, "BRAKE")) return BRAKE; - if(eq(name, "STEER")) return STEER; - if(eq(name, "EXTEND")) return EXTEND; - if(eq(name, "HEXTEND")) return HEXTEND; - if(eq(name, "LEXTEND")) return LEXTEND; - if(eq(name, "LACCEL")) return LACCEL; - if(eq(name, "INCIDENCE")) return INCIDENCE; - if(eq(name, "FLAP0")) return FLAP0; - if(eq(name, "FLAP0EFFECTIVENESS")) return FLAP0EFFECTIVENESS; - if(eq(name, "FLAP1")) return FLAP1; - if(eq(name, "FLAP1EFFECTIVENESS")) return FLAP1EFFECTIVENESS; - if(eq(name, "SLAT")) return SLAT; - if(eq(name, "SPOILER")) return SPOILER; - if(eq(name, "CASTERING")) return CASTERING; - if(eq(name, "PROPPITCH")) return PROPPITCH; - if(eq(name, "PROPFEATHER")) return PROPFEATHER; - if(eq(name, "COLLECTIVE")) return COLLECTIVE; - if(eq(name, "CYCLICAIL")) return CYCLICAIL; - if(eq(name, "CYCLICELE")) return CYCLICELE; - if(eq(name, "TILTROLL")) return TILTROLL; - if(eq(name, "TILTPITCH")) return TILTPITCH; - if(eq(name, "TILTYAW")) return TILTYAW; - if(eq(name, "ROTORGEARENGINEON")) return ROTORENGINEON; - if(eq(name, "ROTORBRAKE")) return ROTORBRAKE; - if(eq(name, "ROTORENGINEMAXRELTORQUE")) return ROTORENGINEMAXRELTORQUE; - if(eq(name, "ROTORRELTARGET")) return ROTORRELTARGET; - if(eq(name, "ROTORBALANCE")) return ROTORBALANCE; - if(eq(name, "REVERSE_THRUST")) return REVERSE_THRUST; - if(eq(name, "WASTEGATE")) return WASTEGATE; - if(eq(name, "WINCHRELSPEED")) return WINCHRELSPEED; - if(eq(name, "HITCHOPEN")) return HITCHOPEN; - if(eq(name, "PLACEWINCH")) return PLACEWINCH; - if(eq(name, "FINDAITOW")) return FINDAITOW; + if(!strcmp(name, "THROTTLE")) return THROTTLE; + if(!strcmp(name, "MIXTURE")) return MIXTURE; + if(!strcmp(name, "CONDLEVER")) return CONDLEVER; + if(!strcmp(name, "STARTER")) return STARTER; + if(!strcmp(name, "MAGNETOS")) return MAGNETOS; + if(!strcmp(name, "ADVANCE")) return ADVANCE; + if(!strcmp(name, "REHEAT")) return REHEAT; + if(!strcmp(name, "BOOST")) return BOOST; + if(!strcmp(name, "VECTOR")) return VECTOR; + if(!strcmp(name, "PROP")) return PROP; + if(!strcmp(name, "BRAKE")) return BRAKE; + if(!strcmp(name, "STEER")) return STEER; + if(!strcmp(name, "EXTEND")) return EXTEND; + if(!strcmp(name, "HEXTEND")) return HEXTEND; + if(!strcmp(name, "LEXTEND")) return LEXTEND; + if(!strcmp(name, "LACCEL")) return LACCEL; + if(!strcmp(name, "INCIDENCE")) return INCIDENCE; + if(!strcmp(name, "FLAP0")) return FLAP0; + if(!strcmp(name, "FLAP0EFFECTIVENESS")) return FLAP0EFFECTIVENESS; + if(!strcmp(name, "FLAP1")) return FLAP1; + if(!strcmp(name, "FLAP1EFFECTIVENESS")) return FLAP1EFFECTIVENESS; + if(!strcmp(name, "SLAT")) return SLAT; + if(!strcmp(name, "SPOILER")) return SPOILER; + if(!strcmp(name, "CASTERING")) return CASTERING; + if(!strcmp(name, "PROPPITCH")) return PROPPITCH; + if(!strcmp(name, "PROPFEATHER")) return PROPFEATHER; + if(!strcmp(name, "COLLECTIVE")) return COLLECTIVE; + if(!strcmp(name, "CYCLICAIL")) return CYCLICAIL; + if(!strcmp(name, "CYCLICELE")) return CYCLICELE; + if(!strcmp(name, "TILTROLL")) return TILTROLL; + if(!strcmp(name, "TILTPITCH")) return TILTPITCH; + if(!strcmp(name, "TILTYAW")) return TILTYAW; + if(!strcmp(name, "ROTORGEARENGINEON")) return ROTORENGINEON; + if(!strcmp(name, "ROTORBRAKE")) return ROTORBRAKE; + if(!strcmp(name, "ROTORENGINEMAXRELTORQUE")) return ROTORENGINEMAXRELTORQUE; + if(!strcmp(name, "ROTORRELTARGET")) return ROTORRELTARGET; + if(!strcmp(name, "ROTORBALANCE")) return ROTORBALANCE; + if(!strcmp(name, "REVERSE_THRUST")) return REVERSE_THRUST; + if(!strcmp(name, "WASTEGATE")) return WASTEGATE; + if(!strcmp(name, "WINCHRELSPEED")) return WINCHRELSPEED; + if(!strcmp(name, "HITCHOPEN")) return HITCHOPEN; + if(!strcmp(name, "PLACEWINCH")) return PLACEWINCH; + if(!strcmp(name, "FINDAITOW")) return FINDAITOW; SG_LOG(SG_FLIGHT,SG_ALERT,"Unrecognized control type '" << name << "' in YASim aircraft description."); exit(1); } +ControlMap::ObjectID ControlMap::getObjectID(void* object, int subObj) +{ + ObjectID o; + o.object = object; + o.subObj = subObj; + return o; +} + } // namespace yasim diff --git a/src/FDM/YASim/ControlMap.hpp b/src/FDM/YASim/ControlMap.hpp index b385187bb..94374ea2a 100644 --- a/src/FDM/YASim/ControlMap.hpp +++ b/src/FDM/YASim/ControlMap.hpp @@ -62,26 +62,32 @@ public: OPT_SQUARE = 0x04 }; - struct PropHandle { char* name; int handle; }; + struct PropHandle { + char* name {nullptr}; + int handle {0}; + }; + struct ObjectID { + void* object {nullptr}; + int subObj {0}; + }; // map control name to int (enum) Control parseControl(const char* name); - // Adds a mapping to between input handle and a particular setting - // on an output object. The value of output MUST match the type - // of object! - void addMapping(int input, Control control, void* object, int options=0); + // create ID from object and optional sub index (e.g. for wing section) + ObjectID getObjectID(void* object, int subObj = 0); + + // add input property for a control to an object + void addMapping(const char* prop, Control control, ObjectID id, int options = 0); - // An additional form to specify a mapping range. Input values - // outside of [src0:src1] are clamped, and are then mapped to - // [dst0:dst1] before being set on the object. - void addMapping(int input, Control control, void* object, int options, - float src0, float src1, float dst0, float dst1); + // same with limits. Input values are clamped to [src0:src1] and then mapped to + // [dst0:dst1] before being set on the objects control. + void addMapping(const char* prop, Control control, ObjectID id, int options, float src0, float src1, float dst0, float dst1); // Resets our accumulated input values. Call before any // setInput() invokations. void reset(); - // Sets the specified input (as returned by propertyHandle) to the + // Sets the specified input (as returned by getPropertyHandle()) to the // specified value. void setInput(int propHandle, float value); @@ -97,7 +103,7 @@ public: // Each output record is identified by both an object/type tuple // and a numeric handle. - int getOutputHandle(void* obj, Control control); + int getOutputHandle(ObjectID id, Control control); // Sets the transition time for the control output to swing // through its full range. @@ -110,14 +116,14 @@ public: float getOutputR(int handle); // register property name, return handle - int propertyHandle(const char* name); + int getPropertyHandle(const char* name); int numProperties() { return _properties.size(); } PropHandle* getProperty(const int i) { return ((PropHandle*)_properties.get(i)); } private: struct OutRec { Control control; - void* object {nullptr}; + ObjectID oid; Vector maps; float oldL {0}; float oldR {0}; diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index f5545fc7e..1a8c82c63 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -4,9 +4,11 @@ #include #include +#include #include
+#include "yasim-common.hpp" #include "Math.hpp" #include "Jet.hpp" #include "SimpleJet.hpp" @@ -38,7 +40,7 @@ FGFDM::FGFDM() // Map /controls/flight/elevator to the approach elevator control. This // should probably be settable, but there are very few aircraft // who trim their approaches using things other than elevator. - _airplane.setElevatorControl(_airplane.getControlMap()->propertyHandle("/controls/flight/elevator-trim")); + _airplane.setElevatorControl("/controls/flight/elevator-trim"); // FIXME: read seed from somewhere? int seed = 0; @@ -214,85 +216,23 @@ void FGFDM::init() } // Not the worlds safest parser. But it's short & sweet. -void FGFDM::startElement(const char* name, const XMLAttributes &atts) +void FGFDM::startElement(const char* name, const XMLAttributes &a) { - XMLAttributes* a = (XMLAttributes*)&atts; + //XMLAttributes* a = (XMLAttributes*)&atts; float v[3] {0,0,0}; - char buf[64]; - float f {0}; - if(eq(name, "airplane")) { - if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; } - else if (a->hasAttribute("mass-lbs")) { f = attrf(a, "mass-lbs") * LBS2KG; } - else if (a->hasAttribute("mass-kg")) { f = attrf(a, "mass-kg"); } - else { - SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, airplane needs one of {mass-lbs, mass-kg}"); - exit(1); - } - _airplane.setEmptyWeight(f); - if(a->hasAttribute("version")) { - _airplane.setVersion( a->getValue("version") ); - } - if( !_airplane.isVersionOrNewer( Version::YASIM_VERSION_CURRENT ) ) { - SG_LOG(SG_FLIGHT, SG_DEV_ALERT, "This aircraft does not use the latest yasim configuration version."); - } - _airplane.setDesiredCGRangeInPercentOfMAC(attrf(a, "cg-min", 0.25f), attrf(a, "cg-max", 0.3f)); //FIXME find reasonable defaults - if (attrb(a, "auto-ballast")) { - _airplane.setAutoBallast(true); - } - } else if(eq(name, "approach")) { - float spd, alt = 0; - if (a->hasAttribute("speed")) { spd = attrf(a, "speed") * KTS2MPS; } - else if (a->hasAttribute("speed-kt")) { spd = attrf(a, "speed-kt") * KTS2MPS; } - else if (a->hasAttribute("speed-kmh")) { spd = attrf(a, "speed-kmh") * KMH2MPS; } - else { - SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, approach needs one of {speed-kt, speed-kmh}"); - exit(1); - } - if (a->hasAttribute("alt")) { alt = attrf(a, "alt") * FT2M; } - else if (a->hasAttribute("alt-ft")) { alt = attrf(a, "alt-ft") * FT2M; } - else if (a->hasAttribute("alt-m")) { alt = attrf(a, "alt-m"); } - float aoa = attrf(a, "aoa", 0) * DEG2RAD; - float gla = attrf(a, "glide-angle", 0) * DEG2RAD; - _airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2), gla); - _cruiseCurr = false; - } else if(eq(name, "cruise")) { - float spd, alt = 0; - if (a->hasAttribute("speed")) { spd = attrf(a, "speed") * KTS2MPS; } - else if (a->hasAttribute("speed-kt")) { spd = attrf(a, "speed-kt") * KTS2MPS; } - else if (a->hasAttribute("speed-kmh")) { spd = attrf(a, "speed-kmh") * KMH2MPS; } - else { - SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, approach needs one of {speed-kt, speed-kmh}"); - exit(1); - } - if (a->hasAttribute("alt")) { alt = attrf(a, "alt") * FT2M; } - else if (a->hasAttribute("alt-ft")) { alt = attrf(a, "alt-ft") * FT2M; } - else if (a->hasAttribute("alt-m")) { alt = attrf(a, "alt-m"); } - float gla = attrf(a, "glide-angle", 0) * DEG2RAD; - _airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla); - _cruiseCurr = true; - } else if(eq(name, "solve-weight")) { - int idx = attri(a, "idx"); - if(a->hasAttribute("weight")) { f = attrf(a, "weight") * LBS2KG; } - else if(a->hasAttribute("weight-lbs")) { f = attrf(a, "weight-lbs") * LBS2KG; } - else if(a->hasAttribute("weight-kg")) { f = attrf(a, "weight-kg"); } - else { - SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, solve-weight needs one of {weight-lbs, weight-kg}"); - exit(1); - } - _airplane.addSolutionWeight(!_cruiseCurr, idx, f); - } else if(eq(name, "cockpit")) { - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - _airplane.setPilotPos(v); - } else if(eq(name, "rotor")) { - _airplane.getModel()->getRotorgear()->addRotor(parseRotor(a, name)); - } else if(eq(name, "rotorgear")) { + if(!strcmp(name, "airplane")) { parseAirplane(&a); } + else if(!strcmp(name, "approach") || !strcmp(name, "cruise")) { + parseApproachCruise(&a, name); + } + else if(!strcmp(name, "solve-weight")) { parseSolveWeight(&a); } + else if(!strcmp(name, "cockpit")) { parseCockpit(&a); } + else if(!strcmp(name, "rotor")) { parseRotor(&a, name); } + else if(!strcmp(name, "rotorgear")) { Rotorgear* r = _airplane.getModel()->getRotorgear(); - _currObj = r; - #define p(x) if (a->hasAttribute(#x)) r->setParameter((char *)#x,attrf(a,#x) ); - #define p2(x,y) if (a->hasAttribute(y)) r->setParameter((char *)#x,attrf(a,y) ); + _currObj = r; + #define p(x) if ((&a)->hasAttribute(#x)) r->setParameter((char *)#x,attrf(&a,#x) ); + #define p2(x,y) if ((&a)->hasAttribute(y)) r->setParameter((char *)#x,attrf(&a,y) ); p2(max_power_engine,"max-power-engine") p2(engine_prop_factor,"engine-prop-factor") p(yasimdragfactor) @@ -303,325 +243,113 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) #undef p #undef p2 r->setInUse(); - } else if(eq(name, "wing")) { - Wing *wing = parseWing(a, name, &_airplane); - _airplane.setWing(wing); - } else if(eq(name, "hstab")) { - _airplane.setTail(parseWing(a, name, &_airplane)); - } else if(eq(name, "vstab") || eq(name, "mstab")) { - _airplane.addVStab(parseWing(a, name, &_airplane)); - } else if(eq(name, "piston-engine")) { - parsePistonEngine(a); - } else if(eq(name, "turbine-engine")) { - parseTurbineEngine(a); - } else if(eq(name, "propeller")) { - parsePropeller(a); - } else if(eq(name, "thruster")) { - SimpleJet* j = new SimpleJet(); - _currObj = j; - v[0] = attrf(a, "x"); v[1] = attrf(a, "y"); v[2] = attrf(a, "z"); - j->setPosition(v); - _airplane.addThruster(j, 0, v); - v[0] = attrf(a, "vx"); v[1] = attrf(a, "vy"); v[2] = attrf(a, "vz"); - j->setDirection(v); - j->setThrust(attrf(a, "thrust") * LBS2N); - } else if(eq(name, "jet")) { - Jet* j = new Jet(); - _currObj = j; - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - float mass; - if(a->hasAttribute("mass")) { mass = attrf(a, "mass") * LBS2KG; } - else if(a->hasAttribute("mass-lbs")) { mass = attrf(a, "mass-lbs") * LBS2KG; } - else if(a->hasAttribute("mass-kg")) { mass = attrf(a, "mass-kg"); } - else { - SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, jet needs one of {mass-lbs, mass-kg}"); - exit(1); - } - j->setMaxThrust(attrf(a, "thrust") * LBS2N, - attrf(a, "afterburner", 0) * LBS2N); - j->setVectorAngle(attrf(a, "rotate", 0) * DEG2RAD); - j->setReverseThrust(attrf(a, "reverse", 0.2)); - - float n1min = attrf(a, "n1-idle", 55); - float n1max = attrf(a, "n1-max", 102); - float n2min = attrf(a, "n2-idle", 73); - float n2max = attrf(a, "n2-max", 103); - j->setRPMs(n1min, n1max, n2min, n2max); - - j->setTSFC(attrf(a, "tsfc", 0.8)); - j->setATSFC(attrf(a, "atsfc", 0.0)); - if(a->hasAttribute("egt")) j->setEGT(attrf(a, "egt")); - if(a->hasAttribute("epr")) j->setEPR(attrf(a, "epr")); - if(a->hasAttribute("exhaust-speed")) - j->setVMax(attrf(a, "exhaust-speed") * KTS2MPS); - if(a->hasAttribute("spool-time")) - j->setSpooling(attrf(a, "spool-time")); - - j->setPosition(v); - _airplane.addThruster(j, mass, v); - sprintf(buf, "/engines/engine[%d]", _nextEngine++); - EngRec* er = new EngRec(); - er->eng = j; - er->prefix = dup(buf); - _thrusters.add(er); - } else if(eq(name, "hitch")) { - Hitch* h = new Hitch(a->getValue("name")); - _currObj = h; - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - h->setPosition(v); - if(a->hasAttribute("force-is-calculated-by-other")) h->setForceIsCalculatedByOther(attrb(a,"force-is-calculated-by-other")); - _airplane.addHitch(h); - } else if(eq(name, "tow")) { - Hitch* h = (Hitch*)_currObj; - if(a->hasAttribute("length")) - h->setTowLength(attrf(a, "length")); - if(a->hasAttribute("elastic-constant")) - h->setTowElasticConstant(attrf(a, "elastic-constant")); - if(a->hasAttribute("break-force")) - h->setTowBreakForce(attrf(a, "break-force")); - if(a->hasAttribute("weight-per-meter")) - h->setTowWeightPerM(attrf(a, "weight-per-meter")); - if(a->hasAttribute("mp-auto-connect-period")) - h->setMpAutoConnectPeriod(attrf(a, "mp-auto-connect-period")); - } else if(eq(name, "winch")) { - Hitch* h = (Hitch*)_currObj; - double pos[3]; - pos[0] = attrd(a, "x",0); - pos[1] = attrd(a, "y",0); - pos[2] = attrd(a, "z",0); - h->setWinchPosition(pos); - if(a->hasAttribute("max-speed")) - h->setWinchMaxSpeed(attrf(a, "max-speed")); - if(a->hasAttribute("power")) - h->setWinchPower(attrf(a, "power") * 1000); - if(a->hasAttribute("max-force")) - h->setWinchMaxForce(attrf(a, "max-force")); - if(a->hasAttribute("initial-tow-length")) - h->setWinchInitialTowLength(attrf(a, "initial-tow-length")); - if(a->hasAttribute("max-tow-length")) - h->setWinchMaxTowLength(attrf(a, "max-tow-length")); - if(a->hasAttribute("min-tow-length")) - h->setWinchMinTowLength(attrf(a, "min-tow-length")); - } else if(eq(name, "gear")) { - Gear* g = new Gear(); - _currObj = g; - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - g->setPosition(v); - float nrm = Math::mag3(v); - if (_vehicle_radius < nrm) - _vehicle_radius = nrm; - if(a->hasAttribute("upx")) { - v[0] = attrf(a, "upx"); - v[1] = attrf(a, "upy"); - v[2] = attrf(a, "upz"); - Math::unit3(v, v); - } else { - v[0] = 0; - v[1] = 0; - v[2] = 1; - } - for(int i=0; i<3; i++) - v[i] *= attrf(a, "compression", 1); - g->setCompression(v); - g->setBrake(attrf(a, "skid", 0)); - g->setInitialLoad(attrf(a, "initial-load", 0)); - g->setStaticFriction(attrf(a, "sfric", 0.8)); - g->setDynamicFriction(attrf(a, "dfric", 0.7)); - g->setSpring(attrf(a, "spring", 1)); - g->setDamping(attrf(a, "damp", 1)); - if(a->hasAttribute("on-water")) g->setOnWater(attrb(a,"on-water")); - if(a->hasAttribute("on-solid")) g->setOnSolid(attrb(a,"on-solid")); - if(a->hasAttribute("ignored-by-solver")) g->setIgnoreWhileSolving(attrb(a,"ignored-by-solver")); - g->setSpringFactorNotPlaning(attrf(a, "spring-factor-not-planing", 1)); - g->setSpeedPlaning(attrf(a, "speed-planing", 0) * KTS2MPS); - g->setReduceFrictionByExtension(attrf(a, "reduce-friction-by-extension", 0)); - _airplane.addGear(g); - } else if(eq(name, "hook")) { - Hook* h = new Hook(); - _currObj = h; - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - h->setPosition(v); - float length = attrf(a, "length", 1.0); - h->setLength(length); - float nrm = length+Math::mag3(v); - if (_vehicle_radius < nrm) - _vehicle_radius = nrm; - h->setDownAngle(attrf(a, "down-angle", 70) * DEG2RAD); - h->setUpAngle(attrf(a, "up-angle", 0) * DEG2RAD); - _airplane.addHook(h); - } else if(eq(name, "launchbar")) { - Launchbar* l = new Launchbar(); - _currObj = l; - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - l->setLaunchbarMount(v); - v[0] = attrf(a, "holdback-x", v[0]); - v[1] = attrf(a, "holdback-y", v[1]); - v[2] = attrf(a, "holdback-z", v[2]); - l->setHoldbackMount(v); - float length = attrf(a, "length", 1.0); - l->setLength(length); - l->setDownAngle(attrf(a, "down-angle", 45) * DEG2RAD); - l->setUpAngle(attrf(a, "up-angle", -45) * DEG2RAD); - l->setHoldbackLength(attrf(a, "holdback-length", 2.0)); - _airplane.addLaunchbar(l); - } else if(eq(name, "fuselage")) { - float b[3]; - v[0] = attrf(a, "ax"); - v[1] = attrf(a, "ay"); - v[2] = attrf(a, "az"); - b[0] = attrf(a, "bx"); - b[1] = attrf(a, "by"); - b[2] = attrf(a, "bz"); - float taper = attrf(a, "taper", 1); - float mid = attrf(a, "midpoint", 0.5); - if (_airplane.isVersionOrNewer(Version::YASIM_VERSION_32)) { - // A fuselage's "midpoint" XML attribute is defined from the - // fuselage's front end, but the Fuselage object's internal - // "mid" attribute is actually defined from the rear end. - // Thus YASim's original interpretation of "midpoint" was wrong. - // Complement the "midpoint" value to ensure the fuselage - // points the right way. - mid = 1 - mid; - } - float cx = attrf(a, "cx", 1); - float cy = attrf(a, "cy", 1); - float cz = attrf(a, "cz", 1); - float idrag = attrf(a, "idrag", 1); - _airplane.addFuselage(v, b, attrf(a, "width"), taper, mid, - cx, cy, cz, idrag); - } else if(eq(name, "tank")) { - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - float density = 6.0; // gasoline, in lbs/gal - if(a->hasAttribute("jet")) density = 6.72; - density *= LBS2KG*CM2GALS; - float capacity = 0; - if(a->hasAttribute("capacity")) { capacity = attrf(a, "capacity") * LBS2KG; } - else if(a->hasAttribute("capacity-lbs")) { capacity = attrf(a, "capacity-lbs") * LBS2KG; } - else if(a->hasAttribute("capacity-kg")) { capacity = attrf(a, "capacity-kg"); } - else { - SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, tank needs one of {capacity-lbs, capacity-kg}"); - exit(1); - } - _airplane.addTank(v, capacity, density); - } else if(eq(name, "ballast")) { - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; } - else if (a->hasAttribute("mass-lbs")) { f = attrf(a, "mass-lbs") * LBS2KG; } - else if (a->hasAttribute("mass-kg")) { f = attrf(a, "mass-kg"); } - else { - SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, airplane needs one of {mass-lbs, mass-kg}"); - exit(1); - } - _airplane.addBallast(v, f); - } else if(eq(name, "weight")) { - parseWeight(a); - } else if(eq(name, "stall")) { - Wing* w = (Wing*)_currObj; - StallParams sp; - sp.aoa = attrf(a, "aoa") * DEG2RAD; - sp.width = attrf(a, "width", 2) * DEG2RAD; - sp.peak = attrf(a, "peak", 1.5); - w->setStallParams(sp); - } else if(eq(name, "flap0") || eq(name, "flap1") || eq(name, "spoiler") || eq(name, "slat")) { - FlapParams fp; - fp.start = attrf(a, "start"); - fp.end = attrf(a, "end"); - if (eq(name, "slat")) { - fp.aoa = attrf(a, "aoa"); - } - else { - fp.lift = attrf(a, "lift"); - } - fp.drag = attrf(a, "drag"); - - if (eq(name, "flap0")) { - ((Wing*)_currObj)->setFlapParams(WING_FLAP0, fp); - } - if (eq(name, "flap1")) { - ((Wing*)_currObj)->setFlapParams(WING_FLAP1, fp); - } - if (eq(name, "spoiler")) { - ((Wing*)_currObj)->setFlapParams(WING_SPOILER, fp); - } - if (eq(name, "slat")) { - ((Wing*)_currObj)->setFlapParams(WING_SLAT, fp); - } - } else if(eq(name, "actionpt")) { - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - ((Thruster*)_currObj)->setPosition(v); - } else if(eq(name, "dir")) { - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - ((Thruster*)_currObj)->setDirection(v); - } else if(eq(name, "control-setting")) { - // A cruise or approach control setting - const char* axis = a->getValue("axis"); - float value = attrf(a, "value", 0); - ControlMap* cm = _airplane.getControlMap(); - if(_cruiseCurr) - _airplane.addCruiseControl(cm->propertyHandle(axis), value); - else - _airplane.addApproachControl(cm->propertyHandle(axis), value); - } else if(eq(name, "control-input")) { - ControlMap* cm = _airplane.getControlMap(); - // A mapping of input property to a control - int propHandle = cm->propertyHandle(a->getValue("axis")); - ControlMap::Control control = cm->parseControl(a->getValue("control")); - int opt = 0; - opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0; - opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0; - opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0; - if(a->hasAttribute("src0")) { - cm->addMapping(propHandle, control, _currObj, opt, attrf(a, "src0"), attrf(a, "src1"), attrf(a, "dst0"), attrf(a, "dst1")); - } else { - cm->addMapping(propHandle, control, _currObj, opt); - } - } else if(eq(name, "control-output")) { - // A property output for a control on the current object - ControlMap* cm = _airplane.getControlMap(); - ControlMap::Control control = cm->parseControl(a->getValue("control")); - - PropOut* p = new PropOut(); - p->prop = fgGetNode(a->getValue("prop"), true); - p->handle = cm->getOutputHandle(_currObj, control); - p->control = control; - p->left = !(a->hasAttribute("side") && - eq("right", a->getValue("side"))); - p->min = attrf(a, "min", cm->rangeMin(control)); - p->max = attrf(a, "max", cm->rangeMax(control)); - _controlProps.add(p); - - } else if(eq(name, "control-speed")) { - ControlMap* cm = _airplane.getControlMap(); - ControlMap::Control control = cm->parseControl(a->getValue("control")); - int handle = cm->getOutputHandle(_currObj, control); - float time = attrf(a, "transition-time", 0); - - cm->setTransitionTime(handle, time); - } else { - SG_LOG(SG_FLIGHT,SG_ALERT,"Unexpected tag '" - << name << "' found in YASim aircraft description"); + } + else if(!strcmp(name, "wing") || !strcmp(name, "hstab") || !strcmp(name, "vstab") || !strcmp(name, "mstab")) { + parseWing(&a, name, &_airplane); + } + else if(!strcmp(name, "piston-engine")) { parsePistonEngine(&a); } + else if(!strcmp(name, "turbine-engine")) { parseTurbineEngine(&a); } + else if(!strcmp(name, "propeller")) { parsePropeller(&a); } + else if(!strcmp(name, "thruster")) { parseThruster(&a); } + else if(!strcmp(name, "jet")) { parseJet(&a); } + else if(!strcmp(name, "hitch")) { parseHitch(&a); } + else if(!strcmp(name, "tow")) { parseTow(&a); } + else if(!strcmp(name, "winch")) { parseWinch(&a); } + else if(!strcmp(name, "gear")) { parseGear(&a); } + else if(!strcmp(name, "hook")) { parseHook(&a); } + else if(!strcmp(name, "launchbar")) { parseLaunchbar(&a); } + else if(!strcmp(name, "fuselage")) { parseFuselage(&a); } + else if(!strcmp(name, "tank")) { parseTank(&a); } + else if(!strcmp(name, "ballast")) { parseBallast(&a); } + else if(!strcmp(name, "weight")) { parseWeight(&a); } + else if(!strcmp(name, "stall")) { parseStall(&a); } + else if(!strcmp(name, "flap0") || !strcmp(name, "flap1") || !strcmp(name, "spoiler") || !strcmp(name, "slat")) { + parseFlap(&a, name); + } + else if(!strcmp(name, "actionpt")) { + attrf_xyz(&a, v); + ((Thruster*)_currObj)->setPosition(v); + } + else if(!strcmp(name, "dir")) { + attrf_xyz(&a, v); + ((Thruster*)_currObj)->setDirection(v); + } + else if(!strcmp(name, "control-setting")) { parseControlSetting(&a); } + else if(!strcmp(name, "control-input")) { parseControlIn(&a); } + else if(!strcmp(name, "control-output")) { parseControlOut(&a); } + else if(!strcmp(name, "control-speed")) { parseControlSpeed(&a); } + else { + SG_LOG(SG_FLIGHT,SG_ALERT,"Unexpected tag '" << name << "' found in YASim aircraft description"); exit(1); } +} // startElement + +void FGFDM::parseAirplane(const XMLAttributes* a) +{ + float f {0}; + if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; } + else if (a->hasAttribute("mass-lbs")) { f = attrf(a, "mass-lbs") * LBS2KG; } + else if (a->hasAttribute("mass-kg")) { f = attrf(a, "mass-kg"); } + else { + SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, airplane needs one of {mass-lbs, mass-kg}"); + exit(1); + } + _airplane.setEmptyWeight(f); + if(a->hasAttribute("version")) { _airplane.setVersion(a->getValue("version")); } + if( !_airplane.isVersionOrNewer( Version::YASIM_VERSION_CURRENT ) ) { + SG_LOG(SG_FLIGHT, SG_DEV_ALERT, "This aircraft does not use the latest yasim configuration version."); + } + _airplane.setDesiredCGRangeInPercentOfMAC(attrf(a, "cg-min", 0.25f), attrf(a, "cg-max", 0.3f)); + if (attrb(a, "auto-ballast")) { _airplane.setAutoBallast(true); } } +void FGFDM::parseApproachCruise(const XMLAttributes* a, const char* name) +{ + float spd, alt = 0; + if (a->hasAttribute("speed")) { spd = attrf(a, "speed") * KTS2MPS; } + else if (a->hasAttribute("speed-kt")) { spd = attrf(a, "speed-kt") * KTS2MPS; } + else if (a->hasAttribute("speed-kmh")) { spd = attrf(a, "speed-kmh") * KMH2MPS; } + else { + SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, "<< name << " needs one of {speed-kt, speed-kmh}"); + exit(1); + } + if (a->hasAttribute("alt")) { alt = attrf(a, "alt") * FT2M; } + else if (a->hasAttribute("alt-ft")) { alt = attrf(a, "alt-ft") * FT2M; } + else if (a->hasAttribute("alt-m")) { alt = attrf(a, "alt-m"); } + float gla = attrf(a, "glide-angle", 0) * DEG2RAD; + if (!strcmp(name, "approach")) { + float aoa = attrf(a, "aoa", 0) * DEG2RAD; + _airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2), gla); + _cruiseCurr = false; + } + else { + _airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla); + _cruiseCurr = true; + } +} + +void FGFDM::parseSolveWeight(const XMLAttributes* a) +{ + float f {0}; + int idx = attri(a, "idx"); + if(a->hasAttribute("weight")) { f = attrf(a, "weight") * LBS2KG; } + else if(a->hasAttribute("weight-lbs")) { f = attrf(a, "weight-lbs") * LBS2KG; } + else if(a->hasAttribute("weight-kg")) { f = attrf(a, "weight-kg"); } + else { + SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, solve-weight needs one of {weight-lbs, weight-kg}"); + exit(1); + } + _airplane.addSolutionWeight(!_cruiseCurr, idx, f); +} + +void FGFDM::parseCockpit(const XMLAttributes* a) +{ + float v[3]; + attrf_xyz(a, v); + _airplane.setPilotPos(v); +} + + void FGFDM::getExternalInput(float dt) { char buf[256]; @@ -801,69 +529,89 @@ void FGFDM::setOutputProperties(float dt) } } -Wing* FGFDM::parseWing(XMLAttributes* a, const char* type, Version * version) +void FGFDM::parseWing(const XMLAttributes* a, const char* type, Airplane* airplane) { float defDihed = 0; bool mirror = true; - if(eq(type, "vstab")) { - defDihed = 90; - mirror = false; + if(!strcmp(type, "vstab")) { + defDihed = 90; + mirror = false; } - float isSection = attrb(a, "section"); float base[3] {0,0,0}; float chord {0}; - if (!isSection) { - base[0] = attrf(a, "x"); - base[1] = attrf(a, "y"); - base[2] = attrf(a, "z"); - chord = attrf(a, "chord"); - } float length = attrf(a, "length"); + // These come in with positive indicating positive AoA, but the + // internals expect a rotation about the left-pointing Y axis, so + // invert the sign. + float incidence {0}; + float twist = attrf(a, "twist", 0) * DEG2RAD * -1; + + // if this element is declared as section of a wing, skip attributes + // that are ignored in class Wing anyway because they are calculated + float isSection = attrb(a, "append"); + if (!isSection) { + attrf_xyz(a, base); + chord = attrf(a, "chord"); + incidence = attrf(a, "incidence", 0) * DEG2RAD * -1; + } + // optional attributes (with defaults) float sweep = attrf(a, "sweep", 0) * DEG2RAD; float taper = attrf(a, "taper", 1); float dihedral = attrf(a, "dihedral", defDihed) * DEG2RAD; - // These come in with positive indicating positive AoA, but the - // internals expect a rotation about the left-pointing Y axis, so - // invert the sign. - float incidence = attrf(a, "incidence", 0) * DEG2RAD * -1; - float twist = attrf(a, "twist", 0) * DEG2RAD * -1; float camber = attrf(a, "camber", 0); - if (!version->isVersionOrNewer(Version::YASIM_VERSION_2017_2) && (camber == 0)) { - SG_LOG(SG_FLIGHT, SG_DEV_WARN, "YASIM warning: versions before 2017.2 are buggy for wings with camber=0"); + if (!airplane->isVersionOrNewer(Version::YASIM_VERSION_2017_2) && (camber == 0)) { + SG_LOG(SG_FLIGHT, SG_DEV_WARN, "YASIM warning: versions before 2017.2 are buggy for wings with camber=0"); } - Wing* w = new Wing(version, mirror, base, chord, length, - taper, sweep, dihedral, twist); - w->setIncidence(incidence); - w->setCamber(camber); - // The 70% is a magic number that sorta kinda seems to match known // throttle settings to approach speed. - w->setInducedDrag(0.7*attrf(a, "idrag", 1)); + float idrag = 0.7*attrf(a, "idrag", 1); - float effect = attrf(a, "effectiveness", 1); - w->multiplyDragCoefficient(effect); - + // get wing object by type + Wing* w; + if (!strcmp(type, "wing")) + { + w = airplane->getWing(); + } + else if (!strcmp(type, "hstab")) { + w = airplane->getTail(); + } else { + w = new Wing(airplane, mirror); + } + // add section; if wing object has already section, base will be overridden + // by tip of last section + _wingSection = w->addWingSection(base, chord, length, taper, sweep, dihedral, twist, camber, idrag, incidence); + if (!strcmp(type, "vstab") || !strcmp(type, "mstab")) + { + airplane->addVStab(w); + } + + float dragFactor = attrf(a, "pdrag", 1); + if (a->hasAttribute("effectiveness")) { + SG_LOG(SG_FLIGHT, SG_ALERT, "Warning: " << + "deprecated attribute 'effectiveness' in YASim configuration file. " << + "Use 'pdrag' instead to add parasitic drag."); + + dragFactor = attrf(a, "effectiveness", 1); + } + w->setSectionDrag(_wingSection, dragFactor); _currObj = w; - return w; } -Rotor* FGFDM::parseRotor(XMLAttributes* a, const char* type) +void FGFDM::parseRotor(const XMLAttributes* a, const char* type) { Rotor* w = new Rotor(); // float defDihed = 0; float pos[3]; - pos[0] = attrf(a, "x"); - pos[1] = attrf(a, "y"); - pos[2] = attrf(a, "z"); + attrf_xyz(a, pos); w->setBase(pos); float normal[3]; @@ -920,24 +668,21 @@ Rotor* FGFDM::parseRotor(XMLAttributes* a, const char* type) if(attrb(a,"sharedflaphinge")) w->setSharedFlapHinge(true); - if(a->hasAttribute("name")) - w->setName(a->getValue("name") ); - if(a->hasAttribute("alphaout0")) - w->setAlphaoutput(0,a->getValue("alphaout0") ); - if(a->hasAttribute("alphaout1")) w->setAlphaoutput(1,a->getValue("alphaout1") ); - if(a->hasAttribute("alphaout2")) w->setAlphaoutput(2,a->getValue("alphaout2") ); - if(a->hasAttribute("alphaout3")) w->setAlphaoutput(3,a->getValue("alphaout3") ); - if(a->hasAttribute("coneout")) w->setAlphaoutput(4,a->getValue("coneout") ); - if(a->hasAttribute("yawout")) w->setAlphaoutput(5,a->getValue("yawout") ); - if(a->hasAttribute("rollout")) w->setAlphaoutput(6,a->getValue("rollout") ); + if(a->hasAttribute("name")) w->setName(a->getValue("name")); + if(a->hasAttribute("alphaout0")) w->setAlphaoutput(0,a->getValue("alphaout0")); + if(a->hasAttribute("alphaout1")) w->setAlphaoutput(1,a->getValue("alphaout1")); + if(a->hasAttribute("alphaout2")) w->setAlphaoutput(2,a->getValue("alphaout2")); + if(a->hasAttribute("alphaout3")) w->setAlphaoutput(3,a->getValue("alphaout3")); + if(a->hasAttribute("coneout")) w->setAlphaoutput(4,a->getValue("coneout")); + if(a->hasAttribute("yawout")) w->setAlphaoutput(5,a->getValue("yawout")); + if(a->hasAttribute("rollout")) w->setAlphaoutput(6,a->getValue("rollout")); w->setPitchA(attrf(a, "pitch-a", 10)); w->setPitchB(attrf(a, "pitch-b", 10)); w->setForceAtPitchA(attrf(a, "forceatpitch-a", 3000)); w->setPowerAtPitch0(attrf(a, "poweratpitch-0", 300)); w->setPowerAtPitchB(attrf(a, "poweratpitch-b", 3000)); - if(attrb(a,"notorque")) - w->setNotorque(1); + if(attrb(a,"notorque")) w->setNotorque(1); #define p(x) if (a->hasAttribute(#x)) w->setParameter((char *)#x,attrf(a,#x) ); #define p2(x,y) if (a->hasAttribute(y)) w->setParameter((char *)#x,attrf(a,y) ); @@ -971,10 +716,10 @@ Rotor* FGFDM::parseRotor(XMLAttributes* a, const char* type) #undef p #undef p2 _currObj = w; - return w; -} + _airplane.getModel()->getRotorgear()->addRotor(w); +} //parseRotor -void FGFDM::parsePistonEngine(XMLAttributes* a) +void FGFDM::parsePistonEngine(const XMLAttributes* a) { float engP = attrf(a, "eng-power") * HP2W; float engS = attrf(a, "eng-rpm") * RPM2RAD; @@ -1003,7 +748,7 @@ void FGFDM::parsePistonEngine(XMLAttributes* a) ((PropEngine*)_currObj)->setEngine(eng); } -void FGFDM::parseTurbineEngine(XMLAttributes* a) +void FGFDM::parseTurbineEngine(const XMLAttributes* a) { float power = attrf(a, "eng-power") * HP2W; float omega = attrf(a, "eng-rpm") * RPM2RAD; @@ -1022,7 +767,7 @@ void FGFDM::parseTurbineEngine(XMLAttributes* a) ((PropEngine*)_currObj)->setEngine(eng); } -void FGFDM::parsePropeller(XMLAttributes* a) +void FGFDM::parsePropeller(const XMLAttributes* a) { // Legacy Handling for the old engines syntax: PistonEngine* eng = 0; @@ -1046,9 +791,7 @@ void FGFDM::parsePropeller(XMLAttributes* a) // Now parse the actual propeller definition: float cg[3]; - cg[0] = attrf(a, "x"); - cg[1] = attrf(a, "y"); - cg[2] = attrf(a, "z"); + attrf_xyz(a, cg); float mass = attrf(a, "mass") * LBS2KG; float moment = attrf(a, "moment"); float radius = attrf(a, "radius"); @@ -1091,30 +834,364 @@ void FGFDM::parsePropeller(XMLAttributes* a) sprintf(buf, "/engines/engine[%d]", _nextEngine++); EngRec* er = new EngRec(); er->eng = thruster; - er->prefix = dup(buf); + er->prefix = strdup(buf); _thrusters.add(er); _currObj = thruster; } +void FGFDM::parseThruster(const XMLAttributes* a) +{ + float v[3]; + SimpleJet* j = new SimpleJet(); + _currObj = j; + attrf_xyz(a, v); + j->setPosition(v); + _airplane.addThruster(j, 0, v); + v[0] = attrf(a, "vx"); v[1] = attrf(a, "vy"); v[2] = attrf(a, "vz"); + j->setDirection(v); + j->setThrust(attrf(a, "thrust") * LBS2N); +} -void FGFDM::parseWeight(XMLAttributes* a) +void FGFDM::parseJet(const XMLAttributes* a) +{ + float v[3]; + Jet* j = new Jet(); + _currObj = j; + attrf_xyz(a, v); + float mass; + if(a->hasAttribute("mass")) { mass = attrf(a, "mass") * LBS2KG; } + else if(a->hasAttribute("mass-lbs")) { mass = attrf(a, "mass-lbs") * LBS2KG; } + else if(a->hasAttribute("mass-kg")) { mass = attrf(a, "mass-kg"); } + else { + SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, jet needs one of {mass-lbs, mass-kg}"); + exit(1); + } + j->setMaxThrust(attrf(a, "thrust") * LBS2N, attrf(a, "afterburner", 0) * LBS2N); + j->setVectorAngle(attrf(a, "rotate", 0) * DEG2RAD); + j->setReverseThrust(attrf(a, "reverse", 0.2)); + + float n1min = attrf(a, "n1-idle", 55); + float n1max = attrf(a, "n1-max", 102); + float n2min = attrf(a, "n2-idle", 73); + float n2max = attrf(a, "n2-max", 103); + j->setRPMs(n1min, n1max, n2min, n2max); + + j->setTSFC(attrf(a, "tsfc", 0.8)); + j->setATSFC(attrf(a, "atsfc", 0.0)); + if(a->hasAttribute("egt")) j->setEGT(attrf(a, "egt")); + if(a->hasAttribute("epr")) j->setEPR(attrf(a, "epr")); + if(a->hasAttribute("exhaust-speed")) + j->setVMax(attrf(a, "exhaust-speed") * KTS2MPS); + if(a->hasAttribute("spool-time")) + j->setSpooling(attrf(a, "spool-time")); + + j->setPosition(v); + _airplane.addThruster(j, mass, v); + char buf[64]; + sprintf(buf, "/engines/engine[%d]", _nextEngine++); + EngRec* er = new EngRec(); + er->eng = j; + er->prefix = strdup(buf); + _thrusters.add(er); +} + +void FGFDM::parseHitch(const XMLAttributes* a) +{ + float v[3]; + Hitch* h = new Hitch(a->getValue("name")); + _currObj = h; + attrf_xyz(a, v); + h->setPosition(v); + if(a->hasAttribute("force-is-calculated-by-other")) h->setForceIsCalculatedByOther(attrb(a,"force-is-calculated-by-other")); + _airplane.addHitch(h); +} + +void FGFDM::parseTow(const XMLAttributes* a) +{ + Hitch* h = (Hitch*)_currObj; + if(a->hasAttribute("length")) + h->setTowLength(attrf(a, "length")); + if(a->hasAttribute("elastic-constant")) + h->setTowElasticConstant(attrf(a, "elastic-constant")); + if(a->hasAttribute("break-force")) + h->setTowBreakForce(attrf(a, "break-force")); + if(a->hasAttribute("weight-per-meter")) + h->setTowWeightPerM(attrf(a, "weight-per-meter")); + if(a->hasAttribute("mp-auto-connect-period")) + h->setMpAutoConnectPeriod(attrf(a, "mp-auto-connect-period")); +} + +void FGFDM::parseWinch(const XMLAttributes* a) +{ + Hitch* h = (Hitch*)_currObj; + double pos[3]; + pos[0] = attrd(a, "x",0); + pos[1] = attrd(a, "y",0); + pos[2] = attrd(a, "z",0); + h->setWinchPosition(pos); + if(a->hasAttribute("max-speed")) + h->setWinchMaxSpeed(attrf(a, "max-speed")); + if(a->hasAttribute("power")) + h->setWinchPower(attrf(a, "power") * 1000); + if(a->hasAttribute("max-force")) + h->setWinchMaxForce(attrf(a, "max-force")); + if(a->hasAttribute("initial-tow-length")) + h->setWinchInitialTowLength(attrf(a, "initial-tow-length")); + if(a->hasAttribute("max-tow-length")) + h->setWinchMaxTowLength(attrf(a, "max-tow-length")); + if(a->hasAttribute("min-tow-length")) + h->setWinchMinTowLength(attrf(a, "min-tow-length")); +} + +void FGFDM::parseGear(const XMLAttributes* a) +{ + float v[3]; + Gear* g = new Gear(); + _currObj = g; + attrf_xyz(a, v); + g->setPosition(v); + float nrm = Math::mag3(v); + if (_vehicle_radius < nrm) + _vehicle_radius = nrm; + if(a->hasAttribute("upx")) { + v[0] = attrf(a, "upx"); + v[1] = attrf(a, "upy"); + v[2] = attrf(a, "upz"); + Math::unit3(v, v); + } else { + v[0] = 0; + v[1] = 0; + v[2] = 1; + } + for(int i=0; i<3; i++) + v[i] *= attrf(a, "compression", 1); + g->setCompression(v); + g->setBrake(attrf(a, "skid", 0)); + g->setInitialLoad(attrf(a, "initial-load", 0)); + g->setStaticFriction(attrf(a, "sfric", 0.8)); + g->setDynamicFriction(attrf(a, "dfric", 0.7)); + g->setSpring(attrf(a, "spring", 1)); + g->setDamping(attrf(a, "damp", 1)); + if(a->hasAttribute("on-water")) g->setOnWater(attrb(a,"on-water")); + if(a->hasAttribute("on-solid")) g->setOnSolid(attrb(a,"on-solid")); + if(a->hasAttribute("ignored-by-solver")) g->setIgnoreWhileSolving(attrb(a,"ignored-by-solver")); + g->setSpringFactorNotPlaning(attrf(a, "spring-factor-not-planing", 1)); + g->setSpeedPlaning(attrf(a, "speed-planing", 0) * KTS2MPS); + g->setReduceFrictionByExtension(attrf(a, "reduce-friction-by-extension", 0)); + _airplane.addGear(g); +} + +void FGFDM::parseHook(const XMLAttributes* a) +{ + float v[3]; + Hook* h = new Hook(); + _currObj = h; + attrf_xyz(a, v); + h->setPosition(v); + float length = attrf(a, "length", 1.0); + h->setLength(length); + float nrm = length+Math::mag3(v); + if (_vehicle_radius < nrm) + _vehicle_radius = nrm; + h->setDownAngle(attrf(a, "down-angle", 70) * DEG2RAD); + h->setUpAngle(attrf(a, "up-angle", 0) * DEG2RAD); + _airplane.addHook(h); +} + +void FGFDM::parseLaunchbar(const XMLAttributes* a) +{ + float v[3]; + Launchbar* l = new Launchbar(); + _currObj = l; + attrf_xyz(a, v); + l->setLaunchbarMount(v); + v[0] = attrf(a, "holdback-x", v[0]); + v[1] = attrf(a, "holdback-y", v[1]); + v[2] = attrf(a, "holdback-z", v[2]); + l->setHoldbackMount(v); + float length = attrf(a, "length", 1.0); + l->setLength(length); + l->setDownAngle(attrf(a, "down-angle", 45) * DEG2RAD); + l->setUpAngle(attrf(a, "up-angle", -45) * DEG2RAD); + l->setHoldbackLength(attrf(a, "holdback-length", 2.0)); + _airplane.addLaunchbar(l); +} + +void FGFDM::parseFuselage(const XMLAttributes* a) +{ + float v[3]; + float b[3]; + v[0] = attrf(a, "ax"); + v[1] = attrf(a, "ay"); + v[2] = attrf(a, "az"); + b[0] = attrf(a, "bx"); + b[1] = attrf(a, "by"); + b[2] = attrf(a, "bz"); + float taper = attrf(a, "taper", 1); + float mid = attrf(a, "midpoint", 0.5); + if (_airplane.isVersionOrNewer(Version::YASIM_VERSION_32)) { + // A fuselage's "midpoint" XML attribute is defined from the + // fuselage's front end, but the Fuselage object's internal + // "mid" attribute is actually defined from the rear end. + // Thus YASim's original interpretation of "midpoint" was wrong. + // Complement the "midpoint" value to ensure the fuselage + // points the right way. + mid = 1 - mid; + } + float cx = attrf(a, "cx", 1); + float cy = attrf(a, "cy", 1); + float cz = attrf(a, "cz", 1); + float idrag = attrf(a, "idrag", 1); + _airplane.addFuselage(v, b, attrf(a, "width"), taper, mid, cx, cy, cz, idrag); +} + +void FGFDM::parseTank(const XMLAttributes* a) +{ + float v[3]; + attrf_xyz(a, v); + float density = 6.0; // gasoline, in lbs/gal + if(a->hasAttribute("jet")) density = 6.72; + density *= LBS2KG*CM2GALS; + float capacity = 0; + if(a->hasAttribute("capacity")) { capacity = attrf(a, "capacity") * LBS2KG; } + else if(a->hasAttribute("capacity-lbs")) { capacity = attrf(a, "capacity-lbs") * LBS2KG; } + else if(a->hasAttribute("capacity-kg")) { capacity = attrf(a, "capacity-kg"); } + else { + SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, tank needs one of {capacity-lbs, capacity-kg}"); + exit(1); + } + _airplane.addTank(v, capacity, density); +} + +void FGFDM::parseBallast(const XMLAttributes* a) +{ + float v[3]; + float f; + attrf_xyz(a, v); + if(a->hasAttribute("mass")) { f = attrf(a, "mass") * LBS2KG; } + else if (a->hasAttribute("mass-lbs")) { f = attrf(a, "mass-lbs") * LBS2KG; } + else if (a->hasAttribute("mass-kg")) { f = attrf(a, "mass-kg"); } + else { + SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, airplane needs one of {mass-lbs, mass-kg}"); + exit(1); + } + _airplane.addBallast(v, f); +} + +/* +void FGFDM::parseXXX(const XMLAttributes* a) +{ + float v[3]; +} +*/ + +void FGFDM::parseWeight(const XMLAttributes* a) { WeightRec* wr = new WeightRec(); float v[3]; - v[0] = attrf(a, "x"); - v[1] = attrf(a, "y"); - v[2] = attrf(a, "z"); - - wr->prop = dup(a->getValue("mass-prop")); + attrf_xyz(a, v); + wr->prop = strdup(a->getValue("mass-prop")); wr->size = attrf(a, "size", 0); wr->handle = _airplane.addWeight(v, wr->size); - _weights.add(wr); } -int FGFDM::attri(XMLAttributes* atts, const char* attr) +void FGFDM::parseStall(const XMLAttributes* a) +{ + Wing* w = (Wing*)_currObj; + StallParams sp; + sp.aoa = attrf(a, "aoa") * DEG2RAD; + sp.width = attrf(a, "width", 2) * DEG2RAD; + sp.peak = attrf(a, "peak", 1.5); + w->setSectionStallParams(_wingSection, sp); +} + +void FGFDM::parseFlap(const XMLAttributes* a, const char* name) +{ + FlapParams fp; + fp.start = attrf(a, "start"); + fp.end = attrf(a, "end"); + if (!strcmp(name, "slat")) { + fp.aoa = attrf(a, "aoa"); + } + else { + fp.lift = attrf(a, "lift"); + } + fp.drag = attrf(a, "drag"); + if (!strcmp(name, "flap0")) { + ((Wing*)_currObj)->setFlapParams(_wingSection, WING_FLAP0, fp); + } + if (!strcmp(name, "flap1")) { + ((Wing*)_currObj)->setFlapParams(_wingSection, WING_FLAP1, fp); + } + if (!strcmp(name, "spoiler")) { + ((Wing*)_currObj)->setFlapParams(_wingSection, WING_SPOILER, fp); + } + if (!strcmp(name, "slat")) { + ((Wing*)_currObj)->setFlapParams(_wingSection, WING_SLAT, fp); + } +} + +void FGFDM::parseControlSetting(const XMLAttributes* a) +{ + // A cruise or approach control setting + float value = attrf(a, "value", 0); + if(_cruiseCurr) { + _airplane.addCruiseControl(a->getValue("axis"), value); + } + else { + _airplane.addApproachControl(a->getValue("axis"), value); + } +} + +void FGFDM::parseControlIn(const XMLAttributes* a) +{ + // map input property to a YASim control + ControlMap* cm = _airplane.getControlMap(); + ControlMap::Control control = cm->parseControl(a->getValue("control")); + ControlMap::ObjectID oid = cm->getObjectID(_currObj, _wingSection); + int opt = 0; + opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0; + opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0; + opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0; + if(a->hasAttribute("src0")) { + cm->addMapping(a->getValue("axis"), control, oid, opt, attrf(a, "src0"), attrf(a, "src1"), attrf(a, "dst0"), attrf(a, "dst1")); + } else { + cm->addMapping(a->getValue("axis"), control, oid, opt); + } +} + +void FGFDM::parseControlOut(const XMLAttributes* a) +{ + // A property output for a control on the current object + ControlMap* cm = _airplane.getControlMap(); + ControlMap::Control control = cm->parseControl(a->getValue("control")); + ControlMap::ObjectID oid = cm->getObjectID(_currObj, _wingSection); + + PropOut* p = new PropOut(); + p->prop = fgGetNode(a->getValue("prop"), true); + p->handle = cm->getOutputHandle(oid, control); + p->control = control; + p->left = !(a->hasAttribute("side") && + !strcmp("right", a->getValue("side"))); + p->min = attrf(a, "min", cm->rangeMin(control)); + p->max = attrf(a, "max", cm->rangeMax(control)); + _controlProps.add(p); +} + +void FGFDM::parseControlSpeed(const XMLAttributes* a) +{ + ControlMap* cm = _airplane.getControlMap(); + ControlMap::Control control = cm->parseControl(a->getValue("control")); + ControlMap::ObjectID oid = cm->getObjectID(_currObj, _wingSection); + int handle = cm->getOutputHandle(oid, control); + float time = attrf(a, "transition-time", 0); + cm->setTransitionTime(handle, time); +} + +int FGFDM::attri(const XMLAttributes* atts, const char* attr) { if(!atts->hasAttribute(attr)) { SG_LOG(SG_FLIGHT,SG_ALERT,"Missing '" << attr << @@ -1124,14 +1201,14 @@ int FGFDM::attri(XMLAttributes* atts, const char* attr) return attri(atts, attr, 0); } -int FGFDM::attri(XMLAttributes* atts, const char* attr, int def) +int FGFDM::attri(const XMLAttributes* atts, const char* attr, int def) { const char* val = atts->getValue(attr); if(val == 0) return def; else return atol(val); } -float FGFDM::attrf(XMLAttributes* atts, const char* attr) +float FGFDM::attrf(const XMLAttributes* atts, const char* attr) { if(!atts->hasAttribute(attr)) { SG_LOG(SG_FLIGHT,SG_ALERT,"Missing '" << attr << @@ -1141,14 +1218,21 @@ float FGFDM::attrf(XMLAttributes* atts, const char* attr) return attrf(atts, attr, 0); } -float FGFDM::attrf(XMLAttributes* atts, const char* attr, float def) +float FGFDM::attrf(const XMLAttributes* atts, const char* attr, float def) { const char* val = atts->getValue(attr); if(val == 0) return def; else return (float)atof(val); } -double FGFDM::attrd(XMLAttributes* atts, const char* attr) +void FGFDM::attrf_xyz(const XMLAttributes* atts, float* out) +{ + out[0] = attrf(atts, "x"); + out[1] = attrf(atts, "y"); + out[2] = attrf(atts, "z"); +} + +double FGFDM::attrd(const XMLAttributes* atts, const char* attr) { if(!atts->hasAttribute(attr)) { SG_LOG(SG_FLIGHT,SG_ALERT,"Missing '" << attr << @@ -1158,7 +1242,7 @@ double FGFDM::attrd(XMLAttributes* atts, const char* attr) return attrd(atts, attr, 0); } -double FGFDM::attrd(XMLAttributes* atts, const char* attr, double def) +double FGFDM::attrd(const XMLAttributes* atts, const char* attr, double def) { const char* val = atts->getValue(attr); if(val == 0) return def; @@ -1176,12 +1260,12 @@ double FGFDM::attrd(XMLAttributes* atts, const char* attr, double def) // Unfortunately, this usage creeped into existing configuration files // while I wasn't active, and it's going to be hard to remove. Issue // a warning to nag people into changing their ways for now... -bool FGFDM::attrb(XMLAttributes* atts, const char* attr) +bool FGFDM::attrb(const XMLAttributes* atts, const char* attr) { const char* val = atts->getValue(attr); if(val == 0) return false; - if(eq(val,"true")) { + if(!strcmp(val,"true")) { SG_LOG(SG_FLIGHT, SG_ALERT, "Warning: " << "deprecated 'true' boolean in YASim configuration file. " << "Use numeric booleans (attribute=\"1\") instead"); diff --git a/src/FDM/YASim/FGFDM.hpp b/src/FDM/YASim/FGFDM.hpp index 49644163f..845873d66 100644 --- a/src/FDM/YASim/FGFDM.hpp +++ b/src/FDM/YASim/FGFDM.hpp @@ -4,7 +4,6 @@ #include #include -#include "yasim-common.hpp" #include "Airplane.hpp" #include "Vector.hpp" @@ -50,22 +49,49 @@ private: float max {0}; }; + void parseAirplane(const XMLAttributes* a); + void parseApproachCruise(const XMLAttributes* a, const char* name); + void parseSolveWeight(const XMLAttributes* a); + void parseCockpit(const XMLAttributes* a); + + void setOutputProperties(float dt); - Rotor* parseRotor(XMLAttributes* a, const char* name); - Wing* parseWing(XMLAttributes* a, const char* name, Version * version); + void parseRotor(const XMLAttributes* a, const char* name); + void parseWing(const XMLAttributes* a, const char* name, Airplane* airplane); int parseOutput(const char* name); - void parseWeight(XMLAttributes* a); - void parseTurbineEngine(XMLAttributes* a); - void parsePistonEngine(XMLAttributes* a); - void parsePropeller(XMLAttributes* a); - int attri(XMLAttributes* atts, const char* attr); - int attri(XMLAttributes* atts, const char* attr, int def); - float attrf(XMLAttributes* atts, const char* attr); - float attrf(XMLAttributes* atts, const char* attr, float def); - double attrd(XMLAttributes* atts, const char* attr); - double attrd(XMLAttributes* atts, const char* attr, double def); - bool attrb(XMLAttributes* atts, const char* attr); + void parseWeight(const XMLAttributes* a); + void parseStall(const XMLAttributes* a); + void parseFlap(const XMLAttributes* a, const char* name); + + void parseTurbineEngine(const XMLAttributes* a); + void parsePistonEngine(const XMLAttributes* a); + void parsePropeller(const XMLAttributes* a); + void parseThruster(const XMLAttributes* a); + void parseJet(const XMLAttributes* a); + void parseHitch(const XMLAttributes* a); + void parseTow(const XMLAttributes* a); + void parseWinch(const XMLAttributes* a); + void parseGear(const XMLAttributes* a); + void parseHook(const XMLAttributes* a); + void parseLaunchbar(const XMLAttributes* a); + void parseFuselage(const XMLAttributes* a); + void parseTank(const XMLAttributes* a); + void parseBallast(const XMLAttributes* a); + void parseControlSetting(const XMLAttributes* a); + void parseControlIn(const XMLAttributes* a); + void parseControlOut(const XMLAttributes* a); + void parseControlSpeed(const XMLAttributes* a); + + + int attri(const XMLAttributes* atts, const char* attr); + int attri(const XMLAttributes* atts, const char* attr, int def); + float attrf(const XMLAttributes* atts, const char* attr); + float attrf(const XMLAttributes* atts, const char* attr, float def); + void attrf_xyz(const XMLAttributes* atts, float* out); + double attrd(const XMLAttributes* atts, const char* attr); + double attrd(const XMLAttributes* atts, const char* attr, double def); + bool attrb(const XMLAttributes* atts, const char* attr); // The core Airplane object we manage. Airplane _airplane; @@ -89,6 +115,7 @@ private: void* _currObj {nullptr}; bool _cruiseCurr {false}; int _nextEngine {0}; + int _wingSection {0}; class FuelProps { diff --git a/src/FDM/YASim/Surface.cpp b/src/FDM/YASim/Surface.cpp index 6f01dc836..ffb5723bf 100644 --- a/src/FDM/YASim/Surface.cpp +++ b/src/FDM/YASim/Surface.cpp @@ -67,8 +67,10 @@ void Surface::setSpoilerParams(float liftPenalty, float dragPenalty) void Surface::setFlapPos(float pos) { if (_flapPos != pos) { - _flapPos = pos; - if (_surfN != 0) _flapN->setFloatValue(pos); + _flapPos = pos; + if (_surfN != 0) { + _flapN->setFloatValue(pos); + } } } @@ -76,7 +78,9 @@ void Surface::setSlatPos(float pos) { if (_slatPos != pos) { _slatPos = pos; - if (_surfN != 0) _slatN->setFloatValue(pos); + if (_surfN != 0) { + _slatN->setFloatValue(pos); + } } } diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index 3c3c3dc21..02757fa2f 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -5,81 +5,95 @@ namespace yasim { -Wing::Wing(Version *ver, bool mirror, float* base, float chord, - float length, float taper, float sweep, float dihedral, float twist) : +Wing::Wing(Version *ver, bool mirror) : _version(ver), - _mirror(mirror), - _rootChordLength(chord), - _length(length), - _taper(taper), - _sweepAngleCenterLine(sweep), - _dihedral(dihedral), - _twist(twist) + _mirror(mirror) { - Math::set3(base, _base); - _meanChord = _rootChordLength*(_taper+1)*0.5f; - calculateWingCoordinateSystem(); - calculateTip(); - calculateSpan(); - calculateMAC(); } Wing::~Wing() { - for(int i=0; i<_surfs.size(); i++) { - SurfRec* s = (SurfRec*)_surfs.get(i); - delete s->surface; - delete s; - } -} - -void Wing::setIncidence(float incidence) -{ - _incidence = incidence; - for(int i=0; i<_surfs.size(); i++) - ((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence); -} - -void Wing::setFlapParams(WingFlaps i, FlapParams fp) -{ - _flapParams[i] = fp; -} - -void Wing::setFlapPos(WingFlaps f,float lval, float rval) -{ - float min {-1}; - if (f == WING_SPOILER || f == WING_SLAT) { - min = 0; - } - lval = Math::clamp(lval, min, 1); - rval = Math::clamp(rval, min, 1); - for(int i=0; i<_flapSurfs[f].size(); i++) { - switch (f) { - case WING_FLAP0: - case WING_FLAP1: - ((Surface*)_flapSurfs[f].get(i))->setFlapPos(lval); - if(_mirror) ((Surface*)_flapSurfs[f].get(++i))->setFlapPos(rval); - break; - case WING_SLAT: - ((Surface*)_flapSurfs[f].get(i))->setSlatPos(lval); - break; - case WING_SPOILER: - ((Surface*)_flapSurfs[f].get(i))->setSpoilerPos(lval); - if(_mirror) ((Surface*)_flapSurfs[f].get(++i))->setSpoilerPos(rval); - break; + WingSection* ws; + for (int s=0; s < _sections.size(); s++){ + ws = (WingSection*)_sections.get(s); + for(int i=0; i_surfs.size(); i++) { + SurfRec* s = (SurfRec*)ws->_surfs.get(i); + delete s->surface; + delete s; } } } -void Wing::setFlapEffectiveness(WingFlaps f, float lval) +int Wing::addWingSection(float* base, float chord, float wingLength, float taper, + float sweep, float dihedral, float twist, float camber, + float idrag, float incidence) { - lval = Math::clamp(lval, 1, 10); - for(int i=0; i<_flapSurfs[f].size(); i++) { - ((Surface*)_flapSurfs[f].get(i))->setFlapEffectiveness(lval); + WingSection* ws = new WingSection; + if (_sections.size() == 0) { + // first section + Math::set3(base, _base); + ws->_rootChord = _float2chord(base, chord); + ws->_sectionIncidence = incidence; + } else { + WingSection* prev = (WingSection*)_sections.get(_sections.size()-1); + //use old wing tip instead of base argument + ws->_rootChord = prev->_tipChord; + ws->_sectionIncidence = prev->_sectionIncidence + prev->_twist; } + ws->_length = wingLength; + ws->_taper = taper; + ws->_sweepAngleCenterLine = sweep; + ws->_dihedral = dihedral; + ws->_twist = twist; + ws->_camber = camber; + ws->_inducedDrag = idrag; + ws->calculateGeometry(); + int idx = _sections.add(ws); + // first / only section + if (idx == 0) { + _mac = ws->getMAC(); + _wingspan = ws->_wingspan; + _area = ws->getArea(); + _meanChord = ws->_meanChord; + } + // append section: Calculate wing MAC from MACs of section and prev wing + else { + _mac = Wing::calculateMAC(_mac, ws->getMAC()); + _wingspan += ws->_wingspan; + _area += ws->getArea(); + _meanChord = _meanChord * ws->_meanChord * 0.5f; + } + _chord2float(ws->_tipChord, _tip); + return idx; } -void Wing::calculateWingCoordinateSystem() { +Chord Wing::_float2chord(float* pos, float lenght) +{ + Chord c; + c.x = pos[0]; + c.y = pos[1]; + c.z = pos[2]; + c.length = lenght; + return c; +} + +void Wing::_chord2float(Chord c, float* pos) +{ + pos[0] = c.x; + pos[1] = c.y; + pos[2] = c.z; +} + +void Wing::WingSection::calculateGeometry() +{ + _meanChord = _rootChord.length*(_taper+1)*0.5f; + calculateWingCoordinateSystem(); + calculateTipChord(); + calculateSpan(); + calculateMAC(); +} + +void Wing::WingSection::calculateWingCoordinateSystem() { // prepare wing coordinate system, ignoring incidence and twist for now // (tail incidence is varied by the solver) // Generating a unit vector pointing out the left wing. @@ -110,168 +124,257 @@ void Wing::calculateWingCoordinateSystem() { for(i=3; i<6; i++) _rightOrient[i] = -_rightOrient[i]; } -void Wing::calculateTip() { +void Wing::WingSection::calculateTipChord() { float *y = _orient+3; - Math::mul3(_length, y, _tip); - Math::add3(_base, _tip, _tip); + _tipChord.x = _rootChord.x + _length * y[0]; + _tipChord.y = _rootChord.y + _length * y[1]; + _tipChord.z = _rootChord.z + _length * y[2]; + _tipChord.length = _rootChord.length * _taper; } -void Wing::calculateSpan() +void Wing::WingSection::calculateSpan() { // wingspan in y-direction (not for vstab) - _wingspan = Math::abs(2*_tip[1]); - _netSpan = Math::abs(2*(_tip[1]-_base[1])); + _wingspan = Math::abs(2*_tipChord.y); _aspectRatio = _wingspan / _meanChord; } -void Wing::calculateMAC() +void Wing::WingSection::calculateMAC() { + //FIXME call static method, use absolute y values + // http://www.nasascale.org/p2/wp-content/uploads/mac-calculator.htm - const float commonFactor = _rootChordLength*(0.5+_taper)/(3*_rootChordLength*(1+_taper)); - _mac.length = _rootChordLength-(2*_rootChordLength*(1-_taper)*commonFactor); - _mac.y = _netSpan*commonFactor; - _mac.x = _base[0]-Math::tan(_sweepAngleCenterLine) * _mac.y + _mac.length/2; + const float commonFactor = _rootChord.length*(0.5+_taper)/(3*_rootChord.length*(1+_taper)); + _mac.length = _rootChord.length-(2*_rootChord.length*(1-_taper)*commonFactor); + _mac.y = Math::abs(2*(_tipChord.y-_rootChord.y))*commonFactor; + _mac.x = _rootChord.x-Math::tan(_sweepAngleCenterLine)*_mac.y + _mac.length/2; + _mac.y += _rootChord.y; } -Chord Wing::calculateMAC(Chord root, Chord tip) -{ - assert(root.length > 0); - //const float taper = tip.length / root.length; - const float commonFactor = (root.length*0.5+tip.length)/(3*(root.length+tip.length)); - Chord m; - m.length = root.length-(2*(root.length - tip.length)*commonFactor); - m.y = Math::abs(2*(tip.y - root.y))*commonFactor; - m.x = root.x - (root.x - tip.x)*(root.y - m.y)/(root.y - tip.y); - return m; -} - -float Wing::calculateSweepAngleLeadingEdge() +float Wing::WingSection::calculateSweepAngleLeadingEdge() { if (_length == 0) { return 0; } return Math::atan( - (sin(_sweepAngleCenterLine)+(1-_taper)*_rootChordLength/(2*_length)) / + (sin(_sweepAngleCenterLine)+(1-_taper)*_rootChord.length/(2*_length)) / cos(_sweepAngleCenterLine) ); } +void Wing::WingSection::setIncidence(float incidence) +{ + //update surface + for(int i=0; i<_surfs.size(); i++) + ((SurfRec*)_surfs.get(i))->surface->setIncidence(incidence + _sectionIncidence); +} + +// root and tip (x,y) coordinates are on leading edge +Chord Wing::calculateMAC(Chord root, Chord tip) +{ + assert(root.length > 0); + //taper = tip.length / root.length; + const float commonFactor = (root.length*0.5+tip.length)/(3*(root.length+tip.length)); + Chord m; + m.length = root.length-(2*(root.length - tip.length)*commonFactor); + m.y = Math::abs(2*(tip.y - root.y))*commonFactor + root.y; + m.x = root.x - (root.x - tip.x)*(root.y - m.y)/(root.y - tip.y); + return m; +} + +void Wing::setFlapParams(int section, WingFlaps type, FlapParams fp) +{ + ((WingSection*)_sections.get(section))->_flapParams[type] = fp; +} + +void Wing::setSectionDrag(int section, float pdrag) +{ + ((WingSection*)_sections.get(section))->_dragScale = pdrag; +} + +void Wing::setSectionStallParams(int section, StallParams sp) +{ + ((WingSection*)_sections.get(section))->_stallParams = sp; +} + +void Wing::setFlapPos(WingFlaps type,float lval, float rval) +{ + float min {-1}; + if (type == WING_SPOILER || type == WING_SLAT) { + min = 0; + } + lval = Math::clamp(lval, min, 1); + rval = Math::clamp(rval, min, 1); + WingSection* ws; + for (int section=0; section < _sections.size(); section++) + { + ws = (WingSection*)_sections.get(section); + for(int i=0; i < ws->_flapSurfs[type].size(); i++) { + switch (type) { + case WING_FLAP0: + case WING_FLAP1: + ((Surface*)ws->_flapSurfs[type].get(i))->setFlapPos(lval); + if(_mirror) ((Surface*)ws->_flapSurfs[type].get(++i))->setFlapPos(rval); + break; + case WING_SLAT: + ((Surface*)ws->_flapSurfs[type].get(i))->setSlatPos(lval); + break; + case WING_SPOILER: + ((Surface*)ws->_flapSurfs[type].get(i))->setSpoilerPos(lval); + if(_mirror) ((Surface*)ws->_flapSurfs[type].get(++i))->setSpoilerPos(rval); + break; + } + } + } +} + +void Wing::setFlapEffectiveness(WingFlaps f, float lval) +{ + lval = Math::clamp(lval, 1, 10); + WingSection* ws; + for (int section=0; section < _sections.size(); section++) + { + ws = (WingSection*)_sections.get(section); + for(int i=0; i_flapSurfs[f].size(); i++) { + ((Surface*)ws->_flapSurfs[f].get(i))->setFlapEffectiveness(lval); + } + } +} + void Wing::compile() { - // Have we already been compiled? - if(! _surfs.empty()) return; + WingSection* ws; + for (int section=0; section < _sections.size(); section++) + { + ws = (WingSection*)_sections.get(section); + // Have we already been compiled? + if(! ws->_surfs.empty()) return; + + // Assemble the start/end coordinates of all control surfaces + // and the wing itself into an array, sort them, + // and remove duplicates. This gives us the boundaries of our + // segments. + const int NUM_BOUNDS {10}; + float bounds[NUM_BOUNDS]; + bounds[0] = ws->_flapParams[WING_FLAP0].start; + bounds[1] = ws->_flapParams[WING_FLAP0].end; + bounds[2] = ws->_flapParams[WING_FLAP1].start; + bounds[3] = ws->_flapParams[WING_FLAP1].end; + bounds[4] = ws->_flapParams[WING_SPOILER].start; + bounds[5] = ws->_flapParams[WING_SPOILER].end; + bounds[6] = ws->_flapParams[WING_SLAT].start; + bounds[7] = ws->_flapParams[WING_SLAT].end; + //and don't forget the root and the tip of the wing itself + bounds[8] = 0; bounds[9] = 1; - // Assemble the start/end coordinates of all control surfaces - // and the wing itself into an array, sort them, - // and remove duplicates. This gives us the boundaries of our - // segments. - const int NUM_BOUNDS {10}; - float bounds[NUM_BOUNDS]; - bounds[0] = _flapParams[WING_FLAP0].start; - bounds[1] = _flapParams[WING_FLAP0].end; - bounds[2] = _flapParams[WING_FLAP1].start; - bounds[3] = _flapParams[WING_FLAP1].end; - bounds[4] = _flapParams[WING_SPOILER].start; - bounds[5] = _flapParams[WING_SPOILER].end; - bounds[6] = _flapParams[WING_SLAT].start; - bounds[7] = _flapParams[WING_SLAT].end; - //and don't forget the root and the tip of the wing itself - bounds[8] = 0; bounds[9] = 1; - - // Sort in increasing order - int i; - for(i=0; i_meanChord / ws->_length; - // Now go through each boundary and make segments - for(i=0; i<(nbounds-1); i++) { - float start = bounds[i]; - float end = bounds[i+1]; - float mid = (start+end)/2; + // Now go through each boundary and make segments + for(int i=0; i<(nbounds-1); i++) { + float start = bounds[i]; + float end = bounds[i+1]; + float mid = (start+end)/2; - bool hasFlap0=0, hasFlap1=0, hasSlat=0, hasSpoiler=0; - if(_flapParams[WING_FLAP0].start < mid && mid < _flapParams[WING_FLAP0].end) hasFlap0 = 1; - if(_flapParams[WING_FLAP1].start < mid && mid < _flapParams[WING_FLAP1].end) hasFlap1 = 1; - if(_flapParams[WING_SLAT].start < mid && mid < _flapParams[WING_SLAT].end) hasSlat = 1; - if(_flapParams[WING_SPOILER].start < mid && mid < _flapParams[WING_SPOILER].end) hasSpoiler = 1; + bool hasFlap0=0, hasFlap1=0, hasSlat=0, hasSpoiler=0; + if(ws->_flapParams[WING_FLAP0].start < mid && mid < ws->_flapParams[WING_FLAP0].end) + hasFlap0 = 1; + if(ws->_flapParams[WING_FLAP1].start < mid && mid < ws->_flapParams[WING_FLAP1].end) + hasFlap1 = 1; + if(ws->_flapParams[WING_SLAT].start < mid && mid < ws->_flapParams[WING_SLAT].end) + hasSlat = 1; + if(ws->_flapParams[WING_SPOILER].start < mid && mid < ws->_flapParams[WING_SPOILER].end) + hasSpoiler = 1; - // FIXME: Should probably detect an error here if both flap0 - // and flap1 are set. Right now flap1 overrides. + // FIXME: Should probably detect an error here if both flap0 + // and flap1 are set. Right now flap1 overrides. - int nSegs = (int)Math::ceil((end-start)/segLen); - if (_twist != 0 && nSegs < 8) // more segments if twisted - nSegs = 8; - float segWid = _length * (end - start)/nSegs; + int nSegs = (int)Math::ceil((end-start)/segLen); + if (ws->_twist != 0 && nSegs < 8) // more segments if twisted + nSegs = 8; + float segWid = ws->_length * (end - start)/nSegs; - int j; - for(j=0; j_rootChord.length * (1 - (1-ws->_taper)*frac); + float weight = chord * segWid; + float twist = ws->_twist * frac; - Surface *s = newSurface(pos, _orient, chord, - hasFlap0, hasFlap1, hasSlat, hasSpoiler); + ws->newSurface(_version, pos, ws->_orient, chord, hasFlap0, hasFlap1, hasSlat, hasSpoiler, weight, twist); - addSurface(s, weight, twist); - - if(_mirror) { - pos[1] = -pos[1]; - s = newSurface(pos, _rightOrient, chord, - hasFlap0, hasFlap1, hasSlat, hasSpoiler); - addSurface(s, weight, twist); + if(_mirror) { + pos[1] = -pos[1]; + ws->newSurface(_version, pos, ws->_rightOrient, chord, + hasFlap0, hasFlap1, hasSlat, hasSpoiler, weight, twist); + } } } + // Last of all, re-set the incidence in case setIncidence() was + // called before we were compiled. + setIncidence(_incidence); } - // Last of all, re-set the incidence in case setIncidence() was - // called before we were compiled. - setIncidence(_incidence); writeInfoToProptree(); } void Wing::multiplyLiftRatio(float factor) { - setLiftRatio(_liftRatio * factor); + WingSection* ws; + for (int section=0; section < _sections.size(); section++) + { + ws = (WingSection*)_sections.get(section); + ws->multiplyLiftRatio(factor); + } } -void Wing::addSurface(Surface* s, float weight, float twist) +void Wing::multiplyDragCoefficient(float factor) { - SurfRec *sr = new SurfRec(); - sr->surface = s; - sr->weight = weight; - s->setDragCoefficient(sr->weight); - s->setTwist(twist); - _surfs.add(sr); + WingSection* ws; + for (int section=0; section < _sections.size(); section++) + { + ws = (WingSection*)_sections.get(section); + ws->multiplyDragCoefficient(factor); + } } -void Wing::setDragCoefficient(float scale) +void Wing::setIncidence(float incidence) +{ + WingSection* ws; + for (int section=0; section < _sections.size(); section++) + { + ws = (WingSection*)_sections.get(section); + ws->setIncidence(incidence); + } +} + +void Wing::WingSection::setDragCoefficient(float scale) { _dragScale = scale; for(int i=0; i<_surfs.size(); i++) { @@ -280,20 +383,24 @@ void Wing::setDragCoefficient(float scale) } } -void Wing::multiplyDragCoefficient(float factor) +void Wing::WingSection::multiplyDragCoefficient(float factor) { setDragCoefficient(_dragScale * factor); } -void Wing::setLiftRatio(float ratio) +void Wing::WingSection::setLiftRatio(float ratio) { _liftRatio = ratio; for(int i=0; i<_surfs.size(); i++) ((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio); } -Surface* Wing::newSurface(float* pos, float* orient, float chord, - bool hasFlap0, bool hasFlap1, bool hasSlat, bool hasSpoiler) +void Wing::WingSection::multiplyLiftRatio(float factor) +{ + setLiftRatio(_liftRatio * factor); +} + +void Wing::WingSection::newSurface(Version* _version, float* pos, float* orient, float chord, bool hasFlap0, bool hasFlap1, bool hasSlat, bool hasSpoiler, float weight, float twist) { Surface* s = new Surface(_version); @@ -347,7 +454,12 @@ Surface* Wing::newSurface(float* pos, float* orient, float chord, s->setInducedDrag(_inducedDrag); - return s; + SurfRec *sr = new SurfRec(); + sr->surface = s; + sr->weight = weight; + s->setDragCoefficient(sr->weight); + s->setTwist(twist); + _surfs.add(sr); } void Wing::interp(const float* v1, const float* v2, const float frac, float* out) @@ -361,30 +473,40 @@ void Wing::writeInfoToProptree() { if (_wingN == nullptr) return; + WingSection* ws = (WingSection*)_sections.get(0); + float chord = ws->_rootChord.length; + ws = (WingSection*)_sections.get(_sections.size()-1); + float taper = ws->_rootChord.length * ws->_taper; _wingN->getNode("tip-x", true)->setFloatValue(_tip[0]); _wingN->getNode("tip-y", true)->setFloatValue(_tip[1]); _wingN->getNode("tip-z", true)->setFloatValue(_tip[2]); _wingN->getNode("base-x", true)->setFloatValue(_base[0]); _wingN->getNode("base-y", true)->setFloatValue(_base[1]); _wingN->getNode("base-z", true)->setFloatValue(_base[2]); + _wingN->getNode("chord", true)->setFloatValue(chord); + _wingN->getNode("taper", true)->setFloatValue(taper); _wingN->getNode("wing-span", true)->setFloatValue(_wingspan); _wingN->getNode("wing-area", true)->setFloatValue(_wingspan*_meanChord); _wingN->getNode("aspect-ratio", true)->setFloatValue(_aspectRatio); _wingN->getNode("standard-mean-chord", true)->setFloatValue(_meanChord); _wingN->getNode("mac", true)->setFloatValue(_mac.length); _wingN->getNode("mac-x", true)->setFloatValue(_mac.x); - _wingN->getNode("mac-y", true)->setFloatValue(_base[1]+_mac.y); + _wingN->getNode("mac-y", true)->setFloatValue(_mac.y); float wgt = 0; float dragSum = 0; - for(int surf=0; surf < numSurfaces(); surf++) { - Surface* s = (Surface*)getSurface(surf); - float drag = s->getDragCoefficient(); - dragSum += drag; - float mass = getSurfaceWeight(surf); - mass = mass * Math::sqrt(mass); - wgt += mass; + for (int section=0; section < _sections.size(); section++) { + ws = (WingSection*)_sections.get(section); + for (int surf=0; surf < ws->numSurfaces(); surf++) { + Surface* s = ws->getSurface(surf); + float drag = s->getDragCoefficient(); + dragSum += drag; + + float mass = ws->getSurfaceWeight(surf); + mass = mass * Math::sqrt(mass); + wgt += mass; + } } _wingN->getNode("weight", true)->setFloatValue(wgt); _wingN->getNode("drag", true)->setFloatValue(dragSum); @@ -393,21 +515,25 @@ void Wing::writeInfoToProptree() float Wing::updateModel(Model* model) { float wgt = 0; - for(int surf=0; surf < numSurfaces(); surf++) { - Surface* s = (Surface*)getSurface(surf); - model->addSurface(s); + WingSection* ws; + for (int section=0; section < _sections.size(); section++) { + ws = (WingSection*)_sections.get(section); + for(int surf=0; surf < ws->numSurfaces(); surf++) { + Surface* s = ws->getSurface(surf); + model->addSurface(s); - float mass = getSurfaceWeight(surf); - mass = mass * Math::sqrt(mass); - wgt += mass; + float mass = ws->getSurfaceWeight(surf); + mass = mass * Math::sqrt(mass); + wgt += mass; - float pos[3]; - s->getPosition(pos); - int mid = model->getBody()->addMass(mass, pos, true); - if (_wingN != nullptr) { - SGPropertyNode_ptr n = _wingN->getNode("surfaces", true)->getChild("surface", s->getID(), true); - n->getNode("drag", true)->setFloatValue(s->getDragCoefficient()); - n->getNode("mass-id", true)->setIntValue(mid); + float pos[3]; + s->getPosition(pos); + int mid = model->getBody()->addMass(mass, pos, true); + if (_wingN != nullptr) { + SGPropertyNode_ptr n = _wingN->getNode("surfaces", true)->getChild("surface", s->getID(), true); + n->getNode("drag", true)->setFloatValue(s->getDragCoefficient()); + n->getNode("mass-id", true)->setIntValue(mid); + } } } return wgt; diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index b4142612a..cb8bd5644 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -29,6 +29,7 @@ struct StallParams { struct Chord { float x {0}; float y {0}; + float z {0}; float length {0}; }; @@ -39,133 +40,132 @@ enum WingFlaps { WING_SLAT, }; -// FIXME: need to handle "inverted" controls for mirrored wings. class Wing { SGPropertyNode_ptr _wingN {nullptr}; + + struct SurfRec { + Surface* surface; + float weight; + }; + + struct WingSection { + Chord _rootChord; + // length is distance from base to tip, not wing span + float _length {0}; + float _taper {1}; + // sweep of center line, not leading edge! + float _sweepAngleCenterLine {0}; + float _dihedral {0}; + float _twist {0}; + float _camber {0}; + float _inducedDrag {1}; + + StallParams _stallParams; + + //fixed incidence of section as given in config XML + float _sectionIncidence {0}; + float _dragScale {1}; + float _liftRatio {1}; + + FlapParams _flapParams[sizeof(WingFlaps)]; + + // calculated from above + float _orient[9]; + float _rightOrient[9]; + Chord _tipChord; + float _meanChord {0}; // std. mean chord + Chord _mac; // mean aerodynamic chord (x,y) leading edge + float _wingspan {0}; + float _aspectRatio {1}; + // all SurfRec of this wing + Vector _surfs; + // surfaces having a certain type of flap (flap, slat, spoiler) + Vector _flapSurfs[sizeof(WingFlaps)]; + + void calculateGeometry(); + void calculateWingCoordinateSystem(); + void calculateTipChord(); + void calculateSpan(); + void calculateMAC(); + float calculateSweepAngleLeadingEdge(); + //set incidence value to all surfaces of this section + void setIncidence(float incidence); + // parameters for stall curve + void setStallParams(StallParams sp) { _stallParams = sp; } + + // valid only after Wing::compile() was called + Chord getMAC() const { return _mac; }; + float getArea() const { return _wingspan*_meanChord; }; + void setDragCoefficient(float scale); + void multiplyDragCoefficient(float factor); + // The ratio of force along the Z (lift) direction of each wing + // segment to that along the X (drag) direction. + void setLiftRatio(float ratio); + void multiplyLiftRatio(float factor); + + void newSurface(Version* _version, float* pos, float* orient, float chord, + bool hasFlap0, bool hasFlap1, bool hasSlat, bool hasSpoiler, + float weight, float twist); + int numSurfaces() const { return _surfs.size(); } + Surface* getSurface(int n) { return ((SurfRec*)_surfs.get(n))->surface; } + float getSurfaceWeight(int n) const { return ((SurfRec*)_surfs.get(n))->weight; } + }; //struct WingSection + + //-- wing member variables -- + Version* _version; + bool _mirror {false}; + Vector _sections; + Chord _mac; + float _base[3] {0,0,0}; + float _tip[3] {0,0,0}; + float _wingspan {0}; + float _area {0}; + float _aspectRatio {0}; + float _meanChord {0}; + float _incidence {0}; + + Chord _float2chord(float* pos, float lenght = 0); + void _chord2float(Chord c, float* pos); + void interp(const float* v1, const float* v2, const float frac, float* out); + void writeInfoToProptree(); + public: - Wing(Version *ver, bool mirror, float* base, float chord, float length, - float taper = 1, float sweep = 0, float dihedral = 0, float twist = 0); + Wing(Version* ver, bool mirror); ~Wing(); - // Do we mirror ourselves about the XZ plane? - void setMirror(bool mirror) { _mirror = mirror; } - const bool isMirrored() { return _mirror; }; - - // Wing geometry in local coordinates: - - // base point of wing - void getBase(float* base) const { Math::set3(_base, base); }; - // dist. ALONG wing (not span!) - float getLength() const { return _length; }; - // at base, measured along X axis - float getChord() const { return _rootChordLength; }; - // fraction of chord at wing tip, 0..1 - float getTaper() const { return _taper; }; - // radians - float getSweep() const { return _sweepAngleCenterLine; }; - // radians, positive is "up" - void setDihedral(float dihedral) { _dihedral = dihedral; } - float getDihedral() const { return _dihedral; }; - - void setIncidence(float incidence); - - - // parameters for stall curve - void setStallParams(StallParams sp) { _stallParams = sp; } - void setCamber(float camber) { _camber = camber; } - void setInducedDrag(float drag) { _inducedDrag = drag; } - - - void setFlapParams(WingFlaps i, FlapParams fp); + int addWingSection(float* base, float chord, float wingLength, + float taper = 1, float sweep = 0, float dihedral = 0, float twist = 0, float camber = 0, float idrag = 1, float incidence = 0); - // propergate the control axes value for the sub-surfaces - void setFlapPos(WingFlaps i, float lval, float rval = 0); - void setFlapEffectiveness(WingFlaps f, float lval); + static Chord calculateMAC(Chord root, Chord tip); + void setFlapParams(int section, WingFlaps type, FlapParams fp); + void setSectionDrag(int section, float pdrag); + void setSectionStallParams(int section, StallParams sp); + // Compile the thing into a bunch of Surface objects void compile(); - void getTip(float* tip) const { Math::set3(_tip, tip);}; - - // valid only after Wing::compile() was called + void multiplyLiftRatio(float factor); + void multiplyDragCoefficient(float factor); + void setIncidence(float incidence); + + bool isMirrored() const { return _mirror; }; + void getBase(float* base) const { Math::set3(_base, base); }; + void getTip(float* tip) const { Math::set3(_tip, tip); }; float getSpan() const { return _wingspan; }; - float getArea() const { return _wingspan*_meanChord; }; + float getArea() const { return _area; }; float getAspectRatio() const { return _aspectRatio; }; float getSMC() const { return _meanChord; }; - Chord getMAC() const { return _mac; }; float getMACLength() const { return _mac.length; }; // get length of MAC - float getMACx() const { return _mac.x; }; // get x-coord of MAC - float getMACy() const { return _base[1]+_mac.y; }; // get y-coord of MAC - - - int numSurfaces() const { return _surfs.size(); } - Surface* getSurface(int n) { return ((SurfRec*)_surfs.get(n))->surface; } - float getSurfaceWeight(int n) const { return ((SurfRec*)_surfs.get(n))->weight; } - - // The overall drag coefficient for the wing as a whole. Units are - // arbitrary. - void setDragCoefficient(float scale); - void multiplyDragCoefficient(float factor); - - // The ratio of force along the Z (lift) direction of each wing - // segment to that along the X (drag) direction. - void setLiftRatio(float ratio); - void multiplyLiftRatio(float factor); + float getMACx() const { return _mac.x; }; // get x-coord of MAC leading edge + float getMACy() const { return _mac.y; }; // get y-coord of MAC leading edge + +//----------------------------- + // propergate the control axes value for the sub-surfaces + void setFlapPos(WingFlaps type, float lval, float rval = 0); + void setFlapEffectiveness(WingFlaps f, float lval); void setPropertyNode(SGPropertyNode_ptr n) { _wingN = n; }; float updateModel(Model* model); - -private: - void interp(const float* v1, const float* v2, const float frac, float* out); - Surface* newSurface(float* pos, float* orient, float chord, - bool hasFlap0, bool hasFlap1, bool hasSlat, bool hasSpoiler); - void calculateWingCoordinateSystem(); - void calculateTip(); - void calculateSpan(); - void calculateMAC(); - static Chord calculateMAC(Chord root, Chord tip); - float calculateSweepAngleLeadingEdge(); - - void addSurface(Surface* s, float weight, float twist); - void writeInfoToProptree(); - - struct SurfRec { Surface * surface; float weight; }; - // all surfaces of this wing - Vector _surfs; - // surfaces having a certain type of flap (flap, slat, spoiler) - Vector _flapSurfs[sizeof(WingFlaps)]; - - Version * _version; - bool _mirror {false}; - float _base[3] {0,0,0}; - float _rootChordLength {0}; - // length is distance from base to tip, not wing span - float _length {0}; - float _taper {1}; - // sweep of center line, not leading edge! - float _sweepAngleCenterLine {0}; - float _dihedral {0}; - - // calculated from above - float _orient[9]; - float _rightOrient[9]; - float _tip[3] {0,0,0}; - float _meanChord {0}; // std. mean chord - Chord _mac; // mean aerodynamic chord (x,y) leading edge - float _netSpan {0}; - float _wingspan {0}; - float _aspectRatio {1}; - - StallParams _stallParams; - - float _twist {0}; - float _camber {0}; - float _incidence {0}; - float _inducedDrag {1}; - - float _dragScale {1}; - float _liftRatio {1}; - - FlapParams _flapParams[sizeof(WingFlaps)]; }; diff --git a/src/FDM/YASim/proptest.cpp b/src/FDM/YASim/proptest.cpp index c32c849e3..aaeb87d6f 100644 --- a/src/FDM/YASim/proptest.cpp +++ b/src/FDM/YASim/proptest.cpp @@ -5,6 +5,7 @@ #include #include +#include "yasim-common.hpp" #include "Math.hpp" #include "FGFDM.hpp" #include "PropEngine.hpp" diff --git a/src/FDM/YASim/yasim-common.cpp b/src/FDM/YASim/yasim-common.cpp index 23bbf7f6a..79273bdf8 100644 --- a/src/FDM/YASim/yasim-common.cpp +++ b/src/FDM/YASim/yasim-common.cpp @@ -1,23 +1,5 @@ #include "yasim-common.hpp" namespace yasim { - /// duplicate null-terminated string - char* dup(const char* s) - { - int len=0; - while(s[len++]); - char* s2 = new char[len+1]; - char* p = s2; - while((*p++ = *s++)); - s2[len] = 0; - return s2; - } - /// compare null-terminated strings - bool eq(const char* a, const char* b) - { - while(*a && *b && *a == *b) { a++; b++; } - // equal if both a and b points to null chars - return !(*a || *b); - } }; //namespace yasim diff --git a/src/FDM/YASim/yasim-common.hpp b/src/FDM/YASim/yasim-common.hpp index 32097af7e..aceb3e834 100644 --- a/src/FDM/YASim/yasim-common.hpp +++ b/src/FDM/YASim/yasim-common.hpp @@ -31,10 +31,6 @@ namespace yasim { static const float NM2FTLB = (1/(LBS2N*FT2M)); static const float SLUG2KG = 14.59390f; - - char* dup(const char* s); - bool eq(const char* a, const char* b); - }; //namespace yasim #endif // ifndef _YASIM_COMMON_HPP diff --git a/src/FDM/YASim/yasim-test.cpp b/src/FDM/YASim/yasim-test.cpp index 685164756..fb08639d7 100644 --- a/src/FDM/YASim/yasim-test.cpp +++ b/src/FDM/YASim/yasim-test.cpp @@ -246,11 +246,12 @@ int main(int argc, char** argv) float SI_inertia[9]; a->getModel()->getBody()->getInertiaMatrix(SI_inertia); float MAC = 0, MACx = 0, MACy = 0; - Wing* wing = a->getWing(); - if (wing) { - MAC = a->getWing()->getMACLength(); - MACx = a->getWing()->getMACx(); - MACy = a->getWing()->getMACy(); + Wing* wing {nullptr}; + if (a->hasWing()) { + wing = a->getWing(); + MAC = wing->getMACLength(); + MACx = wing->getMACx(); + MACy = wing->getMACy(); } printf(" Iterations: %d\n", a->getSolutionIterations()); printf(" Drag Coefficient: %.3f\n", drag); From f7c5d2b1f948384484c8484e07949a6242408bdf Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Wed, 6 Dec 2017 20:26:41 +0100 Subject: [PATCH 26/29] YASIM refactoring class Surface and export more properties to proptree --- src/FDM/YASim/Airplane.cpp | 125 +++++++++++++++++-------------------- src/FDM/YASim/Surface.cpp | 63 +++++++++++++------ src/FDM/YASim/Surface.hpp | 9 +-- src/FDM/YASim/Wing.cpp | 4 +- 4 files changed, 109 insertions(+), 92 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index 8a3fb9afd..56dfad66e 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -254,9 +254,7 @@ int Airplane::addWeight(float* pos, float size) WeightRec* wr = new WeightRec(); wr->handle = _model.getBody()->addMass(0, pos); - wr->surf = new Surface(this); - wr->surf->setPosition(pos); - wr->surf->setDragCoefficient(size*size); + wr->surf = new Surface(this, pos, size*size); _model.addSurface(wr->surf); _surfs.add(wr->surf); @@ -273,13 +271,13 @@ void Airplane::setWeight(int handle, float mass) // Kill the aerodynamic drag if the mass is exactly zero. This is // how we simulate droppable stores. if(mass == 0) { - wr->surf->setXDrag(0); - wr->surf->setYDrag(0); - wr->surf->setZDrag(0); + wr->surf->setXDrag(0); + wr->surf->setYDrag(0); + wr->surf->setZDrag(0); } else { - wr->surf->setXDrag(1); - wr->surf->setYDrag(1); - wr->surf->setZDrag(1); + wr->surf->setXDrag(1); + wr->surf->setYDrag(1); + wr->surf->setZDrag(1); } } @@ -347,7 +345,7 @@ float Airplane::compileFuselage(Fuselage* f) float len = Math::mag3(fwd); if (len == 0) { _failureMsg = "Zero length fuselage"; - return 0; + return 0; } float wid = f->width; int segs = (int)Math::ceil(len/wid); @@ -355,19 +353,18 @@ float Airplane::compileFuselage(Fuselage* f) int j; for(j=0; jmid) scale = f->taper+(1-f->taper) * (frac / f->mid); else { - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { - // Correct calculation of width for fuselage taper. - scale = 1 - (1-f->taper) * (frac - f->mid) / (1 - f->mid); - } else { - // Original, incorrect calculation of width for fuselage taper. - scale = f->taper+(1-f->taper) * (frac - f->mid) / (1 - f->mid); - } - } + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + // Correct calculation of width for fuselage taper. + scale = 1 - (1-f->taper) * (frac - f->mid) / (1 - f->mid); + } else { + // Original, incorrect calculation of width for fuselage taper. + scale = f->taper+(1-f->taper) * (frac - f->mid) / (1 - f->mid); + } + } // Where are we? float pos[3]; @@ -379,44 +376,42 @@ float Airplane::compileFuselage(Fuselage* f) _model.getBody()->addMass(mass, pos, true); wgt += mass; + + // The following is the original YASim value for sideDrag. + // Originally YASim calculated the fuselage's lateral drag + // coefficient as (solver drag factor) * (len/wid). + // However, this greatly underestimates a fuselage's lateral drag. + float sideDrag = len/wid; + + if ( isVersionOrNewer( YASIM_VERSION_32 ) ) { + // New YASim assumes a fixed lateral drag coefficient of 0.5. + // This will not be multiplied by the solver drag factor, because + // that factor is tuned to match the drag in the direction of + // flight, which is completely independent of lateral drag. + // The value of 0.5 is only a ballpark estimate, roughly matching + // the side-on drag for a long cylinder at the higher Reynolds + // numbers typical for an aircraft's lateral drag. + // This fits if the fuselage is long and has a round cross section. + // For flat-sided fuselages, the value should be increased, up to + // a limit of around 2 for a long rectangular prism. + // For very short fuselages, in which the end effects are strong, + // the value should be reduced. + // Such adjustments can be made using the fuselage's "cy" and "cz" + // XML parameters: "cy" for the sides, "cz" for top and bottom. + sideDrag = 0.5; + } + float dragCoefficient = scale*segWgt*f->_cx; + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + dragCoefficient = scale*segWgt; + } + // Make a Surface too - Surface* s = new Surface(this); - s->setPosition(pos); - - // The following is the original YASim value for sideDrag. - // Originally YASim calculated the fuselage's lateral drag - // coefficient as (solver drag factor) * (len/wid). - // However, this greatly underestimates a fuselage's lateral drag. - float sideDrag = len/wid; - - if ( isVersionOrNewer( YASIM_VERSION_32 ) ) { - // New YASim assumes a fixed lateral drag coefficient of 0.5. - // This will not be multiplied by the solver drag factor, because - // that factor is tuned to match the drag in the direction of - // flight, which is completely independent of lateral drag. - // The value of 0.5 is only a ballpark estimate, roughly matching - // the side-on drag for a long cylinder at the higher Reynolds - // numbers typical for an aircraft's lateral drag. - // This fits if the fuselage is long and has a round cross section. - // For flat-sided fuselages, the value should be increased, up to - // a limit of around 2 for a long rectangular prism. - // For very short fuselages, in which the end effects are strong, - // the value should be reduced. - // Such adjustments can be made using the fuselage's "cy" and "cz" - // XML parameters: "cy" for the sides, "cz" for top and bottom. - sideDrag = 0.5; - } - - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { - s->setXDrag(f->_cx); - } + Surface* s = new Surface(this, pos, dragCoefficient); + if( isVersionOrNewer( YASIM_VERSION_32 ) ) { + s->setXDrag(f->_cx); + } s->setYDrag(sideDrag*f->_cy); s->setZDrag(sideDrag*f->_cz); - if( isVersionOrNewer( YASIM_VERSION_32 ) ) { - s->setDragCoefficient(scale*segWgt); - } else { - s->setDragCoefficient(scale*segWgt*f->_cx); - } s->setInducedDrag(f->_idrag); // FIXME: fails for fuselages aligned along the Y axis @@ -425,8 +420,8 @@ float Airplane::compileFuselage(Fuselage* f) Math::unit3(fwd, x); y[0] = 0; y[1] = 1; y[2] = 0; Math::cross3(x, y, z); - Math::unit3(z, z); - Math::cross3(z, x, y); + Math::unit3(z, z); + Math::cross3(z, x, y); s->setOrientation(o); _model.addSurface(s); @@ -441,9 +436,6 @@ void Airplane::compileGear(GearRec* gr) { Gear* g = gr->gear; - // Make a Surface object for the aerodynamic behavior - Surface* s = new Surface(this); - gr->surf = s; // Put the surface at the half-way point on the gear strut, give // it a drag coefficient equal to a square of the same dimension @@ -456,8 +448,9 @@ void Airplane::compileGear(GearRec* gr) Math::mul3(0.5, cmp, cmp); Math::add3(pos, cmp, pos); - s->setPosition(pos); - s->setDragCoefficient(length*length); + // Make a Surface object for the aerodynamic behavior + Surface* s = new Surface(this, pos, length*length); + gr->surf = s; _model.addGear(g); _model.addSurface(s); @@ -812,17 +805,17 @@ void Airplane::applyDragFactor(float factor) } else { // Originally YASim applied the drag factor to all axes // for Fuselage Surfaces. - s->setDragCoefficient(s->getDragCoefficient() * applied); + s->mulDragCoefficient(applied); } } } for(i=0; i<_weights.size(); i++) { - WeightRec* wr = (WeightRec*)_weights.get(i); - wr->surf->setDragCoefficient(wr->surf->getDragCoefficient() * applied); + WeightRec* wr = (WeightRec*)_weights.get(i); + wr->surf->mulDragCoefficient(applied); } for(i=0; i<_gears.size(); i++) { - GearRec* gr = (GearRec*)_gears.get(i); - gr->surf->setDragCoefficient(gr->surf->getDragCoefficient() * applied); + GearRec* gr = (GearRec*)_gears.get(i); + gr->surf->mulDragCoefficient(applied); } } diff --git a/src/FDM/YASim/Surface.cpp b/src/FDM/YASim/Surface.cpp index ffb5723bf..e9284dc4d 100644 --- a/src/FDM/YASim/Surface.cpp +++ b/src/FDM/YASim/Surface.cpp @@ -1,11 +1,13 @@ #include
+#include "Math.hpp" #include "Surface.hpp" namespace yasim { int Surface::s_idGenerator = 0; -Surface::Surface( Version * version ) : - _version(version) +Surface::Surface(Version* version, float* pos, float dragCoefficient = 1 ) : + _version(version), + _c0(dragCoefficient) { _id = s_idGenerator++; @@ -13,36 +15,59 @@ Surface::Surface( Version * version ) : _orient[3] = 0; _orient[4] = 1; _orient[5] = 0; _orient[6] = 0; _orient[7] = 0; _orient[8] = 1; + Math::set3(pos, _pos); + _surfN = fgGetNode("/fdm/yasim/debug/surfaces", true); if (_surfN != 0) { - _surfN = _surfN->getChild("surface", _id, true); - _fxN = _surfN->getNode("f-x", true); - _fyN = _surfN->getNode("f-y", true); - _fzN = _surfN->getNode("f-z", true); - _fabsN = _surfN->getNode("f-abs", true); - _alphaN = _surfN->getNode("alpha", true); - _stallAlphaN = _surfN->getNode("stall-alpha", true); - _flapN = _surfN->getNode("flap-pos", true); - _slatN = _surfN->getNode("slat-pos", true); - _spoilerN = _surfN->getNode("spoiler-pos", true); + _surfN = _surfN->getChild("surface", _id, true); + _fxN = _surfN->getNode("f-x", true); + _fyN = _surfN->getNode("f-y", true); + _fzN = _surfN->getNode("f-z", true); + _fabsN = _surfN->getNode("f-abs", true); + _alphaN = _surfN->getNode("alpha", true); + _stallAlphaN = _surfN->getNode("stall-alpha", true); + _flapN = _surfN->getNode("flap-pos", true); + _slatN = _surfN->getNode("slat-pos", true); + _spoilerN = _surfN->getNode("spoiler-pos", true); + _surfN->getNode("pos-x", true)->setFloatValue(pos[0]); + _surfN->getNode("pos-y", true)->setFloatValue(pos[1]); + _surfN->getNode("pos-z", true)->setFloatValue(pos[2]); + _surfN->getNode("chord",true)->setFloatValue(0); + _surfN->getNode("axis-x", true)->setFloatValue(0); + _surfN->getNode("axis-y", true)->setFloatValue(0); + _surfN->getNode("axis-z", true)->setFloatValue(0); } } -void Surface::setPosition(const float* p) +void Surface::setPosition(const float* pos) { - int i; - for(i=0; i<3; i++) _pos[i] = p[i]; + Math::set3(pos, _pos); if (_surfN != 0) { - _surfN->getNode("pos-x", true)->setFloatValue(p[0]); - _surfN->getNode("pos-y", true)->setFloatValue(p[1]); - _surfN->getNode("pos-z", true)->setFloatValue(p[2]); + _surfN->getNode("pos-x", true)->setFloatValue(pos[0]); + _surfN->getNode("pos-y", true)->setFloatValue(pos[1]); + _surfN->getNode("pos-z", true)->setFloatValue(pos[2]); + } +} + +void Surface::setChord(float chord) +{ + _chord = chord; + if (_surfN != 0) { + _surfN->getNode("chord",true)->setFloatValue(_chord); } } void Surface::setOrientation(const float* o) { - for(int i=0; i<9; i++) _orient[i] = o[i]; + for(int i=0; i<9; i++) _orient[i] = o[i]; + if (_surfN) { + float xaxis[3] {-1,0,0}; + Math::tmul33(_orient,xaxis, xaxis); + _surfN->getNode("axis-x", true)->setFloatValue(xaxis[0]); + _surfN->getNode("axis-y", true)->setFloatValue(xaxis[1]); + _surfN->getNode("axis-z", true)->setFloatValue(xaxis[2]); + } } diff --git a/src/FDM/YASim/Surface.hpp b/src/FDM/YASim/Surface.hpp index 4d5538ce1..fc16bc501 100644 --- a/src/FDM/YASim/Surface.hpp +++ b/src/FDM/YASim/Surface.hpp @@ -16,7 +16,7 @@ class Surface int _id; //index for property tree public: - Surface( Version * version ); + Surface(Version * version, float* pos, float dragCoefficient); int getID() const { return _id; }; static void resetIDgen() { s_idGenerator = 0; }; @@ -25,8 +25,8 @@ public: void setPosition(const float* p); void getPosition(float* out) const { Math::set3(_pos, out); } - // Distance scale along the X axis - void setChord(float chord) { _chord = chord; } + // Distance scale along the X axis used for torque (pitch) calculation + void setChord(float chord); // Slats act to move the stall peak by the specified angle, and // increase drag by the multiplier specified. @@ -60,6 +60,7 @@ public: void setTwist(float angle) { _twist = angle; } void setDragCoefficient(float c0) { _c0 = c0; } + void mulDragCoefficient(float factor) { _c0 *= factor; } float getDragCoefficient() const { return _c0; } void setXDrag(float cx) { _cx = cx; } @@ -87,6 +88,7 @@ public: private: SGPropertyNode_ptr _surfN; + Version * _version; float stallFunc(float* v); float flapLift(float alpha); @@ -123,7 +125,6 @@ private: float _stallAlpha {0}; float _alpha {0}; - Version * _version; SGPropertyNode* _fxN; SGPropertyNode* _fyN; SGPropertyNode* _fzN; diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index 02757fa2f..3c9c8ffc4 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -402,9 +402,8 @@ void Wing::WingSection::multiplyLiftRatio(float factor) void Wing::WingSection::newSurface(Version* _version, float* pos, float* orient, float chord, bool hasFlap0, bool hasFlap1, bool hasSlat, bool hasSpoiler, float weight, float twist) { - Surface* s = new Surface(_version); + Surface* s = new Surface(_version, pos, weight); - s->setPosition(pos); s->setOrientation(orient); s->setChord(chord); @@ -457,7 +456,6 @@ void Wing::WingSection::newSurface(Version* _version, float* pos, float* orient, SurfRec *sr = new SurfRec(); sr->surface = s; sr->weight = weight; - s->setDragCoefficient(sr->weight); s->setTwist(twist); _surfs.add(sr); } From 7c55aa2c4a669fd968f8e2744eb464a3539a51c6 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Tue, 12 Dec 2017 08:04:22 +0100 Subject: [PATCH 27/29] YASim variable and method name clarification in class Surface --- src/FDM/YASim/Airplane.cpp | 82 ++++++++++++++++++++------------------ src/FDM/YASim/Surface.cpp | 20 +++++----- src/FDM/YASim/Surface.hpp | 17 ++++---- src/FDM/YASim/Wing.cpp | 29 +++++++++----- src/FDM/YASim/Wing.hpp | 4 +- 5 files changed, 84 insertions(+), 68 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index 56dfad66e..9510f65e8 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -133,9 +133,9 @@ void Airplane::updateGearState() GearRec* gr = (GearRec*)_gears.get(i); float ext = gr->gear->getExtension(); - gr->surf->setXDrag(ext); + gr->surf->setDragCoefficient(ext); gr->surf->setYDrag(ext); - gr->surf->setZDrag(ext); + gr->surf->setLiftCoefficient(ext); } } @@ -271,13 +271,13 @@ void Airplane::setWeight(int handle, float mass) // Kill the aerodynamic drag if the mass is exactly zero. This is // how we simulate droppable stores. if(mass == 0) { - wr->surf->setXDrag(0); + wr->surf->setDragCoefficient(0); wr->surf->setYDrag(0); - wr->surf->setZDrag(0); + wr->surf->setLiftCoefficient(0); } else { - wr->surf->setXDrag(1); + wr->surf->setDragCoefficient(1); wr->surf->setYDrag(1); - wr->surf->setZDrag(1); + wr->surf->setLiftCoefficient(1); } } @@ -408,10 +408,10 @@ float Airplane::compileFuselage(Fuselage* f) // Make a Surface too Surface* s = new Surface(this, pos, dragCoefficient); if( isVersionOrNewer( YASIM_VERSION_32 ) ) { - s->setXDrag(f->_cx); + s->setDragCoefficient(f->_cx); } s->setYDrag(sideDrag*f->_cy); - s->setZDrag(sideDrag*f->_cz); + s->setLiftCoefficient(sideDrag*f->_cz); s->setInducedDrag(f->_idrag); // FIXME: fails for fuselages aligned along the Y axis @@ -512,38 +512,38 @@ void Airplane::compile() // The Wing objects if (_wing) { - if (baseN != 0) { - _wingsN = baseN->getChild("wing", 0, true); - _wing->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(_wing); - - // convert % to absolute x coordinates - _cgDesiredFront = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMin; - _cgDesiredAft = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMax; - if (baseN != 0) { - SGPropertyNode_ptr n = fgGetNode("/fdm/yasim/model", true); - n->getNode("cg-x-range-front", true)->setFloatValue(_cgDesiredFront); - n->getNode("cg-x-range-aft", true)->setFloatValue(_cgDesiredAft); - } + if (baseN != 0) { + _wingsN = baseN->getChild("wing", 0, true); + _wing->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(_wing); + + // convert % to absolute x coordinates + _cgDesiredFront = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMin; + _cgDesiredAft = _wing->getMACx() - _wing->getMACLength()*_cgDesiredMax; + if (baseN != 0) { + SGPropertyNode_ptr n = fgGetNode("/fdm/yasim/model", true); + n->getNode("cg-x-range-front", true)->setFloatValue(_cgDesiredFront); + n->getNode("cg-x-range-aft", true)->setFloatValue(_cgDesiredAft); + } } if (_tail) { - if (baseN != 0) { - _wingsN = baseN->getChild("tail", 0, true); - _tail->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(_tail); + if (baseN != 0) { + _wingsN = baseN->getChild("tail", 0, true); + _tail->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(_tail); } int i; for(i=0; i<_vstabs.size(); i++) { - Wing* vs = (Wing*)_vstabs.get(i); - if (baseN != 0) { - _wingsN = baseN->getChild("stab", i, true); - vs->setPropertyNode(_wingsN); - } - aeroWgt += compileWing(vs); + Wing* vs = (Wing*)_vstabs.get(i); + if (baseN != 0) { + _wingsN = baseN->getChild("stab", i, true); + vs->setPropertyNode(_wingsN); + } + aeroWgt += compileWing(vs); } // The fuselage(s) @@ -557,9 +557,13 @@ void Airplane::compile() // Rescale to the specified empty weight float wscale = (_emptyWeight-nonAeroWgt)/aeroWgt; - for(i=firstMass; inumMasses(); i++) + for(i=firstMass; inumMasses(); i++) { body->setMass(i, body->getMass(i)*wscale); - + } + if (_wingsN != nullptr) { + float w = _wingsN->getNode("weight", true)->getFloatValue(); + _wingsN->getNode("mass", true)->setFloatValue(w * wscale); + } // Add the thruster masses for(i=0; i<_thrusters.size(); i++) { ThrustRec* t = (ThrustRec*)_thrusters.get(i); @@ -801,21 +805,21 @@ void Airplane::applyDragFactor(float factor) // it won't be affected by the streamlining done to reduce // longitudinal drag. So the solver should only adjust the // fuselage's longitudinal (X axis) drag coefficient. - s->setXDrag(s->getXDrag() * applied); + s->setDragCoefficient(s->getDragCoefficient() * applied); } else { // Originally YASim applied the drag factor to all axes // for Fuselage Surfaces. - s->mulDragCoefficient(applied); + s->mulTotalForceCoefficient(applied); } } } for(i=0; i<_weights.size(); i++) { WeightRec* wr = (WeightRec*)_weights.get(i); - wr->surf->mulDragCoefficient(applied); + wr->surf->mulTotalForceCoefficient(applied); } for(i=0; i<_gears.size(); i++) { GearRec* gr = (GearRec*)_gears.get(i); - gr->surf->mulDragCoefficient(applied); + gr->surf->mulTotalForceCoefficient(applied); } } diff --git a/src/FDM/YASim/Surface.cpp b/src/FDM/YASim/Surface.cpp index e9284dc4d..2865b72c6 100644 --- a/src/FDM/YASim/Surface.cpp +++ b/src/FDM/YASim/Surface.cpp @@ -1,4 +1,5 @@ #include
+#include "yasim-common.hpp" #include "Math.hpp" #include "Surface.hpp" @@ -119,23 +120,24 @@ void Surface::setSpoilerPos(float pos) // Calculate the aerodynamic force given a wind vector v (in the // aircraft's "local" coordinates) and an air density rho. Returns a -// torque about the Y axis, too. +// torque about the Y axis ("pitch"), too. void Surface::calcForce(const float* v, const float rho, float* out, float* torque) { + // initialize outputs to zero + Math::zero3(out); + Math::zero3(torque); + // Split v into magnitude and direction: float vel = Math::mag3(v); // Zero velocity means zero force by definition (also prevents div0). if(vel == 0) { - int i; - for(i=0; i<3; i++) out[i] = torque[i] = 0; - return; + return; } // special case this so the logic below doesn't produce a non-zero // force; should probably have a "no force" flag instead... if(_cx == 0. && _cy == 0. && _cz == 0.) { - for(int i=0; i<3; i++) out[i] = torque[i] = 0.; return; } @@ -145,10 +147,10 @@ void Surface::calcForce(const float* v, const float rho, float* out, float* torq // "Rotate" by the incidence angle. Assume small angles, so we // need to diddle only the Z component, X is relatively unchanged - // by small rotations. + // by small rotations. sin(a) ~ a, cos(a) ~ 1 for small a float incidence = _incidence + _twist; out[2] += incidence * out[0]; // z' = z + incidence * x - + // Hold onto the local wind vector so we can multiply the induced // drag at the end. float lwind[3]; @@ -190,9 +192,9 @@ void Surface::calcForce(const float* v, const float rho, float* out, float* torq // roughly parallel with Z, the small-angle approximation // must change its X component. if( _version->isVersionOrNewer( Version::YASIM_VERSION_32 )) { - out[0] += incidence * out[2]; + out[0] += incidence * out[2]; } else { - out[2] -= incidence * out[0]; + out[2] -= incidence * out[0]; } // Convert back to external coordinates diff --git a/src/FDM/YASim/Surface.hpp b/src/FDM/YASim/Surface.hpp index fc16bc501..bd5c35f04 100644 --- a/src/FDM/YASim/Surface.hpp +++ b/src/FDM/YASim/Surface.hpp @@ -59,17 +59,18 @@ public: // The offset from base incidence for this surface. void setTwist(float angle) { _twist = angle; } - void setDragCoefficient(float c0) { _c0 = c0; } - void mulDragCoefficient(float factor) { _c0 *= factor; } - float getDragCoefficient() const { return _c0; } + void setTotalForceCoefficient(float c0) { _c0 = c0; } + void mulTotalForceCoefficient(float factor) { _c0 *= factor; } + float getTotalForceCoefficient() const { return _c0; } - void setXDrag(float cx) { _cx = cx; } - void setYDrag(float cy) { _cy = cy; } - void setZDrag(float cz) { _cz = cz; } - float getXDrag() const { return _cx; } + void setDragCoefficient(float cx) { _cx = cx; } + float getDragCoefficient() const { return _cx; } + void setYDrag(float cy) { _cy = cy; } + void setLiftCoefficient(float cz) { _cz = cz; } + float getLiftCoefficient() const { return _cz; } // zero-alpha Z drag ("camber") specified as a fraction of cz - void setBaseZDrag(float cz0) { _cz0 = cz0; } + void setZeroAlphaLift(float cz0) { _cz0 = cz0; } // i: 0 == forward, 1 == backwards void setStallPeak(int i, float peak) { _peaks[i] = peak; } diff --git a/src/FDM/YASim/Wing.cpp b/src/FDM/YASim/Wing.cpp index 3c9c8ffc4..6b8ad1a90 100644 --- a/src/FDM/YASim/Wing.cpp +++ b/src/FDM/YASim/Wing.cpp @@ -379,7 +379,7 @@ void Wing::WingSection::setDragCoefficient(float scale) _dragScale = scale; for(int i=0; i<_surfs.size(); i++) { SurfRec* s = (SurfRec*)_surfs.get(i); - s->surface->setDragCoefficient(scale * s->weight); + s->surface->setTotalForceCoefficient(scale * s->weight); } } @@ -392,7 +392,7 @@ void Wing::WingSection::setLiftRatio(float ratio) { _liftRatio = ratio; for(int i=0; i<_surfs.size(); i++) - ((SurfRec*)_surfs.get(i))->surface->setZDrag(ratio); + ((SurfRec*)_surfs.get(i))->surface->setLiftCoefficient(ratio); } void Wing::WingSection::multiplyLiftRatio(float factor) @@ -408,7 +408,7 @@ void Wing::WingSection::newSurface(Version* _version, float* pos, float* orient, s->setChord(chord); // Camber is expressed as a fraction of stall peak, so convert. - s->setBaseZDrag(_camber*_stallParams.peak); + s->setZeroAlphaLift(_camber*_stallParams.peak); // The "main" (i.e. normal) stall angle float stallAoA = _stallParams.aoa - _stallParams.width/4; @@ -498,7 +498,7 @@ void Wing::writeInfoToProptree() ws = (WingSection*)_sections.get(section); for (int surf=0; surf < ws->numSurfaces(); surf++) { Surface* s = ws->getSurface(surf); - float drag = s->getDragCoefficient(); + float drag = s->getTotalForceCoefficient(); dragSum += drag; float mass = ws->getSurfaceWeight(surf); @@ -510,9 +510,11 @@ void Wing::writeInfoToProptree() _wingN->getNode("drag", true)->setFloatValue(dragSum); } +// estimate a mass distibution and add masses to the model +// they will be scaled to match total mass of aircraft later float Wing::updateModel(Model* model) { - float wgt = 0; + _weight = 0; WingSection* ws; for (int section=0; section < _sections.size(); section++) { ws = (WingSection*)_sections.get(section); @@ -520,21 +522,26 @@ float Wing::updateModel(Model* model) Surface* s = ws->getSurface(surf); model->addSurface(s); - float mass = ws->getSurfaceWeight(surf); - mass = mass * Math::sqrt(mass); - wgt += mass; + float weight = ws->getSurfaceWeight(surf); + weight = weight * Math::sqrt(weight); + _weight += weight; float pos[3]; s->getPosition(pos); - int mid = model->getBody()->addMass(mass, pos, true); + int mid = model->getBody()->addMass(weight, pos, true); if (_wingN != nullptr) { SGPropertyNode_ptr n = _wingN->getNode("surfaces", true)->getChild("surface", s->getID(), true); - n->getNode("drag", true)->setFloatValue(s->getDragCoefficient()); + n->getNode("c0", true)->setFloatValue(s->getTotalForceCoefficient()); + n->getNode("cdrag", true)->setFloatValue(s->getDragCoefficient()); + n->getNode("clift", true)->setFloatValue(s->getLiftCoefficient()); n->getNode("mass-id", true)->setIntValue(mid); } } } - return wgt; + if (_wingN != nullptr) { + _wingN->getNode("weight", true)->setFloatValue(_weight); + } + return _weight; } }; // namespace yasim diff --git a/src/FDM/YASim/Wing.hpp b/src/FDM/YASim/Wing.hpp index cb8bd5644..6481ba16c 100644 --- a/src/FDM/YASim/Wing.hpp +++ b/src/FDM/YASim/Wing.hpp @@ -49,6 +49,7 @@ class Wing { }; struct WingSection { + int _id; Chord _rootChord; // length is distance from base to tip, not wing span float _length {0}; @@ -123,7 +124,9 @@ class Wing { float _aspectRatio {0}; float _meanChord {0}; float _incidence {0}; + float _weight {0}; + //-- private methods Chord _float2chord(float* pos, float lenght = 0); void _chord2float(Chord c, float* pos); void interp(const float* v1, const float* v2, const float frac, float* out); @@ -166,7 +169,6 @@ public: void setPropertyNode(SGPropertyNode_ptr n) { _wingN = n; }; float updateModel(Model* model); - }; }; // namespace yasim From 87149931dd2bcc9939d7e8cd53d214c988e3fb78 Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Tue, 12 Dec 2017 08:14:30 +0100 Subject: [PATCH 28/29] YASim refactoring parser --- src/FDM/YASim/Airplane.cpp | 27 +++++++-------- src/FDM/YASim/Airplane.hpp | 10 ++++-- src/FDM/YASim/ControlMap.cpp | 52 ++++++++++++++-------------- src/FDM/YASim/ControlMap.hpp | 7 ++-- src/FDM/YASim/FGFDM.cpp | 66 ++++++++++++++++++++---------------- src/FDM/YASim/FGFDM.hpp | 3 +- 6 files changed, 87 insertions(+), 78 deletions(-) diff --git a/src/FDM/YASim/Airplane.cpp b/src/FDM/YASim/Airplane.cpp index 9510f65e8..0a4b128b6 100644 --- a/src/FDM/YASim/Airplane.cpp +++ b/src/FDM/YASim/Airplane.cpp @@ -161,31 +161,30 @@ void Airplane::setCruise(float speed, float altitude, float fuel, float gla) void Airplane::setElevatorControl(const char* prop) { - _approachElevator.propHandle = getControlMap()->getPropertyHandle(prop); + _approachElevator.propHandle = getControlMap()->getInputPropertyHandle(prop); _approachElevator.val = 0; _approachConfig.controls.add(&_approachElevator); } -void Airplane::addApproachControl(const char* prop, float val) +void Airplane::addControlSetting(Configuration cfg, const char* prop, float val) { ControlSetting* c = new ControlSetting(); - c->propHandle = getControlMap()->getPropertyHandle(prop); + c->propHandle = getControlMap()->getInputPropertyHandle(prop); c->val = val; - _approachConfig.controls.add(c); + switch (cfg) { + case APPROACH: + _approachConfig.controls.add(c); + break; + case CRUISE: + _cruiseConfig.controls.add(c); + break; + } } -void Airplane::addCruiseControl(const char* prop, float val) -{ - ControlSetting* c = new ControlSetting(); - c->propHandle = getControlMap()->getPropertyHandle(prop); - c->val = val; - _cruiseConfig.controls.add(c); -} - -void Airplane::addSolutionWeight(bool approach, int idx, float wgt) +void Airplane::addSolutionWeight(Configuration cfg, int idx, float wgt) { SolveWeight* w = new SolveWeight(); - w->approach = approach; + w->approach = (cfg == APPROACH); w->idx = idx; w->wgt = wgt; _solveWeights.add(w); diff --git a/src/FDM/YASim/Airplane.hpp b/src/FDM/YASim/Airplane.hpp index 0f22cfc22..7304e986c 100644 --- a/src/FDM/YASim/Airplane.hpp +++ b/src/FDM/YASim/Airplane.hpp @@ -24,6 +24,11 @@ public: Airplane(); ~Airplane(); + enum Configuration { + APPROACH, + CRUISE, + }; + void iterate(float dt); void calcFuelWeights(); @@ -60,10 +65,9 @@ public: void setCruise(float speed, float altitude, float fuel, float gla); void setElevatorControl(const char* prop); - void addApproachControl(const char* prop, float val); - void addCruiseControl(const char* prop, float val); + void addControlSetting(Configuration cfg, const char* prop, float val); - void addSolutionWeight(bool approach, int idx, float wgt); + void addSolutionWeight(Configuration cfg, int idx, float wgt); int numGear() const { return _gears.size(); } Gear* getGear(int g) { return ((GearRec*)_gears.get(g))->gear; } diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp index db644691d..679d7aec5 100644 --- a/src/FDM/YASim/ControlMap.cpp +++ b/src/FDM/YASim/ControlMap.cpp @@ -50,13 +50,7 @@ options: bits OPT_INVERT, OPT_SPLIT, OPT_SQUARE */ void ControlMap::addMapping(const char* prop, Control control, ObjectID id, int options, float src0, float src1, float dst0, float dst1) { - addMapping(prop, control, id, options); - int inputPropHandle = getPropertyHandle(prop); - - // The one we just added is last in the list (ugly, awful hack!) - Vector* maps = (Vector*)_inputs.get(inputPropHandle); - MapRec* m = (MapRec*)maps->get(maps->size() - 1); - + MapRec* m = (MapRec*)addMapping(prop, control, id, options); m->src0 = src0; m->src1 = src1; m->dst0 = dst0; @@ -69,12 +63,13 @@ control: identifier (see enum OutputType) object: object to which this input belongs to options: bits OPT_INVERT, OPT_SPLIT, OPT_SQUARE */ -void ControlMap::addMapping(const char* prop, Control control, ObjectID id, int options) +void* ControlMap::addMapping(const char* prop, Control control, ObjectID id, int options) { - int inputPropHandle = getPropertyHandle(prop); + int inputPropHandle = getInputPropertyHandle(prop); // See if the output object already exists OutRec* out {nullptr}; - for(int i = 0; i < _outputs.size(); i++) { + int i; + for(i = 0; i < _outputs.size(); i++) { OutRec* o = (OutRec*)_outputs.get(i); if(o->oid.object == id.object && o->oid.subObj == id.subObj && o->control == control) @@ -105,6 +100,7 @@ void ControlMap::addMapping(const char* prop, Control control, ObjectID id, int // And add it to the approproate vectors. Vector* maps = (Vector*)_inputs.get(inputPropHandle); maps->add(map); + return map; } void ControlMap::reset() @@ -138,9 +134,9 @@ int ControlMap::getOutputHandle(ObjectID id, Control control) OutRec* o = (OutRec*)_outputs.get(i); if(o->oid.object == id.object && o->oid.subObj == id.subObj && o->control == control) - return i; + return i; } - fprintf(stderr, "ControlMap::getOutputHandle cannot find *%ld, control %d \n", (long)id.object, control); + fprintf(stderr, "ControlMap::getOutputHandle cannot find *%ld, control %d \nMissing in XML?!", (long)id.object, control); return -1; } @@ -330,6 +326,7 @@ void ControlMap::applyControls(float dt) ((Hitch*)obj)->findBestAIObject(lval!=0); break; case PROP: + break; case INCIDENCE: break; } @@ -369,24 +366,24 @@ float ControlMap::rangeMax(Control control) } /// register property name, return ID (int) -int ControlMap::getPropertyHandle(const char* name) +int ControlMap::getInputPropertyHandle(const char* name) { - for(int i=0; i < _properties.size(); i++) { - PropHandle* p = (PropHandle*)_properties.get(i); - if(!strcmp(p->name, name)) - return p->handle; - } + for(int i=0; i < _properties.size(); i++) { + PropHandle* p = (PropHandle*)_properties.get(i); + if(!strcmp(p->name, name)) + return p->handle; + } - // create new - PropHandle* p = new PropHandle(); - p->name = strdup(name); - - fgGetNode(p->name, true); + // create new + PropHandle* p = new PropHandle(); + p->name = strdup(name); + + fgGetNode(p->name, true); - Vector* v = new Vector(); - p->handle = _inputs.add(v); - _properties.add(p); - return p->handle; + Vector* v = new Vector(); + p->handle = _inputs.add(v); + _properties.add(p); + return p->handle; } @@ -442,6 +439,7 @@ ControlMap::Control ControlMap::parseControl(const char* name) ControlMap::ObjectID ControlMap::getObjectID(void* object, int subObj) { + assert(object != nullptr); ObjectID o; o.object = object; o.subObj = subObj; diff --git a/src/FDM/YASim/ControlMap.hpp b/src/FDM/YASim/ControlMap.hpp index 94374ea2a..5c150c1e1 100644 --- a/src/FDM/YASim/ControlMap.hpp +++ b/src/FDM/YASim/ControlMap.hpp @@ -9,7 +9,7 @@ namespace yasim { class ControlMap { public: ~ControlMap(); - + enum Control { THROTTLE, MIXTURE, @@ -77,7 +77,6 @@ public: ObjectID getObjectID(void* object, int subObj = 0); // add input property for a control to an object - void addMapping(const char* prop, Control control, ObjectID id, int options = 0); // same with limits. Input values are clamped to [src0:src1] and then mapped to // [dst0:dst1] before being set on the objects control. @@ -116,7 +115,7 @@ public: float getOutputR(int handle); // register property name, return handle - int getPropertyHandle(const char* name); + int getInputPropertyHandle(const char* name); int numProperties() { return _properties.size(); } PropHandle* getProperty(const int i) { return ((PropHandle*)_properties.get(i)); } @@ -148,6 +147,8 @@ private: Vector _outputs; // control properties Vector _properties; + + void* addMapping(const char* prop, Control control, ObjectID id, int options = 0); }; }; // namespace yasim diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index 1a8c82c63..3c21a5ed7 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -228,22 +228,7 @@ void FGFDM::startElement(const char* name, const XMLAttributes &a) else if(!strcmp(name, "solve-weight")) { parseSolveWeight(&a); } else if(!strcmp(name, "cockpit")) { parseCockpit(&a); } else if(!strcmp(name, "rotor")) { parseRotor(&a, name); } - else if(!strcmp(name, "rotorgear")) { - Rotorgear* r = _airplane.getModel()->getRotorgear(); - _currObj = r; - #define p(x) if ((&a)->hasAttribute(#x)) r->setParameter((char *)#x,attrf(&a,#x) ); - #define p2(x,y) if ((&a)->hasAttribute(y)) r->setParameter((char *)#x,attrf(&a,y) ); - p2(max_power_engine,"max-power-engine") - p2(engine_prop_factor,"engine-prop-factor") - p(yasimdragfactor) - p(yasimliftfactor) - p2(max_power_rotor_brake,"max-power-rotor-brake") - p2(rotorgear_friction,"rotorgear-friction") - p2(engine_accel_limit,"engine-accel-limit") - #undef p - #undef p2 - r->setInUse(); - } + else if(!strcmp(name, "rotorgear")) { parseRotorGear(&a); } else if(!strcmp(name, "wing") || !strcmp(name, "hstab") || !strcmp(name, "vstab") || !strcmp(name, "mstab")) { parseWing(&a, name, &_airplane); } @@ -320,11 +305,11 @@ void FGFDM::parseApproachCruise(const XMLAttributes* a, const char* name) if (!strcmp(name, "approach")) { float aoa = attrf(a, "aoa", 0) * DEG2RAD; _airplane.setApproach(spd, alt, aoa, attrf(a, "fuel", 0.2), gla); - _cruiseCurr = false; + _airplaneCfg = Airplane::Configuration::APPROACH; } else { _airplane.setCruise(spd, alt, attrf(a, "fuel", 0.5),gla); - _cruiseCurr = true; + _airplaneCfg = Airplane::Configuration::CRUISE; } } @@ -339,7 +324,7 @@ void FGFDM::parseSolveWeight(const XMLAttributes* a) SG_LOG(SG_FLIGHT,SG_ALERT,"YASim fatal: missing attribute, solve-weight needs one of {weight-lbs, weight-kg}"); exit(1); } - _airplane.addSolutionWeight(!_cruiseCurr, idx, f); + _airplane.addSolutionWeight(_airplaneCfg, idx, f); } void FGFDM::parseCockpit(const XMLAttributes* a) @@ -594,10 +579,13 @@ void FGFDM::parseWing(const XMLAttributes* a, const char* type, Airplane* airpla float dragFactor = attrf(a, "pdrag", 1); if (a->hasAttribute("effectiveness")) { +/* FIXME: + * check if all attibutes have "good" names and update parser AND documentation together + * only after that issue warnings SG_LOG(SG_FLIGHT, SG_ALERT, "Warning: " << "deprecated attribute 'effectiveness' in YASim configuration file. " << "Use 'pdrag' instead to add parasitic drag."); - +*/ dragFactor = attrf(a, "effectiveness", 1); } w->setSectionDrag(_wingSection, dragFactor); @@ -719,6 +707,24 @@ void FGFDM::parseRotor(const XMLAttributes* a, const char* type) _airplane.getModel()->getRotorgear()->addRotor(w); } //parseRotor +void FGFDM::parseRotorGear(const XMLAttributes* a) +{ + Rotorgear* r = _airplane.getModel()->getRotorgear(); + _currObj = r; + #define p(x) if (a->hasAttribute(#x)) r->setParameter((char *)#x,attrf(a,#x) ); + #define p2(x,y) if (a->hasAttribute(y)) r->setParameter((char *)#x,attrf(a,y) ); + p2(max_power_engine,"max-power-engine") + p2(engine_prop_factor,"engine-prop-factor") + p(yasimdragfactor) + p(yasimliftfactor) + p2(max_power_rotor_brake,"max-power-rotor-brake") + p2(rotorgear_friction,"rotorgear-friction") + p2(engine_accel_limit,"engine-accel-limit") + #undef p + #undef p2 + r->setInUse(); +} + void FGFDM::parsePistonEngine(const XMLAttributes* a) { float engP = attrf(a, "eng-power") * HP2W; @@ -1138,12 +1144,7 @@ void FGFDM::parseControlSetting(const XMLAttributes* a) { // A cruise or approach control setting float value = attrf(a, "value", 0); - if(_cruiseCurr) { - _airplane.addCruiseControl(a->getValue("axis"), value); - } - else { - _airplane.addApproachControl(a->getValue("axis"), value); - } + _airplane.addControlSetting(_airplaneCfg, a->getValue("axis"), value); } void FGFDM::parseControlIn(const XMLAttributes* a) @@ -1156,11 +1157,16 @@ void FGFDM::parseControlIn(const XMLAttributes* a) opt |= a->hasAttribute("split") ? ControlMap::OPT_SPLIT : 0; opt |= a->hasAttribute("invert") ? ControlMap::OPT_INVERT : 0; opt |= a->hasAttribute("square") ? ControlMap::OPT_SQUARE : 0; + float src0, src1, dst0, dst1; + src0 = dst0 = cm->rangeMin(control); + src1 = dst1 = cm->rangeMax(control); if(a->hasAttribute("src0")) { - cm->addMapping(a->getValue("axis"), control, oid, opt, attrf(a, "src0"), attrf(a, "src1"), attrf(a, "dst0"), attrf(a, "dst1")); - } else { - cm->addMapping(a->getValue("axis"), control, oid, opt); - } + src0 = attrf(a, "src0"); + src1 = attrf(a, "src1"); + dst0 = attrf(a, "dst0"); + dst1 = attrf(a, "dst1"); + } + cm->addMapping(a->getValue("axis"), control, oid, opt, src0, src1, dst0, dst1); } void FGFDM::parseControlOut(const XMLAttributes* a) diff --git a/src/FDM/YASim/FGFDM.hpp b/src/FDM/YASim/FGFDM.hpp index 845873d66..a546d1262 100644 --- a/src/FDM/YASim/FGFDM.hpp +++ b/src/FDM/YASim/FGFDM.hpp @@ -58,6 +58,7 @@ private: void setOutputProperties(float dt); void parseRotor(const XMLAttributes* a, const char* name); + void parseRotorGear(const XMLAttributes* a); void parseWing(const XMLAttributes* a, const char* name, Airplane* airplane); int parseOutput(const char* name); void parseWeight(const XMLAttributes* a); @@ -113,7 +114,7 @@ private: // Parsing temporaries void* _currObj {nullptr}; - bool _cruiseCurr {false}; + Airplane::Configuration _airplaneCfg; int _nextEngine {0}; int _wingSection {0}; From 9289c79e05169cf253691cc0cfa6cf8630aa3dce Mon Sep 17 00:00:00 2001 From: Henning Stahlke Date: Thu, 14 Dec 2017 20:02:52 +0100 Subject: [PATCH 29/29] YASIM reduce precision of lift/drag output from CLI tool to .4 --- src/FDM/YASim/yasim-test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FDM/YASim/yasim-test.cpp b/src/FDM/YASim/yasim-test.cpp index fb08639d7..4ac88869c 100644 --- a/src/FDM/YASim/yasim-test.cpp +++ b/src/FDM/YASim/yasim-test.cpp @@ -95,7 +95,7 @@ void yasim_graph(Airplane* a, const float alt, const float kts, int cfg = CONFIG ld_max= ld; ld_max_deg = deg; } - printf("%d %g %g %g\n", deg, lift, drag, ld); + printf("%d %.4g %.4g %.4g\n", deg, lift, drag, ld); } printf("# cl_max %g at %d deg\n", cl_max, cl_max_deg); printf("# cd_min %g at %d deg\n", cd_min, cd_min_deg);