]> git.mxchange.org Git - flightgear.git/blob - src/ATC/AIMgr.cxx
Add David Culp's AI model manager code which is derived from David Luff's AI/ATC...
[flightgear.git] / src / ATC / AIMgr.cxx
1 // AIMgr.cxx - implementation of FGAIMgr 
2 // - a global management class for FlightGear generated AI traffic
3 //
4 // Written by David Luff, started March 2002.
5 //
6 // Copyright (C) 2002  David C Luff - david.luff@nottingham.ac.uk
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 #include <simgear/misc/sg_path.hxx>
23
24 #include <Main/fg_props.hxx>
25 #include <Main/globals.hxx>
26
27 #include <list>
28
29 #ifdef _MSC_VER
30 #  include <io.h>
31 #else
32 #  include <sys/types.h>        // for directory reading
33 #  include <dirent.h>           // for directory reading
34 #endif
35
36 #include "AIMgr.hxx"
37 #include "AILocalTraffic.hxx"
38 #include "ATCutils.hxx"
39
40 SG_USING_STD(list);
41 SG_USING_STD(cout);
42
43 FGAIMgr::FGAIMgr() {
44         ATC = globals->get_ATC_mgr();
45         initDone = false;
46 }
47
48 FGAIMgr::~FGAIMgr() {
49 }
50
51 void FGAIMgr::init() {
52         // Pointers to user's position
53         lon_node = fgGetNode("/position/longitude-deg", true);
54         lat_node = fgGetNode("/position/latitude-deg", true);
55         elev_node = fgGetNode("/position/altitude-ft", true);
56
57         lon = lon_node->getDoubleValue();
58         lat = lat_node->getDoubleValue();
59         elev = elev_node->getDoubleValue();
60         
61         // go through the $FG_ROOT/ATC directory and find all *.taxi files
62         SGPath path(globals->get_fg_root());
63         path.append("ATC/");
64         string dir = path.dir();
65     string ext;
66     string file, f_ident;
67         int pos;
68         
69         // WARNING - I (DCL) haven't tested this on MSVC - this is simply cribbed from TerraGear
70 #ifdef _MSC_VER 
71         long hfile;
72         struct _finddata_t de;
73         string path_str;
74         
75         path_str = dir + "\\*.*";
76         
77         if ( ( hfile = _findfirst( path.c_str(), &de ) ) == -1 ) {
78                 SG_LOG(SG_ATC, SG_WARN, "cannot open directory " << dir);
79         } else {                
80                 // load all .taxi files
81                 do {
82                         file = de.name;
83                         pos = file.find(".");
84                         ext = file.substr(pos + 1);
85                         if(ext == "taxi") {
86                                 f_ident = file.substr(0, pos);
87                                 FGAirport a;
88                                 if(dclFindAirportID(f_ident, &a)) {
89                                         SGBucket sgb(a.longitude, a.latitude);
90                                         int idx = sgb.gen_index();
91                                         if(airports.find(idx) != airports.end()) {
92                                                 airports[idx]->push_back(f_ident);
93                                         } else {
94                                                 aptID_list_type* apts = new aptID_list_type;
95                                                 apts->push_back(f_ident);
96                                                 airports[idx] = apts;
97                                         }
98                                         SG_LOG(SG_ATC, SG_BULK, "Mapping " << f_ident << " to bucket " << idx); 
99                                 }
100                         }
101                 } while ( _findnext( hfile, &de ) == 0 );
102         }
103 #else
104
105     DIR *d;
106     struct dirent *de;
107
108     if ( (d = opendir( dir.c_str() )) == NULL ) {
109                 SG_LOG(SG_ATC, SG_WARN, "cannot open directory " << dir);
110         } else {
111                 // load all .taxi files
112                 while ( (de = readdir(d)) != NULL ) {
113                         file = de->d_name;
114                         pos = file.find(".");
115                         ext = file.substr(pos + 1);
116                         if(ext == "taxi") {
117                                 f_ident = file.substr(0, pos);
118                                 FGAirport a;
119                                 if(dclFindAirportID(f_ident, &a)) {
120                                         SGBucket sgb(a.longitude, a.latitude);
121                                         int idx = sgb.gen_index();
122                                         if(airports.find(idx) != airports.end()) {
123                                                 airports[idx]->push_back(f_ident);
124                                         } else {
125                                                 aptID_list_type* apts = new aptID_list_type;
126                                                 apts->push_back(f_ident);
127                                                 airports[idx] = apts;
128                                         }
129                                         SG_LOG(SG_ATC, SG_BULK, "Mapping " << f_ident << " to bucket " << idx);
130                                 }
131                         }
132                 }               
133                 closedir(d);
134         }
135 #endif
136         
137         // See if are in range at startup and activate if necessary
138         SearchByPos(10.0);
139         
140         initDone = true;
141 }
142
143 void FGAIMgr::bind() {
144 }
145
146 void FGAIMgr::unbind() {
147 }
148
149 void FGAIMgr::update(double dt) {
150         if(!initDone) {
151                 init();
152                 SG_LOG(SG_ATC, SG_WARN, "Warning - AIMgr::update(...) called before AIMgr::init()");
153         }
154         
155         static int i = 0;
156         static int j = 0;
157
158         // Don't update any planes for first 50 runs through - this avoids some possible initialisation anomalies
159         // Might not need it now we have fade-in though?
160         if(i < 50) {
161                 ++i;
162                 return;
163         }
164         
165         if(j == 215) {
166                 SearchByPos(15.0);
167                 j = 0;
168         }
169         
170         ++j;
171         
172         // TODO - need to add a check of if any activated airports have gone out of range
173         
174         // Traverse the list of active planes and run all their update methods
175         // TODO - spread the load - not all planes should need updating every frame.
176         // Note that this will require dt to be calculated for each plane though
177         // since they rely on it to calculate distance travelled.
178         ai_list_itr = ai_list.begin();
179         while(ai_list_itr != ai_list.end()) {
180                 (*ai_list_itr)->Update(dt);
181                 ++ai_list_itr;
182         }
183 }
184
185
186 // Activate AI traffic at an airport
187 void FGAIMgr::ActivateAirport(string ident) {
188         ATC->AIRegisterAirport(ident);
189         // TODO - need to start the traffic more randomly
190         FGAILocalTraffic* local_traffic = new FGAILocalTraffic;
191         //local_traffic->Init(ident, IN_PATTERN, TAKEOFF_ROLL);
192         local_traffic->Init(ident);
193         local_traffic->FlyCircuits(1, true);    // Fly 2 circuits with touch & go in between
194         ai_list.push_back(local_traffic);
195         activated[ident] = 1;
196 }       
197
198
199 // Search for valid airports in the vicinity of the user and activate them if necessary
200 void FGAIMgr::SearchByPos(double range)
201 {
202         //cout << "In SearchByPos(...)" << endl;
203         
204         // get bucket number for plane position
205         lon = lon_node->getDoubleValue();
206         lat = lat_node->getDoubleValue();
207         SGBucket buck(lon, lat);
208
209         // get neigboring buckets
210         int bx = (int)( range*SG_NM_TO_METER / buck.get_width_m() / 2);
211         //cout << "bx = " << bx << endl;
212         int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 );
213         //cout << "by = " << by << endl;
214         
215         // loop over bucket range 
216         for ( int i=-bx; i<=bx; i++) {
217                 //cout << "i loop\n";
218                 for ( int j=-by; j<=by; j++) {
219                         //cout << "j loop\n";
220                         buck = sgBucketOffset(lon, lat, i, j);
221                         long int bucket = buck.gen_index();
222                         //cout << "bucket is " << bucket << endl;
223                         if(airports.find(bucket) != airports.end()) {
224                                 aptID_list_type* apts = airports[bucket];
225                                 aptID_list_iterator current = apts->begin();
226                                 aptID_list_iterator last = apts->end();
227                                 
228                                 //cout << "Size of apts is " << apts->size() << endl;
229                                 
230                                 //double rlon = lon * SGD_DEGREES_TO_RADIANS;
231                                 //double rlat = lat * SGD_DEGREES_TO_RADIANS;
232                                 //Point3D aircraft = sgGeodToCart( Point3D(rlon, rlat, elev) );
233                                 //Point3D airport;
234                                 for(; current != last; ++current) {
235                                         //cout << "Found " << *current << endl;;
236                                         if(activated.find(*current) == activated.end()) {
237                                                 //cout << "Activating " << *current << endl;
238                                                 //FGAirport a;
239                                                 //if(dclFindAirportID(*current, &a)) {
240                                                         //      // We can do something here based on distance from the user if we wish.
241                                                 //}
242                                                 ActivateAirport(*current);
243                                                 //cout << "Activation done" << endl;
244                                         } else {
245                                                 //cout << *current << " already activated" << endl;
246                                         }
247                                 }
248                         }
249                 }
250         }
251 }