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>
29 #include <Airports/groundnetwork.hxx>
33 /*****************************************************************************
34 * Helper function for parsing position string
35 ****************************************************************************/
36 static double processPosition(const string &pos)
45 prefix= subs.substr(0,1);
46 if (prefix == string("S") || (prefix == string("W")))
48 subs = subs.substr(1, subs.length());
49 degree = subs.substr(0, subs.find(" ",0));
50 decimal = subs.substr(subs.find(" ",0), subs.length());
52 value = sign * (atof(degree.c_str()) + atof(decimal.c_str())/60.0);
56 FGAirportDynamicsXMLLoader::FGAirportDynamicsXMLLoader(FGAirportDynamics* dyn):
57 XMLVisitor(), _dynamics(dyn)
60 void FGAirportDynamicsXMLLoader::startXML () {
61 //cout << "FGAirportDynamicsLoader::Start XML" << endl;
64 void FGAirportDynamicsXMLLoader::endXML ()
66 ParkingPushbackIndex::const_iterator it;
68 for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
69 NodeIndexMap::const_iterator j = _indexMap.find(it->second);
70 if (j == _indexMap.end()) {
71 SG_LOG(SG_NAVAID, SG_WARN, "bad groundnet, no node for index:" << it->first);
75 it->first->setPushBackPoint(j->second);
79 BOOST_FOREACH(FGTaxiNodeRef node, _unreferencedNodes) {
80 SG_LOG(SG_NAVAID, SG_WARN, "unreferenced groundnet node:" << node->ident());
85 void FGAirportDynamicsXMLLoader::startParking(const XMLAttributes &atts)
89 string gateName, gateNumber;
94 int pushBackRoute = 0;
96 for (int i = 0; i < atts.size(); i++)
98 string attname(atts.getName(i));
99 if (attname == "index") {
100 index = std::atoi(atts.getValue(i));
101 } else if (attname == "type")
102 type = atts.getValue(i);
103 else if (attname == "name")
104 gateName = atts.getValue(i);
105 else if (attname == "number")
106 gateNumber = atts.getValue(i);
107 else if (attname == "lat")
108 lat = atts.getValue(i);
109 else if (attname == "lon")
110 lon = atts.getValue(i);
111 else if (attname == "heading")
112 heading = std::atof(atts.getValue(i));
113 else if (attname == "radius") {
114 string radiusStr = atts.getValue(i);
115 if (radiusStr.find("M") != string::npos)
116 radiusStr = radiusStr.substr(0, radiusStr.find("M",0));
117 radius = std::atof(radiusStr.c_str());
119 else if (attname == "airlineCodes")
120 airlineCodes = atts.getValue(i);
121 else if (attname == "pushBackRoute") {
122 pushBackRoute = std::atoi(atts.getValue(i));
126 SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
128 FGParkingRef parking(new FGParking(index,
129 pos, heading, radius,
130 gateName + gateNumber,
131 type, airlineCodes));
132 if (pushBackRoute > 0) {
133 _parkingPushbacks[parking] = pushBackRoute;
136 _indexMap[index] = parking;
137 _dynamics->getGroundNetwork()->addParking(parking);
140 void FGAirportDynamicsXMLLoader::startNode(const XMLAttributes &atts)
144 bool onRunway = false;
145 int holdPointType = 0;
147 for (int i = 0; i < atts.size() ; i++)
149 string attname(atts.getName(i));
150 if (attname == "index")
151 index = std::atoi(atts.getValue(i));
152 else if (attname == "lat")
153 lat = atts.getValue(i);
154 else if (attname == "lon")
155 lon = atts.getValue(i);
156 else if (attname == "isOnRunway")
157 onRunway = std::atoi(atts.getValue(i)) != 0;
158 else if (attname == "holdPointType") {
159 string attval = atts.getValue(i);
160 if (attval=="none") {
162 } else if (attval=="normal") {
164 } else if (attval=="CAT II/III") {
166 } else if (attval=="PushBack") {
174 if (_indexMap.find(index) != _indexMap.end()) {
175 SG_LOG(SG_NAVAID, SG_WARN, "duplicate ground-net index:" << index);
178 SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
179 FGTaxiNodeRef node(new FGTaxiNode(index, pos, onRunway, holdPointType));
180 _indexMap[index] = node;
181 _unreferencedNodes.insert(node);
184 void FGAirportDynamicsXMLLoader::startArc(const XMLAttributes &atts)
186 int begin = 0, end = 0;
187 bool isPushBackRoute = false;
189 for (int i = 0; i < atts.size() ; i++)
191 string attname = atts.getName(i);
192 if (attname == "begin")
193 begin = std::atoi(atts.getValue(i));
194 else if (attname == "end")
195 end = std::atoi(atts.getValue(i));
196 else if (attname == "isPushBackRoute")
197 isPushBackRoute = std::atoi(atts.getValue(i)) != 0;
200 IntPair e(begin, end);
201 if (_arcSet.find(e) != _arcSet.end()) {
202 SG_LOG(SG_NAVAID, SG_WARN, _dynamics->parent()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
206 NodeIndexMap::const_iterator it;
207 FGTaxiNodeRef fromNode, toNode;
208 it = _indexMap.find(begin);
209 if (it == _indexMap.end()) {
210 SG_LOG(SG_NAVAID, SG_WARN, "ground-net: bad edge:" << begin << "->" << end << ", begin index unknown");
213 _unreferencedNodes.erase(it->second);
214 fromNode = it->second;
217 it = _indexMap.find(end);
218 if (it == _indexMap.end()) {
219 SG_LOG(SG_NAVAID, SG_WARN, "ground-net: bad edge:" << begin << "->" << end << ", end index unknown");
222 _unreferencedNodes.erase(it->second);
227 _dynamics->getGroundNetwork()->addSegment(fromNode, toNode);
230 void FGAirportDynamicsXMLLoader::startElement (const char * name, const XMLAttributes &atts)
232 if (!strcmp("Parking", name)) {
234 } else if (!strcmp("node", name)) {
236 } else if (!strcmp("arc", name)) {
241 void FGAirportDynamicsXMLLoader::endElement (const char * name)
243 int valueAsInt = atoi(value.c_str());
244 if (!strcmp("version", name)) {
245 _dynamics->getGroundNetwork()->addVersion(valueAsInt);
246 } else if (!strcmp("AWOS", name)) {
247 _dynamics->addAwosFreq(valueAsInt);
248 } else if (!strcmp("UNICOM", name)) {
249 _dynamics->addUnicomFreq(valueAsInt);
250 } else if (!strcmp("CLEARANCE", name)) {
251 _dynamics->addClearanceFreq(valueAsInt);
252 } else if (!strcmp("GROUND", name)) {
253 _dynamics->addGroundFreq(valueAsInt);
254 } else if (!strcmp("TOWER", name)) {
255 _dynamics->addTowerFreq(valueAsInt);
256 } else if (!strcmp("APPROACH", name)) {
257 _dynamics->addApproachFreq(valueAsInt);
261 void FGAirportDynamicsXMLLoader::data (const char * s, int len) {
262 string token = string(s,len);
263 //cout << "Character data " << string(s,len) << endl;
264 if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
270 void FGAirportDynamicsXMLLoader::pi (const char * target, const char * data) {
271 //cout << "Processing instruction " << target << ' ' << data << endl;
274 void FGAirportDynamicsXMLLoader::warning (const char * message, int line, int column) {
275 SG_LOG(SG_IO, SG_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
278 void FGAirportDynamicsXMLLoader::error (const char * message, int line, int column) {
279 SG_LOG(SG_IO, SG_ALERT, "Error: " << message << " (" << line << ',' << column << ')');