FlightGear next
AIEscort.cxx
Go to the documentation of this file.
1// FGAIEscort - FGAIShip-derived class creates an AI Ground Vehicle
2// by adding a ground following utility
3//
4// Written by Vivian Meazza, started August 2009.
5// - vivian.meazza at lineone.net
6//
7// This program is free software; you can redistribute it and/or
8// modify it under the terms of the GNU General Public License as
9// published by the Free Software Foundation; either version 2 of the
10// License, or (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful, but
13// WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15// General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program; if not, write to the Free Software
19// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
24
25#include <algorithm>
26#include <string>
27#include <vector>
28
29#include <simgear/sg_inlines.h>
30#include <simgear/math/sg_geodesy.hxx>
31#include <simgear/math/sg_random.hxx>
32
33#include <cmath>
34#include <Main/util.hxx>
35#include <Main/globals.hxx>
36#include <Viewer/view.hxx>
37
38#include <Scenery/scenery.hxx>
39
40#include "AIEscort.hxx"
41
42using std::string;
43
48
49void FGAIEscort::readFromScenario(SGPropertyNode* scFileNode) {
50 if (!scFileNode)
51 return;
52
54
55 setName(scFileNode->getStringValue("name", "Escort"));
56 setSMPath(scFileNode->getStringValue("submodel-path", ""));
57 setStnRange(scFileNode->getDoubleValue("station/range-nm", 1));
58 setStnBrg(scFileNode->getDoubleValue("station/brg-deg", 0.0));
59 setStnLimit(scFileNode->getDoubleValue("station/range-limit-nm", 0.2));
60 setStnAngleLimit(scFileNode->getDoubleValue("station/angle-limit-deg", 15.0));
61 setStnSpeed(scFileNode->getDoubleValue("station/speed-kts", 2.5));
62 setStnPatrol(scFileNode->getBoolValue("station/patrol", false));
63 setStnHtFt(scFileNode->getDoubleValue("station/height-ft", 0.0));
64 setStnDegTrue(scFileNode->getBoolValue("station/deg-true", false));
65 setParentName(scFileNode->getStringValue("station/parent", ""));
66 setMaxSpeed(scFileNode->getDoubleValue("max-speed-kts", 30.0));
67 setUpdateInterval(scFileNode->getDoubleValue("update-interval-sec", 10.0));
68 setCallSign(scFileNode->getStringValue("callsign", ""));
69
70 if(_patrol)
71 sg_srandom_time();
72
73}
74
77
78 tie("station/rel-bearing-deg",
79 SGRawValuePointer<double>(&_stn_relbrg));
80 tie("station/true-bearing-deg",
81 SGRawValuePointer<double>(&_stn_truebrg));
82 tie("station/range-nm",
83 SGRawValuePointer<double>(&_stn_range));
84 tie("station/range-limit-nm",
85 SGRawValuePointer<double>(&_stn_limit));
86 tie("station/angle-limit-deg",
87 SGRawValuePointer<double>(&_stn_angle_limit));
88 tie("station/speed-kts",
89 SGRawValuePointer<double>(&_stn_speed));
90 tie("station/height-ft",
91 SGRawValuePointer<double>(&_stn_height));
92 tie("controls/update-interval-sec",
93 SGRawValuePointer<double>(&_interval));
94 tie("controls/parent-mp-control",
95 SGRawValuePointer<bool>(&_MPControl));
96 tie("station/target-range-nm",
97 SGRawValuePointer<double>(&_tgtrange));
98 tie("station/target-brg-deg-t",
99 SGRawValuePointer<double>(&_tgtbrg));
100 tie("station/patrol",
101 SGRawValuePointer<bool>(&_patrol));
102}
103
105 if (!FGAIShip::init(searchOrder))
106 return false;
107 reinit();
108 return true;
109}
110
112 invisible = false;
113 no_roll = false;
114
115 props->setStringValue("controls/parent-name", _parent.c_str());
116
117 if (setParentNode()){
118 setParent();
119 pos = _tgtpos;
120 speed = _parent_speed;
121 hdg = _parent_hdg;
122 }
123
125}
126
127void FGAIEscort::update(double dt) {
129
130 RunEscort(dt);
131}
132
133void FGAIEscort::setStnRange(double r) {
134 _stn_range = r;
135}
136
137void FGAIEscort::setStnBrg(double b) {
138 _stn_brg = b;
139}
140
141void FGAIEscort::setStnLimit(double l) {
142 _stn_limit = l;
143}
144
145void FGAIEscort::setStnAngleLimit(double al) {
146 _stn_angle_limit = al;
147}
148
149void FGAIEscort::setStnSpeed(double s) {
150 _stn_speed = s;
151}
152
153void FGAIEscort::setStnHtFt(double h) {
154 _stn_height = h;
155}
156
157void FGAIEscort::setStnDegTrue(bool t) {
158 _stn_deg_true = t;
159}
160
161void FGAIEscort::setMaxSpeed(double m) {
162 _max_speed = m;
163}
164
165void FGAIEscort::setUpdateInterval(double i) {
166 _interval = i;
167}
168
169void FGAIEscort::setStnPatrol(bool p) {
170 _patrol = p;
171}
172
173bool FGAIEscort::getGroundElev(SGGeod inpos) {
174
175 double height_m ;
176
177 const simgear::BVHMaterial* mat = 0;
178 if (globals->get_scenery()->get_elevation_m(SGGeod::fromGeodM(inpos, 3000), height_m, &mat, 0)){
179 const SGMaterial* material = dynamic_cast<const SGMaterial*>(mat);
180 _ht_agl_ft = inpos.getElevationFt() - height_m * SG_METER_TO_FEET;
181
182 if (material) {
183 const std::vector<std::string>& names = material->get_names();
184
185 _solid = material->get_solid();
186
187 if (!names.empty())
188 props->setStringValue("material/name", names[0].c_str());
189 else
190 props->setStringValue("material/name", "");
191
192 //cout << "material " << names[0].c_str()
193 // << " _elevation_m " << _elevation_m
194 // << " solid " << _solid
195 // << " load " << _load_resistance
196 // << " frictionFactor " << _frictionFactor
197 // << endl;
198
199 }
200
201 return true;
202 } else {
203 return false;
204 }
205
206}
207
208void FGAIEscort::setParent()
209{
210 double lat = _selected_ac->getDoubleValue("position/latitude-deg");
211 double lon = _selected_ac->getDoubleValue("position/longitude-deg");
212 double elevation = _selected_ac->getDoubleValue("position/altitude-ft");
213 _MPControl = _selected_ac->getBoolValue("controls/mp-control");
214
215 _selectedpos.setLatitudeDeg(lat);
216 _selectedpos.setLongitudeDeg(lon);
217 _selectedpos.setElevationFt(elevation);
218
219 _parent_speed = _selected_ac->getDoubleValue("velocities/speed-kts");
220 _parent_hdg = _selected_ac->getDoubleValue("orientation/true-heading-deg");
221
222 if(!_stn_deg_true){
223 _stn_truebrg = calcTrueBearingDeg(_stn_brg, _parent_hdg);
224 _stn_relbrg = _stn_brg;
225 //cout << _name <<" set rel"<<endl;
226 } else {
227 _stn_truebrg = _stn_brg;
228 _stn_relbrg = calcRelBearingDeg(_stn_brg, _parent_hdg);
229 //cout << _name << " set true"<<endl;
230 }
231
232 double course2;
233
234 SGGeodesy::direct( _selectedpos, _stn_truebrg, _stn_range * SG_NM_TO_METER,
235 _tgtpos, course2);
236
237 _tgtpos.setElevationFt(_stn_height);
238
239 calcRangeBearing(pos.getLatitudeDeg(), pos.getLongitudeDeg(),
240 _tgtpos.getLatitudeDeg(), _tgtpos.getLongitudeDeg(), _tgtrange, _tgtbrg);
241
242 _relbrg = calcRelBearingDeg(_tgtbrg, hdg);
243
244}
245
246void FGAIEscort::calcRangeBearing(double lat, double lon, double lat2, double lon2,
247 double &range, double &bearing) const
248{
249 // calculate the bearing and range of the second pos from the first
250 double az2, distance;
251 geo_inverse_wgs_84(lat, lon, lat2, lon2, &bearing, &az2, &distance);
252 range = distance * SG_METER_TO_NM;
253}
254
255double FGAIEscort::calcTrueBearingDeg(double bearing, double heading)
256{
257 double angle = bearing + heading;
258 SG_NORMALIZE_RANGE(angle, 0.0, 360.0);
259 return angle;
260}
261
262SGVec3d FGAIEscort::getCartHitchPosAt(const SGVec3d& _off) const {
263 double hdg = _selected_ac->getDoubleValue("orientation/true-heading-deg");
264 double pitch = _selected_ac->getDoubleValue("orientation/pitch-deg");
265 double roll = _selected_ac->getDoubleValue("orientation/roll-deg");
266
267 // Transform that one to the horizontal local coordinate system.
268 SGQuatd hlTrans = SGQuatd::fromLonLat(_selectedpos);
269
270 // and postrotate the orientation of the AIModel wrt the horizontal
271 // local frame
272 hlTrans *= SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll);
273
274 // The offset converted to the usual body fixed coordinate system
275 // rotated to the earth fiexed coordinates axis
276 SGVec3d off = hlTrans.backTransform(_off);
277
278 // Add the position offset of the AIModel to gain the earth centered position
279 SGVec3d cartPos = SGVec3d::fromGeod(_selectedpos);
280
281 return cartPos + off;
282}
283
284
285void FGAIEscort::setStationSpeed(){
286
287 double speed = 0;
288 double angle = 0;
289
290 // these are the AI rules for the manoeuvring of escorts
291
292 if (_MPControl && _tgtrange > 4.0 * _stn_limit) {
293 SG_LOG(SG_AI, SG_ALERT, "AIEscort: " << _name
294 << " re-aligning to MP pos");
295 pos = _tgtpos;
296 speed = 0.0;
297 angle = 0.0;
298 } else if ((_relbrg < -90.0 || _relbrg > 90.0) && _tgtrange > _stn_limit) {
299 angle =_relbrg;
300
301 if(_tgtrange > 4.0 * _stn_limit)
302 speed = 4.0 * -_stn_speed;
303 else
304 speed = -_stn_speed;
305
306 } else if ((_relbrg >= -90.0 && _relbrg <= 90.0) && _tgtrange > _stn_limit) {
307 angle = _relbrg;
308
309 if(_tgtrange > 4.0 * _stn_limit)
310 speed = 4.0 * _stn_speed;
311 else
312 speed = _stn_speed;
313
314 } else {
315 if (_patrol){
316 angle = 15.0 * sg_random();
317 speed = 5.0 * sg_random();
318 } else {
319 angle = 0.0;
320 speed = 0.0;
321 }
322 }
323
324 double station_speed = _parent_speed + speed;
325
326 SG_CLAMP_RANGE(station_speed, 5.0, _max_speed);
327 SG_CLAMP_RANGE(angle, -_stn_angle_limit, _stn_angle_limit);
328
329 AccelTo(station_speed);
330 TurnTo(_parent_hdg + angle);
331 ClimbTo(_stn_height);
332}
333
334void FGAIEscort::RunEscort(double dt){
335
336 _dt_count += dt;
337
338
339
341 // Check execution time (currently once every 0.05 sec or 20 fps)
342 // Add a bit of randomization to prevent the execution of all flight plans
343 // in synchrony, which can add significant periodic framerate flutter.
344 // Randomization removed to get better appearance
346
347 //cout << "_start_sec " << _start_sec << " time_sec " << time_sec << endl;
348 if (_dt_count < _next_run)
349 return;
350 _next_run = _interval /*+ (0.015 * sg_random())*/;
351
352 if(_parent == ""){
353 return;
354 }
355
356 setParent();
357 setStationSpeed();
358
359 _dt_count = 0;
360
361}
362
363// end AIEscort
#define p(x)
#define i(x)
std::string _parent
Definition AIBase.hxx:191
void setName(const std::string &n)
Definition AIBase.hxx:491
SGGeod pos
Definition AIBase.hxx:212
void setCallSign(const std::string &)
Definition AIBase.hxx:451
void setParentName(const std::string &p)
Definition AIBase.hxx:486
std::string _name
Definition AIBase.hxx:190
bool invisible
Definition AIBase.hxx:256
SGPropertyNode_ptr _selected_ac
Definition AIBase.hxx:204
double speed
Definition AIBase.hxx:216
double bearing
Definition AIBase.hxx:239
double range
Definition AIBase.hxx:241
bool setParentNode()
Definition AIBase.cxx:953
double hdg
Definition AIBase.hxx:213
double elevation
Definition AIBase.hxx:240
double _max_speed
Definition AIBase.hxx:182
void setSMPath(const std::string &p)
Definition AIBase.hxx:394
double pitch
Definition AIBase.hxx:215
ModelSearchOrder
Definition AIBase.hxx:63
double calcRelBearingDeg(double bearing, double heading)
Definition AIBase.hxx:521
double roll
Definition AIBase.hxx:214
void tie(const char *aRelPath, const SGRawValue< T > &aRawValue)
Tied-properties helper, record nodes which are tied for easy un-tie-ing.
Definition AIBase.hxx:198
SGPropertyNode_ptr props
Definition AIBase.hxx:205
bool no_roll
Definition AIBase.hxx:257
void bind() override
Definition AIEscort.cxx:75
void reinit() override
Definition AIEscort.cxx:111
bool init(ModelSearchOrder searchOrder) override
Definition AIEscort.cxx:104
void readFromScenario(SGPropertyNode *scFileNode) override
Definition AIEscort.cxx:49
void update(double dt) override
Definition AIEscort.cxx:127
void readFromScenario(SGPropertyNode *scFileNode) override
Definition AIShip.cxx:63
double _next_run
Definition AIShip.hxx:83
void ClimbTo(double altitude)
Definition AIShip.cxx:451
void update(double dt) override
Definition AIShip.cxx:199
void bind() override
Definition AIShip.cxx:124
void TurnTo(double heading)
Definition AIShip.cxx:457
void AccelTo(double speed)
Definition AIShip.cxx:431
double _dt_count
Definition AIShip.hxx:83
FGAIShip(object_type ot=object_type::otShip)
Definition AIShip.cxx:30
bool init(ModelSearchOrder searchOrder) override
Definition AIShip.cxx:92
void reinit() override
Definition AIShip.cxx:98
FGScenery * get_scenery() const
Definition globals.cxx:950
bool get_elevation_m(const SGGeod &geod, double &alt, const simgear::BVHMaterial **material, const osg::Node *butNotFrom=0)
Compute the elevation of the scenery at geodetic latitude lat, geodetic longitude lon and not higher ...
Definition scenery.cxx:527
FGGlobals * globals
Definition globals.cxx:142