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