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