Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/netload/NLEdgeControlBuilder.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 NLEdgeControlBuilder.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Jakob Erdmann
17
/// @author Michael Behrisch
18
/// @author Leonhard Luecken
19
/// @date Mon, 9 Jul 2001
20
///
21
// Interface for building edges
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <vector>
26
#include <string>
27
#include <map>
28
#include <algorithm>
29
#include <iterator>
30
#include <mesosim/MELoop.h>
31
#include <microsim/MSGlobals.h>
32
#include <microsim/MSLane.h>
33
#include <microsim/MSEdge.h>
34
#include <microsim/MSEdgeControl.h>
35
#include <utils/common/StringTokenizer.h>
36
#include <utils/common/UtilExceptions.h>
37
#include <utils/options/OptionsCont.h>
38
#include "NLBuilder.h"
39
#include "NLEdgeControlBuilder.h"
40
#include <utils/iodevices/OutputDevice.h>
41
42
43
// ===========================================================================
44
// method definitions
45
// ===========================================================================
46
NLEdgeControlBuilder::NLEdgeControlBuilder()
47
: myCurrentNumericalLaneID(0), myCurrentNumericalEdgeID(0), myEdges(0), myCurrentLaneIndex(-1) {
48
myActiveEdge = (MSEdge*) nullptr;
49
myLaneStorage = new std::vector<MSLane*>();
50
}
51
52
53
NLEdgeControlBuilder::~NLEdgeControlBuilder() {
54
delete myLaneStorage;
55
}
56
57
58
void
59
NLEdgeControlBuilder::beginEdgeParsing(
60
const std::string& id, const SumoXMLEdgeFunc function,
61
const std::string& streetName,
62
const std::string& edgeType,
63
int priority,
64
const std::string& bidi,
65
double distance) {
66
// closeEdge might not have been called because the last edge had an error, so we clear the lane storage
67
myLaneStorage->clear();
68
myActiveEdge = buildEdge(id, function, streetName, edgeType, priority, distance);
69
if (MSEdge::dictionary(id) != nullptr) {
70
throw InvalidArgument("Another edge with the id '" + id + "' exists.");
71
}
72
myEdges.push_back(myActiveEdge);
73
if (bidi != "") {
74
myBidiEdges[myActiveEdge] = bidi;
75
}
76
}
77
78
79
MSLane*
80
NLEdgeControlBuilder::addLane(const std::string& id,
81
double maxSpeed, double friction, double length,
82
const PositionVector& shape, double width,
83
SVCPermissions permissions,
84
SVCPermissions changeLeft, SVCPermissions changeRight,
85
int index, bool isRampAccel,
86
const std::string& type,
87
const PositionVector& outlineShape) {
88
MSLane* lane = new MSLane(id, maxSpeed, friction, length, myActiveEdge, myCurrentNumericalLaneID++, shape, width, permissions, changeLeft, changeRight, index, isRampAccel, type, outlineShape);
89
myLaneStorage->push_back(lane);
90
myCurrentLaneIndex = index;
91
return lane;
92
}
93
94
95
void
96
NLEdgeControlBuilder::addStopOffsets(const StopOffset& stopOffset) {
97
if (myCurrentLaneIndex == -1) {
98
setDefaultStopOffset(stopOffset);
99
} else {
100
updateCurrentLaneStopOffset(stopOffset);
101
}
102
}
103
104
105
std::string
106
NLEdgeControlBuilder::reportCurrentEdgeOrLane() const {
107
std::stringstream ss;
108
if (myCurrentLaneIndex != -1) {
109
ss << "lane " << myCurrentLaneIndex << " of ";
110
}
111
ss << "edge '" << myActiveEdge->getID() << "'";
112
return ss.str();
113
}
114
115
116
void
117
NLEdgeControlBuilder::updateCurrentLaneStopOffset(const StopOffset& stopOffset) {
118
if (myLaneStorage->size() == 0) {
119
throw ProcessError("myLaneStorage cannot be empty");
120
}
121
if (stopOffset.isDefined()) {
122
if (myLaneStorage->back()->getLaneStopOffsets().isDefined()) {
123
WRITE_WARNING("Duplicate stopOffset definition for lane " + toString(myLaneStorage->back()->getIndex()) +
124
" on edge " + myActiveEdge->getID() + "!")
125
} else {
126
myLaneStorage->back()->setLaneStopOffset(stopOffset);
127
}
128
}
129
}
130
131
132
void
133
NLEdgeControlBuilder::setDefaultStopOffset(const StopOffset& stopOffsets) {
134
if (myCurrentDefaultStopOffset.isDefined()) {
135
WRITE_WARNING("Duplicate stopOffset definition for edge " + myActiveEdge->getID() + ". Ignoring duplicate specification.")
136
} else {
137
myCurrentDefaultStopOffset = stopOffsets;
138
}
139
}
140
141
142
void
143
NLEdgeControlBuilder::applyDefaultStopOffsetsToLanes() {
144
if (myActiveEdge == nullptr) {
145
throw ProcessError("myActiveEdge cannot be nullptr");
146
}
147
if (myCurrentDefaultStopOffset.isDefined()) {
148
for (const auto& l : *myLaneStorage) {
149
if (!l->getLaneStopOffsets().isDefined()) {
150
l->setLaneStopOffset(myCurrentDefaultStopOffset);
151
}
152
}
153
}
154
}
155
156
157
void
158
NLEdgeControlBuilder::addNeigh(const std::string id) {
159
myOppositeLanes.push_back({myLaneStorage->back(), id});
160
}
161
162
163
MSEdge*
164
NLEdgeControlBuilder::closeEdge() {
165
applyDefaultStopOffsetsToLanes();
166
std::vector<MSLane*>* lanes = new std::vector<MSLane*>();
167
lanes->reserve(myLaneStorage->size());
168
copy(myLaneStorage->begin(), myLaneStorage->end(), back_inserter(*lanes));
169
myLaneStorage->clear();
170
myActiveEdge->initialize(lanes);
171
myCurrentDefaultStopOffset.reset();
172
return myActiveEdge;
173
}
174
175
176
void
177
NLEdgeControlBuilder::closeLane() {
178
myCurrentLaneIndex = -1;
179
}
180
181
182
MSEdgeControl*
183
NLEdgeControlBuilder::build(const MMVersion& networkVersion) {
184
if (MSGlobals::gUseMesoSim && !OptionsCont::getOptions().getBool("meso-lane-queue")) {
185
MSEdge::setMesoIgnoredVClasses(parseVehicleClasses(OptionsCont::getOptions().getStringVector("meso-ignore-lanes-by-vclass")));
186
}
187
// connecting opposite lanes must happen before MSEdge::closeBuilding
188
for (auto item : myOppositeLanes) {
189
MSLane* oppo = MSLane::dictionary(item.second);
190
if (oppo == nullptr) {
191
WRITE_ERRORF("Unknown neigh lane '%' for lane '%'", item.second, item.first->getID());
192
} else {
193
item.first->setOpposite(oppo);
194
}
195
}
196
// consistency check
197
std::set<const MSLane*> checked;
198
for (auto item : myOppositeLanes) {
199
if (item.first->getOpposite() != nullptr) {
200
if (item.first->getOpposite()->getOpposite() != item.first) {
201
if (checked.count(item.first->getOpposite()) == 0) {
202
WRITE_WARNINGF(TL("Asymmetrical neigh lane '%' for lane '%'"), item.second, item.first->getID());
203
item.first->getOpposite()->setOpposite(item.first);
204
} else {
205
throw ProcessError(TLF("Mutually inconsistent neigh lane definitions for lanes '%', '%' and '%'",
206
item.first->getID(), item.first->getOpposite()->getID(), Named::getIDSecure(item.first->getOpposite()->getOpposite())));
207
}
208
}
209
checked.insert(item.first);
210
checked.insert(item.first->getOpposite());
211
}
212
}
213
for (MSEdge* const edge : myEdges) {
214
edge->closeBuilding();
215
}
216
for (MSEdge* const edge : myEdges) {
217
edge->rebuildAllowedTargets(false);
218
// segment building depends on the finished list of successors (for multi-queue)
219
if (MSGlobals::gUseMesoSim && !edge->getLanes().empty()) {
220
MSGlobals::gMesoNet->buildSegmentsFor(*edge, OptionsCont::getOptions());
221
}
222
}
223
// mark internal edges belonging to a roundabout (after all edges are build)
224
if (MSGlobals::gUsingInternalLanes) {
225
for (MSEdge* const edge : myEdges) {
226
if (edge->isInternal()) {
227
if (edge->getNumSuccessors() != 1 || edge->getNumPredecessors() != 1) {
228
throw ProcessError(TLF("Internal edge '%' is not properly connected (probably a manually modified net.xml).", edge->getID()));
229
}
230
if (edge->getSuccessors()[0]->isRoundabout() || edge->getPredecessors()[0]->isRoundabout()) {
231
edge->markAsRoundabout();
232
}
233
}
234
}
235
}
236
if (!deprecatedVehicleClassesSeen.empty()) {
237
WRITE_WARNINGF(TL("Deprecated vehicle classes '%' in input network."), toString(deprecatedVehicleClassesSeen));
238
deprecatedVehicleClassesSeen.clear();
239
}
240
// check for bi-directional edges (this are edges in opposing direction and superposable/congruent shapes)
241
if (myBidiEdges.size() > 0 || networkVersion > MMVersion(1, 0)) {
242
for (auto& item : myBidiEdges) {
243
item.first->checkAndRegisterBiDirEdge(item.second);
244
}
245
//WRITE_MESSAGEF(TL("Loaded % bidirectional edges"), toString(myBidiEdges.size()));
246
} else {
247
// legacy network
248
for (MSEdge* e : myEdges) {
249
e->checkAndRegisterBiDirEdge();
250
}
251
}
252
// take into account bidi lanes when deciding on whether an edge allows changing
253
for (MSEdge* const edge : myEdges) {
254
edge->buildLaneChanger();
255
}
256
return new MSEdgeControl(myEdges);
257
}
258
259
260
MSEdge*
261
NLEdgeControlBuilder::buildEdge(const std::string& id, const SumoXMLEdgeFunc function,
262
const std::string& streetName, const std::string& edgeType, const int priority, const double distance) {
263
return new MSEdge(id, myCurrentNumericalEdgeID++, function, streetName, edgeType, priority, distance);
264
}
265
266
void NLEdgeControlBuilder::addCrossingEdges(const std::vector<std::string>& crossingEdges) {
267
myActiveEdge->setCrossingEdges(crossingEdges);
268
}
269
270
271
/****************************************************************************/
272
273