]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AICarrier.cxx
e6ab561479bb0dc883d06fec71f9f400e49c8b45
[flightgear.git] / src / AIModel / AICarrier.cxx
1 // FGAICarrier - FGAIShip-derived class creates an AI aircraft carrier
2 //
3 // Written by David Culp, started October 2004.
4 // - davidculp2@comcast.net
5 //
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License as
8 // published by the Free Software Foundation; either version 2 of the
9 // License, or (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 #ifdef HAVE_CONFIG_H
21 #  include <config.h>
22 #endif
23
24 #include <string>
25 #include <vector>
26
27 #include <simgear/math/point3d.hxx>
28 #include <simgear/math/sg_geodesy.hxx>
29 #include <math.h>
30 #include <Main/util.hxx>
31 #include <Main/viewer.hxx>
32
33 #include "AICarrier.hxx"
34
35
36 FGAICarrier::FGAICarrier(FGAIManager* mgr) : FGAIShip(mgr) {
37 }
38
39 FGAICarrier::~FGAICarrier() {
40 }
41
42 void FGAICarrier::setSolidObjects(const list<string>& so) {
43   solid_objects = so;
44 }
45
46 void FGAICarrier::setWireObjects(const list<string>& wo) {
47   wire_objects = wo;
48 }
49
50 void FGAICarrier::setCatapultObjects(const list<string>& co) {
51   catapult_objects = co;
52 }
53
54 void FGAICarrier::getVelocityWrtEarth(sgVec3 v) {
55   sgCopyVec3(v, vel_wrt_earth );
56 }
57
58 void FGAICarrier::update(double dt) {
59    UpdateFlols(dt);
60    FGAIShip::update(dt);
61
62    // Update the velocity information stored in those nodes.
63    double v_north = 0.51444444*speed*cos(hdg * SGD_DEGREES_TO_RADIANS);
64    double v_east  = 0.51444444*speed*sin(hdg * SGD_DEGREES_TO_RADIANS);
65
66    double sin_lat = sin(pos.lat() * SGD_DEGREES_TO_RADIANS);
67    double cos_lat = cos(pos.lat() * SGD_DEGREES_TO_RADIANS);
68    double sin_lon = sin(pos.lon() * SGD_DEGREES_TO_RADIANS);
69    double cos_lon = cos(pos.lon() * SGD_DEGREES_TO_RADIANS);
70    sgSetVec3( vel_wrt_earth,
71               - cos_lon*sin_lat*v_north - sin_lon*v_east,
72               - sin_lon*sin_lat*v_north + cos_lon*v_east,
73                 cos_lat*v_north );
74
75 }
76
77 bool FGAICarrier::init() {
78    if (!FGAIShip::init())
79       return false;
80
81    // process the 3d model here
82    // mark some objects solid, mark the wires ...
83
84    // The model should be used for altitude computations.
85    // To avoid that every detail in a carrier 3D model will end into
86    // the aircraft local cache, only set the HOT traversal bit on
87    // selected objects.
88    ssgEntity *sel = aip.getSceneGraph();
89    // Clear the HOT traversal flag
90    mark_nohot(sel);
91    // Selectively set that flag again for wires/cats/solid objects.
92    // Attach a pointer to this carrier class to those objects.
93    mark_wires(sel, wire_objects);
94    mark_cat(sel, catapult_objects);
95    mark_solid(sel, solid_objects);
96
97    return true;
98 }
99 void FGAICarrier::bind() {
100    FGAIBase::bind();
101
102    props->tie("controls/flols/source-lights",
103                 SGRawValuePointer<int>(&source));
104    props->tie("controls/flols/distance-m",
105                 SGRawValuePointer<double>(&dist)); 
106    props->tie("controls/flols/angle-degs",
107                 SGRawValuePointer<double>(&angle));                                              
108    props->setBoolValue("controls/flols/cut-lights", false);
109    props->setBoolValue("controls/flols/wave-off-lights", false);
110    props->setBoolValue("controls/flols/cond-datum-lights", true);  
111    props->setBoolValue("controls/crew", false);  
112    }
113
114 void FGAICarrier::unbind() {
115     FGAIBase::unbind();
116     props->untie("controls/flols/source-lights");
117     props->untie("controls/flols/distance-m"); 
118     props->untie("controls/flols/angle-degs");    
119 }
120    
121 void FGAICarrier::mark_nohot(ssgEntity* e) {
122   if (e->isAKindOf(ssgTypeBranch())) {
123     ssgBranch* br = (ssgBranch*)e;
124     ssgEntity* kid;
125     for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
126       mark_nohot(kid);
127
128     br->clrTraversalMaskBits(SSGTRAV_HOT);
129     
130   } else if (e->isAKindOf(ssgTypeLeaf())) {
131
132     e->clrTraversalMaskBits(SSGTRAV_HOT);
133
134   }
135 }
136
137 bool FGAICarrier::mark_wires(ssgEntity* e, const list<string>& wire_objects, bool mark) {
138   bool found = false;
139   if (e->isAKindOf(ssgTypeBranch())) {
140     ssgBranch* br = (ssgBranch*)e;
141     ssgEntity* kid;
142
143     list<string>::const_iterator it;
144     for (it = wire_objects.begin(); it != wire_objects.end(); ++it)
145       mark = mark || (e->getName() && (*it) == e->getName());
146
147     for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
148       found = mark_wires(kid, wire_objects, mark) || found;
149
150     if (found)
151       br->setTraversalMaskBits(SSGTRAV_HOT);
152     
153   } else if (e->isAKindOf(ssgTypeLeaf())) {
154     list<string>::const_iterator it;
155     for (it = wire_objects.begin(); it != wire_objects.end(); ++it) {
156       if (mark || (e->getName() && (*it) == e->getName())) {
157         e->setTraversalMaskBits(SSGTRAV_HOT);
158         ssgBase* ud = e->getUserData();
159         if (ud) {
160           FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
161           if (ch) {
162             SG_LOG(SG_GENERAL, SG_WARN,
163                    "AICarrier: Carrier hardware gets marked twice!\n"
164                    "           You have propably a whole branch marked as"
165                    " a wire which also includes other carrier hardware."
166                    );
167           } else {
168             SG_LOG(SG_GENERAL, SG_ALERT,
169                    "AICarrier: Found user data attached to a leaf node which "
170                    "should be marked as a wire!\n    ****Skipping!****");
171           }
172         } else {
173           e->setUserData( FGAICarrierHardware::newWire( this ) );
174           ssgLeaf *l = (ssgLeaf*)e;
175           if ( l->getNumLines() != 1 ) {
176             SG_LOG(SG_GENERAL, SG_ALERT,
177                    "AICarrier: Found wires not modelled with exactly one line!");
178           }
179           found = true;
180         }
181       }
182     }
183   }
184   return found;
185 }
186
187 bool FGAICarrier::mark_solid(ssgEntity* e, const list<string>& solid_objects, bool mark) {
188   bool found = false;
189   if (e->isAKindOf(ssgTypeBranch())) {
190     ssgBranch* br = (ssgBranch*)e;
191     ssgEntity* kid;
192
193     list<string>::const_iterator it;
194     for (it = solid_objects.begin(); it != solid_objects.end(); ++it)
195       mark = mark || (e->getName() && (*it) == e->getName());
196
197     for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
198       found = mark_solid(kid, solid_objects, mark) || found;
199
200     if (found)
201       br->setTraversalMaskBits(SSGTRAV_HOT);
202     
203   } else if (e->isAKindOf(ssgTypeLeaf())) {
204     list<string>::const_iterator it;
205     for (it = solid_objects.begin(); it != solid_objects.end(); ++it) {
206       if (mark || (e->getName() && (*it) == e->getName())) {
207         e->setTraversalMaskBits(SSGTRAV_HOT);
208         ssgBase* ud = e->getUserData();
209         if (ud) {
210           FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
211           if (ch) {
212             SG_LOG(SG_GENERAL, SG_WARN,
213                    "AICarrier: Carrier hardware gets marked twice!\n"
214                    "           You have propably a whole branch marked solid"
215                    " which also includes other carrier hardware."
216                    );
217           } else {
218             SG_LOG(SG_GENERAL, SG_ALERT,
219                    "AICarrier: Found user data attached to a leaf node which "
220                    "should be marked solid!\n    ****Skipping!****");
221           }
222         } else {
223           e->setUserData( FGAICarrierHardware::newSolid( this ) );
224           found = true;
225         }
226       }
227     }
228   }
229   return found;
230 }
231
232 bool FGAICarrier::mark_cat(ssgEntity* e, const list<string>& cat_objects, bool mark) {
233   bool found = false;
234   if (e->isAKindOf(ssgTypeBranch())) {
235     ssgBranch* br = (ssgBranch*)e;
236     ssgEntity* kid;
237
238     list<string>::const_iterator it;
239     for (it = cat_objects.begin(); it != cat_objects.end(); ++it)
240       mark = mark || (e->getName() && (*it) == e->getName());
241
242     for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
243       found = mark_cat(kid, cat_objects, mark) || found;
244
245     if (found)
246       br->setTraversalMaskBits(SSGTRAV_HOT);
247     
248   } else if (e->isAKindOf(ssgTypeLeaf())) {
249     list<string>::const_iterator it;
250     for (it = cat_objects.begin(); it != cat_objects.end(); ++it) {
251       if (mark || (e->getName() && (*it) == e->getName())) {
252         e->setTraversalMaskBits(SSGTRAV_HOT);
253         ssgBase* ud = e->getUserData();
254         if (ud) {
255           FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
256           if (ch) {
257             SG_LOG(SG_GENERAL, SG_WARN,
258                    "AICarrier: Carrier hardware gets marked twice!\n"
259                    "You have probably a whole branch marked as"
260                    "a catapult which also includes other carrier hardware."
261                     );
262           } else {
263             SG_LOG(SG_GENERAL, SG_ALERT,
264                    "AICarrier: Found user data attached to a leaf node which "
265                    "should be marked as a catapult!\n    ****Skipping!****");
266           }
267         } else {
268           e->setUserData( FGAICarrierHardware::newCatapult( this ) );
269           ssgLeaf *l = (ssgLeaf*)e;
270           if ( l->getNumLines() != 1 ) {
271             SG_LOG(SG_GENERAL, SG_ALERT,
272                    "AICarrier: Found a cat not modelled with exactly "
273                    "one line!");
274           } else {
275             // Now some special code to make sure the cat points in the right
276             // direction. The 0 index must be the backward end, the 1 index
277             // the forward end.
278             // Forward is positive x-direction in our 3D model, also the model
279             // as such is flattened when it is loaded, so we do not need to
280             // care for transforms ...
281             short v[2];
282             l->getLine(0, v, v+1 );
283             sgVec3 ends[2];
284             for (int k=0; k<2; ++k)
285               sgCopyVec3( ends[k], l->getVertex( v[k] ) );
286             
287             // When the 1 end is behind the 0 end, swap the coordinates.
288             if (ends[0][0] < ends[1][0]) {
289               sgCopyVec3( l->getVertex( v[0] ), ends[1] );
290               sgCopyVec3( l->getVertex( v[1] ), ends[0] );
291             }
292
293             found = true;
294           }
295         }
296       }
297     }
298   }
299   return found;
300 }
301
302 void FGAICarrier::UpdateFlols( double dt) {
303 /*    cout << "x_offset " << flols_x_offset 
304           << " y_offset " << flols_y_offset 
305           << " z_offset " << flols_z_offset << endl;
306         
307      cout << "roll " << roll 
308           << " heading " << hdg
309           << " pitch " << pitch << endl;
310         
311      cout << "carrier lon " << pos[0] 
312           << " lat " <<  pos[1]
313           << " alt " << pos[2] << endl;*/
314         
315 // set the Flols intitial position to the carrier position
316  
317   flolspos = pos;
318   
319 /*  cout << "flols lon " << flolspos[0] 
320           << " lat " <<  flolspos[1]
321           << " alt " << flolspos[2] << endl;*/
322           
323 // set the offsets in metres
324
325 /*  cout << "flols_x_offset " << flols_x_offset << endl
326        << "flols_y_offset " << flols_y_offset << endl
327        << "flols_z_offset " << flols_z_offset << endl;*/
328      
329   in[0] = flols_x_offset;  
330   in[1] = flols_y_offset;
331   in[2] = flols_z_offset;    
332
333 // pre-process the trig functions
334
335     cosRx = cos(roll * SG_DEGREES_TO_RADIANS);
336     sinRx = sin(roll * SG_DEGREES_TO_RADIANS);
337     cosRy = cos(pitch * SG_DEGREES_TO_RADIANS);
338     sinRy = sin(pitch * SG_DEGREES_TO_RADIANS);
339     cosRz = cos(hdg * SG_DEGREES_TO_RADIANS);
340     sinRz = sin(hdg * SG_DEGREES_TO_RADIANS);
341
342 // set up the transform matrix
343
344     trans[0][0] =  cosRy * cosRz;
345     trans[0][1] =  -1 * cosRx * sinRz + sinRx * sinRy * cosRz ;
346     trans[0][2] =  sinRx * sinRz + cosRx * sinRy * cosRz;
347
348     trans[1][0] =  cosRy * sinRz;
349     trans[1][1] =  cosRx * cosRz + sinRx * sinRy * sinRz;
350     trans[1][2] =  -1 * sinRx * cosRx + cosRx * sinRy * sinRz;
351
352     trans[2][0] =  -1 * sinRy;
353     trans[2][1] =  sinRx * cosRy;
354     trans[2][2] =  cosRx * cosRy;
355
356 // multiply the input and transform matrices
357
358    out[0] = in[0] * trans[0][0] + in[1] * trans[0][1] + in[2] * trans[0][2];
359    out[1] = in[0] * trans[1][0] + in[1] * trans[1][1] + in[2] * trans[1][2];
360    out[2] = in[0] * trans[2][0] + in[1] * trans[2][1] + in[2] * trans[2][2];
361  
362 // convert meters to ft to degrees of latitude
363    out[0] = (out[0] * 3.28083989501) /(366468.96 - 3717.12 * cos(flolspos[0] * SG_DEGREES_TO_RADIANS));
364
365 // convert meters to ft to degrees of longitude
366    out[1] = (out[1] * 3.28083989501)/(365228.16 * cos(flolspos[1] * SG_DEGREES_TO_RADIANS));
367
368 //print out the result
369 /*   cout  << "lat adjust deg" << out[0] 
370         << " lon adjust deg " << out[1] 
371         << " alt adjust m " << out[2]  << endl;*/
372
373 // adjust Flols position    
374    flolspos[0] += out[0];
375    flolspos[1] += out[1];
376    flolspos[2] += out[2];   
377
378 // convert flols position to cartesian co-ordinates 
379
380   sgGeodToCart(flolspos[1] * SG_DEGREES_TO_RADIANS,
381                flolspos[0] * SG_DEGREES_TO_RADIANS,
382                flolspos[2] , flolsXYZ );
383
384
385 /*  cout << "flols X " << flolsXYZ[0] 
386        << " Y " <<  flolsXYZ[1]
387        << " Z " << flolsXYZ[2] << endl; 
388
389 // check the conversion
390          
391   sgCartToGeod(flolsXYZ, &lat, &lon, &alt);
392  
393   cout << "flols check lon " << lon   
394         << " lat " << lat 
395         << " alt " << alt << endl;      */
396                
397 //get the current position of the pilot's eyepoint (cartesian cordinates)
398
399   sgdCopyVec3( eyeXYZ, globals->get_current_view()->get_absolute_view_pos() );
400   
401  /* cout  << "Eye_X "  << eyeXYZ[0] 
402         << " Eye_Y " << eyeXYZ[1] 
403         << " Eye_Z " << eyeXYZ[2]  << endl; */
404         
405   sgCartToGeod(eyeXYZ, &lat, &lon, &alt);
406   
407   eyepos[0] = lon * SG_RADIANS_TO_DEGREES;
408   eyepos[1] = lat * SG_RADIANS_TO_DEGREES;
409   eyepos[2] = alt;
410   
411 /*  cout << "eye lon " << eyepos[0]
412         << " eye lat " << eyepos[1] 
413         << " eye alt " << eyepos[2] << endl; */
414
415 //calculate the ditance from eye to flols
416       
417   dist = sgdDistanceVec3( flolsXYZ, eyeXYZ );
418
419 //apply an index error
420
421   dist -= 100;
422   
423   //cout << "distance " << dist << endl; 
424   
425   if ( dist < 5000 ) {
426        // calculate height above FLOLS 
427        double y = eyepos[2] - flolspos[2];
428        
429        // calculate the angle from the flols to eye
430        // above the horizontal
431        // double angle;
432        
433        if ( dist != 0 ) {
434            angle = asin( y / dist );
435          } else {
436            angle = 0.0;
437          }
438         
439        angle *= SG_RADIANS_TO_DEGREES;
440         
441       
442   // cout << " height " << y << " angle " << angle ;
443
444 // set the value of source  
445         
446        if ( angle <= 4.35 && angle > 4.01 )
447          { source = 1; }
448          else if ( angle <= 4.01 && angle > 3.670 )
449          { source = 2; }
450          else if ( angle <= 3.670 && angle > 3.330 )
451          { source = 3; }
452          else if ( angle <= 3.330 && angle > 2.990 )
453          { source = 4; }
454          else if ( angle <= 2.990 && angle > 2.650 )
455          { source = 5; }
456          else if ( angle <= 2.650  )
457          { source = 6; }
458          else
459          { source = 0; }
460          
461 //         cout << " source " << source << endl;
462                      
463    }   
464 } // end updateflols
465
466 int FGAICarrierHardware::unique_id = 1;