Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netimport/NIXMLPTHandler.cpp
193735 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4
// This program and the accompanying materials are made available under the
5
// terms of the Eclipse Public License 2.0 which is available at
6
// https://www.eclipse.org/legal/epl-2.0/
7
// This Source Code may also be made available under the following Secondary
8
// Licenses when the conditions for such availability set forth in the Eclipse
9
// Public License 2.0 are satisfied: GNU General Public License, version 2
10
// or later which is available at
11
// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
/****************************************************************************/
14
/// @file NIXMLPTHandler.cpp
15
/// @author Jakob Erdmann
16
/// @date Sat, 28 Jul 2018
17
///
18
// Importer for static public transport information
19
/****************************************************************************/
20
#include <config.h>
21
22
#include <string>
23
#include <iostream>
24
#include <map>
25
#include <cmath>
26
#include <utils/xml/SUMOSAXHandler.h>
27
#include <utils/xml/SUMOXMLDefinitions.h>
28
#include <utils/common/MsgHandler.h>
29
#include <utils/common/StringUtils.h>
30
#include <utils/common/StringTokenizer.h>
31
#include <utils/geom/GeomConvHelper.h>
32
#include <utils/common/ToString.h>
33
#include <utils/options/OptionsCont.h>
34
#include <utils/geom/GeoConvHelper.h>
35
#include <netbuild/NBNodeCont.h>
36
#include <netbuild/NBTypeCont.h>
37
#include <netbuild/NBNetBuilder.h>
38
#include <netbuild/NBPTStop.h>
39
#include "NIImporter_OpenStreetMap.h"
40
#include "NIXMLNodesHandler.h"
41
#include "NIXMLPTHandler.h"
42
43
44
// ===========================================================================
45
// method definitions
46
// ===========================================================================
47
NIXMLPTHandler::NIXMLPTHandler(NBEdgeCont& ec, NBPTStopCont& sc, NBPTLineCont& lc) :
48
SUMOSAXHandler("public transport - file"),
49
myEdgeCont(ec),
50
myStopCont(sc),
51
myLineCont(lc),
52
myCurrentStop(nullptr),
53
myCurrentLine(nullptr),
54
myCurrentCompletion(0),
55
myCurrentStopWasIgnored(false)
56
{ }
57
58
59
NIXMLPTHandler::~NIXMLPTHandler() {}
60
61
62
void
63
NIXMLPTHandler::myStartElement(int element,
64
const SUMOSAXAttributes& attrs) {
65
switch (element) {
66
case SUMO_TAG_BUS_STOP:
67
case SUMO_TAG_TRAIN_STOP:
68
case SUMO_TAG_STOP:
69
if (myCurrentRouteID != "") {
70
addRouteStop(attrs);
71
} else if (myCurrentLine == nullptr) {
72
addPTStop(element, attrs);
73
} else {
74
addPTLineStop(attrs);
75
}
76
break;
77
case SUMO_TAG_ACCESS:
78
addAccess(attrs);
79
break;
80
case SUMO_TAG_PT_LINE:
81
addPTLine(attrs);
82
break;
83
case SUMO_TAG_ROUTE:
84
if (myCurrentLine == nullptr) {
85
addRoute(attrs);
86
} else {
87
addPTLineRoute(attrs);
88
}
89
break;
90
case SUMO_TAG_FLOW:
91
case SUMO_TAG_TRIP:
92
addPTLineFromFlow(attrs);
93
break;
94
case SUMO_TAG_PARAM: {
95
bool ok = true;
96
const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
97
if (myCurrentLine != nullptr) {
98
if (key == "completeness") {
99
myCurrentCompletion = attrs.get<double>(SUMO_ATTR_VALUE, nullptr, ok);
100
} else if (key == "name") {
101
myCurrentLine->setName(attrs.get<std::string>(SUMO_ATTR_VALUE, nullptr, ok));
102
} else if (key == "missingBefore") {
103
myMissingBefore = attrs.get<int>(SUMO_ATTR_VALUE, nullptr, ok);
104
} else if (key == "missingAfter") {
105
myMissingAfter = attrs.get<int>(SUMO_ATTR_VALUE, nullptr, ok);
106
}
107
} else if (myCurrentStop != nullptr) {
108
const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
109
myCurrentStop->setParameter(key, val);
110
}
111
}
112
break;
113
default:
114
break;
115
}
116
}
117
118
void
119
NIXMLPTHandler::myEndElement(int element) {
120
switch (element) {
121
case SUMO_TAG_BUS_STOP:
122
case SUMO_TAG_TRAIN_STOP:
123
myCurrentStop = nullptr;
124
myCurrentStopWasIgnored = false;
125
break;
126
case SUMO_TAG_PT_LINE:
127
case SUMO_TAG_FLOW:
128
case SUMO_TAG_TRIP:
129
if (myCurrentLine != nullptr) {
130
myCurrentLine->setNumOfStops((int)((double)myCurrentLine->getStops().size() / myCurrentCompletion), myMissingBefore, myMissingAfter);
131
}
132
myCurrentLine = nullptr;
133
break;
134
case SUMO_TAG_ROUTE:
135
myCurrentRouteID = "";
136
break;
137
default:
138
break;
139
}
140
}
141
142
143
void
144
NIXMLPTHandler::addPTStop(int element, const SUMOSAXAttributes& attrs) {
145
bool ok = true;
146
const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, "busStop", ok);
147
const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
148
const std::string laneID = attrs.get<std::string>(SUMO_ATTR_LANE, id.c_str(), ok);
149
double startPos = attrs.get<double>(SUMO_ATTR_STARTPOS, id.c_str(), ok);
150
double endPos = attrs.get<double>(SUMO_ATTR_ENDPOS, id.c_str(), ok);
151
const double parkingLength = attrs.getOpt<double>(SUMO_ATTR_PARKING_LENGTH, id.c_str(), ok, 0);
152
const RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor(false));
153
const std::string lines = attrs.getOpt<std::string>(SUMO_ATTR_LINES, id.c_str(), ok, "");
154
const int laneIndex = NBEdge::getLaneIndexFromLaneID(laneID);
155
std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(laneID);
156
NBEdge* edge = myEdgeCont.retrieve(edgeID);
157
if (edge == nullptr) {
158
edge = myEdgeCont.retrieve(edgeID, true);
159
if (edge != nullptr && myEdgeCont.getSplit(edge) == nullptr) {
160
// splits are treated later
161
edge = nullptr;
162
}
163
}
164
if (edge == nullptr) {
165
if (!myEdgeCont.wasIgnored(edgeID)) {
166
WRITE_ERRORF(TL("Edge '%' for stop '%' not found"), edgeID, id);
167
} else {
168
myCurrentStopWasIgnored = true;
169
NBPTStopCont::addIgnored(id);
170
}
171
return;
172
}
173
if (edge->getNumLanes() <= laneIndex) {
174
WRITE_ERRORF(TL("Lane '%' for stop '%' not found"), laneID, id);
175
return;
176
}
177
SVCPermissions permissions = edge->getPermissions(laneIndex);
178
// possibly the stops were written for a different network. If the lane is not a typical public transport stop lane, assume bus as the default
179
if (!isRailway(permissions) && permissions != SVC_SHIP && permissions != SVC_TAXI) {
180
permissions = SVC_BUS;
181
}
182
if (ok) {
183
if (startPos < 0) {
184
startPos += edge->getLoadedLength();
185
}
186
if (endPos < 0) {
187
endPos += edge->getLoadedLength();
188
}
189
if (myEdgeCont.wasRemoved(edgeID) && (
190
startPos >= endPos || startPos < 0 || endPos < 0
191
|| startPos >= edge->getLoadedLength()
192
|| endPos >= edge->getLoadedLength())) {
193
NBEdge* longest = myEdgeCont.getSplitBase(edgeID);
194
if (longest != nullptr) {
195
edge = longest;
196
}
197
}
198
Position pos = edge->geometryPositionAtOffset((startPos + endPos) / 2);
199
myCurrentStop = std::make_shared<NBPTStop>((SumoXMLTag)element, id, pos, edgeID, edgeID, endPos - startPos, name, permissions, parkingLength, color, startPos);
200
while (myEdgeCont.getSplit(edge) != nullptr) {
201
myCurrentStop->resetLoaded();
202
const std::pair<NBEdge*, NBEdge*> split = *myEdgeCont.getSplit(edge);
203
if (myCurrentStop->replaceEdge(edgeID, {split.first, split.second})) {
204
edge = split.first->getID() == myCurrentStop->getEdgeId() ? split.first : split.second;
205
edgeID = edge->getID();
206
}
207
}
208
for (const std::string& line : StringTokenizer(lines).getVector()) {
209
myCurrentStop->addLine(line);
210
}
211
if (!myStopCont.insert(myCurrentStop)) {
212
WRITE_ERRORF(TL("Could not add public transport stop '%' (already exists)"), id);
213
}
214
}
215
}
216
217
void
218
NIXMLPTHandler::addAccess(const SUMOSAXAttributes& attrs) {
219
if (myCurrentStop == nullptr) {
220
if (myCurrentStopWasIgnored) {
221
return;
222
} else {
223
throw InvalidArgument("Could not add access outside a stopping place.");
224
}
225
}
226
bool ok = true;
227
const std::string laneID = attrs.get<std::string>(SUMO_ATTR_LANE, "access", ok);
228
const std::string edgeID = SUMOXMLDefinitions::getEdgeIDFromLane(laneID);
229
if (myEdgeCont.retrieve(edgeID) == nullptr) {
230
if (!myEdgeCont.wasIgnored(edgeID)) {
231
WRITE_ERRORF(TL("Edge '%' for access to stop '%' not found"), edgeID, myCurrentStop->getID());
232
}
233
return;
234
}
235
const double pos = attrs.get<double>(SUMO_ATTR_POSITION, "access", ok);
236
const double length = attrs.getOpt<double>(SUMO_ATTR_LENGTH, "access", ok, -1);
237
if (ok) {
238
myCurrentStop->addAccess(laneID, pos, length);
239
}
240
}
241
242
243
void
244
NIXMLPTHandler::addPTLine(const SUMOSAXAttributes& attrs) {
245
bool ok = true;
246
const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, "ptLine", ok);
247
const std::string name = attrs.getOpt<std::string>(SUMO_ATTR_NAME, id.c_str(), ok, "");
248
const std::string line = attrs.getOpt<std::string>(SUMO_ATTR_LINE, id.c_str(), ok, "");
249
const std::string type = attrs.getOpt<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok, "");
250
SUMOVehicleClass vClass = NIImporter_OpenStreetMap::interpretTransportType(type);
251
if (attrs.hasAttribute(SUMO_ATTR_VCLASS)) {
252
vClass = getVehicleClassID(attrs.get<std::string>(SUMO_ATTR_VCLASS, id.c_str(), ok));
253
}
254
RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor(false));
255
const int intervalS = attrs.getOpt<int>(SUMO_ATTR_PERIOD, id.c_str(), ok, -1);
256
const std::string nightService = attrs.getStringSecure("nightService", "");
257
myCurrentCompletion = StringUtils::toDouble(attrs.getStringSecure("completeness", "1"));
258
myMissingBefore = StringUtils::toInt(attrs.getStringSecure("missingBefore", "0"));
259
myMissingAfter = StringUtils::toInt(attrs.getStringSecure("missingAfter", "0"));
260
if (ok) {
261
// patching existing line?
262
myCurrentLine = myLineCont.retrieve(id);
263
if (myCurrentLine == nullptr) {
264
myCurrentLine = new NBPTLine(id, name, type, line, intervalS / 60, nightService, vClass, color);
265
myLineCont.insert(myCurrentLine);
266
} else {
267
WRITE_MESSAGEF(TL("Duplicate ptLine id occurred ('%'); assuming overwriting is wished."), id);
268
if (name != "") {
269
myCurrentLine->setName(name);
270
}
271
if (line != "") {
272
myCurrentLine->setRef(line);
273
}
274
if (intervalS != -1) {
275
myCurrentLine->setPeriod(intervalS);
276
}
277
}
278
}
279
}
280
281
282
void
283
NIXMLPTHandler::addPTLineFromFlow(const SUMOSAXAttributes& attrs) {
284
bool ok = true;
285
myMissingBefore = 0;
286
myMissingAfter = 0;
287
const std::string id = attrs.get<std::string>(SUMO_ATTR_ID, "flow", ok);
288
const std::string line = attrs.get<std::string>(SUMO_ATTR_LINE, id.c_str(), ok);
289
const std::string type = attrs.get<std::string>(SUMO_ATTR_TYPE, id.c_str(), ok);
290
const std::string route = attrs.get<std::string>(SUMO_ATTR_ROUTE, id.c_str(), ok);
291
SUMOVehicleClass vClass = NIImporter_OpenStreetMap::interpretTransportType(type);
292
const int intervalS = attrs.getOpt<int>(SUMO_ATTR_PERIOD, id.c_str(), ok, -1);
293
RGBColor color = attrs.getOpt<RGBColor>(SUMO_ATTR_COLOR, id.c_str(), ok, RGBColor(false));
294
if (ok) {
295
myCurrentLine = new NBPTLine(id, "", type, line, intervalS / 60, "", vClass, color);
296
myCurrentLine->setEdges(myRouteEdges[route]);
297
for (std::shared_ptr<NBPTStop> stop : myRouteStops[route]) {
298
myCurrentLine->addPTStop(stop);
299
}
300
myLineCont.insert(myCurrentLine);
301
}
302
}
303
304
305
void
306
NIXMLPTHandler::addPTLineRoute(const SUMOSAXAttributes& attrs) {
307
if (myCurrentLine == nullptr) {
308
WRITE_ERROR(TL("Found route outside line definition"));
309
return;
310
}
311
bool ok = true;
312
const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, nullptr, ok);
313
EdgeVector edges;
314
for (const std::string& edgeID : edgeIDs) {
315
NBEdge* edge = myEdgeCont.retrieve(edgeID);
316
if (edge == nullptr) {
317
if (!myEdgeCont.wasIgnored(edgeID)) {
318
WRITE_ERRORF(TL("Edge '%' in route of line '%' not found"), edgeID, myCurrentLine->getName());
319
}
320
} else {
321
edges.push_back(edge);
322
}
323
}
324
myCurrentLine->setEdges(edges);
325
}
326
327
328
void
329
NIXMLPTHandler::addRoute(const SUMOSAXAttributes& attrs) {
330
bool ok = true;
331
myCurrentRouteID = attrs.get<std::string>(SUMO_ATTR_ID, "route", ok);
332
const std::vector<std::string>& edgeIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_EDGES, myCurrentRouteID.c_str(), ok);
333
EdgeVector edges;
334
for (const std::string& edgeID : edgeIDs) {
335
NBEdge* edge = myEdgeCont.retrieve(edgeID);
336
if (edge == nullptr) {
337
if (!myEdgeCont.wasIgnored(edgeID)) {
338
WRITE_ERRORF(TL("Edge '%' in route of line '%' not found"), edgeID, myCurrentLine->getName());
339
}
340
} else {
341
edges.push_back(edge);
342
}
343
}
344
myRouteEdges[myCurrentRouteID] = edges;
345
}
346
347
348
void
349
NIXMLPTHandler::addPTLineStop(const SUMOSAXAttributes& attrs) {
350
bool ok = true;
351
const std::string id = attrs.hasAttribute(SUMO_ATTR_ID)
352
? attrs.get<std::string>(SUMO_ATTR_ID, "ptLine", ok)
353
: attrs.get<std::string>(SUMO_ATTR_BUS_STOP, "ptline", ok);
354
std::shared_ptr<NBPTStop> stop = myStopCont.get(id);
355
if (stop == nullptr) {
356
if (!NBPTStopCont::wasIgnored(id)) {
357
WRITE_ERRORF(TL("Stop '%' within line '%' not found"), id, toString(myCurrentLine->getLineID()));
358
}
359
return;
360
}
361
myCurrentLine->addPTStop(stop);
362
}
363
364
void
365
NIXMLPTHandler::addRouteStop(const SUMOSAXAttributes& attrs) {
366
assert(myCurrentRouteID != "");
367
bool ok = true;
368
const std::string id = attrs.hasAttribute(SUMO_ATTR_ID)
369
? attrs.get<std::string>(SUMO_ATTR_ID, "ptLine", ok)
370
: attrs.get<std::string>(SUMO_ATTR_BUS_STOP, "ptline", ok);
371
std::shared_ptr<NBPTStop> stop = myStopCont.get(id);
372
if (stop == nullptr) {
373
WRITE_ERRORF(TL("Stop '%' within route '%' not found"), id, toString(myCurrentRouteID));
374
return;
375
}
376
myRouteStops[myCurrentRouteID].push_back(stop);
377
}
378
379
380
/****************************************************************************/
381
382