]> git.mxchange.org Git - flightgear.git/blob - src/Airports/dynamicloader.cxx
Overhaul the ground-net / parking code.
[flightgear.git] / src / Airports / dynamicloader.cxx
1 // This program is free software; you can redistribute it and/or
2 // modify it under the terms of the GNU General Public License as
3 // published by the Free Software Foundation; either version 2 of the
4 // License, or (at your option) any later version.
5 //
6 // This program is distributed in the hope that it will be useful, but
7 // WITHOUT ANY WARRANTY; without even the implied warranty of
8 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9 // General Public License for more details.
10 //
11 // You should have received a copy of the GNU General Public License
12 // along with this program; if not, write to the Free Software
13 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
14 //
15
16 #ifdef HAVE_CONFIG_H
17 #  include <config.h>
18 #endif
19
20 #include <cstdlib>
21 #include <cstring> // for strcmp
22 #include <boost/foreach.hpp>
23
24 #include "dynamicloader.hxx"
25
26 #include <Navaids/NavDataCache.hxx>
27 #include <Airports/dynamics.hxx>
28 #include <Airports/simple.hxx>
29
30 /*****************************************************************************
31  * Helper function for parsing position string
32  ****************************************************************************/
33 static double processPosition(const string &pos)
34 {
35   string prefix;
36   string subs;
37   string degree;
38   string decimal;
39   int sign = 1;
40   double value;
41   subs = pos;
42   prefix= subs.substr(0,1);
43   if (prefix == string("S") || (prefix == string("W")))
44     sign = -1;
45   subs    = subs.substr(1, subs.length());
46   degree  = subs.substr(0, subs.find(" ",0));
47   decimal = subs.substr(subs.find(" ",0), subs.length());
48   
49   value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0);
50   return value;
51 }
52
53 FGAirportDynamicsXMLLoader::FGAirportDynamicsXMLLoader(FGAirportDynamics* dyn):
54     XMLVisitor(), _dynamics(dyn)
55 {}
56
57 void  FGAirportDynamicsXMLLoader::startXML () {
58   //cout << "FGAirportDynamicsLoader::Start XML" << endl;
59 }
60
61 void  FGAirportDynamicsXMLLoader::endXML ()
62 {
63   std::map<PositionedID, int>::iterator it;
64   flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
65   
66   for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
67     std::map<int, PositionedID>::iterator j = _idMap.find(it->second);
68     if (j == _idMap.end()) {
69       SG_LOG(SG_GENERAL, SG_WARN, "bad groundnet, no node for index:" << it->first);
70       continue;
71     }
72     
73     cache->setParkingPushBackRoute(it->first, j->second);
74   }
75   
76   BOOST_FOREACH(PositionedID id, _unreferencedNodes) {
77     SG_LOG(SG_GENERAL, SG_WARN, "unreferenced groundnet node:" << id);
78   }
79   
80 }
81
82 void FGAirportDynamicsXMLLoader::startParking(const XMLAttributes &atts)
83 {
84   string type;
85   int index = 0;
86   string gateName, gateNumber;
87   string lat, lon;
88   double heading = 0.0;
89   double radius = 1.0;
90   string airlineCodes;
91   int pushBackRoute = 0;
92   
93   for (int i = 0; i < atts.size(); i++)
94         {
95     string attname(atts.getName(i));
96           if (attname == "index") {
97       index = std::atoi(atts.getValue(i));
98     } else if (attname == "type")
99             type = atts.getValue(i);
100     else if (attname == "name")
101       gateName = atts.getValue(i);
102           else if (attname == "number")
103             gateNumber = atts.getValue(i);
104           else if (attname == "lat")
105       lat = atts.getValue(i);
106           else if (attname == "lon")
107             lon = atts.getValue(i);
108           else if (attname == "heading")
109             heading = std::atof(atts.getValue(i));
110           else if (attname == "radius") {
111             string radiusStr = atts.getValue(i);
112             if (radiusStr.find("M") != string::npos)
113               radiusStr = radiusStr.substr(0, radiusStr.find("M",0));
114             radius = std::atof(radiusStr.c_str());
115           }
116           else if (attname == "airlineCodes")
117       airlineCodes = atts.getValue(i);
118     else if (attname == "pushBackRoute") {
119       pushBackRoute = std::atoi(atts.getValue(i));      
120     }
121         }
122  
123   SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
124   
125   PositionedID guid = flightgear::NavDataCache::instance()->insertParking(gateName + gateNumber, pos,
126                                                       _dynamics->parent()->guid(),
127                                                       heading, radius, type, airlineCodes);
128   if (pushBackRoute > 0) {
129     _parkingPushbacks[guid] = pushBackRoute;
130   }
131   
132   _idMap[index] = guid;
133 }
134
135 void FGAirportDynamicsXMLLoader::startNode(const XMLAttributes &atts)
136 {
137   int index = 0;
138   string lat, lon;
139   bool onRunway = false;
140   int holdPointType = 0;
141   
142   for (int i = 0; i < atts.size() ; i++)
143         {
144           string attname(atts.getName(i));
145           if (attname == "index")
146             index = std::atoi(atts.getValue(i));
147           else if (attname == "lat")
148       lat = atts.getValue(i);
149           else if (attname == "lon")
150             lon = atts.getValue(i);
151     else if (attname == "isOnRunway")
152       onRunway = std::atoi(atts.getValue(i)) != 0;
153           else if (attname == "holdPointType") {
154       string attval = atts.getValue(i);
155       if (attval=="none") {
156         holdPointType=0;
157       } else if (attval=="normal") {
158         holdPointType=1;
159       } else if (attval=="CAT II/III") {
160         holdPointType=3;
161       } else if (attval=="PushBack") {
162         holdPointType=3;
163       } else {
164         holdPointType=0;
165       }
166     }
167         }
168   
169   if (_idMap.find(index) != _idMap.end()) {
170     SG_LOG(SG_GENERAL, SG_WARN, "duplicate ground-net index:" << index);
171   }
172   
173   SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
174   PositionedID guid = flightgear::NavDataCache::instance()->insertTaxiNode(pos,
175     _dynamics->parent()->guid(), holdPointType, onRunway);
176   _idMap[index] = guid;
177   _unreferencedNodes.insert(guid);
178 }
179
180 void FGAirportDynamicsXMLLoader::startArc(const XMLAttributes &atts)
181 {  
182   int begin = 0, end = 0;
183   bool isPushBackRoute = false;
184   
185   for (int i = 0; i < atts.size() ; i++)
186         {
187           string attname = atts.getName(i);
188           if (attname == "begin")
189             begin = std::atoi(atts.getValue(i));
190           else if (attname == "end")
191             end = std::atoi(atts.getValue(i));
192     else if (attname == "isPushBackRoute")
193             isPushBackRoute = std::atoi(atts.getValue(i)) != 0;
194         }
195   
196   IntPair e(begin, end);
197   if (_arcSet.find(e) != _arcSet.end()) {
198     SG_LOG(SG_GENERAL, SG_WARN, _dynamics->parent()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
199     return;
200   }
201   
202   _arcSet.insert(e);
203   flightgear::NavDataCache::instance()->insertGroundnetEdge(_dynamics->parent()->guid(),
204                                                             _idMap[begin], _idMap[end]);
205   
206   _unreferencedNodes.erase(_idMap[begin]);
207   _unreferencedNodes.erase(_idMap[end]);
208   
209   if (isPushBackRoute) {
210     flightgear::NavDataCache::instance()->markGroundnetAsPushback(_idMap[end]);
211   }
212 }
213
214 void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttributes &atts)
215 {
216   if (!strcmp("Parking", name)) {
217     startParking(atts);
218   } else if (!strcmp("node", name)) {
219     startNode(atts);
220   } else if (!strcmp("arc", name)) {
221     startArc(atts);
222   }
223 }
224
225 void  FGAirportDynamicsXMLLoader::endElement (const char * name)
226 {
227   int valueAsInt = atoi(value.c_str());
228   if (!strcmp("version", name)) {
229     _dynamics->getGroundNetwork()->addVersion(valueAsInt);
230   } else if (!strcmp("AWOS", name)) {
231     _dynamics->addAwosFreq(valueAsInt);
232   } else if (!strcmp("UNICOM", name)) {
233     _dynamics->addUnicomFreq(valueAsInt);
234   } else if (!strcmp("CLEARANCE", name)) {
235     _dynamics->addClearanceFreq(valueAsInt);
236   } else if (!strcmp("GROUND", name)) {
237     _dynamics->addGroundFreq(valueAsInt);
238   } else if (!strcmp("TOWER", name)) {
239     _dynamics->addTowerFreq(valueAsInt);
240   } else if (!strcmp("APPROACH", name)) {
241     _dynamics->addApproachFreq(valueAsInt);
242   }
243 }
244
245 void  FGAirportDynamicsXMLLoader::data (const char * s, int len) {
246   string token = string(s,len);
247   //cout << "Character data " << string(s,len) << endl;
248   if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
249     value += token;
250   else
251     value = string("");
252 }
253
254 void  FGAirportDynamicsXMLLoader::pi (const char * target, const char * data) {
255   //cout << "Processing instruction " << target << ' ' << data << endl;
256 }
257
258 void  FGAirportDynamicsXMLLoader::warning (const char * message, int line, int column) {
259   SG_LOG(SG_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
260 }
261
262 void  FGAirportDynamicsXMLLoader::error (const char * message, int line, int column) {
263   SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
264 }