1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2002-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 ROVehicle.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Axel Wegener
13 /// @author Michael Behrisch
14 /// @author Jakob Erdmann
15 /// @date Sept 2002
16 /// @version $Id$
17 ///
18 // A vehicle as used by router
19 /****************************************************************************/
20
21
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26
27 #include <string>
28 #include <iostream>
29 #include <utils/common/StringUtils.h>
30 #include <utils/common/ToString.h>
31 #include <utils/common/MsgHandler.h>
32 #include <utils/geom/GeoConvHelper.h>
33 #include <utils/vehicle/SUMOVTypeParameter.h>
34 #include <utils/options/OptionsCont.h>
35 #include <utils/iodevices/OutputDevice.h>
36 #include "RORouteDef.h"
37 #include "RORoute.h"
38 #include "ROHelper.h"
39 #include "RONet.h"
40 #include "ROLane.h"
41 #include "ROVehicle.h"
42
43
44 // ===========================================================================
45 // method definitions
46 // ===========================================================================
ROVehicle(const SUMOVehicleParameter & pars,RORouteDef * route,const SUMOVTypeParameter * type,const RONet * net,MsgHandler * errorHandler)47 ROVehicle::ROVehicle(const SUMOVehicleParameter& pars,
48 RORouteDef* route, const SUMOVTypeParameter* type,
49 const RONet* net, MsgHandler* errorHandler)
50 : RORoutable(pars, type), myRoute(route) {
51 getParameter().stops.clear();
52 if (route != nullptr && route->getFirstRoute() != nullptr) {
53 for (std::vector<SUMOVehicleParameter::Stop>::const_iterator s = route->getFirstRoute()->getStops().begin(); s != route->getFirstRoute()->getStops().end(); ++s) {
54 addStop(*s, net, errorHandler);
55 }
56 }
57 for (std::vector<SUMOVehicleParameter::Stop>::const_iterator s = pars.stops.begin(); s != pars.stops.end(); ++s) {
58 addStop(*s, net, errorHandler);
59 }
60 if (pars.via.size() != 0) {
61 // via takes precedence over stop edges
62 // XXX check for inconsistencies #2275
63 myStopEdges.clear();
64 for (std::vector<std::string>::const_iterator it = pars.via.begin(); it != pars.via.end(); ++it) {
65 assert(net->getEdge(*it) != 0);
66 myStopEdges.push_back(net->getEdge(*it));
67 }
68 }
69 }
70
71
72 void
addStop(const SUMOVehicleParameter::Stop & stopPar,const RONet * net,MsgHandler * errorHandler)73 ROVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, const RONet* net, MsgHandler* errorHandler) {
74 const ROEdge* stopEdge = net->getEdgeForLaneID(stopPar.lane);
75 assert(stopEdge != 0); // was checked when parsing the stop
76 if (stopEdge->prohibits(this)) {
77 if (errorHandler != nullptr) {
78 errorHandler->inform("Stop edge '" + stopEdge->getID() + "' does not allow vehicle '" + getID() + "'.");
79 }
80 return;
81 }
82 // where to insert the stop
83 std::vector<SUMOVehicleParameter::Stop>::iterator iter = getParameter().stops.begin();
84 ConstROEdgeVector::iterator edgeIter = myStopEdges.begin();
85 if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(getParameter().stops.size())) {
86 if (getParameter().stops.size() > 0) {
87 iter = getParameter().stops.end();
88 edgeIter = myStopEdges.end();
89 }
90 } else {
91 if (stopPar.index == STOP_INDEX_FIT) {
92 const ConstROEdgeVector edges = myRoute->getFirstRoute()->getEdgeVector();
93 ConstROEdgeVector::const_iterator stopEdgeIt = std::find(edges.begin(), edges.end(), stopEdge);
94 if (stopEdgeIt == edges.end()) {
95 iter = getParameter().stops.end();
96 edgeIter = myStopEdges.end();
97 } else {
98 while (iter != getParameter().stops.end()) {
99 if (edgeIter > stopEdgeIt || (edgeIter == stopEdgeIt && iter->endPos >= stopPar.endPos)) {
100 break;
101 }
102 ++iter;
103 ++edgeIter;
104 }
105 }
106 } else {
107 iter += stopPar.index;
108 edgeIter += stopPar.index;
109 }
110 }
111 getParameter().stops.insert(iter, stopPar);
112 myStopEdges.insert(edgeIter, stopEdge);
113 }
114
115
~ROVehicle()116 ROVehicle::~ROVehicle() {}
117
118
119 const ROEdge*
getDepartEdge() const120 ROVehicle:: getDepartEdge() const {
121 return myRoute->getFirstRoute()->getFirst();
122 }
123
124
125 void
computeRoute(const RORouterProvider & provider,const bool removeLoops,MsgHandler * errorHandler)126 ROVehicle::computeRoute(const RORouterProvider& provider,
127 const bool removeLoops, MsgHandler* errorHandler) {
128 SUMOAbstractRouter<ROEdge, ROVehicle>& router = provider.getVehicleRouter();
129 std::string noRouteMsg = "The vehicle '" + getID() + "' has no valid route.";
130 RORouteDef* const routeDef = getRouteDefinition();
131 // check if the route definition is valid
132 if (routeDef == nullptr) {
133 errorHandler->inform(noRouteMsg);
134 myRoutingSuccess = false;
135 return;
136 }
137 RORoute* current = routeDef->buildCurrentRoute(router, getDepartureTime(), *this);
138 if (current == nullptr || current->size() == 0) {
139 delete current;
140 errorHandler->inform(noRouteMsg);
141 myRoutingSuccess = false;
142 return;
143 }
144 // check whether we have to evaluate the route for not containing loops
145 if (removeLoops) {
146 const ROEdge* requiredStart = (getParameter().departPosProcedure == DEPART_POS_GIVEN
147 || getParameter().departLaneProcedure == DEPART_LANE_GIVEN ? current->getEdgeVector().front() : 0);
148 const ROEdge* requiredEnd = (getParameter().arrivalPosProcedure == ARRIVAL_POS_GIVEN
149 || getParameter().arrivalLaneProcedure == ARRIVAL_LANE_GIVEN ? current->getEdgeVector().back() : 0);
150 current->recheckForLoops(getMandatoryEdges(requiredStart, requiredEnd));
151 // check whether the route is still valid
152 if (current->size() == 0) {
153 delete current;
154 errorHandler->inform(noRouteMsg + " (after removing loops)");
155 myRoutingSuccess = false;
156 return;
157 }
158 }
159 // add built route
160 routeDef->addAlternative(router, this, current, getDepartureTime());
161 myRoutingSuccess = true;
162 }
163
164
165 ConstROEdgeVector
getMandatoryEdges(const ROEdge * requiredStart,const ROEdge * requiredEnd) const166 ROVehicle::getMandatoryEdges(const ROEdge* requiredStart, const ROEdge* requiredEnd) const {
167 ConstROEdgeVector mandatory;
168 if (requiredStart) {
169 mandatory.push_back(requiredStart);
170 }
171 for (const ROEdge* e : getStopEdges()) {
172 if (e->isInternal()) {
173 // the edges before and after the internal edge are mandatory
174 const ROEdge* before = e->getNormalBefore();
175 const ROEdge* after = e->getNormalAfter();
176 if (mandatory.size() == 0 || after != mandatory.back()) {
177 mandatory.push_back(before);
178 mandatory.push_back(after);
179 }
180 } else {
181 if (mandatory.size() == 0 || e != mandatory.back()) {
182 mandatory.push_back(e);
183 }
184 }
185 }
186 if (requiredEnd) {
187 if (mandatory.size() < 2 || mandatory.back() != requiredEnd) {
188 mandatory.push_back(requiredEnd);
189 }
190 }
191 return mandatory;
192 }
193
194
195 void
saveAsXML(OutputDevice & os,OutputDevice * const typeos,bool asAlternatives,OptionsCont & options) const196 ROVehicle::saveAsXML(OutputDevice& os, OutputDevice* const typeos, bool asAlternatives, OptionsCont& options) const {
197 if (typeos != nullptr && getType() != nullptr && !getType()->saved) {
198 getType()->write(*typeos);
199 getType()->saved = true;
200 }
201 if (getType() != nullptr && !getType()->saved) {
202 getType()->write(os);
203 getType()->saved = asAlternatives;
204 }
205
206 const bool writeTrip = options.exists("write-trips") && options.getBool("write-trips");
207 const bool writeGeoTrip = writeTrip && options.getBool("write-trips.geo");
208 // write the vehicle (new style, with included routes)
209 getParameter().write(os, options, writeTrip ? SUMO_TAG_TRIP : SUMO_TAG_VEHICLE);
210
211 // save the route
212 if (writeTrip) {
213 const ConstROEdgeVector edges = myRoute->getFirstRoute()->getEdgeVector();
214 const ROEdge* from = nullptr;
215 const ROEdge* to = nullptr;
216 if (edges.size() > 0) {
217 if (edges.front()->isTazConnector()) {
218 if (edges.size() > 1) {
219 from = edges[1];
220 }
221 } else {
222 from = edges[0];
223 }
224 if (edges.back()->isTazConnector()) {
225 if (edges.size() > 1) {
226 to = edges[edges.size() - 2];
227 }
228 } else {
229 to = edges[edges.size() - 1];
230 }
231 }
232 if (from != nullptr) {
233 if (writeGeoTrip) {
234 Position fromPos = from->getLanes()[0]->getShape().positionAtOffset2D(0);
235 if (GeoConvHelper::getFinal().usingGeoProjection()) {
236 os.setPrecision(gPrecisionGeo);
237 GeoConvHelper::getFinal().cartesian2geo(fromPos);
238 os.writeAttr(SUMO_ATTR_FROMLONLAT, fromPos);
239 os.setPrecision(gPrecision);
240 } else {
241 os.writeAttr(SUMO_ATTR_FROMXY, fromPos);
242 }
243 } else {
244 os.writeAttr(SUMO_ATTR_FROM, from->getID());
245 }
246 }
247 if (to != nullptr) {
248 if (writeGeoTrip) {
249 Position toPos = to->getLanes()[0]->getShape().positionAtOffset2D(to->getLanes()[0]->getShape().length2D());
250 if (GeoConvHelper::getFinal().usingGeoProjection()) {
251 os.setPrecision(gPrecisionGeo);
252 GeoConvHelper::getFinal().cartesian2geo(toPos);
253 os.writeAttr(SUMO_ATTR_TOLONLAT, toPos);
254 os.setPrecision(gPrecision);
255 } else {
256 os.writeAttr(SUMO_ATTR_TOXY, toPos);
257 }
258 } else {
259 os.writeAttr(SUMO_ATTR_TO, to->getID());
260 }
261 }
262 if (getParameter().via.size() > 0) {
263 if (writeGeoTrip) {
264 PositionVector viaPositions;
265 for (const std::string& viaID : getParameter().via) {
266 const ROEdge* viaEdge = RONet::getInstance()->getEdge(viaID);
267 assert(viaEdge != nullptr);
268 Position viaPos = viaEdge->getLanes()[0]->getShape().positionAtOffset2D(viaEdge->getLanes()[0]->getShape().length2D() / 2);
269 viaPositions.push_back(viaPos);
270 }
271 if (GeoConvHelper::getFinal().usingGeoProjection()) {
272 for (int i = 0; i < (int)viaPositions.size(); i++) {
273 GeoConvHelper::getFinal().cartesian2geo(viaPositions[i]);
274 }
275 os.setPrecision(gPrecisionGeo);
276 os.writeAttr(SUMO_ATTR_VIALONLAT, viaPositions);
277 os.setPrecision(gPrecision);
278 } else {
279 os.writeAttr(SUMO_ATTR_VIAXY, viaPositions);
280 }
281
282 } else {
283 os.writeAttr(SUMO_ATTR_VIA, getParameter().via);
284 }
285 }
286 } else {
287 myRoute->writeXMLDefinition(os, this, asAlternatives, options.getBool("exit-times"));
288 }
289 for (std::vector<SUMOVehicleParameter::Stop>::const_iterator stop = getParameter().stops.begin(); stop != getParameter().stops.end(); ++stop) {
290 stop->write(os);
291 }
292 getParameter().writeParams(os);
293 os.closeTag();
294 }
295
296
297 /****************************************************************************/
298
299