]> git.mxchange.org Git - flightgear.git/blob - src/AIModel/AICarrier.cxx
161dbe53687f2216beb91dbfa215eb1eec5e4d03
[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 #include "AIScenario.hxx"
37
38
39 FGAICarrier::FGAICarrier(FGAIManager* mgr) : FGAIShip(mgr) {
40   _type_str = "carrier";
41   _otype = otCarrier;
42 }
43
44 FGAICarrier::~FGAICarrier() {
45 }
46
47 void FGAICarrier::setSolidObjects(const list<string>& so) {
48   solid_objects = so;
49 }
50
51 void FGAICarrier::setWireObjects(const list<string>& wo) {
52   wire_objects = wo;
53 }
54
55 void FGAICarrier::setCatapultObjects(const list<string>& co) {
56   catapult_objects = co;
57 }
58
59 void FGAICarrier::setParkingPositions(const list<ParkPosition>& p) {
60   ppositions = p;
61 }
62
63 void FGAICarrier::setSign(const string& s) {
64   sign = s;
65 }
66
67 void FGAICarrier::setFlolsOffset(const Point3D& off) {
68   flols_off = off;
69 }
70
71 void FGAICarrier::getVelocityWrtEarth(sgVec3 v) {
72   sgCopyVec3(v, vel_wrt_earth );
73 }
74
75 void FGAICarrier::update(double dt) {
76    UpdateFlols(dt);
77    FGAIShip::update(dt);
78
79    // Update the velocity information stored in those nodes.
80    double v_north = 0.51444444*speed*cos(hdg * SGD_DEGREES_TO_RADIANS);
81    double v_east  = 0.51444444*speed*sin(hdg * SGD_DEGREES_TO_RADIANS);
82
83    double sin_lat = sin(pos.lat() * SGD_DEGREES_TO_RADIANS);
84    double cos_lat = cos(pos.lat() * SGD_DEGREES_TO_RADIANS);
85    double sin_lon = sin(pos.lon() * SGD_DEGREES_TO_RADIANS);
86    double cos_lon = cos(pos.lon() * SGD_DEGREES_TO_RADIANS);
87    sgSetVec3( vel_wrt_earth,
88               - cos_lon*sin_lat*v_north - sin_lon*v_east,
89               - sin_lon*sin_lat*v_north + cos_lon*v_east,
90                 cos_lat*v_north );
91
92 }
93
94 bool FGAICarrier::init() {
95    if (!FGAIShip::init())
96       return false;
97
98    // process the 3d model here
99    // mark some objects solid, mark the wires ...
100
101    // The model should be used for altitude computations.
102    // To avoid that every detail in a carrier 3D model will end into
103    // the aircraft local cache, only set the HOT traversal bit on
104    // selected objects.
105    ssgEntity *sel = aip.getSceneGraph();
106    // Clear the HOT traversal flag
107    mark_nohot(sel);
108    // Selectively set that flag again for wires/cats/solid objects.
109    // Attach a pointer to this carrier class to those objects.
110    mark_wires(sel, wire_objects);
111    mark_cat(sel, catapult_objects);
112    mark_solid(sel, solid_objects);
113
114    return true;
115 }
116
117 void FGAICarrier::bind() {
118    FGAIShip::bind();
119
120    props->tie("controls/flols/source-lights",
121                 SGRawValuePointer<int>(&source));
122    props->tie("controls/flols/distance-m",
123                 SGRawValuePointer<double>(&dist));
124    props->tie("controls/flols/angle-degs",
125                 SGRawValuePointer<double>(&angle));
126    props->setBoolValue("controls/flols/cut-lights", false);
127    props->setBoolValue("controls/flols/wave-off-lights", false);
128    props->setBoolValue("controls/flols/cond-datum-lights", true);
129    props->setBoolValue("controls/crew", false);
130
131    props->setStringValue("sign", sign.c_str());
132 }
133
134 void FGAICarrier::unbind() {
135     FGAIShip::unbind();
136     props->untie("controls/flols/source-lights");
137     props->untie("controls/flols/distance-m");
138     props->untie("controls/flols/angle-degs");
139 }
140
141 bool FGAICarrier::getParkPosition(const string& id, Point3D& geodPos,
142                                   double& hdng, sgdVec3 uvw)
143 {
144   list<ParkPosition>::iterator it = ppositions.begin();
145   while (it != ppositions.end()) {
146     // Take either the specified one or the first one ...
147     if ((*it).name == id || id.empty()) {
148       ParkPosition ppos = *it;
149       geodPos = getGeocPosAt(ppos.offset);
150       hdng = hdg + ppos.heading_deg;
151       double shdng = sin(ppos.heading_deg * SGD_DEGREES_TO_RADIANS);
152       double chdng = cos(ppos.heading_deg * SGD_DEGREES_TO_RADIANS);
153       double speed_fps = speed*1.6878099;
154       sgdSetVec3(uvw, chdng*speed_fps, shdng*speed_fps, 0);
155       return true;
156     }
157     ++it;
158   }
159
160   return false;
161 }
162
163 void FGAICarrier::mark_nohot(ssgEntity* e) {
164   if (e->isAKindOf(ssgTypeBranch())) {
165     ssgBranch* br = (ssgBranch*)e;
166     ssgEntity* kid;
167     for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
168       mark_nohot(kid);
169
170     br->clrTraversalMaskBits(SSGTRAV_HOT);
171     
172   } else if (e->isAKindOf(ssgTypeLeaf())) {
173
174     e->clrTraversalMaskBits(SSGTRAV_HOT);
175
176   }
177 }
178
179 bool FGAICarrier::mark_wires(ssgEntity* e, const list<string>& wire_objects, bool mark) {
180   bool found = false;
181   if (e->isAKindOf(ssgTypeBranch())) {
182     ssgBranch* br = (ssgBranch*)e;
183     ssgEntity* kid;
184
185     list<string>::const_iterator it;
186     for (it = wire_objects.begin(); it != wire_objects.end(); ++it)
187       mark = mark || (e->getName() && (*it) == e->getName());
188
189     for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
190       found = mark_wires(kid, wire_objects, mark) || found;
191
192     if (found)
193       br->setTraversalMaskBits(SSGTRAV_HOT);
194     
195   } else if (e->isAKindOf(ssgTypeLeaf())) {
196     list<string>::const_iterator it;
197     for (it = wire_objects.begin(); it != wire_objects.end(); ++it) {
198       if (mark || (e->getName() && (*it) == e->getName())) {
199         e->setTraversalMaskBits(SSGTRAV_HOT);
200         ssgBase* ud = e->getUserData();
201         if (ud) {
202           FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
203           if (ch) {
204             SG_LOG(SG_GENERAL, SG_WARN,
205                    "AICarrier: Carrier hardware gets marked twice!\n"
206                    "           You have propably a whole branch marked as"
207                    " a wire which also includes other carrier hardware."
208                    );
209           } else {
210             SG_LOG(SG_GENERAL, SG_ALERT,
211                    "AICarrier: Found user data attached to a leaf node which "
212                    "should be marked as a wire!\n    ****Skipping!****");
213           }
214         } else {
215           e->setUserData( FGAICarrierHardware::newWire( this ) );
216           ssgLeaf *l = (ssgLeaf*)e;
217           if ( l->getNumLines() != 1 ) {
218             SG_LOG(SG_GENERAL, SG_ALERT,
219                    "AICarrier: Found wires not modelled with exactly one line!");
220           }
221           found = true;
222         }
223       }
224     }
225   }
226   return found;
227 }
228
229 bool FGAICarrier::mark_solid(ssgEntity* e, const list<string>& solid_objects, bool mark) {
230   bool found = false;
231   if (e->isAKindOf(ssgTypeBranch())) {
232     ssgBranch* br = (ssgBranch*)e;
233     ssgEntity* kid;
234
235     list<string>::const_iterator it;
236     for (it = solid_objects.begin(); it != solid_objects.end(); ++it)
237       mark = mark || (e->getName() && (*it) == e->getName());
238
239     for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
240       found = mark_solid(kid, solid_objects, mark) || found;
241
242     if (found)
243       br->setTraversalMaskBits(SSGTRAV_HOT);
244     
245   } else if (e->isAKindOf(ssgTypeLeaf())) {
246     list<string>::const_iterator it;
247     for (it = solid_objects.begin(); it != solid_objects.end(); ++it) {
248       if (mark || (e->getName() && (*it) == e->getName())) {
249         e->setTraversalMaskBits(SSGTRAV_HOT);
250         ssgBase* ud = e->getUserData();
251         if (ud) {
252           FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
253           if (ch) {
254             SG_LOG(SG_GENERAL, SG_WARN,
255                    "AICarrier: Carrier hardware gets marked twice!\n"
256                    "           You have propably a whole branch marked solid"
257                    " which also includes other carrier hardware."
258                    );
259           } else {
260             SG_LOG(SG_GENERAL, SG_ALERT,
261                    "AICarrier: Found user data attached to a leaf node which "
262                    "should be marked solid!\n    ****Skipping!****");
263           }
264         } else {
265           e->setUserData( FGAICarrierHardware::newSolid( this ) );
266           found = true;
267         }
268       }
269     }
270   }
271   return found;
272 }
273
274 bool FGAICarrier::mark_cat(ssgEntity* e, const list<string>& cat_objects, bool mark) {
275   bool found = false;
276   if (e->isAKindOf(ssgTypeBranch())) {
277     ssgBranch* br = (ssgBranch*)e;
278     ssgEntity* kid;
279
280     list<string>::const_iterator it;
281     for (it = cat_objects.begin(); it != cat_objects.end(); ++it)
282       mark = mark || (e->getName() && (*it) == e->getName());
283
284     for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
285       found = mark_cat(kid, cat_objects, mark) || found;
286
287     if (found)
288       br->setTraversalMaskBits(SSGTRAV_HOT);
289     
290   } else if (e->isAKindOf(ssgTypeLeaf())) {
291     list<string>::const_iterator it;
292     for (it = cat_objects.begin(); it != cat_objects.end(); ++it) {
293       if (mark || (e->getName() && (*it) == e->getName())) {
294         e->setTraversalMaskBits(SSGTRAV_HOT);
295         ssgBase* ud = e->getUserData();
296         if (ud) {
297           FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
298           if (ch) {
299             SG_LOG(SG_GENERAL, SG_WARN,
300                    "AICarrier: Carrier hardware gets marked twice!\n"
301                    "You have probably a whole branch marked as"
302                    "a catapult which also includes other carrier hardware."
303                     );
304           } else {
305             SG_LOG(SG_GENERAL, SG_ALERT,
306                    "AICarrier: Found user data attached to a leaf node which "
307                    "should be marked as a catapult!\n    ****Skipping!****");
308           }
309         } else {
310           e->setUserData( FGAICarrierHardware::newCatapult( this ) );
311           ssgLeaf *l = (ssgLeaf*)e;
312           if ( l->getNumLines() != 1 ) {
313             SG_LOG(SG_GENERAL, SG_ALERT,
314                    "AICarrier: Found a cat not modelled with exactly "
315                    "one line!");
316           } else {
317             // Now some special code to make sure the cat points in the right
318             // direction. The 0 index must be the backward end, the 1 index
319             // the forward end.
320             // Forward is positive x-direction in our 3D model, also the model
321             // as such is flattened when it is loaded, so we do not need to
322             // care for transforms ...
323             short v[2];
324             l->getLine(0, v, v+1 );
325             sgVec3 ends[2];
326             for (int k=0; k<2; ++k)
327               sgCopyVec3( ends[k], l->getVertex( v[k] ) );
328             
329             // When the 1 end is behind the 0 end, swap the coordinates.
330             if (ends[0][0] < ends[1][0]) {
331               sgCopyVec3( l->getVertex( v[0] ), ends[1] );
332               sgCopyVec3( l->getVertex( v[1] ), ends[0] );
333             }
334
335             found = true;
336           }
337         }
338       }
339     }
340   }
341   return found;
342 }
343
344 void FGAICarrier::UpdateFlols( double dt) {
345     
346     float trans[3][3];
347     float in[3];
348     float out[3];
349
350     float cosRx, sinRx;
351     float cosRy, sinRy;
352     float cosRz, sinRz;
353         
354     double flolsXYZ[3], eyeXYZ[3]; 
355     double lat, lon, alt;
356     Point3D eyepos;
357     Point3D flolspos;   
358
359 /*    cout << "x_offset " << flols_x_offset 
360           << " y_offset " << flols_y_offset 
361           << " z_offset " << flols_z_offset << endl;
362         
363      cout << "roll " << roll 
364           << " heading " << hdg
365           << " pitch " << pitch << endl;
366         
367      cout << "carrier lon " << pos[0] 
368           << " lat " <<  pos[1]
369           << " alt " << pos[2] << endl;*/
370         
371 // set the Flols intitial position to the carrier position
372  
373   flolspos = pos;
374   
375 /*  cout << "flols lon " << flolspos[0] 
376           << " lat " <<  flolspos[1]
377           << " alt " << flolspos[2] << endl;*/
378           
379 // set the offsets in metres
380
381 /*  cout << "flols_x_offset " << flols_x_offset << endl
382        << "flols_y_offset " << flols_y_offset << endl
383        << "flols_z_offset " << flols_z_offset << endl;*/
384      
385   in[0] = flols_off.x();  
386   in[1] = flols_off.y();
387   in[2] = flols_off.z();    
388
389 // pre-process the trig functions
390
391     cosRx = cos(roll * SG_DEGREES_TO_RADIANS);
392     sinRx = sin(roll * SG_DEGREES_TO_RADIANS);
393     cosRy = cos(pitch * SG_DEGREES_TO_RADIANS);
394     sinRy = sin(pitch * SG_DEGREES_TO_RADIANS);
395     cosRz = cos(hdg * SG_DEGREES_TO_RADIANS);
396     sinRz = sin(hdg * SG_DEGREES_TO_RADIANS);
397
398 // set up the transform matrix
399
400     trans[0][0] =  cosRy * cosRz;
401     trans[0][1] =  -1 * cosRx * sinRz + sinRx * sinRy * cosRz ;
402     trans[0][2] =  sinRx * sinRz + cosRx * sinRy * cosRz;
403
404     trans[1][0] =  cosRy * sinRz;
405     trans[1][1] =  cosRx * cosRz + sinRx * sinRy * sinRz;
406     trans[1][2] =  -1 * sinRx * cosRx + cosRx * sinRy * sinRz;
407
408     trans[2][0] =  -1 * sinRy;
409     trans[2][1] =  sinRx * cosRy;
410     trans[2][2] =  cosRx * cosRy;
411
412 // multiply the input and transform matrices
413
414    out[0] = in[0] * trans[0][0] + in[1] * trans[0][1] + in[2] * trans[0][2];
415    out[1] = in[0] * trans[1][0] + in[1] * trans[1][1] + in[2] * trans[1][2];
416    out[2] = in[0] * trans[2][0] + in[1] * trans[2][1] + in[2] * trans[2][2];
417  
418 // convert meters to ft to degrees of latitude
419    out[0] = (out[0] * 3.28083989501) /(366468.96 - 3717.12 * cos(flolspos[0] * SG_DEGREES_TO_RADIANS));
420
421 // convert meters to ft to degrees of longitude
422    out[1] = (out[1] * 3.28083989501)/(365228.16 * cos(flolspos[1] * SG_DEGREES_TO_RADIANS));
423
424 //print out the result
425 /*   cout  << "lat adjust deg" << out[0] 
426         << " lon adjust deg " << out[1] 
427         << " alt adjust m " << out[2]  << endl;*/
428
429 // adjust Flols position    
430    flolspos[0] += out[0];
431    flolspos[1] += out[1];
432    flolspos[2] += out[2];   
433
434 // convert flols position to cartesian co-ordinates 
435
436   sgGeodToCart(flolspos[1] * SG_DEGREES_TO_RADIANS,
437                flolspos[0] * SG_DEGREES_TO_RADIANS,
438                flolspos[2] , flolsXYZ );
439
440
441 /*  cout << "flols X " << flolsXYZ[0] 
442        << " Y " <<  flolsXYZ[1]
443        << " Z " << flolsXYZ[2] << endl; 
444
445 // check the conversion
446          
447   sgCartToGeod(flolsXYZ, &lat, &lon, &alt);
448  
449   cout << "flols check lon " << lon   
450         << " lat " << lat 
451         << " alt " << alt << endl;      */
452                
453 //get the current position of the pilot's eyepoint (cartesian cordinates)
454
455   sgdCopyVec3( eyeXYZ, globals->get_current_view()->get_absolute_view_pos() );
456   
457  /* cout  << "Eye_X "  << eyeXYZ[0] 
458         << " Eye_Y " << eyeXYZ[1] 
459         << " Eye_Z " << eyeXYZ[2]  << endl; */
460         
461   sgCartToGeod(eyeXYZ, &lat, &lon, &alt);
462   
463   eyepos[0] = lon * SG_RADIANS_TO_DEGREES;
464   eyepos[1] = lat * SG_RADIANS_TO_DEGREES;
465   eyepos[2] = alt;
466   
467 /*  cout << "eye lon " << eyepos[0]
468         << " eye lat " << eyepos[1] 
469         << " eye alt " << eyepos[2] << endl; */
470
471 //calculate the ditance from eye to flols
472       
473   dist = sgdDistanceVec3( flolsXYZ, eyeXYZ );
474
475 //apply an index error
476
477   dist -= 100;
478   
479   //cout << "distance " << dist << endl; 
480   
481   if ( dist < 5000 ) {
482        // calculate height above FLOLS 
483        double y = eyepos[2] - flolspos[2];
484        
485        // calculate the angle from the flols to eye
486        // above the horizontal
487        // double angle;
488        
489        if ( dist != 0 ) {
490            angle = asin( y / dist );
491          } else {
492            angle = 0.0;
493          }
494         
495        angle *= SG_RADIANS_TO_DEGREES;
496         
497       
498   // cout << " height " << y << " angle " << angle ;
499
500 // set the value of source  
501         
502        if ( angle <= 4.35 && angle > 4.01 )
503          { source = 1; }
504          else if ( angle <= 4.01 && angle > 3.670 )
505          { source = 2; }
506          else if ( angle <= 3.670 && angle > 3.330 )
507          { source = 3; }
508          else if ( angle <= 3.330 && angle > 2.990 )
509          { source = 4; }
510          else if ( angle <= 2.990 && angle > 2.650 )
511          { source = 5; }
512          else if ( angle <= 2.650  )
513          { source = 6; }
514          else
515          { source = 0; }
516          
517 //         cout << " source " << source << endl;
518                      
519    }   
520 } // end updateflols
521
522 int FGAICarrierHardware::unique_id = 1;