1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file NLEdgeControlBuilder.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Michael Behrisch
14 /// @author Leonhard Luecken
15 /// @date Mon, 9 Jul 2001
16 /// @version $Id$
17 ///
18 // Interface for building edges
19 /****************************************************************************/
20
21
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26
27 #include <vector>
28 #include <string>
29 #include <map>
30 #include <algorithm>
31 #include <iterator>
32 #include <microsim/MSGlobals.h>
33 #include <microsim/MSLane.h>
34 #include <microsim/MSEdge.h>
35 #include <microsim/MSEdgeControl.h>
36 #include <utils/common/StringTokenizer.h>
37 #include <utils/common/UtilExceptions.h>
38 #include "NLBuilder.h"
39 #include "NLEdgeControlBuilder.h"
40 #include <utils/options/OptionsCont.h>
41 #include <utils/iodevices/OutputDevice.h>
42
43
44 // ===========================================================================
45 // method definitions
46 // ===========================================================================
NLEdgeControlBuilder()47 NLEdgeControlBuilder::NLEdgeControlBuilder()
48 : myCurrentNumericalLaneID(0), myCurrentNumericalEdgeID(0), myEdges(0), myCurrentLaneIndex(-1) {
49 myActiveEdge = (MSEdge*) nullptr;
50 myLaneStorage = new std::vector<MSLane*>();
51 }
52
53
~NLEdgeControlBuilder()54 NLEdgeControlBuilder::~NLEdgeControlBuilder() {
55 delete myLaneStorage;
56 }
57
58
59 void
beginEdgeParsing(const std::string & id,const SumoXMLEdgeFunc function,const std::string & streetName,const std::string & edgeType,int priority,const std::string & bidi)60 NLEdgeControlBuilder::beginEdgeParsing(
61 const std::string& id, const SumoXMLEdgeFunc function,
62 const std::string& streetName,
63 const std::string& edgeType,
64 int priority,
65 const std::string& bidi) {
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);
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*
addLane(const std::string & id,double maxSpeed,double length,const PositionVector & shape,double width,SVCPermissions permissions,int index,bool isRampAccel)80 NLEdgeControlBuilder::addLane(const std::string& id,
81 double maxSpeed, double length,
82 const PositionVector& shape, double width,
83 SVCPermissions permissions, int index, bool isRampAccel) {
84 MSLane* lane = new MSLane(id, maxSpeed, length, myActiveEdge, myCurrentNumericalLaneID++, shape, width, permissions, index, isRampAccel);
85 myLaneStorage->push_back(lane);
86 myCurrentLaneIndex = index;
87 return lane;
88 }
89
90
91 void
addStopOffsets(const std::map<SVCPermissions,double> & stopOffsets)92 NLEdgeControlBuilder::addStopOffsets(const std::map<SVCPermissions, double>& stopOffsets) {
93
94 if (myCurrentLaneIndex == -1) {
95 setDefaultStopOffsets(stopOffsets);
96 } else {
97 updateCurrentLaneStopOffsets(stopOffsets);
98 }
99 }
100
101
102
103 std::string
reportCurrentEdgeOrLane() const104 NLEdgeControlBuilder::reportCurrentEdgeOrLane() const {
105 std::stringstream ss;
106 if (myCurrentLaneIndex != -1) {
107 ss << "lane " << myCurrentLaneIndex << " of ";
108 }
109 ss << "edge '" << myActiveEdge->getID() << "'";
110 return ss.str();
111 }
112
113
114 void
updateCurrentLaneStopOffsets(const std::map<SVCPermissions,double> & stopOffsets)115 NLEdgeControlBuilder::updateCurrentLaneStopOffsets(const std::map<SVCPermissions, double>& stopOffsets) {
116 assert(myLaneStorage->size() != 0);
117 if (stopOffsets.size() == 0) {
118 return;
119 }
120 if (myLaneStorage->back()->getStopOffsets().size() != 0) {
121 std::stringstream ss;
122 ss << "Duplicate stopOffset definition for lane " << myLaneStorage->back()->getIndex() << " on edge " << myActiveEdge->getID() << "!";
123 WRITE_WARNING(ss.str())
124 } else {
125 myLaneStorage->back()->setStopOffsets(stopOffsets);
126 }
127 }
128
129
130 void
setDefaultStopOffsets(std::map<SVCPermissions,double> stopOffsets)131 NLEdgeControlBuilder::setDefaultStopOffsets(std::map<SVCPermissions, double> stopOffsets) {
132 if (myCurrentDefaultStopOffsets.size() != 0) {
133 std::stringstream ss;
134 ss << "Duplicate stopOffset definition for edge " << myActiveEdge->getID() << ". Ignoring duplicate specification.";
135 WRITE_WARNING(ss.str())
136 } else {
137 myCurrentDefaultStopOffsets = stopOffsets;
138 }
139 }
140
141
142 void
applyDefaultStopOffsetsToLanes()143 NLEdgeControlBuilder::applyDefaultStopOffsetsToLanes() {
144 assert(myActiveEdge != 0);
145 if (myCurrentDefaultStopOffsets.size() == 0) {
146 return;
147 }
148 for (MSLane* l : *myLaneStorage) {
149 if (l->getStopOffsets().size() == 0) {
150 l->setStopOffsets(myCurrentDefaultStopOffsets);
151 }
152 }
153 }
154
155
156 void
addNeigh(const std::string id)157 NLEdgeControlBuilder::addNeigh(const std::string id) {
158 myLaneStorage->back()->addNeigh(id);
159 }
160
161
162 MSEdge*
closeEdge()163 NLEdgeControlBuilder::closeEdge() {
164 applyDefaultStopOffsetsToLanes();
165 std::vector<MSLane*>* lanes = new std::vector<MSLane*>();
166 lanes->reserve(myLaneStorage->size());
167 copy(myLaneStorage->begin(), myLaneStorage->end(), back_inserter(*lanes));
168 myLaneStorage->clear();
169 myActiveEdge->initialize(lanes);
170 myCurrentDefaultStopOffsets.clear();
171 return myActiveEdge;
172 }
173
174
175 void
closeLane()176 NLEdgeControlBuilder::closeLane() {
177 myCurrentLaneIndex = -1;
178 }
179
180
181 MSEdgeControl*
build(double networkVersion)182 NLEdgeControlBuilder::build(double networkVersion) {
183 for (MSEdgeVector::iterator i1 = myEdges.begin(); i1 != myEdges.end(); i1++) {
184 (*i1)->closeBuilding();
185 }
186 for (MSEdgeVector::iterator i1 = myEdges.begin(); i1 != myEdges.end(); i1++) {
187 (*i1)->buildLaneChanger();
188 }
189 // mark internal edges belonging to a roundabout (after all edges are build)
190 if (MSGlobals::gUsingInternalLanes) {
191 for (MSEdgeVector::iterator i1 = myEdges.begin(); i1 != myEdges.end(); i1++) {
192 MSEdge* edge = *i1;
193 if (edge->isInternal()) {
194 if (edge->getNumSuccessors() != 1 || edge->getNumPredecessors() != 1) {
195 throw ProcessError("Internal edge '" + edge->getID() + "' is not properly connected (probably a manually modified net.xml).");
196 }
197 if (edge->getSuccessors()[0]->isRoundabout() || edge->getPredecessors()[0]->isRoundabout()) {
198 edge->markAsRoundabout();
199 }
200 }
201 }
202 }
203 if (!deprecatedVehicleClassesSeen.empty()) {
204 WRITE_WARNING("Deprecated vehicle classes '" + toString(deprecatedVehicleClassesSeen) + "' in input network.");
205 deprecatedVehicleClassesSeen.clear();
206 }
207 // check for bi-directional edges (this are edges in opposing direction and superposable/congruent shapes)
208 if (myBidiEdges.size() > 0 || networkVersion > 1.0) {
209 for (auto& item : myBidiEdges) {
210 item.first->checkAndRegisterBiDirEdge(item.second);
211 }
212 //WRITE_MESSAGE("Loaded " + toString(myBidiEdges.size()) + " bidirectional edges");
213 } else {
214 // legacy network
215 for (MSEdge* e : myEdges) {
216 e->checkAndRegisterBiDirEdge();
217 }
218 }
219 return new MSEdgeControl(myEdges);
220 }
221
222
223 MSEdge*
buildEdge(const std::string & id,const SumoXMLEdgeFunc function,const std::string & streetName,const std::string & edgeType,const int priority)224 NLEdgeControlBuilder::buildEdge(const std::string& id, const SumoXMLEdgeFunc function,
225 const std::string& streetName, const std::string& edgeType, const int priority) {
226 return new MSEdge(id, myCurrentNumericalEdgeID++, function, streetName, edgeType, priority);
227 }
228
addCrossingEdges(const std::vector<std::string> & crossingEdges)229 void NLEdgeControlBuilder::addCrossingEdges(const std::vector<std::string>& crossingEdges) {
230 myActiveEdge->setCrossingEdges(crossingEdges);
231 }
232
233 /****************************************************************************/
234
235