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