FlightGear next
dynamicloader.cxx
Go to the documentation of this file.
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 <string>
21#include <cstdlib>
22#include <cstring> // for strcmp
23
24#include "dynamicloader.hxx"
25
27#include <Airports/airport.hxx>
28#include <Airports/dynamics.hxx>
30#include <simgear/misc/strutils.hxx>
31#include <simgear/debug/logstream.hxx>
32#include <simgear/structure/exception.hxx>
33
34using std::string;
35
36/*****************************************************************************
37 * Helper function for parsing position string
38 ****************************************************************************/
39static double processPosition(const string &pos)
40{
41 string subs{pos};
42 int sign = 1;
43 const auto prefix = subs.substr(0, 1);
44 if (prefix == "S" || (prefix == "W"))
45 sign = -1;
46 subs = subs.substr(1, subs.length()); // drop first character
47 const auto spacePos = subs.find(" ", 0);
48 const auto degree = subs.substr(0, spacePos);
49 const auto decimal = subs.substr(spacePos, subs.length());
50
51 return sign * (stoi(degree) + (stof(decimal) / 60.0));
52}
53
55 XMLVisitor(),
56 _groundNetwork(net)
57{}
58
60 //cout << "FGAirportDynamicsLoader::Start XML" << endl;
61}
62
64{
65 ParkingPushbackIndex::const_iterator it;
66
67 for (it = _parkingPushbacks.begin(); it != _parkingPushbacks.end(); ++it) {
68 NodeIndexMap::const_iterator j = _indexMap.find(it->second);
69 if (j == _indexMap.end()) {
70 _hasErrors = true;
71 SG_LOG(SG_NAVAID, SG_DEV_WARN, "bad groundnet " << _groundNetwork->airport()->getId() << " , no node for index:" << it->first.get()->getIndex());
72 continue;
73 }
74
75 it->first->setPushBackPoint(j->second);
76
77 }
78
79 if (!_unreferencedNodes.empty()) {
80 _hasErrors = true;
81 }
82
83 for (const FGTaxiNodeRef& node: _unreferencedNodes) {
84 SG_LOG(SG_NAVAID, SG_DEV_WARN,
85 "unreferenced groundnet node: " << node->getIndex());
86 }
87
88}
89
90void FGGroundNetXMLLoader::startParking(const XMLAttributes &atts)
91{
92 string type;
93 int index = 0;
94 string gateName, gateNumber;
95 string lat, lon;
96 double heading = 0.0;
97 double radius = 1.0;
98 string airlineCodes;
99 int pushBackRoute = -1; // signals unseen attribute
100
101 savePosition(); // allows to retrieve the line number
102
103 for (int i = 0; i < atts.size(); i++)
104 {
105 string attname(atts.getName(i));
106 if (attname == "index") {
107 index = std::atoi(atts.getValue(i));
108 } else if (attname == "type")
109 type = atts.getValue(i);
110 else if (attname == "name")
111 gateName = atts.getValue(i);
112 else if (attname == "number")
113 gateNumber = atts.getValue(i);
114 else if (attname == "lat")
115 lat = atts.getValue(i);
116 else if (attname == "lon")
117 lon = atts.getValue(i);
118 else if (attname == "heading")
119 heading = std::atof(atts.getValue(i));
120 else if (attname == "radius") {
121 string radiusStr = atts.getValue(i);
122 if (radiusStr.find("M") != string::npos)
123 radiusStr = radiusStr.substr(0, radiusStr.find("M",0));
124 radius = std::atof(radiusStr.c_str());
125 }
126 else if (attname == "airlineCodes")
127 airlineCodes = atts.getValue(i);
128 else if (attname == "pushBackRoute") {
129 const string attrVal = atts.getValue(i);
130 try {
131 if (attrVal.empty() || (attrVal == "None")) {
132 pushBackRoute = -2;
133 } else {
134 pushBackRoute = simgear::strutils::readNonNegativeInt<int>(attrVal);
135 }
136 } catch (const sg_exception& e) {
137 SG_LOG(SG_NAVAID, SG_DEV_WARN,
138 getPath() << ":" << getLine() << ": " <<
139 "invalid value for 'pushBackRoute': " << e.what());
140 _hasErrors = true;
141 pushBackRoute = -2;
142 }
143 }
144 }
145
146 SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
147
148 FGParkingRef parking(new FGParking(index,
149 pos, heading, radius,
150 gateName + gateNumber,
151 type, airlineCodes));
152 if (pushBackRoute >= 0) {
153 _parkingPushbacks[parking] = pushBackRoute;
154 }
155
156 _indexMap[index] = parking;
157 _groundNetwork->addParking(parking);
158}
159
160void FGGroundNetXMLLoader::startNode(const XMLAttributes &atts)
161{
162 int index = 0;
163 string lat, lon;
164 bool onRunway = false;
165 int holdPointType = 0;
166
167 for (int i = 0; i < atts.size() ; i++)
168 {
169 string attname(atts.getName(i));
170 if (attname == "index")
171 index = std::atoi(atts.getValue(i));
172 else if (attname == "lat")
173 lat = atts.getValue(i);
174 else if (attname == "lon")
175 lon = atts.getValue(i);
176 else if (attname == "isOnRunway")
177 onRunway = std::atoi(atts.getValue(i)) != 0;
178 else if (attname == "holdPointType") {
179 string attval = atts.getValue(i);
180 if (attval=="none") {
181 holdPointType=0;
182 } else if (attval=="normal") {
183 holdPointType=1;
184 } else if (attval=="CAT II/III") {
185 holdPointType=3;
186 } else if (attval=="PushBack") {
187 holdPointType=3;
188 } else {
189 holdPointType=0;
190 }
191 }
192 }
193
194 if (_indexMap.find(index) != _indexMap.end()) {
195 SG_LOG(SG_NAVAID, SG_DEV_WARN, "duplicate ground-net index:" << index);
196 _hasErrors = true;
197 }
198
199 SGGeod pos(SGGeod::fromDeg(processPosition(lon), processPosition(lat)));
200 FGTaxiNodeRef node(new FGTaxiNode(FGPositioned::TAXI_NODE, index, pos, onRunway, holdPointType));
201 _indexMap[index] = node;
202 _unreferencedNodes.insert(node);
203}
204
205void FGGroundNetXMLLoader::startArc(const XMLAttributes &atts)
206{
207 int begin = 0, end = 0;
208 bool isPushBackRoute = false;
209
210 for (int i = 0; i < atts.size() ; i++)
211 {
212 string attname = atts.getName(i);
213 if (attname == "begin")
214 begin = std::atoi(atts.getValue(i));
215 else if (attname == "end")
216 end = std::atoi(atts.getValue(i));
217 else if (attname == "isPushBackRoute")
218 isPushBackRoute = std::atoi(atts.getValue(i)) != 0;
219 }
220
221 IntPair e(begin, end);
222 if (_arcSet.find(e) != _arcSet.end()) {
223 SG_LOG(SG_NAVAID, SG_DEV_WARN, _groundNetwork->airport()->ident() << " ground-net: skipping duplicate edge:" << begin << "->" << end);
224 _hasErrors = true;
225 return;
226 }
227
228 NodeIndexMap::const_iterator it;
229 FGTaxiNodeRef fromNode, toNode;
230 it = _indexMap.find(begin);
231 if (it == _indexMap.end()) {
232 SG_LOG(SG_NAVAID, SG_DEV_WARN, "ground-net: bad edge:" << begin << "->" << end << ", begin index unknown");
233 _hasErrors = true;
234 return;
235 } else {
236 _unreferencedNodes.erase(it->second);
237 fromNode = it->second;
238 }
239
240 it = _indexMap.find(end);
241 if (it == _indexMap.end()) {
242 SG_LOG(SG_NAVAID, SG_DEV_WARN, "ground-net: bad edge:" << begin << "->" << end << ", end index unknown");
243 _hasErrors = true;
244 return;
245 } else {
246 _unreferencedNodes.erase(it->second);
247 toNode = it->second;
248 }
249
250 _arcSet.insert(e);
251 _groundNetwork->addSegment(fromNode, toNode);
252 if (isPushBackRoute) {
253// toNode->setIsPushback();
254 }
255}
256
257void FGGroundNetXMLLoader::startElement (const char * name, const XMLAttributes &atts)
258{
259 if (!strcmp("Parking", name)) {
260 startParking(atts);
261 } else if (!strcmp("node", name)) {
262 startNode(atts);
263 } else if (!strcmp("arc", name)) {
264 startArc(atts);
265 }
266}
267
269{
270 int valueAsInt = atoi(value.c_str());
271 if (!strcmp("version", name)) {
272 _groundNetwork->addVersion(valueAsInt);
273 } else if (!strcmp("AWOS", name)) {
274 _groundNetwork->addAwosFreq(valueAsInt);
275 } else if (!strcmp("UNICOM", name)) {
276 _groundNetwork->addUnicomFreq(valueAsInt);
277 } else if (!strcmp("CLEARANCE", name)) {
278 _groundNetwork->addClearanceFreq(valueAsInt);
279 } else if (!strcmp("GROUND", name)) {
280 _groundNetwork->addGroundFreq(valueAsInt);
281 } else if (!strcmp("TOWER", name)) {
282 _groundNetwork->addTowerFreq(valueAsInt);
283 } else if (!strcmp("APPROACH", name)) {
284 _groundNetwork->addApproachFreq(valueAsInt);
285 }
286}
287
288void FGGroundNetXMLLoader::data (const char * s, int len) {
289 string token = string(s,len);
290 //cout << "Character data " << string(s,len) << endl;
291 if ((token.find(" ") == string::npos && (token.find('\n')) == string::npos))
292 value += token;
293 else
294 value = string("");
295}
296
297void FGGroundNetXMLLoader::pi (const char * target, const char * data) {
298 //cout << "Processing instruction " << target << ' ' << data << endl;
299}
300
301void FGGroundNetXMLLoader::warning (const char * message, int line, int column) {
302 SG_LOG(SG_IO, SG_DEV_WARN, "Warning: " << message << " (" << line << ',' << column << ')');
303}
304
305void FGGroundNetXMLLoader::error (const char * message, int line, int column) {
306 SG_LOG(SG_IO, SG_DEV_ALERT, "Error: " << message << " (" << line << ',' << column << ')');
307}
#define i(x)
SGSharedPtr< FGTaxiNode > FGTaxiNodeRef
SGSharedPtr< FGParking > FGParkingRef
virtual void endXML()
virtual void startElement(const char *name, const XMLAttributes &atts)
virtual void warning(const char *message, int line, int column)
virtual void data(const char *s, int len)
FGGroundNetXMLLoader(FGGroundNetwork *gn)
virtual void startXML()
virtual void error(const char *message, int line, int column)
virtual void endElement(const char *name)
virtual void pi(const char *target, const char *data)
static double processPosition(const string &pos)
const char * name
static int atoi(const string &str)
Definition options.cxx:113