Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 43238 : NLEdgeControlBuilder::NLEdgeControlBuilder()
47 43238 : : myCurrentNumericalLaneID(0), myCurrentNumericalEdgeID(0), myEdges(0), myCurrentLaneIndex(-1) {
48 43238 : myActiveEdge = (MSEdge*) nullptr;
49 43238 : myLaneStorage = new std::vector<MSLane*>();
50 43238 : }
51 :
52 :
53 43238 : NLEdgeControlBuilder::~NLEdgeControlBuilder() {
54 43238 : delete myLaneStorage;
55 86476 : }
56 :
57 :
58 : void
59 1745864 : 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 1745864 : myLaneStorage->clear();
68 1745864 : myActiveEdge = buildEdge(id, function, streetName, edgeType, priority, distance);
69 1745864 : if (MSEdge::dictionary(id) != nullptr) {
70 8 : throw InvalidArgument("Another edge with the id '" + id + "' exists.");
71 : }
72 1745860 : myEdges.push_back(myActiveEdge);
73 1745860 : if (bidi != "") {
74 25434 : myBidiEdges[myActiveEdge] = bidi;
75 : }
76 1745860 : }
77 :
78 :
79 : MSLane*
80 1815089 : 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 1815089 : MSLane* lane = new MSLane(id, maxSpeed, friction, length, myActiveEdge, myCurrentNumericalLaneID++, shape, width, permissions, changeLeft, changeRight, index, isRampAccel, type, outlineShape);
89 1815089 : myLaneStorage->push_back(lane);
90 1815089 : myCurrentLaneIndex = index;
91 1815089 : return lane;
92 : }
93 :
94 :
95 : void
96 2178 : NLEdgeControlBuilder::addStopOffsets(const StopOffset& stopOffset) {
97 2178 : if (myCurrentLaneIndex == -1) {
98 1158 : setDefaultStopOffset(stopOffset);
99 : } else {
100 1020 : updateCurrentLaneStopOffset(stopOffset);
101 : }
102 2178 : }
103 :
104 :
105 : std::string
106 0 : NLEdgeControlBuilder::reportCurrentEdgeOrLane() const {
107 0 : std::stringstream ss;
108 0 : if (myCurrentLaneIndex != -1) {
109 0 : ss << "lane " << myCurrentLaneIndex << " of ";
110 : }
111 0 : ss << "edge '" << myActiveEdge->getID() << "'";
112 0 : return ss.str();
113 0 : }
114 :
115 :
116 : void
117 1020 : NLEdgeControlBuilder::updateCurrentLaneStopOffset(const StopOffset& stopOffset) {
118 1020 : if (myLaneStorage->size() == 0) {
119 0 : throw ProcessError("myLaneStorage cannot be empty");
120 : }
121 1020 : if (stopOffset.isDefined()) {
122 1020 : if (myLaneStorage->back()->getLaneStopOffsets().isDefined()) {
123 0 : WRITE_WARNING("Duplicate stopOffset definition for lane " + toString(myLaneStorage->back()->getIndex()) +
124 : " on edge " + myActiveEdge->getID() + "!")
125 : } else {
126 1020 : myLaneStorage->back()->setLaneStopOffset(stopOffset);
127 : }
128 : }
129 1020 : }
130 :
131 :
132 : void
133 1158 : NLEdgeControlBuilder::setDefaultStopOffset(const StopOffset& stopOffsets) {
134 1158 : if (myCurrentDefaultStopOffset.isDefined()) {
135 0 : WRITE_WARNING("Duplicate stopOffset definition for edge " + myActiveEdge->getID() + ". Ignoring duplicate specification.")
136 : } else {
137 1158 : myCurrentDefaultStopOffset = stopOffsets;
138 : }
139 1158 : }
140 :
141 :
142 : void
143 1745732 : NLEdgeControlBuilder::applyDefaultStopOffsetsToLanes() {
144 1745732 : if (myActiveEdge == nullptr) {
145 0 : throw ProcessError("myActiveEdge cannot be nullptr");
146 : }
147 1745732 : if (myCurrentDefaultStopOffset.isDefined()) {
148 3118 : for (const auto& l : *myLaneStorage) {
149 1960 : if (!l->getLaneStopOffsets().isDefined()) {
150 1132 : l->setLaneStopOffset(myCurrentDefaultStopOffset);
151 : }
152 : }
153 : }
154 1745732 : }
155 :
156 :
157 : void
158 7799 : NLEdgeControlBuilder::addNeigh(const std::string id) {
159 7799 : myOppositeLanes.push_back({myLaneStorage->back(), id});
160 7799 : }
161 :
162 :
163 : MSEdge*
164 1745732 : NLEdgeControlBuilder::closeEdge() {
165 1745732 : applyDefaultStopOffsetsToLanes();
166 1745732 : std::vector<MSLane*>* lanes = new std::vector<MSLane*>();
167 1745732 : lanes->reserve(myLaneStorage->size());
168 1745732 : copy(myLaneStorage->begin(), myLaneStorage->end(), back_inserter(*lanes));
169 1745732 : myLaneStorage->clear();
170 1745732 : myActiveEdge->initialize(lanes);
171 1745732 : myCurrentDefaultStopOffset.reset();
172 1745732 : return myActiveEdge;
173 : }
174 :
175 :
176 : void
177 2183054 : NLEdgeControlBuilder::closeLane() {
178 2183054 : myCurrentLaneIndex = -1;
179 2183054 : }
180 :
181 :
182 : MSEdgeControl*
183 42811 : NLEdgeControlBuilder::build(const MMVersion& networkVersion) {
184 48273 : if (MSGlobals::gUseMesoSim && !OptionsCont::getOptions().getBool("meso-lane-queue")) {
185 10848 : MSEdge::setMesoIgnoredVClasses(parseVehicleClasses(OptionsCont::getOptions().getStringVector("meso-ignore-lanes-by-vclass")));
186 : }
187 : // connecting opposite lanes must happen before MSEdge::closeBuilding
188 50610 : for (auto item : myOppositeLanes) {
189 7799 : MSLane* oppo = MSLane::dictionary(item.second);
190 7799 : if (oppo == nullptr) {
191 0 : WRITE_ERRORF("Unknown neigh lane '%' for lane '%'", item.second, item.first->getID());
192 : } else {
193 7799 : item.first->setOpposite(oppo);
194 : }
195 : }
196 : // consistency check
197 50610 : for (auto item : myOppositeLanes) {
198 7799 : if (item.first->getOpposite() != nullptr && item.first->getOpposite()->getOpposite() != item.first) {
199 3 : WRITE_WARNINGF(TL("Asymmetrical neigh lane '%' for lane '%'"), item.second, item.first->getID());
200 1 : item.first->getOpposite()->setOpposite(item.first);
201 : }
202 : }
203 1785921 : for (MSEdge* const edge : myEdges) {
204 1743110 : edge->closeBuilding();
205 : }
206 1785921 : for (MSEdge* const edge : myEdges) {
207 1743110 : edge->rebuildAllowedTargets(false);
208 : // segment building depends on the finished list of successors (for multi-queue)
209 1743110 : if (MSGlobals::gUseMesoSim && !edge->getLanes().empty()) {
210 257885 : MSGlobals::gMesoNet->buildSegmentsFor(*edge, OptionsCont::getOptions());
211 : }
212 : }
213 : // mark internal edges belonging to a roundabout (after all edges are build)
214 42811 : if (MSGlobals::gUsingInternalLanes) {
215 1521131 : for (MSEdge* const edge : myEdges) {
216 1483821 : if (edge->isInternal()) {
217 813071 : if (edge->getNumSuccessors() != 1 || edge->getNumPredecessors() != 1) {
218 0 : throw ProcessError(TLF("Internal edge '%' is not properly connected (probably a manually modified net.xml).", edge->getID()));
219 : }
220 813071 : if (edge->getSuccessors()[0]->isRoundabout() || edge->getPredecessors()[0]->isRoundabout()) {
221 : edge->markAsRoundabout();
222 : }
223 : }
224 : }
225 : }
226 42811 : if (!deprecatedVehicleClassesSeen.empty()) {
227 0 : WRITE_WARNINGF(TL("Deprecated vehicle classes '%' in input network."), toString(deprecatedVehicleClassesSeen));
228 : deprecatedVehicleClassesSeen.clear();
229 : }
230 : // check for bi-directional edges (this are edges in opposing direction and superposable/congruent shapes)
231 42811 : if (myBidiEdges.size() > 0 || networkVersion > MMVersion(1, 0)) {
232 41718 : for (auto& item : myBidiEdges) {
233 25434 : item.first->checkAndRegisterBiDirEdge(item.second);
234 : }
235 : //WRITE_MESSAGEF(TL("Loaded % bidirectional edges"), toString(myBidiEdges.size()));
236 : } else {
237 : // legacy network
238 1078920 : for (MSEdge* e : myEdges) {
239 2104786 : e->checkAndRegisterBiDirEdge();
240 : }
241 : }
242 : // take into account bidi lanes when deciding on whether an edge allows changing
243 1785921 : for (MSEdge* const edge : myEdges) {
244 1743110 : edge->buildLaneChanger();
245 : }
246 42811 : return new MSEdgeControl(myEdges);
247 : }
248 :
249 :
250 : MSEdge*
251 1641377 : NLEdgeControlBuilder::buildEdge(const std::string& id, const SumoXMLEdgeFunc function,
252 : const std::string& streetName, const std::string& edgeType, const int priority, const double distance) {
253 1641377 : return new MSEdge(id, myCurrentNumericalEdgeID++, function, streetName, edgeType, priority, distance);
254 : }
255 :
256 15932 : void NLEdgeControlBuilder::addCrossingEdges(const std::vector<std::string>& crossingEdges) {
257 15932 : myActiveEdge->setCrossingEdges(crossingEdges);
258 15932 : }
259 :
260 :
261 : /****************************************************************************/
|