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