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