]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/submodel.cxx
Mathias Froehlich:
[flightgear.git] / src / AIModel / submodel.cxx
1 // submodel.cxx - models a releasable submodel.
2 // Written by Dave Culp, started Aug 2004
3 //
4 // This file is in the Public Domain and comes with no warranty.
5
6 #include "submodel.hxx"
7
8 #include <simgear/structure/exception.hxx>
9 #include <simgear/misc/sg_path.hxx>
10
11 #include <Main/fg_props.hxx>
12 #include <Main/util.hxx>
13 #include <AIModel/AIManager.hxx>
14 #include <AIModel/AIBallistic.hxx>
15
16
17 const double FGSubmodelMgr::lbs_to_slugs = 0.031080950172;
18
19 FGSubmodelMgr::FGSubmodelMgr ()
20 {
21     
22   x_offset = y_offset = 0.0;
23   z_offset = -4.0;
24   pitch_offset = 2.0;
25   yaw_offset = 0.0;
26   
27   out[0] = out[1] = out[2] = 0;
28   in[3] = out[3] = 1;
29   string contents_node;
30   contrail_altitude = 30000.0;
31 }
32
33 FGSubmodelMgr::~FGSubmodelMgr ()
34 {
35 }
36
37 void
38 FGSubmodelMgr::init ()
39 {
40     load();
41     _serviceable_node = fgGetNode("/sim/submodels/serviceable", true);
42
43     _user_lat_node = fgGetNode("/position/latitude-deg", true);
44     _user_lon_node = fgGetNode("/position/longitude-deg", true);
45     _user_alt_node = fgGetNode("/position/altitude-ft", true);
46
47     _user_heading_node = fgGetNode("/orientation/heading-deg", true);
48     _user_pitch_node =   fgGetNode("/orientation/pitch-deg", true);
49     _user_roll_node =    fgGetNode("/orientation/roll-deg", true);
50     _user_yaw_node =     fgGetNode("/orientation/yaw-deg", true);
51     _user_alpha_node =   fgGetNode("/orientation/alpha-deg", true);
52
53     _user_speed_node = fgGetNode("/velocities/uBody-fps", true);
54
55     _user_wind_from_east_node  = fgGetNode("/environment/wind-from-east-fps",true);
56     _user_wind_from_north_node = fgGetNode("/environment/wind-from-north-fps",true);
57
58     _user_speed_down_fps_node   = fgGetNode("/velocities/speed-down-fps",true);
59     _user_speed_east_fps_node   = fgGetNode("/velocities/speed-east-fps",true);
60     _user_speed_north_fps_node  = fgGetNode("/velocities/speed-north-fps",true);
61
62     _contrail_altitude_node = fgGetNode("/environment/params/contrail-altitude", true);
63     contrail_altitude = _contrail_altitude_node->getDoubleValue();
64     _contrail_trigger = fgGetNode("ai/submodels/contrails", true);
65     _contrail_trigger->setBoolValue(false);
66
67     ai = (FGAIManager*)globals->get_subsystem("ai_model");
68
69 }
70
71 void
72 FGSubmodelMgr::bind ()
73 {
74 }
75
76 void
77 FGSubmodelMgr::unbind ()
78 {
79   submodel_iterator = submodels.begin();
80   while(submodel_iterator != submodels.end()) {
81     (*submodel_iterator)->prop->untie("count");
82     ++submodel_iterator;
83   }
84 }
85
86 void
87 FGSubmodelMgr::update (double dt)
88 {
89   if (!(_serviceable_node->getBoolValue())) return;
90   int i=-1;
91
92   _contrail_trigger->setBoolValue(_user_alt_node->getDoubleValue() > contrail_altitude);
93
94   submodel_iterator = submodels.begin();
95   while(submodel_iterator != submodels.end()) {
96     i++;
97     if ((*submodel_iterator)->trigger->getBoolValue()) {
98         if ((*submodel_iterator)->count != 0) {
99           release( (*submodel_iterator), dt);
100         } 
101     } else {
102       (*submodel_iterator)->first_time = true;
103     }  
104     ++submodel_iterator;
105   }
106    
107 }
108
109 bool
110 FGSubmodelMgr::release (submodel* sm, double dt)
111 {
112   // only run if first time or repeat is set to true
113   if (!sm->first_time && !sm->repeat) return false;
114
115   sm->timer += dt;
116   if (sm->timer < sm->delay) return false;
117   sm->timer = 0.0;
118
119   if (sm->first_time) {
120     dt = 0.0;
121     sm->first_time = false;
122   }
123
124   transform(sm);  // calculate submodel's initial conditions in world-coordinates
125
126   FGAIBallistic* ballist = new FGAIBallistic;
127   ballist->setPath(sm->model.c_str());
128   ballist->setLatitude(IC.lat);
129   ballist->setLongitude(IC.lon);
130   ballist->setAltitude(IC.alt);
131   ballist->setAzimuth(IC.azimuth);
132   ballist->setElevation(IC.elevation);
133   ballist->setRoll(IC.roll);
134   ballist->setSpeed(IC.speed);
135   ballist->setDragArea(sm->drag_area);
136   ballist->setLife(sm->life);
137   ballist->setBuoyancy(sm->buoyancy);
138   ballist->setWind_from_east(IC.wind_from_east);
139   ballist->setWind_from_north(IC.wind_from_north);
140   ballist->setWind(sm->wind);
141   ballist->setCd(sm->cd);
142   ballist->setMass(IC.mass);
143   ballist->setStabilisation(sm->aero_stabilised);
144   ai->attach(ballist);
145  
146   if (sm->count > 0) (sm->count)--; 
147
148   return true;                    
149 }
150
151 void
152 FGSubmodelMgr::load ()
153 {
154     SGPropertyNode *path = fgGetNode("/sim/submodels/path");
155     SGPropertyNode root;
156
157     if (path) {
158       SGPath config( globals->get_fg_root() );
159       config.append( path->getStringValue() );
160
161       try {
162         readProperties(config.str(), &root);
163       } catch (const sg_exception &e) {
164         SG_LOG(SG_GENERAL, SG_ALERT,
165         "Unable to read submodels file: ");
166         cout << config.str() << endl;
167         return;
168       }
169     }
170
171    vector<SGPropertyNode_ptr> children = root.getChildren("submodel");
172    vector<SGPropertyNode_ptr>::iterator it = children.begin();
173    vector<SGPropertyNode_ptr>::iterator end = children.end();
174    for (int i = 0; it != end; ++it, i++) {
175
176      // cout << "Reading submodel " << (*it)->getPath() << endl;
177      submodel* sm = new submodel;
178      SGPropertyNode * entry_node = *it;
179      sm->trigger        = fgGetNode(entry_node->getStringValue("trigger", "none"), true);
180      sm->name           = entry_node->getStringValue("name", "none_defined");
181      sm->model          = entry_node->getStringValue("model", "Models/Geometry/rocket.ac");
182      sm->speed          = entry_node->getDoubleValue("speed", 2329.4 );
183      sm->repeat         = entry_node->getBoolValue  ("repeat", false); 
184      sm->delay          = entry_node->getDoubleValue("delay", 0.25); 
185      sm->count          = entry_node->getIntValue   ("count", 1); 
186      sm->slaved         = entry_node->getBoolValue  ("slaved", false); 
187      sm->x_offset       = entry_node->getDoubleValue("x-offset", 0.0); 
188      sm->y_offset       = entry_node->getDoubleValue("y-offset", 0.0); 
189      sm->z_offset       = entry_node->getDoubleValue("z-offset", 0.0); 
190      sm->yaw_offset     = entry_node->getDoubleValue("yaw-offset", 0.0); 
191      sm->pitch_offset   = entry_node->getDoubleValue("pitch-offset", 0.0);
192      sm->drag_area      = entry_node->getDoubleValue("eda", 0.034);
193      sm->life           = entry_node->getDoubleValue("life", 900.0);
194      sm->buoyancy       = entry_node->getDoubleValue("buoyancy", 0);
195      sm->wind           = entry_node->getBoolValue  ("wind", false); 
196      sm->first_time     = false;
197      sm->cd             = entry_node->getDoubleValue("cd", 0.193);
198      sm->weight         = entry_node->getDoubleValue("weight", 0.25);
199      sm->aero_stabilised = entry_node->getBoolValue  ("aero-stabilised", true);
200      sm->contents_node  = fgGetNode(entry_node->getStringValue("contents", "none"), true);
201
202      sm->trigger->setBoolValue(false);
203      sm->timer = sm->delay;
204  
205      sm->contents = sm->contents_node->getDoubleValue();
206  
207      sm->prop = fgGetNode("/ai/submodels/submodel", i, true);
208      sm->prop->tie("count", SGRawValuePointer<int>(&(sm->count)));
209      sm->prop->tie("repeat", SGRawValuePointer<bool>(&(sm->repeat)));
210
211 //   sm->prop->tie("contents", SGRawValuePointer<double>(&(sm->contents)));
212 //   sm->prop->tie("contents path", SGRawValuePointer<const char *>(&(sm->contents_node)));
213      submodels.push_back( sm );
214    }
215
216   submodel_iterator = submodels.begin();
217   
218 }
219
220
221 void
222 FGSubmodelMgr::transform( submodel* sm) 
223 {
224
225 // get initial conditions 
226  
227 // get the weight of the contents (lbs) and convert to mass (slugs)
228   sm->contents = sm->contents_node->getDoubleValue();
229   
230   IC.mass = (sm->weight + sm->contents) * lbs_to_slugs;;
231 //  cout << IC.mass << endl;
232     
233 // set contents to 0 in the parent
234    sm->contents_node->setDoubleValue(0); 
235     
236   IC.lat =        _user_lat_node->getDoubleValue();    
237   IC.lon =        _user_lon_node->getDoubleValue();   
238   IC.alt =        _user_alt_node->getDoubleValue();    
239   IC.roll =       _user_roll_node->getDoubleValue();    // rotation about x axis 
240   IC.elevation =  _user_pitch_node->getDoubleValue();   // rotation about y axis 
241   IC.azimuth =    _user_heading_node->getDoubleValue(); // rotation about z axis
242   
243   IC.speed =           _user_speed_node->getDoubleValue();
244   IC.wind_from_east =  _user_wind_from_east_node->getDoubleValue();
245   IC.wind_from_north = _user_wind_from_north_node->getDoubleValue();
246   
247   IC.speed_down_fps =   _user_speed_down_fps_node->getDoubleValue();
248   IC.speed_east_fps =   _user_speed_east_fps_node->getDoubleValue();
249   IC.speed_north_fps =  _user_speed_north_fps_node->getDoubleValue();
250
251   
252   in[0] = sm->x_offset;
253   in[1] = sm->y_offset;
254   in[2] = sm->z_offset; 
255  
256   
257 // pre-process the trig functions
258
259     cosRx = cos(-IC.roll * SG_DEGREES_TO_RADIANS);
260     sinRx = sin(-IC.roll * SG_DEGREES_TO_RADIANS);
261     cosRy = cos(-IC.elevation * SG_DEGREES_TO_RADIANS);
262     sinRy = sin(-IC.elevation * SG_DEGREES_TO_RADIANS);
263     cosRz = cos(IC.azimuth * SG_DEGREES_TO_RADIANS);
264     sinRz = sin(IC.azimuth * SG_DEGREES_TO_RADIANS);
265
266 // set up the transform matrix
267
268     trans[0][0] =  cosRy * cosRz;
269     trans[0][1] =  -1 * cosRx * sinRz + sinRx * sinRy * cosRz ;
270     trans[0][2] =  sinRx * sinRz + cosRx * sinRy * cosRz;
271
272     trans[1][0] =  cosRy * sinRz;
273     trans[1][1] =  cosRx * cosRz + sinRx * sinRy * sinRz;
274     trans[1][2] =  -1 * sinRx * cosRx + cosRx * sinRy * sinRz;
275
276     trans[2][0] =  -1 * sinRy;
277     trans[2][1] =  sinRx * cosRy;
278     trans[2][2] =  cosRx * cosRy;
279
280
281 // multiply the input and transform matrices
282
283    out[0] = in[0] * trans[0][0] + in[1] * trans[0][1] + in[2] * trans[0][2];
284    out[1] = in[0] * trans[1][0] + in[1] * trans[1][1] + in[2] * trans[1][2];
285    out[2] = in[0] * trans[2][0] + in[1] * trans[2][1] + in[2] * trans[2][2];
286
287    // convert ft to degrees of latitude
288    out[0] = out[0] /(366468.96 - 3717.12 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
289
290    // convert ft to degrees of longitude
291    out[1] = out[1] /(365228.16 * cos(IC.lat * SG_DEGREES_TO_RADIANS));
292
293    // set submodel initial position
294    IC.lat += out[0];
295    IC.lon += out[1];
296    IC.alt += out[2];
297
298    // get aircraft velocity vector angles in XZ and XY planes
299     //double alpha = _user_alpha_node->getDoubleValue();
300     //double velXZ = IC.elevation - alpha * cosRx;
301     //double velXY = IC.azimuth - (IC.elevation - alpha * sinRx);
302    
303    // Get submodel initial velocity vector angles in XZ and XY planes.
304    // This needs to be fixed. This vector should be added to aircraft's vector. 
305    IC.elevation += (sm->yaw_offset * sinRx) + (sm->pitch_offset * cosRx);
306    IC.azimuth   += (sm->yaw_offset * cosRx) - (sm->pitch_offset * sinRx);
307  
308    // For now assume vector is close to airplane's vector.  This needs to be fixed.
309    //IC.speed += ; 
310
311    // calcuate the total speed north
312
313    IC.total_speed_north = sm->speed * cos(IC.elevation*SG_DEGREES_TO_RADIANS)*
314                     cos(IC.azimuth*SG_DEGREES_TO_RADIANS) + IC.speed_north_fps;
315
316    // calculate the total speed east
317
318    IC.total_speed_east = sm->speed * cos(IC.elevation*SG_DEGREES_TO_RADIANS)*
319                      sin(IC.azimuth*SG_DEGREES_TO_RADIANS) + IC.speed_east_fps;
320
321    // calculate the total speed down
322   
323    IC.total_speed_down = sm->speed * -sin(IC.elevation*SG_DEGREES_TO_RADIANS) +
324                         IC.speed_down_fps;
325
326   // re-calculate speed, elevation and azimuth
327
328    IC.speed = sqrt( IC.total_speed_north * IC.total_speed_north + 
329                     IC.total_speed_east * IC.total_speed_east +
330                     IC.total_speed_down * IC.total_speed_down);
331
332    IC.azimuth = atan(IC.total_speed_east/IC.total_speed_north) * SG_RADIANS_TO_DEGREES;
333    
334    // rationalise the output
335    
336    if (IC.total_speed_north <= 0){
337     IC.azimuth = 180 + IC.azimuth;
338    }
339    else{
340      if(IC.total_speed_east <= 0){
341      IC.azimuth = 360 + IC.azimuth;
342    }
343   }
344  
345     IC.elevation = -atan(IC.total_speed_down/sqrt(IC.total_speed_north * 
346                        IC.total_speed_north + 
347                        IC.total_speed_east * IC.total_speed_east)) * SG_RADIANS_TO_DEGREES;
348
349 }
350
351 void 
352 FGSubmodelMgr::updatelat(double lat) 
353 {
354     double latitude = lat;
355     ft_per_deg_latitude = 366468.96 - 3717.12 * cos(latitude / SG_RADIANS_TO_DEGREES);
356     ft_per_deg_longitude = 365228.16 * cos(latitude / SG_RADIANS_TO_DEGREES);
357 }
358
359 // end of submodel.cxx
360
361
362
363