Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2002-2025 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 ROVehicle.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Axel Wegener
17 : /// @author Michael Behrisch
18 : /// @author Jakob Erdmann
19 : /// @date Sept 2002
20 : ///
21 : // A vehicle as used by router
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <string>
26 : #include <iostream>
27 : #include <utils/common/StringUtils.h>
28 : #include <utils/common/ToString.h>
29 : #include <utils/common/MsgHandler.h>
30 : #include <utils/geom/GeoConvHelper.h>
31 : #include <utils/vehicle/SUMOVTypeParameter.h>
32 : #include <utils/options/OptionsCont.h>
33 : #include <utils/iodevices/OutputDevice.h>
34 : #include "RORouteDef.h"
35 : #include "RORoute.h"
36 : #include "ROHelper.h"
37 : #include "RONet.h"
38 : #include "ROLane.h"
39 : #include "ROVehicle.h"
40 :
41 : // ===========================================================================
42 : // static members
43 : // ===========================================================================
44 : std::map<ConstROEdgeVector, std::string> ROVehicle::mySavedRoutes;
45 :
46 : // ===========================================================================
47 : // method definitions
48 : // ===========================================================================
49 297790 : ROVehicle::ROVehicle(const SUMOVehicleParameter& pars,
50 : RORouteDef* route, const SUMOVTypeParameter* type,
51 297790 : const RONet* net, MsgHandler* errorHandler):
52 : RORoutable(pars, type),
53 297790 : myRoute(route),
54 297790 : myJumpTime(-1) {
55 : getParameter().stops.clear();
56 594667 : if (route != nullptr && route->getFirstRoute() != nullptr) {
57 594078 : for (StopParVector::const_iterator s = route->getFirstRoute()->getStops().begin(); s != route->getFirstRoute()->getStops().end(); ++s) {
58 324 : addStop(*s, net, errorHandler);
59 : }
60 : }
61 298243 : for (StopParVector::const_iterator s = pars.stops.begin(); s != pars.stops.end(); ++s) {
62 453 : addStop(*s, net, errorHandler);
63 : }
64 297790 : if (pars.via.size() != 0) {
65 : // via takes precedence over stop edges
66 : // XXX check for inconsistencies #2275
67 : myStopEdges.clear();
68 48261 : for (std::vector<std::string>::const_iterator it = pars.via.begin(); it != pars.via.end(); ++it) {
69 : assert(net->getEdge(*it) != 0);
70 67200 : myStopEdges.push_back(net->getEdge(*it));
71 : }
72 : }
73 297790 : }
74 :
75 :
76 : void
77 777 : ROVehicle::addStop(const SUMOVehicleParameter::Stop& stopPar, const RONet* net, MsgHandler* errorHandler) {
78 777 : const ROEdge* stopEdge = net->getEdge(stopPar.edge);
79 : assert(stopEdge != 0); // was checked when parsing the stop
80 777 : if (stopEdge->prohibits(this)) {
81 0 : if (errorHandler != nullptr) {
82 0 : errorHandler->inform("Stop edge '" + stopEdge->getID() + "' does not allow vehicle '" + getID() + "'.");
83 : }
84 0 : return;
85 : }
86 : // where to insert the stop
87 : StopParVector::iterator iter = getParameter().stops.begin();
88 : ConstROEdgeVector::iterator edgeIter = myStopEdges.begin();
89 777 : if (stopPar.index == STOP_INDEX_END || stopPar.index >= static_cast<int>(getParameter().stops.size())) {
90 777 : if (getParameter().stops.size() > 0) {
91 : iter = getParameter().stops.end();
92 : edgeIter = myStopEdges.end();
93 : }
94 : } else {
95 0 : if (stopPar.index == STOP_INDEX_FIT) {
96 0 : const ConstROEdgeVector edges = myRoute->getFirstRoute()->getEdgeVector();
97 0 : ConstROEdgeVector::const_iterator stopEdgeIt = std::find(edges.begin(), edges.end(), stopEdge);
98 0 : if (stopEdgeIt == edges.end()) {
99 : iter = getParameter().stops.end();
100 : edgeIter = myStopEdges.end();
101 : } else {
102 0 : while (iter != getParameter().stops.end()) {
103 0 : if (edgeIter > stopEdgeIt || (edgeIter == stopEdgeIt && iter->endPos >= stopPar.endPos)) {
104 : break;
105 : }
106 : ++iter;
107 : ++edgeIter;
108 : }
109 : }
110 0 : } else {
111 : iter += stopPar.index;
112 : edgeIter += stopPar.index;
113 : }
114 : }
115 777 : getParameter().stops.insert(iter, stopPar);
116 777 : myStopEdges.insert(edgeIter, stopEdge);
117 777 : if (stopPar.jump >= 0) {
118 24 : if (stopEdge->isInternal()) {
119 0 : if (errorHandler != nullptr) {
120 0 : errorHandler->inform("Jumps are not supported from internal stop edge '" + stopEdge->getID() + "'.");
121 : }
122 : } else {
123 24 : if (myJumpTime < 0) {
124 20 : myJumpTime = 0;
125 : }
126 24 : myJumpTime += stopPar.jump;
127 : }
128 : }
129 : }
130 :
131 :
132 595493 : ROVehicle::~ROVehicle() {}
133 :
134 :
135 : const ROEdge*
136 511 : ROVehicle:: getDepartEdge() const {
137 511 : return myRoute->getFirstRoute()->getFirst();
138 : }
139 :
140 :
141 : void
142 296649 : ROVehicle::computeRoute(const RORouterProvider& provider,
143 : const bool removeLoops, MsgHandler* errorHandler) {
144 : SUMOAbstractRouter<ROEdge, ROVehicle>& router = provider.getVehicleRouter(getVClass());
145 593298 : std::string noRouteMsg = "The vehicle '" + getID() + "' has no valid route.";
146 : RORouteDef* const routeDef = getRouteDefinition();
147 : // check if the route definition is valid
148 296649 : if (routeDef == nullptr) {
149 0 : errorHandler->inform(noRouteMsg);
150 0 : myRoutingSuccess = false;
151 0 : return;
152 : }
153 296649 : routeDef->validateAlternatives(this, errorHandler);
154 296646 : if (routeDef->getFirstRoute() == nullptr) {
155 : // everything is invalid and no new routes will be computed
156 3 : myRoutingSuccess = false;
157 3 : return;
158 : }
159 296646 : RORoute* current = routeDef->buildCurrentRoute(router, getDepartureTime(), *this);
160 296646 : if (current == nullptr || current->size() == 0) {
161 19117 : delete current;
162 1925 : if (current == nullptr || !routeDef->discardSilent()) {
163 51576 : errorHandler->inform(noRouteMsg);
164 : }
165 19117 : myRoutingSuccess = false;
166 19117 : return;
167 : }
168 : // check whether we have to evaluate the route for not containing loops
169 277529 : if (removeLoops) {
170 5218 : const ROEdge* requiredStart = (getParameter().departPosProcedure == DepartPosDefinition::GIVEN
171 5218 : || getParameter().departLaneProcedure == DepartLaneDefinition::GIVEN ? current->getEdgeVector().front() : 0);
172 5218 : const ROEdge* requiredEnd = (getParameter().arrivalPosProcedure == ArrivalPosDefinition::GIVEN
173 5218 : || getParameter().arrivalLaneProcedure == ArrivalLaneDefinition::GIVEN ? current->getEdgeVector().back() : 0);
174 5218 : current->recheckForLoops(getMandatoryEdges(requiredStart, requiredEnd));
175 : // check whether the route is still valid
176 5218 : if (current->size() == 0) {
177 0 : delete current;
178 16 : errorHandler->inform(noRouteMsg + " (after removing loops)");
179 0 : myRoutingSuccess = false;
180 0 : return;
181 : }
182 : }
183 : // add built route
184 277529 : routeDef->addAlternative(router, this, current, getDepartureTime(), errorHandler);
185 277513 : myRoutingSuccess = true;
186 : }
187 :
188 :
189 : ConstROEdgeVector
190 294441 : ROVehicle::getMandatoryEdges(const ROEdge* requiredStart, const ROEdge* requiredEnd) const {
191 : ConstROEdgeVector mandatory;
192 294441 : if (requiredStart) {
193 289231 : mandatory.push_back(requiredStart);
194 : }
195 328682 : for (const ROEdge* e : getStopEdges()) {
196 34241 : if (e->isInternal()) {
197 : // the edges before and after the internal edge are mandatory
198 8 : const ROEdge* before = e->getNormalBefore();
199 8 : const ROEdge* after = e->getNormalAfter();
200 8 : if (mandatory.size() == 0 || after != mandatory.back()) {
201 8 : mandatory.push_back(before);
202 8 : mandatory.push_back(after);
203 : }
204 : } else {
205 34233 : if (mandatory.size() == 0 || e != mandatory.back()) {
206 28447 : mandatory.push_back(e);
207 : }
208 : }
209 : }
210 294441 : if (requiredEnd) {
211 289231 : if (mandatory.size() < 2 || mandatory.back() != requiredEnd) {
212 287549 : mandatory.push_back(requiredEnd);
213 : }
214 : }
215 294441 : return mandatory;
216 0 : }
217 :
218 :
219 : void
220 289223 : ROVehicle::collectJumps(const ConstROEdgeVector& mandatory, std::set<ConstROEdgeVector::const_iterator>& jumpStarts) const {
221 289223 : auto itM = mandatory.begin();
222 : auto itS = getParameter().stops.begin();
223 : auto itSEnd = getParameter().stops.end();
224 290106 : while (itM != mandatory.end() && itS != itSEnd) {
225 : bool repeatMandatory = false;
226 : // if we stop twice on the same edge, we must treat this as a repeated
227 : // mandatory edge (even though the edge appears only once in the mandatory vector)
228 883 : if ((*itM)->getID() == itS->edge) {
229 621 : if (itS->jump >= 0) {
230 : jumpStarts.insert(itM);
231 : }
232 : itS++;
233 621 : if (itS != itSEnd && itS->edge == (itS - 1)->edge) {
234 : repeatMandatory = true;
235 : }
236 : }
237 : if (!repeatMandatory) {
238 : itM++;
239 : }
240 : }
241 289223 : }
242 :
243 :
244 : void
245 390534 : ROVehicle::saveAsXML(OutputDevice& os, OutputDevice* const typeos, bool asAlternatives, OptionsCont& options, int cloneIndex) const {
246 390534 : if (typeos != nullptr && getType() != nullptr && !getType()->saved) {
247 378 : getType()->write(*typeos);
248 378 : getType()->saved = true;
249 : }
250 390534 : if (getType() != nullptr && !getType()->saved) {
251 3996 : getType()->write(os);
252 3996 : getType()->saved = asAlternatives;
253 : }
254 :
255 776801 : const bool writeTrip = options.exists("write-trips") && options.getBool("write-trips");
256 390534 : const bool writeGeoTrip = writeTrip && options.getBool("write-trips.geo");
257 390534 : const bool writeJunctions = writeTrip && options.getBool("write-trips.junctions");
258 390534 : const bool writeNamedRoute = !asAlternatives && options.getBool("named-routes");
259 776801 : const bool writeCosts = options.exists("write-costs") && options.getBool("write-costs");
260 781068 : const bool writeExit = options.exists("exit-times") && options.getBool("exit-times");
261 776801 : const bool writeLength = options.exists("route-length") && options.getBool("route-length");
262 776801 : const bool writeFlow = options.exists("keep-flows") && options.getBool("keep-flows") && isPartOfFlow();
263 :
264 : std::string routeID;
265 390534 : if (writeNamedRoute) {
266 21 : ConstROEdgeVector edges = myRoute->getUsedRoute()->getNormalEdges();
267 : auto it = mySavedRoutes.find(edges);
268 21 : if (it == mySavedRoutes.end()) {
269 14 : routeID = "r" + toString(mySavedRoutes.size());
270 7 : myRoute->getUsedRoute()->writeXMLDefinition(os, this, writeCosts, false, writeExit,
271 : writeLength, routeID);
272 7 : mySavedRoutes[edges] = routeID;
273 : } else {
274 14 : routeID = it->second;
275 : }
276 21 : }
277 390534 : const SumoXMLTag tag = writeFlow ? SUMO_TAG_FLOW : (writeTrip ? SUMO_TAG_TRIP : SUMO_TAG_VEHICLE);
278 : // write the vehicle (new style, with included routes)
279 390534 : if (cloneIndex == 0) {
280 780828 : getParameter().write(os, options, tag);
281 : } else {
282 120 : SUMOVehicleParameter p = getParameter();
283 : // @note id collisions may occur if scale-suffic occurs in other vehicle ids
284 240 : p.id += options.getString("scale-suffix") + toString(cloneIndex);
285 120 : p.write(os, options, tag);
286 120 : }
287 : // save the route
288 390534 : if (writeTrip) {
289 158652 : const ConstROEdgeVector edges = myRoute->getFirstRoute()->getEdgeVector();
290 : const ROEdge* from = nullptr;
291 : const ROEdge* to = nullptr;
292 79326 : if (edges.size() > 0) {
293 79326 : if (edges.front()->isTazConnector()) {
294 7284 : if (edges.size() > 1) {
295 7284 : from = edges[1];
296 7284 : if (from->isTazConnector() && writeJunctions && edges.front()->getSuccessors().size() > 0) {
297 : // routing was skipped
298 8 : from = edges.front()->getSuccessors(getVClass()).front();
299 : }
300 : }
301 : } else {
302 : from = edges[0];
303 : }
304 79326 : if (edges.back()->isTazConnector()) {
305 7284 : if (edges.size() > 1) {
306 7284 : to = edges[edges.size() - 2];
307 7284 : if (to->isTazConnector() && writeJunctions && edges.back()->getPredecessors().size() > 0) {
308 : // routing was skipped
309 4 : to = edges.back()->getPredecessors().front();
310 : }
311 : }
312 : } else {
313 72042 : to = edges[edges.size() - 1];
314 : }
315 : }
316 79326 : if (from != nullptr) {
317 79326 : if (writeGeoTrip) {
318 16 : Position fromPos = from->getLanes()[0]->getShape().positionAtOffset2D(0);
319 16 : if (GeoConvHelper::getFinal().usingGeoProjection()) {
320 0 : os.setPrecision(gPrecisionGeo);
321 0 : GeoConvHelper::getFinal().cartesian2geo(fromPos);
322 0 : os.writeAttr(SUMO_ATTR_FROMLONLAT, fromPos);
323 0 : os.setPrecision(gPrecision);
324 : } else {
325 16 : os.writeAttr(SUMO_ATTR_FROMXY, fromPos);
326 : }
327 79310 : } else if (writeJunctions) {
328 7244 : os.writeAttr(SUMO_ATTR_FROM_JUNCTION, from->getFromJunction()->getID());
329 : } else {
330 72066 : os.writeAttr(SUMO_ATTR_FROM, from->getID());
331 : }
332 : }
333 79326 : if (to != nullptr) {
334 79326 : if (writeGeoTrip) {
335 16 : Position toPos = to->getLanes()[0]->getShape().positionAtOffset2D(to->getLanes()[0]->getShape().length2D());
336 16 : if (GeoConvHelper::getFinal().usingGeoProjection()) {
337 0 : os.setPrecision(gPrecisionGeo);
338 0 : GeoConvHelper::getFinal().cartesian2geo(toPos);
339 0 : os.writeAttr(SUMO_ATTR_TOLONLAT, toPos);
340 0 : os.setPrecision(gPrecision);
341 : } else {
342 16 : os.writeAttr(SUMO_ATTR_TOXY, toPos);
343 : }
344 79310 : } else if (writeJunctions) {
345 7244 : os.writeAttr(SUMO_ATTR_TO_JUNCTION, to->getToJunction()->getID());
346 : } else {
347 72066 : os.writeAttr(SUMO_ATTR_TO, to->getID());
348 : }
349 : }
350 79326 : if (getParameter().via.size() > 0) {
351 : std::vector<std::string> viaOut;
352 : SumoXMLAttr viaAttr = (writeGeoTrip
353 7236 : ? (GeoConvHelper::getFinal().usingGeoProjection() ? SUMO_ATTR_VIALONLAT : SUMO_ATTR_VIAXY)
354 7228 : : (writeJunctions ? SUMO_ATTR_VIAJUNCTIONS : SUMO_ATTR_VIA));
355 21672 : for (const std::string& viaID : getParameter().via) {
356 14436 : const ROEdge* viaEdge = RONet::getInstance()->getEdge(viaID);
357 14436 : if (viaEdge->isTazConnector()) {
358 20 : if (viaEdge->getPredecessors().size() == 0) {
359 0 : continue;
360 : }
361 : // XXX used edge that was used in route
362 20 : viaEdge = viaEdge->getPredecessors().front();
363 : }
364 : assert(viaEdge != nullptr);
365 14436 : if (writeGeoTrip) {
366 8 : Position viaPos = viaEdge->getLanes()[0]->getShape().positionAtOffset2D(viaEdge->getLanes()[0]->getShape().length2D() / 2);
367 8 : if (GeoConvHelper::getFinal().usingGeoProjection()) {
368 0 : GeoConvHelper::getFinal().cartesian2geo(viaPos);
369 0 : viaOut.push_back(toString(viaPos, gPrecisionGeo));
370 : } else {
371 16 : viaOut.push_back(toString(viaPos, gPrecision));
372 : }
373 14428 : } else if (writeJunctions) {
374 8 : viaOut.push_back(viaEdge->getToJunction()->getID());
375 : } else {
376 14420 : viaOut.push_back(viaEdge->getID());
377 : }
378 : }
379 7236 : os.writeAttr(viaAttr, viaOut);
380 7236 : }
381 390534 : } else if (writeNamedRoute) {
382 21 : os.writeAttr(SUMO_ATTR_ROUTE, routeID);
383 : } else {
384 311187 : myRoute->writeXMLDefinition(os, this, asAlternatives, writeExit, writeCosts, writeLength);
385 : }
386 391780 : for (StopParVector::const_iterator stop = getParameter().stops.begin(); stop != getParameter().stops.end(); ++stop) {
387 1246 : stop->write(os);
388 : }
389 390534 : getParameter().writeParams(os);
390 781068 : os.closeTag();
391 390534 : }
392 :
393 :
394 : /****************************************************************************/
|