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