1
// FGAICarrier - FGAIShip-derived class creates an AI aircraft carrier
3
// Written by David Culp, started October 2004.
4
// - davidculp2@comcast.net
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.
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.
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.
27
#include <simgear/math/point3d.hxx>
28
#include <simgear/math/sg_geodesy.hxx>
30
#include <Main/util.hxx>
31
#include <Main/viewer.hxx>
33
#include "AICarrier.hxx"
36
FGAICarrier::FGAICarrier(FGAIManager* mgr) : FGAIShip(mgr) {
39
FGAICarrier::~FGAICarrier() {
42
void FGAICarrier::setSolidObjects(const list<string>& so) {
46
void FGAICarrier::setWireObjects(const list<string>& wo) {
50
void FGAICarrier::setCatapultObjects(const list<string>& co) {
51
catapult_objects = co;
54
void FGAICarrier::getVelocityWrtEarth(sgVec3 v) {
55
sgCopyVec3(v, vel_wrt_earth );
58
void FGAICarrier::update(double dt) {
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);
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,
77
bool FGAICarrier::init() {
78
if (!FGAIShip::init())
81
// process the 3d model here
82
// mark some objects solid, mark the wires ...
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
88
ssgEntity *sel = aip.getSceneGraph();
89
// Clear the HOT traversal flag
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);
99
void FGAICarrier::bind() {
102
props->tie("controls/flols/source-lights",
103
SGRawValuePointer<int>(&source));
104
props->tie("controls/flols/distance-m",
105
SGRawValuePointer<double>(&dist));
106
props->setBoolValue("controls/flols/cut-lights", false);
107
props->setBoolValue("controls/flols/wave-off-lights", false);
108
props->setBoolValue("controls/flols/cond-datum-lights", true);
111
void FGAICarrier::unbind() {
113
props->untie("controls/flols/source-lights");
116
void FGAICarrier::mark_nohot(ssgEntity* e) {
117
if (e->isAKindOf(ssgTypeBranch())) {
118
ssgBranch* br = (ssgBranch*)e;
120
for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
123
br->clrTraversalMaskBits(SSGTRAV_HOT);
125
} else if (e->isAKindOf(ssgTypeLeaf())) {
127
e->clrTraversalMaskBits(SSGTRAV_HOT);
132
bool FGAICarrier::mark_wires(ssgEntity* e, const list<string>& wire_objects, bool mark) {
134
if (e->isAKindOf(ssgTypeBranch())) {
135
ssgBranch* br = (ssgBranch*)e;
138
list<string>::const_iterator it;
139
for (it = wire_objects.begin(); it != wire_objects.end(); ++it)
140
mark = mark || (e->getName() && (*it) == e->getName());
142
for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
143
found = mark_wires(kid, wire_objects, mark) || found;
146
br->setTraversalMaskBits(SSGTRAV_HOT);
148
} else if (e->isAKindOf(ssgTypeLeaf())) {
149
list<string>::const_iterator it;
150
for (it = wire_objects.begin(); it != wire_objects.end(); ++it) {
151
if (mark || (e->getName() && (*it) == e->getName())) {
152
e->setTraversalMaskBits(SSGTRAV_HOT);
153
ssgBase* ud = e->getUserData();
155
FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
157
SG_LOG(SG_GENERAL, SG_WARN,
158
"AICarrier: Carrier hardware gets marked twice!\n"
159
" You have propably a whole branch marked as"
160
" a wire which also includes other carrier hardware."
163
SG_LOG(SG_GENERAL, SG_ALERT,
164
"AICarrier: Found user data attached to a leaf node which "
165
"should be marked as a wire!\n ****Skipping!****");
168
e->setUserData( FGAICarrierHardware::newWire( this ) );
169
ssgLeaf *l = (ssgLeaf*)e;
170
if ( l->getNumLines() != 1 ) {
171
SG_LOG(SG_GENERAL, SG_ALERT,
172
"AICarrier: Found wires not modelled with exactly one line!");
182
bool FGAICarrier::mark_solid(ssgEntity* e, const list<string>& solid_objects, bool mark) {
184
if (e->isAKindOf(ssgTypeBranch())) {
185
ssgBranch* br = (ssgBranch*)e;
188
list<string>::const_iterator it;
189
for (it = solid_objects.begin(); it != solid_objects.end(); ++it)
190
mark = mark || (e->getName() && (*it) == e->getName());
192
for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
193
found = mark_solid(kid, solid_objects, mark) || found;
196
br->setTraversalMaskBits(SSGTRAV_HOT);
198
} else if (e->isAKindOf(ssgTypeLeaf())) {
199
list<string>::const_iterator it;
200
for (it = solid_objects.begin(); it != solid_objects.end(); ++it) {
201
if (mark || (e->getName() && (*it) == e->getName())) {
202
e->setTraversalMaskBits(SSGTRAV_HOT);
203
ssgBase* ud = e->getUserData();
205
FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
207
SG_LOG(SG_GENERAL, SG_WARN,
208
"AICarrier: Carrier hardware gets marked twice!\n"
209
" You have propably a whole branch marked solid"
210
" which also includes other carrier hardware."
213
SG_LOG(SG_GENERAL, SG_ALERT,
214
"AICarrier: Found user data attached to a leaf node which "
215
"should be marked solid!\n ****Skipping!****");
218
e->setUserData( FGAICarrierHardware::newSolid( this ) );
227
bool FGAICarrier::mark_cat(ssgEntity* e, const list<string>& cat_objects, bool mark) {
229
if (e->isAKindOf(ssgTypeBranch())) {
230
ssgBranch* br = (ssgBranch*)e;
233
list<string>::const_iterator it;
234
for (it = cat_objects.begin(); it != cat_objects.end(); ++it)
235
mark = mark || (e->getName() && (*it) == e->getName());
237
for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() )
238
found = mark_cat(kid, cat_objects, mark) || found;
241
br->setTraversalMaskBits(SSGTRAV_HOT);
243
} else if (e->isAKindOf(ssgTypeLeaf())) {
244
list<string>::const_iterator it;
245
for (it = cat_objects.begin(); it != cat_objects.end(); ++it) {
246
if (mark || (e->getName() && (*it) == e->getName())) {
247
e->setTraversalMaskBits(SSGTRAV_HOT);
248
ssgBase* ud = e->getUserData();
250
FGAICarrierHardware* ch = dynamic_cast<FGAICarrierHardware*>(ud);
252
SG_LOG(SG_GENERAL, SG_WARN,
253
"AICarrier: Carrier hardware gets marked twice!\n"
254
" You have propably a whole branch marked as"
255
" a catapult which also includes other carrier hardware."
258
SG_LOG(SG_GENERAL, SG_ALERT,
259
"AICarrier: Found user data attached to a leaf node which "
260
"should be marked as a catapult!\n ****Skipping!****");
263
e->setUserData( FGAICarrierHardware::newCatapult( this ) );
264
ssgLeaf *l = (ssgLeaf*)e;
265
if ( l->getNumLines() != 1 ) {
266
SG_LOG(SG_GENERAL, SG_ALERT,
267
"AICarrier: Found a cat not modelled with exactly "
270
// Now some special code to make sure the cat points in the right
271
// direction. The 0 index must be the backward end, the 1 index
273
// Forward is positive x-direction in our 3D model, also the model
274
// as such is flattened when it is loaded, so we do not need to
275
// care for transforms ...
277
l->getLine(0, v, v+1 );
279
for (int k=0; k<2; ++k)
280
sgCopyVec3( ends[k], l->getVertex( v[k] ) );
282
// When the 1 end is behind the 0 end, swap the coordinates.
283
if (ends[0][0] < ends[1][0]) {
284
sgCopyVec3( l->getVertex( v[0] ), ends[1] );
285
sgCopyVec3( l->getVertex( v[1] ), ends[0] );
297
void FGAICarrier::UpdateFlols( double dt) {
298
/* cout << "x_offset " << flols_x_offset
299
<< " y_offset " << flols_y_offset
300
<< " z_offset " << flols_z_offset << endl;
302
cout << "roll " << roll
303
<< " heading " << hdg
304
<< " pitch " << pitch << endl;
306
cout << "carrier lon " << pos[0]
308
<< " alt " << pos[2] << endl;*/
310
// set the Flols intitial position to the carrier position
314
/* cout << "flols lon " << flolspos[0]
315
<< " lat " << flolspos[1]
316
<< " alt " << flolspos[2] << endl;*/
318
// set the offsets in metres
320
/* cout << "flols_x_offset " << flols_x_offset << endl
321
<< "flols_y_offset " << flols_y_offset << endl
322
<< "flols_z_offset " << flols_z_offset << endl;*/
324
in[0] = flols_x_offset;
325
in[1] = flols_y_offset;
326
in[2] = flols_z_offset;
328
// pre-process the trig functions
330
cosRx = cos(roll * SG_DEGREES_TO_RADIANS);
331
sinRx = sin(roll * SG_DEGREES_TO_RADIANS);
332
cosRy = cos(pitch * SG_DEGREES_TO_RADIANS);
333
sinRy = sin(pitch * SG_DEGREES_TO_RADIANS);
334
cosRz = cos(hdg * SG_DEGREES_TO_RADIANS);
335
sinRz = sin(hdg * SG_DEGREES_TO_RADIANS);
337
// set up the transform matrix
339
trans[0][0] = cosRy * cosRz;
340
trans[0][1] = -1 * cosRx * sinRz + sinRx * sinRy * cosRz ;
341
trans[0][2] = sinRx * sinRz + cosRx * sinRy * cosRz;
343
trans[1][0] = cosRy * sinRz;
344
trans[1][1] = cosRx * cosRz + sinRx * sinRy * sinRz;
345
trans[1][2] = -1 * sinRx * cosRx + cosRx * sinRy * sinRz;
347
trans[2][0] = -1 * sinRy;
348
trans[2][1] = sinRx * cosRy;
349
trans[2][2] = cosRx * cosRy;
351
// multiply the input and transform matrices
353
out[0] = in[0] * trans[0][0] + in[1] * trans[0][1] + in[2] * trans[0][2];
354
out[1] = in[0] * trans[1][0] + in[1] * trans[1][1] + in[2] * trans[1][2];
355
out[2] = in[0] * trans[2][0] + in[1] * trans[2][1] + in[2] * trans[2][2];
357
// convert meters to ft to degrees of latitude
358
out[0] = (out[0] * 3.28083989501) /(366468.96 - 3717.12 * cos(flolspos[0] * SG_DEGREES_TO_RADIANS));
360
// convert meters to ft to degrees of longitude
361
out[1] = (out[1] * 3.28083989501)/(365228.16 * cos(flolspos[1] * SG_DEGREES_TO_RADIANS));
363
//print out the result
364
/* cout << "lat adjust deg" << out[0]
365
<< " lon adjust deg " << out[1]
366
<< " alt adjust m " << out[2] << endl;*/
368
// adjust Flols position
369
flolspos[0] += out[0];
370
flolspos[1] += out[1];
371
flolspos[2] += out[2];
373
// convert flols position to cartesian co-ordinates
375
sgGeodToCart(flolspos[1] * SG_DEGREES_TO_RADIANS,
376
flolspos[0] * SG_DEGREES_TO_RADIANS,
377
flolspos[2] , flolsXYZ );
380
/* cout << "flols X " << flolsXYZ[0]
381
<< " Y " << flolsXYZ[1]
382
<< " Z " << flolsXYZ[2] << endl;
384
// check the conversion
386
sgCartToGeod(flolsXYZ, &lat, &lon, &alt);
388
cout << "flols check lon " << lon
390
<< " alt " << alt << endl; */
392
//get the current position of the pilot's eyepoint (cartesian cordinates)
394
sgdCopyVec3( eyeXYZ, globals->get_current_view()->get_absolute_view_pos() );
396
/* cout << "Eye_X " << eyeXYZ[0]
397
<< " Eye_Y " << eyeXYZ[1]
398
<< " Eye_Z " << eyeXYZ[2] << endl; */
400
sgCartToGeod(eyeXYZ, &lat, &lon, &alt);
402
eyepos[0] = lon * SG_RADIANS_TO_DEGREES;
403
eyepos[1] = lat * SG_RADIANS_TO_DEGREES;
406
/* cout << "eye lon " << eyepos[0]
407
<< " eye lat " << eyepos[1]
408
<< " eye alt " << eyepos[2] << endl; */
410
//calculate the ditance from eye to flols
412
dist = sgdDistanceVec3( flolsXYZ, eyeXYZ );
414
//cout << "distance " << dist << endl;
417
// calculate height above FLOLS
418
double y = eyepos[2] - flolspos[2];
420
// calculate the angle from the flols to eye
421
// above the horizontal
424
angle = asin( y / dist );
429
angle *= SG_RADIANS_TO_DEGREES;
432
// cout << " height " << y << " angle " << angle ;
434
// set the value of source
436
if ( angle <= 4.35 && angle > 4.01 )
438
else if ( angle <= 4.01 && angle > 3.670 )
440
else if ( angle <= 3.670 && angle > 3.330 )
442
else if ( angle <= 3.330 && angle > 2.990 )
444
else if ( angle <= 2.990 && angle > 2.650 )
446
else if ( angle <= 2.650 )
451
// cout << " source " << source << endl;
456
int FGAICarrierHardware::unique_id = 1;