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.
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.
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.
21 #include <cstring> // for strcmp
22 #include <boost/foreach.hpp>
24 #include "dynamicloader.hxx"
26 #include <Navaids/NavDataCache.hxx>
27 #include <Airports/dynamics.hxx>
28 #include <Airports/airport.hxx>
30 /*****************************************************************************
31 * Helper function for parsing position string
32 ****************************************************************************/
33 static double processPosition(const string &pos)
42 prefix= subs.substr(0,1);
43 if (prefix == string("S") || (prefix == string("W")))
45 subs = subs.substr(1, subs.length());
46 degree = subs.substr(0, subs.find(" ",0));
47 decimal = subs.substr(subs.find(" ",0), subs.length());
49 value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0);
53 FGAirportDynamicsXMLLoader::FGAirportDynamicsXMLLoader(FGAirportDynamics* dyn):
54 XMLVisitor(), _dynamics(dyn)
57 void FGAirportDynamicsXMLLoader::startXML () {
58 //cout << "FGAirportDynamicsLoader::Start XML" << endl;
61 void FGAirportDynamicsXMLLoader::endXML ()
63 std::map<PositionedID, int>::iterator it;
64 flightgear::NavDataCache* cache = flightgear::NavDataCache::instance();
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_NAVAID, SG_WARN, "bad groundnet, no node for index:" << it->first);
73 cache->setParkingPushBackRoute(it->first, j->second);
76 BOOST_FOREACH(PositionedID id, _unreferencedNodes) {
77 SG_LOG(SG_NAVAID, SG_WARN, "unreferenced groundnet node:" << id);
82 void FGAirportDynamicsXMLLoader::startParking(const XMLAttributes &atts)
86 string gateName, gateNumber;
91 int pushBackRoute = 0;
93 for (int i = 0; i < atts.size(); i++)
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());
116 else if (attname == "airlineCodes")
117 airlineCodes = atts.getValue(i);
118 else if (attname == "pushBackRoute") {
119 pushBackRoute = std::atoi(atts.getValue(i));
123 SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
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;
132 _idMap[index] = guid;
135 void FGAirportDynamicsXMLLoader::startNode(const XMLAttributes &atts)
139 bool onRunway = false;
140 int holdPointType = 0;
142 for (int i = 0; i < atts.size() ; i++)
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") {
157 } else if (attval=="normal") {
159 } else if (attval=="CAT II/III") {
161 } else if (attval=="PushBack") {
169 if (_idMap.find(index) != _idMap.end()) {
170 SG_LOG(SG_NAVAID, SG_WARN, "duplicate ground-net index:" << index);
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);
180 void FGAirportDynamicsXMLLoader::startArc(const XMLAttributes &atts)
182 int begin = 0, end = 0;
183 bool isPushBackRoute = false;
185 for (int i = 0; i < atts.size() ; i++)
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;
196 IntPair e(begin, end);
197 if (_arcSet.find(e) != _arcSet.end()) {
198 SG_LOG(SG_NAVAID, SG_WARN, _dynamics->parent()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
203 flightgear::NavDataCache::instance()->insertGroundnetEdge(_dynamics->parent()->guid(),
204 _idMap[begin], _idMap[end]);
206 _unreferencedNodes.erase(_idMap[begin]);
207 _unreferencedNodes.erase(_idMap[end]);
209 if (isPushBackRoute) {
210 flightgear::NavDataCache::instance()->markGroundnetAsPushback(_idMap[end]);
214 void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttributes &atts)
216 if (!strcmp("Parking", name)) {
218 } else if (!strcmp("node", name)) {
220 } else if (!strcmp("arc", name)) {
225 void FGAirportDynamicsXMLLoader::endElement (const char * name)
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);
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))
254 void FGAirportDynamicsXMLLoader::pi (const char * target, const char * data) {
255 //cout << "Processing instruction " << target << ' ' << data << endl;
258 void FGAirportDynamicsXMLLoader::warning (const char * message, int line, int column) {
259 SG_LOG(SG_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
262 void FGAirportDynamicsXMLLoader::error (const char * message, int line, int column) {
263 SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');