]> git.mxchange.org Git - flightgear.git/blob - src/FDM/YASim/ControlMap.cpp
Add support for a turbo prop condition lever.
[flightgear.git] / src / FDM / YASim / ControlMap.cpp
1 #include "Jet.hpp"
2 #include "Thruster.hpp"
3 #include "PropEngine.hpp"
4 #include "PistonEngine.hpp"
5 #include "TurbineEngine.hpp"
6 #include "Gear.hpp"
7 #include "Wing.hpp"
8 #include "Rotor.hpp"
9 #include "Math.hpp"
10 #include "Propeller.hpp"
11
12 #include "ControlMap.hpp"
13 namespace yasim {
14
15 ControlMap::~ControlMap()
16 {
17     int i;
18     for(i=0; i<_inputs.size(); i++) {
19         Vector* v = (Vector*)_inputs.get(i);
20         int j;
21         for(j=0; j<v->size(); j++)
22             delete (MapRec*)v->get(j);
23         delete v;
24     }
25
26     for(i=0; i<_outputs.size(); i++)
27         delete (OutRec*)_outputs.get(i);
28 }
29
30 int ControlMap::newInput()
31 {
32     Vector* v = new Vector();
33     return _inputs.add(v);
34 }
35
36 void ControlMap::addMapping(int input, int type, void* object, int options,
37                             float src0, float src1, float dst0, float dst1)
38 {
39     addMapping(input, type, object, options);
40
41     // The one we just added is last in the list (ugly, awful hack!)
42     Vector* maps = (Vector*)_inputs.get(input);
43     MapRec* m = (MapRec*)maps->get(maps->size() - 1);
44
45     m->src0 = src0;
46     m->src1 = src1;
47     m->dst0 = dst0;
48     m->dst1 = dst1;
49 }
50
51 void ControlMap::addMapping(int input, int type, void* object, int options)
52 {
53     // See if the output object already exists
54     OutRec* out = 0;
55     int i;
56     for(i=0; i<_outputs.size(); i++) {
57         OutRec* o = (OutRec*)_outputs.get(i);
58         if(o->object == object && o->type == type) {
59             out = o;
60             break;
61         }
62     }
63
64     // Create one if it doesn't
65     if(out == 0) {
66         out = new OutRec();
67         out->type = type;
68         out->object = object;
69         out->oldL = out->oldR = out->time = 0;
70         _outputs.add(out);
71     }
72     
73     // Make a new input record
74     MapRec* map = new MapRec();
75     map->out = out;
76     map->opt = options;
77     map->idx = out->maps.add(map);
78
79     // The default ranges differ depending on type!
80     map->src1 = map->dst1 = rangeMax(type);
81     map->src0 = map->dst0 = rangeMin(type);
82
83     // And add it to the approproate vectors.
84     Vector* maps = (Vector*)_inputs.get(input);
85     maps->add(map);
86 }
87
88 void ControlMap::reset()
89 {
90     // Set all the values to zero
91     for(int i=0; i<_outputs.size(); i++) {
92         OutRec* o = (OutRec*)_outputs.get(i);
93         for(int j=0; j<o->maps.size(); j++)
94             ((MapRec*)(o->maps.get(j)))->val = 0;
95     }
96 }
97
98 void ControlMap::setInput(int input, float val)
99 {
100     Vector* maps = (Vector*)_inputs.get(input);
101     for(int i=0; i<maps->size(); i++) {
102         MapRec* m = (MapRec*)maps->get(i);
103
104         float val2 = val;
105
106         // Do the scaling operation.  Clamp to [src0:src1], rescale to
107         // [0:1] within that range, then map to [dst0:dst1].
108         if(val2 < m->src0) val2 = m->src0;
109         if(val2 > m->src1) val2 = m->src1;
110         val2 = (val2 - m->src0) / (m->src1 - m->src0);
111         val2 = m->dst0 + val2 * (m->dst1 - m->dst0);
112
113         m->val = val2;
114     }
115 }
116
117 int ControlMap::getOutputHandle(void* obj, int type)
118 {
119     for(int i=0; i<_outputs.size(); i++) {
120         OutRec* o = (OutRec*)_outputs.get(i);
121         if(o->object == obj && o->type == type)
122             return i;
123     }
124     return 0;
125 }
126
127 void ControlMap::setTransitionTime(int handle, float time)
128 {
129     ((OutRec*)_outputs.get(handle))->time = time;
130 }
131
132 float ControlMap::getOutput(int handle)
133 {
134     return ((OutRec*)_outputs.get(handle))->oldL;
135 }
136
137 float ControlMap::getOutputR(int handle)
138 {
139     return ((OutRec*)_outputs.get(handle))->oldR;
140 }
141
142 void ControlMap::applyControls(float dt)
143 {
144     int outrec;
145     for(outrec=0; outrec<_outputs.size(); outrec++) {
146         OutRec* o = (OutRec*)_outputs.get(outrec);
147         
148         // Generate a summed value.  Note the check for "split"
149         // control axes like ailerons.
150         float lval = 0, rval = 0;
151         int i;
152         for(i=0; i<o->maps.size(); i++) {
153             MapRec* m = (MapRec*)o->maps.get(i);
154             float val = m->val;
155
156             if(m->opt & OPT_SQUARE)
157                 val = val * Math::abs(val);
158             if(m->opt & OPT_INVERT)
159                 val = -val;
160             lval += val;
161             if(m->opt & OPT_SPLIT)
162                 rval -= val;
163             else
164                 rval += val;
165         }
166
167         // If there is a finite transition time, clamp the values to
168         // the maximum travel allowed in this dt.
169         if(o->time > 0) {
170             float dl = lval - o->oldL;
171             float dr = rval - o->oldR;
172             float adl = Math::abs(dl);
173             float adr = Math::abs(dr);
174         
175             float max = (dt/o->time) * (rangeMax(o->type) - rangeMin(o->type));
176             if(adl > max) dl = dl*max/adl;
177             if(adr > max) dr = dr*max/adr;
178
179             lval = o->oldL + dl;
180             rval = o->oldR + dr;
181         }
182
183         o->oldL = lval;
184         o->oldR = rval;
185
186         void* obj = o->object;
187         switch(o->type) {
188         case THROTTLE: ((Thruster*)obj)->setThrottle(lval);        break;
189         case MIXTURE:  ((Thruster*)obj)->setMixture(lval);         break;
190         case CONDLEVER: ((TurbineEngine*)((PropEngine*)obj)->getEngine())->setCondLever(lval); break;
191         case STARTER:  ((Thruster*)obj)->setStarter(lval != 0.0);  break;
192         case MAGNETOS: ((PropEngine*)obj)->setMagnetos((int)lval); break;
193         case ADVANCE:  ((PropEngine*)obj)->setAdvance(lval);       break;
194         case PROPPITCH: ((PropEngine*)obj)->setPropPitch(lval);    break;
195         case PROPFEATHER: ((PropEngine*)obj)->setPropFeather((int)lval); break;
196         case REHEAT:   ((Jet*)obj)->setReheat(lval);               break;
197         case VECTOR:   ((Jet*)obj)->setRotation(lval);             break;
198         case BRAKE:    ((Gear*)obj)->setBrake(lval);               break;
199         case STEER:    ((Gear*)obj)->setRotation(lval);            break;
200         case EXTEND:   ((Gear*)obj)->setExtension(lval);           break;
201         case CASTERING:((Gear*)obj)->setCastering(lval != 0);      break;
202         case SLAT:     ((Wing*)obj)->setSlat(lval);                break;
203         case FLAP0:    ((Wing*)obj)->setFlap0(lval, rval);         break;
204         case FLAP1:    ((Wing*)obj)->setFlap1(lval, rval);         break;
205         case SPOILER:  ((Wing*)obj)->setSpoiler(lval, rval);       break;
206         case COLLECTIVE:   ((Rotor*)obj)->setCollective(lval);     break;
207         case CYCLICAIL:    ((Rotor*)obj)->setCyclicail(lval,rval); break;
208         case CYCLICELE:    ((Rotor*)obj)->setCyclicele(lval,rval); break;
209         case ROTORENGINEON: ((Rotor*)obj)->setEngineOn((int)lval); break;
210         case REVERSE_THRUST: ((Jet*)obj)->setReverse(lval != 0);   break;
211         case BOOST:
212             ((PistonEngine*)((Thruster*)obj)->getEngine())->setBoost(lval);
213             break;
214         }
215     }
216 }
217
218 float ControlMap::rangeMin(int type)
219 {
220     // The minimum of the range for each type of control
221     switch(type) {
222     case FLAP0:    return -1;  // [-1:1]
223     case FLAP1:    return -1;
224     case STEER:    return -1;
225     case CYCLICELE: return -1;
226     case CYCLICAIL: return -1;
227     case COLLECTIVE: return -1;
228     case MAGNETOS: return 0;   // [0:3]
229     default:       return 0;   // [0:1]
230     }
231 }
232
233 float ControlMap::rangeMax(int type)
234 {
235     // The maximum of the range for each type of control
236     switch(type) {
237     case FLAP0:    return 1; // [-1:1]
238     case FLAP1:    return 1;
239     case STEER:    return 1;
240     case MAGNETOS: return 3; // [0:3]
241     default:       return 1; // [0:1]
242     }
243 }
244
245 } // namespace yasim