Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netbuild/NBPTLine.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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 NBPTLine.cpp
15
/// @author Gregor Laemmel
16
/// @author Nikita Cherednychek
17
/// @date Tue, 20 Mar 2017
18
///
19
// The representation of one direction of a single pt line
20
/****************************************************************************/
21
#include <utils/iodevices/OutputDevice.h>
22
23
#include <utility>
24
#include <utils/common/ToString.h>
25
#include <utils/common/StringUtils.h>
26
#include <utils/common/MsgHandler.h>
27
#include "NBEdge.h"
28
#include "NBEdgeCont.h"
29
#include "NBPTStop.h"
30
#include "NBPTStopCont.h"
31
#include "NBPTLine.h"
32
33
34
// ===========================================================================
35
// method definitions
36
// ===========================================================================
37
NBPTLine::NBPTLine(const std::string& id, const std::string& name, const std::string& type, const std::string& ref, int interval, const std::string& nightService,
38
SUMOVehicleClass vClass, RGBColor color) :
39
myName(name),
40
myType(type),
41
myPTLineId(id),
42
myRef(ref != "" ? ref : name),
43
myColor(color),
44
myInterval(interval),
45
myNightService(nightService),
46
myVClass(vClass),
47
myNumOfStops(0),
48
myMissingStopsBefore(0),
49
myMissingStopsAfter(0)
50
{ }
51
52
53
void
54
NBPTLine::addPTStop(std::shared_ptr<NBPTStop> pStop) {
55
if (!myPTStops.empty() && pStop->getName() != "" && myPTStops.back()->getName() == pStop->getName()) {
56
// avoid duplicate stop when both platform and stop_position are given as nodes
57
if (myPTStops.back()->isPlatform() && !pStop->isPlatform()) {
58
myPTStops.pop_back();
59
} else if (pStop->isPlatform()) {
60
return;
61
}
62
}
63
myPTStops.push_back(pStop);
64
}
65
66
67
const std::vector<std::shared_ptr<NBPTStop> >&
68
NBPTLine::getStops() {
69
return myPTStops;
70
}
71
72
73
void
74
NBPTLine::write(OutputDevice& device) {
75
device.openTag(SUMO_TAG_PT_LINE);
76
device.writeAttr(SUMO_ATTR_ID, myPTLineId);
77
if (!myName.empty()) {
78
device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myName));
79
}
80
81
device.writeAttr(SUMO_ATTR_LINE, StringUtils::escapeXML(myRef));
82
device.writeAttr(SUMO_ATTR_TYPE, myType);
83
device.writeAttr(SUMO_ATTR_VCLASS, toString(myVClass));
84
if (myInterval > 0) {
85
// write seconds
86
device.writeAttr(SUMO_ATTR_PERIOD, 60 * myInterval);
87
}
88
if (myNightService != "") {
89
device.writeAttr("nightService", myNightService);
90
}
91
92
if (myColor.isValid()) {
93
device.writeAttr(SUMO_ATTR_COLOR, myColor);
94
}
95
device.writeAttr("completeness", (double)myPTStops.size() / myNumOfStops);
96
if (myMissingStopsBefore != 0) {
97
device.writeAttr("missingBefore", myMissingStopsBefore);
98
}
99
if (myMissingStopsAfter != 0) {
100
device.writeAttr("missingAfter", myMissingStopsAfter);
101
}
102
103
if (!myRoute.empty()) {
104
device.openTag(SUMO_TAG_ROUTE);
105
device.writeAttr(SUMO_ATTR_EDGES, myRoute);
106
device.closeTag();
107
}
108
109
for (auto& myPTStop : myPTStops) {
110
device.openTag(SUMO_TAG_BUS_STOP);
111
device.writeAttr(SUMO_ATTR_ID, myPTStop->getID());
112
device.writeAttr(SUMO_ATTR_NAME, StringUtils::escapeXML(myPTStop->getName()));
113
device.closeTag();
114
}
115
device.closeTag();
116
117
}
118
119
120
void
121
NBPTLine::addWayNode(long long int way, long long int node) {
122
std::string wayStr = toString(way);
123
if (wayStr != myCurrentWay) {
124
myCurrentWay = wayStr;
125
myWays.push_back(wayStr);
126
}
127
myWayNodes[wayStr].push_back(node);
128
}
129
130
131
const std::vector<long long int>*
132
NBPTLine::getWayNodes(std::string wayId) {
133
if (myWayNodes.find(wayId) != myWayNodes.end()) {
134
return &myWayNodes[wayId];
135
}
136
return nullptr;
137
}
138
139
140
void
141
NBPTLine::setEdges(const std::vector<NBEdge*>& edges) {
142
myRoute = edges;
143
// ensure permissions
144
for (NBEdge* e : edges) {
145
SVCPermissions permissions = e->getPermissions();
146
if ((permissions & myVClass) != myVClass) {
147
SVCPermissions nVuln = ~(SVC_PEDESTRIAN | SVC_BICYCLE);
148
if (permissions != 0 && (permissions & nVuln) == 0) {
149
// this is a footpath or sidewalk. Add another lane
150
e->addRestrictedLane(SUMO_const_laneWidth, myVClass);
151
} else {
152
// add permissions to the rightmost lane that is not exclusively used for pedestrians / bicycles
153
for (int i = 0; i < (int)e->getNumLanes(); i++) {
154
if ((e->getPermissions(i) & nVuln) != 0) {
155
e->allowVehicleClass(i, myVClass);
156
break;
157
}
158
}
159
}
160
}
161
}
162
}
163
164
165
void
166
NBPTLine::setNumOfStops(int numStops, int missingBefore, int missingAfter) {
167
myNumOfStops = numStops;
168
myMissingStopsBefore = missingBefore;
169
myMissingStopsAfter = missingAfter;
170
}
171
172
173
const std::vector<NBEdge*>&
174
NBPTLine::getRoute() const {
175
return myRoute;
176
}
177
178
179
std::vector<std::pair<NBEdge*, std::string> >
180
NBPTLine::getStopEdges(const NBEdgeCont& ec) const {
181
std::vector<std::pair<NBEdge*, std::string> > result;
182
for (std::shared_ptr<NBPTStop> stop : myPTStops) {
183
NBEdge* e = ec.retrieve(stop->getEdgeId());
184
if (e != nullptr) {
185
result.push_back({e, stop->getID()});
186
}
187
}
188
return result;
189
}
190
191
192
NBEdge*
193
NBPTLine::getRouteStart(const NBEdgeCont& ec) const {
194
std::vector<NBEdge*> validEdges;
195
// filter out edges that have been removed due to joining junctions
196
for (NBEdge* e : myRoute) {
197
if (ec.retrieve(e->getID())) {
198
validEdges.push_back(e);
199
}
200
}
201
if (validEdges.size() == 0) {
202
return nullptr;
203
}
204
// filter out edges after the first stop
205
if (myPTStops.size() > 0) {
206
NBEdge* firstStopEdge = ec.retrieve(myPTStops.front()->getEdgeId());
207
if (firstStopEdge == nullptr) {
208
WRITE_WARNINGF(TL("Could not retrieve edge '%' for first stop of line '%'."), myPTStops.front()->getEdgeId(), myPTLineId);
209
return nullptr;
210
211
}
212
auto it = std::find(validEdges.begin(), validEdges.end(), firstStopEdge);
213
if (it == validEdges.end()) {
214
WRITE_WARNINGF(TL("First stop edge '%' is not part of the route of line '%'."), firstStopEdge->getID(), myPTLineId);
215
return nullptr;
216
}
217
}
218
return validEdges.front();
219
}
220
221
222
NBEdge*
223
NBPTLine::getRouteEnd(const NBEdgeCont& ec) const {
224
std::vector<NBEdge*> validEdges;
225
// filter out edges that have been removed due to joining junctions
226
for (NBEdge* e : myRoute) {
227
if (ec.retrieve(e->getID())) {
228
validEdges.push_back(e);
229
}
230
}
231
if (validEdges.size() == 0) {
232
return nullptr;
233
}
234
// filter out edges after the last stop
235
if (myPTStops.size() > 0) {
236
NBEdge* lastStopEdge = ec.retrieve(myPTStops.back()->getEdgeId());
237
if (lastStopEdge == nullptr) {
238
WRITE_WARNINGF(TL("Could not retrieve edge '%' for last stop of line '%'."), myPTStops.back()->getEdgeId(), myPTLineId);
239
return nullptr;
240
241
}
242
auto it = std::find(validEdges.begin(), validEdges.end(), lastStopEdge);
243
if (it == validEdges.end()) {
244
WRITE_WARNINGF(TL("Last stop edge '%' is not part of the route of line '%'."), lastStopEdge->getID(), myPTLineId);
245
return nullptr;
246
}
247
}
248
return validEdges.back();
249
}
250
251
252
bool
253
NBPTLine::isConsistent(std::vector<NBEdge*> stops) const {
254
if (myRoute.empty() || stops.empty()) {
255
return true;
256
}
257
if (stops.size() > 1 && stops.front() == stops.back()) {
258
// circular route where we don't expect the route edges to occur twice
259
if (myRoute.front() == stops.front()) {
260
stops.pop_back();
261
} else if (myRoute.back() == stops.back()) {
262
stops.erase(stops.begin());
263
}
264
}
265
std::vector<NBEdge*>::const_iterator stopIt = stops.begin();
266
for (const NBEdge* const e : myRoute) {
267
while (stopIt != stops.end() && e == *stopIt) {
268
++stopIt;
269
}
270
if (stopIt == stops.end()) {
271
return true;
272
}
273
}
274
return false;
275
}
276
277
278
void
279
NBPTLine::replaceStop(std::shared_ptr<NBPTStop> oldStop, std::shared_ptr<NBPTStop> newStop) {
280
for (int i = 0; i < (int)myPTStops.size(); i++) {
281
if (myPTStops[i] == oldStop) {
282
myPTStops[i] = newStop;
283
}
284
}
285
}
286
287
288
void
289
NBPTLine::replaceEdge(const std::string& edgeID, const EdgeVector& replacement) {
290
EdgeVector oldRoute = myRoute;
291
myRoute.clear();
292
for (NBEdge* e : oldRoute) {
293
if (e->getID() == edgeID) {
294
for (NBEdge* e2 : replacement) {
295
if (myRoute.empty() || myRoute.back() != e2) {
296
myRoute.push_back(e2);
297
}
298
}
299
} else {
300
myRoute.push_back(e);
301
}
302
}
303
}
304
305
306
void
307
NBPTLine::deleteInvalidStops(const NBEdgeCont& ec, const NBPTStopCont& sc) {
308
// delete stops that are missing or have no edge
309
for (auto it = myPTStops.begin(); it != myPTStops.end();) {
310
std::shared_ptr<NBPTStop> stop = *it;
311
if (sc.get(stop->getID()) == nullptr ||
312
ec.getByID(stop->getEdgeId()) == nullptr) {
313
WRITE_WARNINGF(TL("Removed invalid stop '%' from line '%'."), stop->getID(), getLineID());
314
it = myPTStops.erase(it);
315
} else {
316
it++;
317
}
318
319
}
320
}
321
322
323
void
324
NBPTLine::deleteDuplicateStops() {
325
// delete subsequent stops that belong to the same stopArea
326
long long int lastAreaID = -1;
327
std::string lastName = "";
328
for (auto it = myPTStops.begin(); it != myPTStops.end();) {
329
std::shared_ptr<NBPTStop> stop = *it;
330
if (lastAreaID != -1 && stop->getAreaID() == lastAreaID) {
331
WRITE_WARNINGF(TL("Removed duplicate stop '%' at area '%' from line '%'."), stop->getID(), toString(lastAreaID), getLineID());
332
it = myPTStops.erase(it);
333
} else if (lastName != "" && stop->getName() == lastName) {
334
WRITE_WARNINGF(TL("Removed duplicate stop '%' named '%' from line '%'."), stop->getID(), lastName, getLineID());
335
it = myPTStops.erase(it);
336
} else {
337
it++;
338
}
339
lastAreaID = stop->getAreaID();
340
lastName = stop->getName();
341
}
342
}
343
344
345
void
346
NBPTLine::removeInvalidEdges(const NBEdgeCont& ec) {
347
for (int i = 0; i < (int)myRoute.size();) {
348
const std::pair<NBEdge*, NBEdge*>* split = ec.getSplit(myRoute[i]);
349
if (split != nullptr) {
350
myRoute[i] = split->first;
351
myRoute.insert(myRoute.begin() + i + 1, split->second);
352
} else if (ec.retrieve(myRoute[i]->getID()) == nullptr) {
353
myRoute.erase(myRoute.begin() + i);
354
} else {
355
i++;
356
}
357
}
358
}
359
360
361
/****************************************************************************/
362
363