Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 RORouteHandler.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Sascha Krieg
18 : /// @author Michael Behrisch
19 : /// @date Mon, 9 Jul 2001
20 : ///
21 : // Parser and container for routes during their loading
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <string>
26 : #include <map>
27 : #include <vector>
28 : #include <iostream>
29 : #include <utils/iodevices/OutputDevice.h>
30 : #include <utils/xml/SUMOSAXHandler.h>
31 : #include <utils/xml/SUMOXMLDefinitions.h>
32 : #include <utils/geom/GeoConvHelper.h>
33 : #include <utils/common/FileHelpers.h>
34 : #include <utils/common/MsgHandler.h>
35 : #include <utils/common/StringTokenizer.h>
36 : #include <utils/common/UtilExceptions.h>
37 : #include <utils/options/OptionsCont.h>
38 : #include <utils/vehicle/SUMOVehicleParserHelper.h>
39 : #include <utils/xml/SUMOSAXReader.h>
40 : #include <utils/xml/XMLSubSys.h>
41 : #include <utils/iodevices/OutputDevice_String.h>
42 : #include "RONet.h"
43 : #include "ROEdge.h"
44 : #include "ROLane.h"
45 : #include "RORouteDef.h"
46 : #include "RORouteHandler.h"
47 :
48 : // ===========================================================================
49 : // method definitions
50 : // ===========================================================================
51 4710 : RORouteHandler::RORouteHandler(RONet& net, const std::string& file,
52 : const bool tryRepair,
53 : const bool emptyDestinationsAllowed,
54 : const bool ignoreErrors,
55 4710 : const bool checkSchema) :
56 : SUMORouteHandler(file, checkSchema ? "routes" : "", true),
57 9420 : MapMatcher(OptionsCont::getOptions().getBool("mapmatch.junctions"),
58 9420 : OptionsCont::getOptions().getBool("mapmatch.taz"),
59 4710 : OptionsCont::getOptions().getFloat("mapmatch.distance"),
60 4710 : ignoreErrors ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
61 4710 : myNet(net),
62 4710 : myActiveRouteRepeat(0),
63 4710 : myActiveRoutePeriod(0),
64 4710 : myActivePlan(nullptr),
65 4710 : myActiveContainerPlan(nullptr),
66 4710 : myActiveContainerPlanSize(0),
67 4710 : myTryRepair(tryRepair),
68 4710 : myEmptyDestinationsAllowed(emptyDestinationsAllowed),
69 4710 : myErrorOutput(ignoreErrors ? MsgHandler::getWarningInstance() : MsgHandler::getErrorInstance()),
70 4710 : myBegin(string2time(OptionsCont::getOptions().getString("begin"))),
71 4710 : myKeepVTypeDist(OptionsCont::getOptions().getBool("keep-vtype-distributions")),
72 9420 : myUnsortedInput(OptionsCont::getOptions().exists("unsorted-input") && OptionsCont::getOptions().getBool("unsorted-input")),
73 9305 : myWriteFlows(OptionsCont::getOptions().exists("keep-flows") && OptionsCont::getOptions().getBool("keep-flows")),
74 4710 : myCurrentVTypeDistribution(nullptr),
75 4710 : myCurrentAlternatives(nullptr),
76 4710 : myUseTaz(OptionsCont::getOptions().getBool("with-taz")),
77 4710 : myWriteJunctions(OptionsCont::getOptions().exists("write-trips")
78 9305 : && OptionsCont::getOptions().getBool("write-trips")
79 29299 : && OptionsCont::getOptions().getBool("write-trips.junctions")) {
80 4710 : myActiveRoute.reserve(100);
81 4710 : }
82 :
83 :
84 9420 : RORouteHandler::~RORouteHandler() {
85 4710 : delete myCurrentAlternatives;
86 14130 : }
87 :
88 :
89 : void
90 4113 : RORouteHandler::deleteActivePlanAndVehicleParameter() {
91 4113 : if (myActivePlan != nullptr) {
92 3884 : for (ROPerson::PlanItem* const it : *myActivePlan) {
93 206 : delete it;
94 : }
95 3678 : delete myActivePlan;
96 3678 : myActivePlan = nullptr;
97 : }
98 4113 : delete myActiveContainerPlan;
99 4113 : myActiveContainerPlan = nullptr;
100 4113 : delete myVehicleParameter;
101 4113 : myVehicleParameter = nullptr;
102 4113 : }
103 :
104 :
105 : void
106 194559 : RORouteHandler::parseFromViaTo(SumoXMLTag tag, const SUMOSAXAttributes& attrs, bool& ok) {
107 194559 : const std::string element = toString(tag);
108 : myActiveRoute.clear();
109 194559 : bool useTaz = myUseTaz;
110 194559 : if (myUseTaz && !myVehicleParameter->wasSet(VEHPARS_FROM_TAZ_SET) && !myVehicleParameter->wasSet(VEHPARS_TO_TAZ_SET)) {
111 0 : WRITE_WARNINGF(TL("Taz usage was requested but no taz present in % '%'!"), element, myVehicleParameter->id);
112 : useTaz = false;
113 : }
114 : SUMOVehicleClass vClass = SVC_PASSENGER;
115 194559 : if (!myNet.getVTypeDistribution(myVehicleParameter->vtypeid)) {
116 194489 : SUMOVTypeParameter* type = myNet.getVehicleTypeSecure(myVehicleParameter->vtypeid);
117 194489 : if (type != nullptr) {
118 194397 : vClass = type->vehicleClass;
119 : }
120 : }
121 : // from-attributes
122 194559 : const std::string rid = "for " + element + " '" + myVehicleParameter->id + "'";
123 210651 : if ((useTaz || (!attrs.hasAttribute(SUMO_ATTR_FROM) && !attrs.hasAttribute(SUMO_ATTR_FROMXY) && !attrs.hasAttribute(SUMO_ATTR_FROMLONLAT))) &&
124 32140 : (attrs.hasAttribute(SUMO_ATTR_FROM_TAZ) || attrs.hasAttribute(SUMO_ATTR_FROM_JUNCTION))) {
125 14989 : const bool useJunction = attrs.hasAttribute(SUMO_ATTR_FROM_JUNCTION);
126 15033 : const std::string tazType = useJunction ? "junction" : "taz";
127 15033 : const std::string tazID = attrs.get<std::string>(useJunction ? SUMO_ATTR_FROM_JUNCTION : SUMO_ATTR_FROM_TAZ, myVehicleParameter->id.c_str(), ok, true);
128 29978 : const ROEdge* fromTaz = myNet.getEdge(tazID + "-source");
129 14989 : if (fromTaz == nullptr) {
130 20 : myErrorOutput->inform("Source " + tazType + " '" + tazID + "' not known for " + element + " '" + myVehicleParameter->id + "'!"
131 10 : + (useJunction ? JUNCTION_TAZ_MISSING_HELP : ""));
132 10 : ok = false;
133 14979 : } else if (fromTaz->getNumSuccessors() == 0 && tag != SUMO_TAG_PERSON) {
134 0 : myErrorOutput->inform("Source " + tazType + " '" + tazID + "' has no outgoing edges for " + element + " '" + myVehicleParameter->id + "'!");
135 0 : ok = false;
136 : } else {
137 14979 : myActiveRoute.push_back(fromTaz);
138 14979 : if (useJunction && tag != SUMO_TAG_PERSON && !myWriteJunctions) {
139 7240 : myVehicleParameter->fromTaz = tazID;
140 7240 : myVehicleParameter->parametersSet |= VEHPARS_FROM_TAZ_SET;
141 : }
142 : }
143 179570 : } else if (attrs.hasAttribute(SUMO_ATTR_FROMXY)) {
144 125 : parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_FROMXY, myVehicleParameter->id.c_str(), ok), false, vClass, myActiveRoute, rid, true, ok);
145 125 : if (myMapMatchTAZ && ok) {
146 25 : myVehicleParameter->fromTaz = myActiveRoute.back()->getID();
147 25 : myVehicleParameter->parametersSet |= VEHPARS_FROM_TAZ_SET;
148 : }
149 179445 : } else if (attrs.hasAttribute(SUMO_ATTR_FROMLONLAT)) {
150 30 : parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_FROMLONLAT, myVehicleParameter->id.c_str(), ok), true, vClass, myActiveRoute, rid, true, ok);
151 30 : if (myMapMatchTAZ && ok) {
152 0 : myVehicleParameter->fromTaz = myActiveRoute.back()->getID();
153 0 : myVehicleParameter->parametersSet |= VEHPARS_FROM_TAZ_SET;
154 : }
155 : } else {
156 358830 : parseEdges(attrs.getOpt<std::string>(SUMO_ATTR_FROM, myVehicleParameter->id.c_str(), ok), myActiveRoute, rid, ok);
157 : }
158 194559 : if (!attrs.hasAttribute(SUMO_ATTR_VIA) && !attrs.hasAttribute(SUMO_ATTR_VIALONLAT) && !attrs.hasAttribute(SUMO_ATTR_VIAXY)) {
159 179896 : myInsertStopEdgesAt = (int)myActiveRoute.size();
160 : }
161 :
162 : // via-attributes
163 : ConstROEdgeVector viaEdges;
164 194559 : if (attrs.hasAttribute(SUMO_ATTR_VIAXY)) {
165 40 : parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_VIAXY, myVehicleParameter->id.c_str(), ok), false, vClass, viaEdges, rid, false, ok);
166 194519 : } else if (attrs.hasAttribute(SUMO_ATTR_VIALONLAT)) {
167 5 : parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_VIALONLAT, myVehicleParameter->id.c_str(), ok), true, vClass, viaEdges, rid, false, ok);
168 194514 : } else if (attrs.hasAttribute(SUMO_ATTR_VIAJUNCTIONS)) {
169 30 : for (std::string junctionID : attrs.get<std::vector<std::string> >(SUMO_ATTR_VIAJUNCTIONS, myVehicleParameter->id.c_str(), ok)) {
170 40 : const ROEdge* viaSink = myNet.getEdge(junctionID + "-sink");
171 20 : if (viaSink == nullptr) {
172 0 : myErrorOutput->inform("Junction-taz '" + junctionID + "' not found." + JUNCTION_TAZ_MISSING_HELP);
173 0 : ok = false;
174 : } else {
175 20 : viaEdges.push_back(viaSink);
176 : }
177 10 : }
178 : } else {
179 389008 : parseEdges(attrs.getOpt<std::string>(SUMO_ATTR_VIA, myVehicleParameter->id.c_str(), ok, "", true), viaEdges, rid, ok);
180 : }
181 228190 : for (const ROEdge* e : viaEdges) {
182 33631 : myActiveRoute.push_back(e);
183 33631 : myVehicleParameter->via.push_back(e->getID());
184 : }
185 :
186 : // to-attributes
187 211530 : if ((useTaz || (!attrs.hasAttribute(SUMO_ATTR_TO) && !attrs.hasAttribute(SUMO_ATTR_TOXY) && !attrs.hasAttribute(SUMO_ATTR_TOLONLAT))) &&
188 33898 : (attrs.hasAttribute(SUMO_ATTR_TO_TAZ) || attrs.hasAttribute(SUMO_ATTR_TO_JUNCTION))) {
189 14974 : const bool useJunction = attrs.hasAttribute(SUMO_ATTR_TO_JUNCTION);
190 15018 : const std::string tazType = useJunction ? "junction" : "taz";
191 15018 : const std::string tazID = attrs.get<std::string>(useJunction ? SUMO_ATTR_TO_JUNCTION : SUMO_ATTR_TO_TAZ, myVehicleParameter->id.c_str(), ok, true);
192 29948 : const ROEdge* toTaz = myNet.getEdge(tazID + "-sink");
193 14974 : if (toTaz == nullptr) {
194 0 : myErrorOutput->inform("Sink " + tazType + " '" + tazID + "' not known for " + element + " '" + myVehicleParameter->id + "'!"
195 0 : + (useJunction ? JUNCTION_TAZ_MISSING_HELP : ""));
196 0 : ok = false;
197 14974 : } else if (toTaz->getNumPredecessors() == 0 && tag != SUMO_TAG_PERSON) {
198 0 : myErrorOutput->inform("Sink " + tazType + " '" + tazID + "' has no incoming edges for " + element + " '" + myVehicleParameter->id + "'!");
199 0 : ok = false;
200 : } else {
201 14974 : myActiveRoute.push_back(toTaz);
202 14974 : if (useJunction && tag != SUMO_TAG_PERSON && !myWriteJunctions) {
203 7240 : myVehicleParameter->toTaz = tazID;
204 7240 : myVehicleParameter->parametersSet |= VEHPARS_TO_TAZ_SET;
205 : }
206 : }
207 179585 : } else if (attrs.hasAttribute(SUMO_ATTR_TOXY)) {
208 125 : parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_TOXY, myVehicleParameter->id.c_str(), ok, true), false, vClass, myActiveRoute, rid, false, ok);
209 125 : if (myMapMatchTAZ && ok) {
210 25 : myVehicleParameter->toTaz = myActiveRoute.back()->getID();
211 25 : myVehicleParameter->parametersSet |= VEHPARS_TO_TAZ_SET;
212 : }
213 179460 : } else if (attrs.hasAttribute(SUMO_ATTR_TOLONLAT)) {
214 30 : parseGeoEdges(attrs.get<PositionVector>(SUMO_ATTR_TOLONLAT, myVehicleParameter->id.c_str(), ok, true), true, vClass, myActiveRoute, rid, false, ok);
215 30 : if (myMapMatchTAZ && ok) {
216 0 : myVehicleParameter->toTaz = myActiveRoute.back()->getID();
217 0 : myVehicleParameter->parametersSet |= VEHPARS_TO_TAZ_SET;
218 : }
219 : } else {
220 358860 : parseEdges(attrs.getOpt<std::string>(SUMO_ATTR_TO, myVehicleParameter->id.c_str(), ok, "", true), myActiveRoute, rid, ok);
221 : }
222 194559 : myActiveRouteID = "!" + myVehicleParameter->id;
223 194559 : if (myVehicleParameter->routeid == "") {
224 : myVehicleParameter->routeid = myActiveRouteID;
225 : }
226 389118 : }
227 :
228 :
229 : void
230 638671 : RORouteHandler::myStartElement(int element,
231 : const SUMOSAXAttributes& attrs) {
232 : try {
233 638671 : if (myActivePlan != nullptr && myActivePlan->empty() && myVehicleParameter->departProcedure == DepartDefinition::TRIGGERED && element != SUMO_TAG_RIDE && element != SUMO_TAG_PARAM) {
234 15 : throw ProcessError(TLF("Triggered departure for person '%' requires starting with a ride.", myVehicleParameter->id));
235 638666 : } else if (myActiveContainerPlan != nullptr && myActiveContainerPlanSize == 0 && myVehicleParameter->departProcedure == DepartDefinition::TRIGGERED && element != SUMO_TAG_TRANSPORT && element != SUMO_TAG_PARAM) {
236 15 : throw ProcessError(TLF("Triggered departure for container '%' requires starting with a transport.", myVehicleParameter->id));
237 : }
238 638661 : SUMORouteHandler::myStartElement(element, attrs);
239 638236 : bool ok = true;
240 638236 : switch (element) {
241 3678 : case SUMO_TAG_PERSON:
242 : case SUMO_TAG_PERSONFLOW: {
243 3678 : myActivePlan = new std::vector<ROPerson::PlanItem*>();
244 3678 : break;
245 : }
246 : case SUMO_TAG_RIDE:
247 : break; // handled in addRide, called from SUMORouteHandler::myStartElement
248 80 : case SUMO_TAG_CONTAINER:
249 : case SUMO_TAG_CONTAINERFLOW:
250 80 : myActiveContainerPlan = new OutputDevice_String(1);
251 80 : myActiveContainerPlanSize = 0;
252 80 : myActiveContainerPlan->openTag((SumoXMLTag)element);
253 80 : (*myActiveContainerPlan) << attrs;
254 : break;
255 75 : case SUMO_TAG_TRANSPORT:
256 : case SUMO_TAG_TRANSHIP:
257 75 : if (myActiveContainerPlan == nullptr) {
258 10 : throw ProcessError(TLF("Found % outside container element", toString((SumoXMLTag)element)));
259 : }
260 : // copy container elements
261 70 : myActiveContainerPlan->openTag((SumoXMLTag)element);
262 70 : (*myActiveContainerPlan) << attrs;
263 70 : myActiveContainerPlan->closeTag();
264 70 : myActiveContainerPlanSize++;
265 70 : break;
266 2819 : case SUMO_TAG_FLOW:
267 2819 : myActiveRouteProbability = DEFAULT_VEH_PROB;
268 2819 : parseFromViaTo((SumoXMLTag)element, attrs, ok);
269 : break;
270 188072 : case SUMO_TAG_TRIP:
271 188072 : myActiveRouteProbability = DEFAULT_VEH_PROB;
272 188072 : parseFromViaTo((SumoXMLTag)element, attrs, ok);
273 : break;
274 : default:
275 : break;
276 : }
277 440 : } catch (ProcessError&) {
278 440 : deleteActivePlanAndVehicleParameter();
279 440 : throw;
280 440 : }
281 638231 : }
282 :
283 :
284 : void
285 115 : RORouteHandler::openVehicleTypeDistribution(const SUMOSAXAttributes& attrs) {
286 115 : bool ok = true;
287 115 : myCurrentVTypeDistributionID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
288 115 : if (ok) {
289 115 : myCurrentVTypeDistribution = new RandomDistributor<SUMOVTypeParameter*>();
290 115 : if (attrs.hasAttribute(SUMO_ATTR_VTYPES)) {
291 : std::vector<double> probs;
292 60 : if (attrs.hasAttribute(SUMO_ATTR_PROBS)) {
293 20 : StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_PROBS, myCurrentVTypeDistributionID.c_str(), ok));
294 60 : while (st.hasNext()) {
295 80 : probs.push_back(StringUtils::toDoubleSecure(st.next(), 1.0));
296 : }
297 20 : }
298 60 : const std::string vTypes = attrs.get<std::string>(SUMO_ATTR_VTYPES, myCurrentVTypeDistributionID.c_str(), ok);
299 60 : StringTokenizer st(vTypes);
300 60 : int probIndex = 0;
301 150 : while (st.hasNext()) {
302 90 : const std::string typeID = st.next();
303 90 : const RandomDistributor<SUMOVTypeParameter*>* const dist = myNet.getVTypeDistribution(typeID);
304 : if (dist != nullptr) {
305 20 : const double distProb = ((int)probs.size() > probIndex ? probs[probIndex] : 1.) / dist->getOverallProb();
306 : std::vector<double>::const_iterator probIt = dist->getProbs().begin();
307 60 : for (SUMOVTypeParameter* const type : dist->getVals()) {
308 40 : myCurrentVTypeDistribution->add(type, distProb * *probIt);
309 : probIt++;
310 : }
311 : } else {
312 70 : SUMOVTypeParameter* const type = myNet.getVehicleTypeSecure(typeID);
313 70 : if (type == nullptr) {
314 30 : myErrorOutput->inform("Unknown vehicle type '" + typeID + "' in distribution '" + myCurrentVTypeDistributionID + "'.");
315 : } else {
316 60 : const double prob = ((int)probs.size() > probIndex ? probs[probIndex] : type->defaultProbability);
317 60 : myCurrentVTypeDistribution->add(type, prob);
318 : }
319 : }
320 90 : probIndex++;
321 : }
322 60 : if (probs.size() > 0 && probIndex != (int)probs.size()) {
323 0 : WRITE_WARNING("Got " + toString(probs.size()) + " probabilities for " + toString(probIndex) +
324 : " types in vTypeDistribution '" + myCurrentVTypeDistributionID + "'");
325 : }
326 120 : }
327 : }
328 115 : }
329 :
330 :
331 : void
332 115 : RORouteHandler::closeVehicleTypeDistribution() {
333 115 : if (myCurrentVTypeDistribution != nullptr) {
334 115 : if (myCurrentVTypeDistribution->getOverallProb() == 0) {
335 10 : delete myCurrentVTypeDistribution;
336 30 : myErrorOutput->inform("Vehicle type distribution '" + myCurrentVTypeDistributionID + "' is empty.");
337 105 : } else if (!myNet.addVTypeDistribution(myCurrentVTypeDistributionID, myCurrentVTypeDistribution)) {
338 0 : delete myCurrentVTypeDistribution;
339 0 : myErrorOutput->inform("Another vehicle type (or distribution) with the id '" + myCurrentVTypeDistributionID + "' exists.");
340 : }
341 115 : myCurrentVTypeDistribution = nullptr;
342 : }
343 115 : }
344 :
345 :
346 : void
347 236872 : RORouteHandler::openRoute(const SUMOSAXAttributes& attrs) {
348 : myActiveRoute.clear();
349 236872 : myInsertStopEdgesAt = -1;
350 : // check whether the id is really necessary
351 : std::string rid;
352 236872 : if (myCurrentAlternatives != nullptr) {
353 233908 : myActiveRouteID = myCurrentAlternatives->getID();
354 701724 : rid = "distribution '" + myCurrentAlternatives->getID() + "'";
355 2964 : } else if (myVehicleParameter != nullptr) {
356 : // ok, a vehicle is wrapping the route,
357 : // we may use this vehicle's id as default
358 1771 : myVehicleParameter->routeid = myActiveRouteID = "!" + myVehicleParameter->id; // !!! document this
359 1771 : if (attrs.hasAttribute(SUMO_ATTR_ID)) {
360 0 : WRITE_WARNINGF(TL("Ids of internal routes are ignored (vehicle '%')."), myVehicleParameter->id);
361 : }
362 : } else {
363 1193 : bool ok = true;
364 1193 : myActiveRouteID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
365 1193 : if (!ok) {
366 20 : return;
367 : }
368 3519 : rid = "'" + myActiveRouteID + "'";
369 : }
370 236852 : if (myVehicleParameter != nullptr) { // have to do this here for nested route distributions
371 703212 : rid = "for vehicle '" + myVehicleParameter->id + "'";
372 : }
373 236852 : bool ok = true;
374 236852 : if (attrs.hasAttribute(SUMO_ATTR_EDGES)) {
375 473684 : parseEdges(attrs.get<std::string>(SUMO_ATTR_EDGES, myActiveRouteID.c_str(), ok), myActiveRoute, rid, ok);
376 : }
377 473704 : myActiveRouteRefID = attrs.getOpt<std::string>(SUMO_ATTR_REFID, myActiveRouteID.c_str(), ok, "");
378 236852 : if (myActiveRouteRefID != "" && myNet.getRouteDef(myActiveRouteRefID) == nullptr) {
379 0 : myErrorOutput->inform("Invalid reference to route '" + myActiveRouteRefID + "' in route " + rid + ".");
380 : }
381 236852 : if (myCurrentAlternatives != nullptr && !attrs.hasAttribute(SUMO_ATTR_PROB)) {
382 60 : WRITE_WARNINGF(TL("No probability for route %, using default."), rid);
383 : }
384 236852 : myActiveRouteProbability = attrs.getOpt<double>(SUMO_ATTR_PROB, myActiveRouteID.c_str(), ok, DEFAULT_VEH_PROB);
385 236852 : if (ok && myActiveRouteProbability < 0) {
386 30 : myErrorOutput->inform("Invalid probability for route '" + myActiveRouteID + "'.");
387 : }
388 236852 : myActiveRouteColor = attrs.hasAttribute(SUMO_ATTR_COLOR) ? new RGBColor(attrs.get<RGBColor>(SUMO_ATTR_COLOR, myActiveRouteID.c_str(), ok)) : nullptr;
389 236852 : ok = true;
390 236852 : myActiveRouteRepeat = attrs.getOpt<int>(SUMO_ATTR_REPEAT, myActiveRouteID.c_str(), ok, 0);
391 236852 : myActiveRoutePeriod = attrs.getOptSUMOTimeReporting(SUMO_ATTR_CYCLETIME, myActiveRouteID.c_str(), ok, 0);
392 236852 : if (myActiveRouteRepeat > 0) {
393 : SUMOVehicleClass vClass = SVC_IGNORING;
394 10 : if (myVehicleParameter != nullptr) {
395 0 : SUMOVTypeParameter* type = myNet.getVehicleTypeSecure(myVehicleParameter->vtypeid);
396 0 : if (type != nullptr) {
397 0 : vClass = type->vehicleClass;
398 : }
399 : }
400 10 : if (myActiveRoute.size() > 0 && !myActiveRoute.back()->isConnectedTo(*myActiveRoute.front(), vClass)) {
401 0 : myErrorOutput->inform("Disconnected route " + rid + " when repeating.");
402 : }
403 : }
404 236852 : myCurrentCosts = attrs.getOpt<double>(SUMO_ATTR_COST, myActiveRouteID.c_str(), ok, -1);
405 236852 : if (ok && myCurrentCosts != -1 && myCurrentCosts < 0) {
406 30 : myErrorOutput->inform("Invalid cost for route '" + myActiveRouteID + "'.");
407 : }
408 : }
409 :
410 :
411 : void
412 2133 : RORouteHandler::openFlow(const SUMOSAXAttributes& /*attrs*/) {
413 : // currently unused
414 2133 : }
415 :
416 :
417 : void
418 686 : RORouteHandler::openRouteFlow(const SUMOSAXAttributes& /*attrs*/) {
419 : // currently unused
420 686 : }
421 :
422 :
423 : void
424 188072 : RORouteHandler::openTrip(const SUMOSAXAttributes& /*attrs*/) {
425 : // currently unused
426 188072 : }
427 :
428 :
429 : void
430 426975 : RORouteHandler::closeRoute(const bool mayBeDisconnected) {
431 426975 : const bool mustReroute = myActiveRoute.size() == 0 && myActiveRouteStops.size() != 0;
432 : if (mustReroute) {
433 : // implicit route from stops
434 25 : for (const SUMOVehicleParameter::Stop& stop : myActiveRouteStops) {
435 20 : ROEdge* edge = myNet.getEdge(stop.edge);
436 20 : myActiveRoute.push_back(edge);
437 : }
438 : }
439 426975 : if (myActiveRoute.size() == 0) {
440 30 : if (myActiveRouteRefID != "" && myCurrentAlternatives != nullptr) {
441 10 : myCurrentAlternatives->addAlternativeDef(myNet.getRouteDef(myActiveRouteRefID));
442 5 : myActiveRouteID = "";
443 : myActiveRouteRefID = "";
444 30 : return;
445 : }
446 25 : if (myVehicleParameter != nullptr) {
447 15 : myErrorOutput->inform("The route for vehicle '" + myVehicleParameter->id + "' has no edges.");
448 : } else {
449 60 : myErrorOutput->inform("Route '" + myActiveRouteID + "' has no edges.");
450 : }
451 25 : myActiveRouteID = "";
452 : myActiveRouteStops.clear();
453 25 : return;
454 : }
455 426945 : if (myActiveRoute.size() == 1 && myActiveRoute.front()->isTazConnector()) {
456 0 : myErrorOutput->inform("The routing information for vehicle '" + myVehicleParameter->id + "' is insufficient.");
457 0 : myActiveRouteID = "";
458 : myActiveRouteStops.clear();
459 0 : return;
460 : }
461 900641 : if (!mayBeDisconnected && OptionsCont::getOptions().exists("no-internal-links") && !OptionsCont::getOptions().getBool("no-internal-links")) {
462 : // fix internal edges which did not get parsed
463 : const ROEdge* last = nullptr;
464 : ConstROEdgeVector fullRoute;
465 1516976 : for (const ROEdge* roe : myActiveRoute) {
466 1280131 : if (last != nullptr) {
467 2544961 : for (const ROEdge* intern : last->getSuccessors()) {
468 1501675 : if (intern->isInternal() && intern->getSuccessors().size() == 1 && intern->getSuccessors().front() == roe) {
469 0 : fullRoute.push_back(intern);
470 : }
471 : }
472 : }
473 1280131 : fullRoute.push_back(roe);
474 : last = roe;
475 : }
476 236845 : myActiveRoute = fullRoute;
477 236845 : }
478 426945 : if (myActiveRouteRepeat > 0) {
479 : // duplicate route
480 10 : ConstROEdgeVector tmpEdges = myActiveRoute;
481 10 : auto tmpStops = myActiveRouteStops;
482 30 : for (int i = 0; i < myActiveRouteRepeat; i++) {
483 20 : myActiveRoute.insert(myActiveRoute.begin(), tmpEdges.begin(), tmpEdges.end());
484 100 : for (SUMOVehicleParameter::Stop stop : tmpStops) {
485 80 : if (stop.until > 0) {
486 40 : if (myActiveRoutePeriod <= 0) {
487 0 : const std::string description = myVehicleParameter != nullptr
488 0 : ? "for vehicle '" + myVehicleParameter->id + "'"
489 0 : : "'" + myActiveRouteID + "'";
490 0 : throw ProcessError(TLF("Cannot repeat stops with 'until' in route % because no cycleTime is defined.", description));
491 : }
492 40 : stop.until += myActiveRoutePeriod * (i + 1);
493 40 : stop.arrival += myActiveRoutePeriod * (i + 1);
494 : }
495 80 : myActiveRouteStops.push_back(stop);
496 80 : }
497 : }
498 10 : }
499 426945 : std::shared_ptr<RORoute> route = std::make_shared<RORoute>(myActiveRouteID, myCurrentCosts, myActiveRouteProbability, myActiveRoute,
500 426945 : myActiveRouteColor, myActiveRouteStops);
501 : myActiveRoute.clear();
502 426945 : if (myCurrentAlternatives == nullptr) {
503 193042 : if (myNet.getRouteDef(myActiveRouteID) != nullptr) {
504 0 : if (myVehicleParameter != nullptr) {
505 0 : myErrorOutput->inform("Another route for vehicle '" + myVehicleParameter->id + "' exists.");
506 : } else {
507 0 : myErrorOutput->inform("Another route (or distribution) with the id '" + myActiveRouteID + "' exists.");
508 : }
509 : myActiveRouteID = "";
510 : myActiveRouteStops.clear();
511 : return;
512 : } else {
513 193042 : myCurrentAlternatives = new RORouteDef(myActiveRouteID, 0, mayBeDisconnected || myTryRepair, mayBeDisconnected);
514 193042 : myCurrentAlternatives->addLoadedAlternative(route);
515 193042 : myNet.addRouteDef(myCurrentAlternatives);
516 193042 : myCurrentAlternatives = nullptr;
517 : }
518 : } else {
519 233903 : myCurrentAlternatives->addLoadedAlternative(route);
520 : }
521 : myActiveRouteID = "";
522 : myActiveRouteStops.clear();
523 : }
524 :
525 :
526 : void
527 92040 : RORouteHandler::openRouteDistribution(const SUMOSAXAttributes& attrs) {
528 : // check whether the id is really necessary
529 92040 : bool ok = true;
530 : std::string id;
531 92040 : if (myVehicleParameter != nullptr) {
532 : // ok, a vehicle is wrapping the route,
533 : // we may use this vehicle's id as default
534 90760 : myVehicleParameter->routeid = id = "!" + myVehicleParameter->id; // !!! document this
535 90760 : if (attrs.hasAttribute(SUMO_ATTR_ID)) {
536 0 : WRITE_WARNINGF(TL("Ids of internal route distributions are ignored (vehicle '%')."), myVehicleParameter->id);
537 : }
538 : } else {
539 1280 : id = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
540 1280 : if (!ok) {
541 : return;
542 : }
543 : }
544 : // try to get the index of the last element
545 92030 : int index = attrs.getOpt<int>(SUMO_ATTR_LAST, id.c_str(), ok, 0);
546 92030 : if (ok && index < 0) {
547 20 : myErrorOutput->inform("Negative index of a route alternative (id='" + id + "').");
548 10 : return;
549 : }
550 : // build the alternative cont
551 92020 : myCurrentAlternatives = new RORouteDef(id, index, myTryRepair, false);
552 92020 : if (attrs.hasAttribute(SUMO_ATTR_ROUTES)) {
553 0 : ok = true;
554 0 : StringTokenizer st(attrs.get<std::string>(SUMO_ATTR_ROUTES, id.c_str(), ok));
555 0 : while (st.hasNext()) {
556 0 : const std::string routeID = st.next();
557 0 : const RORouteDef* route = myNet.getRouteDef(routeID);
558 0 : if (route == nullptr) {
559 0 : myErrorOutput->inform("Unknown route '" + routeID + "' in distribution '" + id + "'.");
560 : } else {
561 0 : myCurrentAlternatives->addAlternativeDef(route);
562 : }
563 : }
564 0 : }
565 : }
566 :
567 :
568 : void
569 92020 : RORouteHandler::closeRouteDistribution() {
570 92020 : if (myCurrentAlternatives != nullptr) {
571 92000 : if (myCurrentAlternatives->getOverallProb() == 0) {
572 0 : myErrorOutput->inform("Route distribution '" + myCurrentAlternatives->getID() + "' is empty.");
573 0 : delete myCurrentAlternatives;
574 92000 : } else if (!myNet.addRouteDef(myCurrentAlternatives)) {
575 0 : myErrorOutput->inform("Another route (or distribution) with the id '" + myCurrentAlternatives->getID() + "' exists.");
576 0 : delete myCurrentAlternatives;
577 : } else {
578 184000 : if (myVehicleParameter != nullptr
579 182885 : && (myUseTaz || OptionsCont::getOptions().getBool("junction-taz"))
580 92190 : && (myVehicleParameter->wasSet(VEHPARS_FROM_TAZ_SET) ||
581 : myVehicleParameter->wasSet(VEHPARS_TO_TAZ_SET))) {
582 : // we are loading a rou.alt.xml, permit rerouting between taz
583 : bool ok = true;
584 : ConstROEdgeVector edges;
585 190 : if (myVehicleParameter->fromTaz != "") {
586 : const std::string tazID = myVehicleParameter->fromTaz;
587 380 : const ROEdge* fromTaz = myNet.getEdge(tazID + "-source");
588 190 : if (fromTaz == nullptr) {
589 0 : myErrorOutput->inform("Source taz '" + tazID + "' not known for vehicle '" + myVehicleParameter->id + "'!");
590 : ok = false;
591 190 : } else if (fromTaz->getNumSuccessors() == 0) {
592 0 : myErrorOutput->inform("Source taz '" + tazID + "' has no outgoing edges for vehicle '" + myVehicleParameter->id + "'!");
593 : ok = false;
594 : } else {
595 190 : edges.push_back(fromTaz);
596 : }
597 : } else {
598 0 : edges.push_back(myCurrentAlternatives->getOrigin());
599 : }
600 190 : if (myVehicleParameter->toTaz != "") {
601 : const std::string tazID = myVehicleParameter->toTaz;
602 380 : const ROEdge* toTaz = myNet.getEdge(tazID + "-sink");
603 190 : if (toTaz == nullptr) {
604 0 : myErrorOutput->inform("Sink taz '" + tazID + "' not known for vehicle '" + myVehicleParameter->id + "'!");
605 : ok = false;
606 190 : } else if (toTaz->getNumPredecessors() == 0) {
607 0 : myErrorOutput->inform("Sink taz '" + tazID + "' has no incoming edges for vehicle '" + myVehicleParameter->id + "'!");
608 : ok = false;
609 : } else {
610 190 : edges.push_back(toTaz);
611 : }
612 : } else {
613 0 : edges.push_back(myCurrentAlternatives->getDestination());
614 : }
615 190 : if (ok) {
616 : // negative probability indicates that this route should not be written
617 380 : myCurrentAlternatives->addLoadedAlternative(std::make_shared<RORoute>(myCurrentAlternatives->getID(), 0, -1, edges, nullptr, myActiveRouteStops));
618 : }
619 190 : }
620 : }
621 92000 : myCurrentAlternatives = nullptr;
622 : }
623 92020 : }
624 :
625 :
626 : void
627 282220 : RORouteHandler::closeVehicle() {
628 282220 : checkLastDepart();
629 : // get the vehicle id
630 282220 : if (myVehicleParameter->departProcedure == DepartDefinition::GIVEN && myVehicleParameter->depart < myBegin) {
631 5 : mySkippedVehicles.insert(myVehicleParameter->id);
632 5 : return;
633 : }
634 : // get vehicle type
635 282215 : SUMOVTypeParameter* type = myNet.getVehicleTypeSecure(myVehicleParameter->vtypeid);
636 282215 : if (type == nullptr) {
637 340 : myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for vehicle '" + myVehicleParameter->id + "' is not known.");
638 170 : type = myNet.getVehicleTypeSecure(DEFAULT_VTYPE_ID);
639 : } else {
640 282045 : if (!myKeepVTypeDist) {
641 : // fix the type id in case we used a distribution
642 282040 : myVehicleParameter->vtypeid = type->id;
643 : }
644 : }
645 282215 : if (type->vehicleClass == SVC_PEDESTRIAN) {
646 150 : WRITE_WARNINGF(TL("Vehicle type '%' with vClass=pedestrian should only be used for persons and not for vehicle '%'."), type->id, myVehicleParameter->id);
647 : }
648 : // get the route
649 282215 : RORouteDef* route = myNet.getRouteDef(myVehicleParameter->routeid);
650 282180 : if (route == nullptr) {
651 70 : myErrorOutput->inform("The route of the vehicle '" + myVehicleParameter->id + "' is not known.");
652 35 : return;
653 : }
654 282180 : if (MsgHandler::getErrorInstance()->wasInformed()) {
655 : return;
656 : }
657 281995 : const bool needCopy = route->getID()[0] != '!';
658 281995 : if (needCopy) {
659 3216 : route = route->copy("!" + myVehicleParameter->id, myVehicleParameter->depart);
660 : }
661 : // build the vehicle
662 281995 : ROVehicle* veh = new ROVehicle(*myVehicleParameter, route, type, &myNet, myErrorOutput);
663 281995 : if (myNet.addVehicle(myVehicleParameter->id, veh)) {
664 281990 : registerLastDepart();
665 5 : } else if (needCopy) {
666 5 : delete route;
667 : }
668 281995 : delete myVehicleParameter;
669 281995 : myVehicleParameter = nullptr;
670 : }
671 :
672 :
673 : void
674 2646 : RORouteHandler::closeVType() {
675 2646 : if (myCurrentVTypeRef.empty()) {
676 2596 : myNet.addVehicleType(myCurrentVType);
677 5192 : if (OptionsCont::getOptions().isSet("restriction-params")) {
678 30 : const std::vector<std::string> paramKeys = OptionsCont::getOptions().getStringVector("restriction-params");
679 30 : myCurrentVType->cacheParamRestrictions(paramKeys);
680 30 : }
681 : }
682 2646 : if (myCurrentVTypeDistribution != nullptr) {
683 110 : if (myCurrentVTypeRef.empty()) {
684 60 : myCurrentVTypeDistribution->add(myCurrentVType, myCurrentVType->defaultProbability);
685 : } else {
686 50 : const RandomDistributor<SUMOVTypeParameter*>* const dist = myNet.getVTypeDistribution(myCurrentVTypeRef);
687 10 : if (dist != nullptr) {
688 20 : const double distProb = (myCurrentVTypeProbability >= 0 ? myCurrentVTypeProbability : 1) / dist->getOverallProb();
689 : std::vector<double>::const_iterator probIt = dist->getProbs().begin();
690 30 : for (SUMOVTypeParameter* const type : dist->getVals()) {
691 20 : myCurrentVTypeDistribution->add(type, distProb * *probIt);
692 : probIt++;
693 : }
694 : } else {
695 40 : SUMOVTypeParameter* const type = myNet.getVehicleTypeSecure(myCurrentVTypeRef);
696 40 : double probability = myCurrentVTypeProbability >= 0 ? myCurrentVTypeProbability : type->defaultProbability;
697 40 : myCurrentVTypeDistribution->add(type, probability);
698 : }
699 : }
700 : }
701 2646 : myCurrentVType = nullptr;
702 2646 : }
703 :
704 :
705 : void
706 3477 : RORouteHandler::closePerson() {
707 3477 : SUMOVTypeParameter* type = myNet.getVehicleTypeSecure(myVehicleParameter->vtypeid);
708 3477 : if (type == nullptr) {
709 0 : myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for person '" + myVehicleParameter->id + "' is not known.");
710 0 : type = myNet.getVehicleTypeSecure(DEFAULT_PEDTYPE_ID);
711 : }
712 3477 : if (myActivePlan == nullptr || myActivePlan->empty()) {
713 50 : WRITE_WARNINGF(TL("Discarding person '%' because her plan is empty"), myVehicleParameter->id);
714 3452 : } else if (myVehicleParameter->departProcedure != DepartDefinition::GIVEN || myVehicleParameter->depart >= myBegin) {
715 3442 : ROPerson* person = new ROPerson(*myVehicleParameter, type);
716 7114 : for (ROPerson::PlanItem* item : *myActivePlan) {
717 3672 : person->getPlan().push_back(item);
718 : }
719 3442 : myActivePlan->clear();
720 3442 : if (myNet.addPerson(person)) {
721 3442 : checkLastDepart();
722 3442 : registerLastDepart();
723 : }
724 : }
725 3477 : deleteActivePlanAndVehicleParameter();
726 3477 : }
727 :
728 :
729 : void
730 196 : RORouteHandler::closePersonFlow() {
731 : std::string typeID = DEFAULT_PEDTYPE_ID;
732 196 : if (myNet.getVehicleTypeSecure(myVehicleParameter->vtypeid) == nullptr) {
733 0 : myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for personFlow '" + myVehicleParameter->id + "' is not known.");
734 : } else {
735 196 : typeID = myVehicleParameter->vtypeid;
736 : }
737 196 : if (myActivePlan == nullptr || myActivePlan->empty()) {
738 0 : WRITE_WARNINGF(TL("Discarding personFlow '%' because their plan is empty"), myVehicleParameter->id);
739 : } else {
740 196 : checkLastDepart();
741 : // instantiate all persons of this flow
742 : int i = 0;
743 196 : std::string baseID = myVehicleParameter->id;
744 196 : if (myWriteFlows) {
745 160 : addFlowPerson(typeID, myVehicleParameter->depart, baseID, i);
746 36 : } else if (myVehicleParameter->repetitionProbability > 0) {
747 5 : if (myVehicleParameter->repetitionEnd == SUMOTime_MAX) {
748 0 : throw ProcessError(TLF("probabilistic personFlow '%' must specify end time", myVehicleParameter->id));
749 : } else {
750 55 : for (SUMOTime t = myVehicleParameter->depart; t < myVehicleParameter->repetitionEnd; t += TIME2STEPS(1)) {
751 50 : if (RandHelper::rand() < myVehicleParameter->repetitionProbability) {
752 25 : addFlowPerson(typeID, t, baseID, i++);
753 : }
754 : }
755 : }
756 : } else {
757 31 : SUMOTime depart = myVehicleParameter->depart;
758 : // uniform sampling of departures from range is equivalent to poisson flow (encoded by negative offset)
759 62 : if (OptionsCont::getOptions().getBool("randomize-flows") && myVehicleParameter->repetitionOffset >= 0) {
760 : std::vector<SUMOTime> departures;
761 5 : const SUMOTime range = myVehicleParameter->repetitionNumber * myVehicleParameter->repetitionOffset;
762 30 : for (int j = 0; j < myVehicleParameter->repetitionNumber; ++j) {
763 25 : departures.push_back(depart + RandHelper::rand(range));
764 : }
765 5 : std::sort(departures.begin(), departures.end());
766 : std::reverse(departures.begin(), departures.end());
767 30 : for (; i < myVehicleParameter->repetitionNumber; i++) {
768 25 : addFlowPerson(typeID, departures[i], baseID, i);
769 : depart += myVehicleParameter->repetitionOffset;
770 : }
771 5 : } else {
772 26 : const bool triggered = myVehicleParameter->departProcedure == DepartDefinition::TRIGGERED;
773 26 : if (myVehicleParameter->repetitionOffset < 0) {
774 : // poisson: randomize first depart
775 5 : myVehicleParameter->incrementFlow(1);
776 : }
777 236 : for (; i < myVehicleParameter->repetitionNumber && (triggered || depart + myVehicleParameter->repetitionTotalOffset <= myVehicleParameter->repetitionEnd); i++) {
778 210 : addFlowPerson(typeID, depart + myVehicleParameter->repetitionTotalOffset, baseID, i);
779 210 : if (myVehicleParameter->departProcedure != DepartDefinition::TRIGGERED) {
780 210 : myVehicleParameter->incrementFlow(1);
781 : }
782 : }
783 : }
784 : }
785 : }
786 196 : deleteActivePlanAndVehicleParameter();
787 196 : }
788 :
789 :
790 : void
791 420 : RORouteHandler::addFlowPerson(const std::string& typeID, SUMOTime depart, const std::string& baseID, int i) {
792 420 : SUMOVehicleParameter pars = *myVehicleParameter;
793 840 : pars.id = baseID + "." + toString(i);
794 420 : pars.depart = depart;
795 420 : const SUMOVTypeParameter* const type = myNet.getVehicleTypeSecure(typeID);
796 420 : if (!myKeepVTypeDist) {
797 420 : pars.vtypeid = type->id;
798 : }
799 420 : ROPerson* person = new ROPerson(pars, type);
800 840 : for (ROPerson::PlanItem* item : *myActivePlan) {
801 420 : person->getPlan().push_back(item->clone());
802 : }
803 420 : if (myNet.addPerson(person)) {
804 420 : if (i == 0) {
805 196 : registerLastDepart();
806 : }
807 : }
808 420 : }
809 :
810 :
811 : void
812 45 : RORouteHandler::closeContainer() {
813 45 : myActiveContainerPlan->closeTag();
814 45 : if (myActiveContainerPlanSize > 0) {
815 45 : myNet.addContainer(myVehicleParameter->depart, myActiveContainerPlan->getString());
816 45 : checkLastDepart();
817 45 : registerLastDepart();
818 : } else {
819 0 : WRITE_WARNINGF(TL("Discarding container '%' because its plan is empty"), myVehicleParameter->id);
820 : }
821 45 : delete myVehicleParameter;
822 45 : myVehicleParameter = nullptr;
823 45 : delete myActiveContainerPlan;
824 45 : myActiveContainerPlan = nullptr;
825 45 : myActiveContainerPlanSize = 0;
826 45 : }
827 :
828 :
829 25 : void RORouteHandler::closeContainerFlow() {
830 25 : myActiveContainerPlan->closeTag();
831 25 : if (myActiveContainerPlanSize > 0) {
832 25 : myNet.addContainer(myVehicleParameter->depart, myActiveContainerPlan->getString());
833 25 : checkLastDepart();
834 25 : registerLastDepart();
835 : } else {
836 0 : WRITE_WARNINGF(TL("Discarding containerFlow '%' because its plan is empty"), myVehicleParameter->id);
837 : }
838 25 : delete myVehicleParameter;
839 25 : myVehicleParameter = nullptr;
840 25 : delete myActiveContainerPlan;
841 25 : myActiveContainerPlan = nullptr;
842 25 : myActiveContainerPlanSize = 0;
843 25 : }
844 :
845 :
846 : void
847 2819 : RORouteHandler::closeFlow() {
848 2819 : checkLastDepart();
849 : // @todo: consider myScale?
850 2819 : if (myVehicleParameter->repetitionNumber == 0) {
851 9 : delete myVehicleParameter;
852 9 : myVehicleParameter = nullptr;
853 9 : return;
854 : }
855 : // let's check whether vehicles had to depart before the simulation starts
856 2810 : myVehicleParameter->repetitionsDone = 0;
857 2810 : const SUMOTime offsetToBegin = myBegin - myVehicleParameter->depart;
858 2994 : while (myVehicleParameter->repetitionTotalOffset < offsetToBegin) {
859 186 : myVehicleParameter->incrementFlow(1);
860 186 : if (myVehicleParameter->repetitionsDone == myVehicleParameter->repetitionNumber) {
861 2 : delete myVehicleParameter;
862 2 : myVehicleParameter = nullptr;
863 2 : return;
864 : }
865 : }
866 2808 : if (myNet.getVehicleTypeSecure(myVehicleParameter->vtypeid) == nullptr) {
867 66 : myErrorOutput->inform("The vehicle type '" + myVehicleParameter->vtypeid + "' for flow '" + myVehicleParameter->id + "' is not known.");
868 : }
869 2808 : if (myVehicleParameter->routeid[0] == '!' && myNet.getRouteDef(myVehicleParameter->routeid) == nullptr) {
870 2031 : closeRoute(true);
871 : }
872 2808 : if (myNet.getRouteDef(myVehicleParameter->routeid) == nullptr) {
873 0 : myErrorOutput->inform("The route '" + myVehicleParameter->routeid + "' for flow '" + myVehicleParameter->id + "' is not known.");
874 0 : delete myVehicleParameter;
875 0 : myVehicleParameter = nullptr;
876 0 : return;
877 : }
878 2808 : myActiveRouteID = "";
879 2808 : if (!MsgHandler::getErrorInstance()->wasInformed()) {
880 5594 : if (myNet.addFlow(myVehicleParameter, OptionsCont::getOptions().getBool("randomize-flows"))) {
881 2792 : registerLastDepart();
882 : } else {
883 10 : myErrorOutput->inform("Another flow with the id '" + myVehicleParameter->id + "' exists.");
884 5 : delete myVehicleParameter;
885 : }
886 : } else {
887 11 : delete myVehicleParameter;
888 : }
889 2808 : myVehicleParameter = nullptr;
890 2808 : myInsertStopEdgesAt = -1;
891 : }
892 :
893 :
894 : void
895 188072 : RORouteHandler::closeTrip() {
896 188072 : closeRoute(true);
897 188072 : closeVehicle();
898 188072 : }
899 :
900 :
901 : const SUMOVehicleParameter::Stop*
902 7065 : RORouteHandler::retrieveStoppingPlace(const SUMOSAXAttributes& attrs, const std::string& errorSuffix, std::string& id, const SUMOVehicleParameter::Stop* stopParam) {
903 : // dummy stop parameter to hold the attributes
904 7065 : SUMOVehicleParameter::Stop stop;
905 7065 : if (stopParam != nullptr) {
906 3307 : stop = *stopParam;
907 : } else {
908 3758 : bool ok = true;
909 7516 : stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
910 3758 : stop.busstop = attrs.getOpt<std::string>(SUMO_ATTR_TRAIN_STOP, nullptr, ok, stop.busstop); // alias
911 3758 : stop.chargingStation = attrs.getOpt<std::string>(SUMO_ATTR_CHARGING_STATION, nullptr, ok, "");
912 3758 : stop.overheadWireSegment = attrs.getOpt<std::string>(SUMO_ATTR_OVERHEAD_WIRE_SEGMENT, nullptr, ok, "");
913 3758 : stop.containerstop = attrs.getOpt<std::string>(SUMO_ATTR_CONTAINER_STOP, nullptr, ok, "");
914 7516 : stop.parkingarea = attrs.getOpt<std::string>(SUMO_ATTR_PARKING_AREA, nullptr, ok, "");
915 : }
916 : const SUMOVehicleParameter::Stop* toStop = nullptr;
917 7065 : if (stop.busstop != "") {
918 3174 : toStop = myNet.getStoppingPlace(stop.busstop, SUMO_TAG_BUS_STOP);
919 : id = stop.busstop;
920 3174 : if (toStop == nullptr) {
921 0 : WRITE_ERROR("The busStop '" + stop.busstop + "' is not known" + errorSuffix);
922 : }
923 3891 : } else if (stop.containerstop != "") {
924 40 : toStop = myNet.getStoppingPlace(stop.containerstop, SUMO_TAG_CONTAINER_STOP);
925 : id = stop.containerstop;
926 40 : if (toStop == nullptr) {
927 0 : WRITE_ERROR("The containerStop '" + stop.containerstop + "' is not known" + errorSuffix);
928 : }
929 3851 : } else if (stop.parkingarea != "") {
930 30 : toStop = myNet.getStoppingPlace(stop.parkingarea, SUMO_TAG_PARKING_AREA);
931 : id = stop.parkingarea;
932 30 : if (toStop == nullptr) {
933 0 : WRITE_ERROR("The parkingArea '" + stop.parkingarea + "' is not known" + errorSuffix);
934 : }
935 3821 : } else if (stop.chargingStation != "") {
936 : // ok, we have a charging station
937 25 : toStop = myNet.getStoppingPlace(stop.chargingStation, SUMO_TAG_CHARGING_STATION);
938 : id = stop.chargingStation;
939 25 : if (toStop == nullptr) {
940 0 : WRITE_ERROR("The chargingStation '" + stop.chargingStation + "' is not known" + errorSuffix);
941 : }
942 3796 : } else if (stop.overheadWireSegment != "") {
943 : // ok, we have an overhead wire segment
944 0 : toStop = myNet.getStoppingPlace(stop.overheadWireSegment, SUMO_TAG_OVERHEAD_WIRE_SEGMENT);
945 : id = stop.overheadWireSegment;
946 0 : if (toStop == nullptr) {
947 0 : WRITE_ERROR("The overhead wire segment '" + stop.overheadWireSegment + "' is not known" + errorSuffix);
948 : }
949 : }
950 7065 : return toStop;
951 7065 : }
952 :
953 : Parameterised*
954 3327 : RORouteHandler::addStop(const SUMOSAXAttributes& attrs) {
955 : Parameterised* result = nullptr;
956 3327 : if (myActiveContainerPlan != nullptr) {
957 20 : myActiveContainerPlan->openTag(SUMO_TAG_STOP);
958 20 : (*myActiveContainerPlan) << attrs;
959 20 : myActiveContainerPlan->closeTag();
960 20 : myActiveContainerPlanSize++;
961 20 : return result;
962 : }
963 : std::string errorSuffix;
964 3307 : if (myActivePlan != nullptr) {
965 450 : errorSuffix = " in person '" + myVehicleParameter->id + "'.";
966 : } else if (myActiveContainerPlan != nullptr) {
967 : errorSuffix = " in container '" + myVehicleParameter->id + "'.";
968 3157 : } else if (myVehicleParameter != nullptr) {
969 2790 : errorSuffix = " in vehicle '" + myVehicleParameter->id + "'.";
970 : } else {
971 6681 : errorSuffix = " in route '" + myActiveRouteID + "'.";
972 : }
973 3307 : SUMOVehicleParameter::Stop stop;
974 6614 : bool ok = parseStop(stop, attrs, errorSuffix, myErrorOutput);
975 3307 : if (!ok) {
976 : return result;
977 : }
978 : // try to parse the assigned bus stop
979 3307 : const ROEdge* edge = nullptr;
980 : std::string stoppingPlaceID;
981 3307 : const SUMOVehicleParameter::Stop* stoppingPlace = retrieveStoppingPlace(attrs, errorSuffix, stoppingPlaceID, &stop);
982 : bool hasPos = false;
983 3307 : if (stoppingPlace != nullptr) {
984 3049 : stop.lane = stoppingPlace->lane;
985 3049 : stop.endPos = stoppingPlace->endPos;
986 3049 : stop.startPos = stoppingPlace->startPos;
987 12196 : edge = myNet.getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
988 : } else {
989 : // no, the lane and the position should be given
990 258 : stop.lane = attrs.getOpt<std::string>(SUMO_ATTR_LANE, nullptr, ok, "");
991 258 : stop.edge = attrs.getOpt<std::string>(SUMO_ATTR_EDGE, nullptr, ok, "");
992 258 : if (ok && stop.edge != "") {
993 69 : edge = myNet.getEdge(stop.edge);
994 69 : if (edge == nullptr) {
995 0 : myErrorOutput->inform("The edge '" + stop.edge + "' for a stop is not known" + errorSuffix);
996 0 : return result;
997 : }
998 189 : } else if (ok && stop.lane != "") {
999 447 : edge = myNet.getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop.lane));
1000 149 : if (edge == nullptr) {
1001 0 : myErrorOutput->inform("The lane '" + stop.lane + "' for a stop is not known" + errorSuffix);
1002 0 : return result;
1003 : }
1004 40 : } else if (ok && ((attrs.hasAttribute(SUMO_ATTR_X) && attrs.hasAttribute(SUMO_ATTR_Y))
1005 25 : || (attrs.hasAttribute(SUMO_ATTR_LON) && attrs.hasAttribute(SUMO_ATTR_LAT)))) {
1006 : Position pos;
1007 : bool geo = false;
1008 40 : if (attrs.hasAttribute(SUMO_ATTR_X) && attrs.hasAttribute(SUMO_ATTR_Y)) {
1009 15 : pos = Position(attrs.get<double>(SUMO_ATTR_X, myVehicleParameter->id.c_str(), ok), attrs.get<double>(SUMO_ATTR_Y, myVehicleParameter->id.c_str(), ok));
1010 : } else {
1011 25 : pos = Position(attrs.get<double>(SUMO_ATTR_LON, myVehicleParameter->id.c_str(), ok), attrs.get<double>(SUMO_ATTR_LAT, myVehicleParameter->id.c_str(), ok));
1012 : geo = true;
1013 : }
1014 40 : PositionVector positions;
1015 40 : positions.push_back(pos);
1016 : ConstROEdgeVector geoEdges;
1017 : SUMOVehicleClass vClass = SVC_PASSENGER;
1018 40 : if (!myNet.getVTypeDistribution(myVehicleParameter->vtypeid)) {
1019 40 : SUMOVTypeParameter* type = myNet.getVehicleTypeSecure(myVehicleParameter->vtypeid);
1020 40 : if (type != nullptr) {
1021 40 : vClass = type->vehicleClass;
1022 : }
1023 : }
1024 40 : parseGeoEdges(positions, geo, vClass, geoEdges, myVehicleParameter->id, true, ok, true);
1025 40 : if (ok) {
1026 40 : edge = geoEdges.front();
1027 : hasPos = true;
1028 40 : if (geo) {
1029 25 : GeoConvHelper::getFinal().x2cartesian_const(pos);
1030 : }
1031 40 : stop.parametersSet |= STOP_END_SET;
1032 40 : stop.endPos = edge->getLanes()[0]->getShape().nearest_offset_to_point2D(pos, false);
1033 : } else {
1034 : return result;
1035 : }
1036 40 : } else if (!ok || (stop.lane == "" && stop.edge == "")) {
1037 0 : myErrorOutput->inform("A stop must be placed on a bus stop, a container stop, a parking area, an edge or a lane" + errorSuffix);
1038 0 : return result;
1039 : }
1040 : if (!hasPos) {
1041 218 : stop.endPos = attrs.getOpt<double>(SUMO_ATTR_ENDPOS, nullptr, ok, edge->getLength());
1042 : }
1043 258 : stop.startPos = attrs.getOpt<double>(SUMO_ATTR_STARTPOS, nullptr, ok, stop.endPos - 2 * POSITION_EPS);
1044 332 : const bool friendlyPos = attrs.getOpt<bool>(SUMO_ATTR_FRIENDLY_POS, nullptr, ok, !attrs.hasAttribute(SUMO_ATTR_STARTPOS) && !attrs.hasAttribute(SUMO_ATTR_ENDPOS));
1045 258 : const double endPosOffset = edge->isInternal() ? edge->getNormalBefore()->getLength() : 0;
1046 258 : if (!ok || (checkStopPos(stop.startPos, stop.endPos, edge->getLength() + endPosOffset, POSITION_EPS, friendlyPos) != SUMORouteHandler::StopPos::STOPPOS_VALID)) {
1047 0 : myErrorOutput->inform("Invalid start or end position for stop" + errorSuffix);
1048 0 : return result;
1049 : }
1050 : }
1051 3307 : stop.edge = edge->getID();
1052 3307 : if (myActivePlan != nullptr) {
1053 150 : ROPerson::addStop(*myActivePlan, stop, edge);
1054 150 : result = myActivePlan->back()->getStopParameters();
1055 3157 : } else if (myVehicleParameter != nullptr) {
1056 930 : myVehicleParameter->stops.push_back(stop);
1057 930 : result = &myVehicleParameter->stops.back();
1058 : } else {
1059 2227 : myActiveRouteStops.push_back(stop);
1060 : result = &myActiveRouteStops.back();
1061 : }
1062 3307 : if (myInsertStopEdgesAt >= 0) {
1063 642 : myActiveRoute.insert(myActiveRoute.begin() + myInsertStopEdgesAt, edge);
1064 642 : myInsertStopEdgesAt++;
1065 : }
1066 : return result;
1067 3307 : }
1068 :
1069 :
1070 : void
1071 130 : RORouteHandler::addRide(const SUMOSAXAttributes& attrs) {
1072 130 : bool ok = true;
1073 130 : std::vector<ROPerson::PlanItem*>& plan = *myActivePlan;
1074 130 : const std::string pid = myVehicleParameter->id;
1075 :
1076 : const ROEdge* from = nullptr;
1077 : const ROEdge* to = nullptr;
1078 130 : parseFromViaTo(SUMO_TAG_PERSON, attrs, ok);
1079 140 : if (attrs.hasAttribute(SUMO_ATTR_FROM) || attrs.hasAttribute(SUMO_ATTR_FROM_JUNCTION) || attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)
1080 140 : || attrs.hasAttribute(SUMO_ATTR_FROMLONLAT) || attrs.hasAttribute(SUMO_ATTR_FROMXY)) {
1081 125 : if (ok) {
1082 125 : from = myActiveRoute.front();
1083 : }
1084 5 : } else if (plan.empty()) {
1085 0 : myErrorOutput->inform("The start edge for person '" + pid + "' is not known.");
1086 0 : return;
1087 : }
1088 : std::string stoppingPlaceID;
1089 260 : const SUMOVehicleParameter::Stop* stop = retrieveStoppingPlace(attrs, " for ride of person '" + myVehicleParameter->id + "'", stoppingPlaceID);
1090 130 : if (stop != nullptr) {
1091 105 : to = myNet.getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(stop->lane));
1092 : } else {
1093 100 : if (attrs.hasAttribute(SUMO_ATTR_TO) || attrs.hasAttribute(SUMO_ATTR_TO_JUNCTION) || attrs.hasAttribute(SUMO_ATTR_TO_TAZ)
1094 100 : || attrs.hasAttribute(SUMO_ATTR_TOLONLAT) || attrs.hasAttribute(SUMO_ATTR_TOXY)) {
1095 95 : to = myActiveRoute.back();
1096 : } else {
1097 0 : myErrorOutput->inform("The to edge is missing within a ride of '" + myVehicleParameter->id + "'.");
1098 0 : return;
1099 : }
1100 : }
1101 130 : double arrivalPos = attrs.getOpt<double>(SUMO_ATTR_ARRIVALPOS, myVehicleParameter->id.c_str(), ok,
1102 : stop == nullptr ? std::numeric_limits<double>::infinity() : stop->endPos);
1103 130 : const std::string lines = attrs.getOpt<std::string>(SUMO_ATTR_LINES, pid.c_str(), ok, LINE_ANY);
1104 260 : const std::string group = attrs.getOpt<std::string>(SUMO_ATTR_GROUP, pid.c_str(), ok, "");
1105 :
1106 130 : if (plan.empty() && myVehicleParameter->departProcedure == DepartDefinition::TRIGGERED) {
1107 45 : StringTokenizer st(lines);
1108 90 : if (st.size() != 1 || st.get(0) == LINE_ANY) {
1109 0 : myErrorOutput->inform("Triggered departure for person '" + pid + "' requires a unique lines value.");
1110 0 : return;
1111 : }
1112 45 : const std::string vehID = st.front();
1113 45 : if (myNet.knowsVehicle(vehID)) {
1114 25 : const SUMOTime vehDepart = myNet.getDeparture(vehID);
1115 25 : if (vehDepart == -1) {
1116 0 : myErrorOutput->inform("Cannot use triggered vehicle '" + vehID + "' in triggered departure for person '" + pid + "'.");
1117 0 : return;
1118 : }
1119 25 : myVehicleParameter->depart = vehDepart + 1; // write person after vehicle
1120 : } else {
1121 : if (mySkippedVehicles.count(vehID) == 0) {
1122 20 : myErrorOutput->inform("Unknown vehicle '" + vehID + "' in triggered departure for person '" + pid + "'.");
1123 10 : return;
1124 : }
1125 10 : myVehicleParameter->departProcedure = DepartDefinition::GIVEN; // make sure the person gets skipped due to depart time
1126 : }
1127 45 : }
1128 120 : ROPerson::addRide(plan, from, to, lines, arrivalPos, stoppingPlaceID, group);
1129 : }
1130 :
1131 :
1132 : void
1133 40 : RORouteHandler::addTransport(const SUMOSAXAttributes& attrs) {
1134 40 : if (myActiveContainerPlan != nullptr && myActiveContainerPlanSize == 0 && myVehicleParameter->departProcedure == DepartDefinition::TRIGGERED) {
1135 15 : bool ok = true;
1136 : const std::string pid = myVehicleParameter->id;
1137 15 : const std::string desc = attrs.get<std::string>(SUMO_ATTR_LINES, pid.c_str(), ok);
1138 20 : StringTokenizer st(desc);
1139 15 : if (st.size() != 1) {
1140 0 : throw ProcessError(TLF("Triggered departure for container '%' requires a unique lines value.", pid));
1141 : }
1142 15 : const std::string vehID = st.front();
1143 15 : if (!myNet.knowsVehicle(vehID)) {
1144 : if (mySkippedVehicles.count(vehID) == 0) {
1145 15 : throw ProcessError("Unknown vehicle '" + vehID + "' in triggered departure for container '" + pid + "'.");
1146 : }
1147 : return;
1148 : }
1149 10 : SUMOTime vehDepart = myNet.getDeparture(vehID);
1150 10 : if (vehDepart == -1) {
1151 0 : throw ProcessError("Cannot use triggered vehicle '" + vehID + "' in triggered departure for container '" + pid + "'.");
1152 : }
1153 10 : myVehicleParameter->depart = vehDepart + 1; // write container after vehicle
1154 15 : }
1155 : }
1156 :
1157 :
1158 : void
1159 40 : RORouteHandler::addTranship(const SUMOSAXAttributes& /*attrs*/) {
1160 40 : }
1161 :
1162 :
1163 : void
1164 790266 : RORouteHandler::parseEdges(const std::string& desc, ConstROEdgeVector& into,
1165 : const std::string& rid, bool& ok) {
1166 3250187 : for (StringTokenizer st(desc); st.hasNext();) {
1167 1669655 : const std::string id = st.next();
1168 1669655 : const ROEdge* edge = myNet.getEdge(id);
1169 1669655 : if (edge == nullptr) {
1170 78 : myErrorOutput->inform("The edge '" + id + "' within the route " + rid + " is not known.");
1171 39 : ok = false;
1172 : } else {
1173 1669616 : into.push_back(edge);
1174 : }
1175 790266 : }
1176 790266 : }
1177 :
1178 :
1179 : void
1180 3538 : RORouteHandler::parseWalkPositions(const SUMOSAXAttributes& attrs, const std::string& personID,
1181 : const ROEdge* /*fromEdge*/, const ROEdge*& toEdge,
1182 : double& departPos, double& arrivalPos, std::string& busStopID,
1183 : const ROPerson::PlanItem* const lastStage, bool& ok) {
1184 3538 : const std::string description = "walk or personTrip of '" + personID + "'.";
1185 3538 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
1186 0 : WRITE_WARNING(TL("The attribute departPos is no longer supported for walks, please use the person attribute, the arrivalPos of the previous step or explicit stops."));
1187 : }
1188 3538 : departPos = myVehicleParameter->departPos;
1189 3538 : if (lastStage != nullptr) {
1190 170 : departPos = lastStage->getDestinationPos();
1191 : }
1192 :
1193 3538 : busStopID = attrs.getOpt<std::string>(SUMO_ATTR_BUS_STOP, nullptr, ok, "");
1194 :
1195 3538 : const SUMOVehicleParameter::Stop* bs = retrieveStoppingPlace(attrs, description, busStopID);
1196 3538 : if (bs != nullptr) {
1197 465 : toEdge = myNet.getEdge(SUMOXMLDefinitions::getEdgeIDFromLane(bs->lane));
1198 155 : arrivalPos = (bs->startPos + bs->endPos) / 2;
1199 : }
1200 3538 : if (toEdge != nullptr) {
1201 3538 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
1202 258 : arrivalPos = SUMOVehicleParserHelper::parseWalkPos(SUMO_ATTR_ARRIVALPOS,
1203 258 : myHardFail, description, toEdge->getLength(),
1204 516 : attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, description.c_str(), ok));
1205 : }
1206 : } else {
1207 0 : throw ProcessError(TLF("No destination edge for %.", description));
1208 : }
1209 3538 : }
1210 :
1211 :
1212 : void
1213 3538 : RORouteHandler::addPersonTrip(const SUMOSAXAttributes& attrs) {
1214 3538 : bool ok = true;
1215 3538 : const char* const id = myVehicleParameter->id.c_str();
1216 : assert(!attrs.hasAttribute(SUMO_ATTR_EDGES));
1217 : const ROEdge* from = nullptr;
1218 3538 : const ROEdge* to = nullptr;
1219 3538 : parseFromViaTo(SUMO_TAG_PERSON, attrs, ok);
1220 3538 : myInsertStopEdgesAt = -1;
1221 4218 : if (attrs.hasAttribute(SUMO_ATTR_FROM) || attrs.hasAttribute(SUMO_ATTR_FROM_JUNCTION) || attrs.hasAttribute(SUMO_ATTR_FROM_TAZ)
1222 3723 : || attrs.hasAttribute(SUMO_ATTR_FROMLONLAT) || attrs.hasAttribute(SUMO_ATTR_FROMXY)) {
1223 3373 : if (ok) {
1224 3358 : from = myActiveRoute.front();
1225 : }
1226 165 : } else if (myActivePlan->empty()) {
1227 0 : throw ProcessError(TLF("Start edge not defined for person '%'.", myVehicleParameter->id));
1228 : } else {
1229 165 : from = myActivePlan->back()->getDestination();
1230 : }
1231 4198 : if (attrs.hasAttribute(SUMO_ATTR_TO) || attrs.hasAttribute(SUMO_ATTR_TO_JUNCTION) || attrs.hasAttribute(SUMO_ATTR_TO_TAZ)
1232 3713 : || attrs.hasAttribute(SUMO_ATTR_TOLONLAT) || attrs.hasAttribute(SUMO_ATTR_TOXY)) {
1233 3383 : to = myActiveRoute.back();
1234 : } // else, to may also be derived from stopping place
1235 :
1236 3538 : const SUMOTime duration = attrs.getOptSUMOTimeReporting(SUMO_ATTR_DURATION, id, ok, -1);
1237 3538 : if (attrs.hasAttribute(SUMO_ATTR_DURATION) && duration <= 0) {
1238 0 : throw ProcessError(TLF("Non-positive walking duration for '%'.", myVehicleParameter->id));
1239 : }
1240 :
1241 3538 : double departPos = 0;
1242 3538 : double arrivalPos = std::numeric_limits<double>::infinity();
1243 : std::string busStopID;
1244 3538 : const ROPerson::PlanItem* const lastStage = myActivePlan->empty() ? nullptr : myActivePlan->back();
1245 3538 : parseWalkPositions(attrs, myVehicleParameter->id, from, to, departPos, arrivalPos, busStopID, lastStage, ok);
1246 :
1247 3538 : const std::string modes = attrs.getOpt<std::string>(SUMO_ATTR_MODES, id, ok, "");
1248 7076 : const std::string group = attrs.getOpt<std::string>(SUMO_ATTR_GROUP, id, ok, "");
1249 : SVCPermissions modeSet = 0;
1250 9770 : for (StringTokenizer st(modes); st.hasNext();) {
1251 2694 : const std::string mode = st.next();
1252 2694 : if (mode == "car") {
1253 855 : modeSet |= SVC_PASSENGER;
1254 1839 : } else if (mode == "taxi") {
1255 105 : modeSet |= SVC_TAXI;
1256 1734 : } else if (mode == "bicycle") {
1257 15 : modeSet |= SVC_BICYCLE;
1258 1719 : } else if (mode == "public") {
1259 1719 : modeSet |= SVC_BUS;
1260 : } else {
1261 0 : throw InvalidArgument("Unknown person mode '" + mode + "'.");
1262 : }
1263 3538 : }
1264 3538 : const std::string types = attrs.getOpt<std::string>(SUMO_ATTR_VTYPES, id, ok, "");
1265 3538 : double walkFactor = attrs.getOpt<double>(SUMO_ATTR_WALKFACTOR, id, ok, OptionsCont::getOptions().getFloat("persontrip.walkfactor"));
1266 3538 : if (ok) {
1267 3523 : const std::string originStopID = myActivePlan->empty() ? "" : myActivePlan->back()->getStopDest();
1268 3523 : ROPerson::addTrip(*myActivePlan, myVehicleParameter->id, from, to, modeSet, types,
1269 : departPos, originStopID, arrivalPos, busStopID, walkFactor, group);
1270 3523 : myParamStack.push_back(myActivePlan->back());
1271 : }
1272 3538 : }
1273 :
1274 :
1275 : void
1276 1324 : RORouteHandler::addWalk(const SUMOSAXAttributes& attrs) {
1277 : // parse walks from->to as person trips
1278 1324 : if (attrs.hasAttribute(SUMO_ATTR_EDGES) || attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
1279 : // XXX allow --repair?
1280 90 : bool ok = true;
1281 90 : if (attrs.hasAttribute(SUMO_ATTR_ROUTE)) {
1282 15 : const std::string routeID = attrs.get<std::string>(SUMO_ATTR_ROUTE, myVehicleParameter->id.c_str(), ok);
1283 15 : RORouteDef* routeDef = myNet.getRouteDef(routeID);
1284 15 : const std::shared_ptr<const RORoute> route = routeDef != nullptr ? routeDef->getFirstRoute() : nullptr;
1285 15 : if (route == nullptr) {
1286 0 : throw ProcessError("The route '" + routeID + "' for walk of person '" + myVehicleParameter->id + "' is not known.");
1287 : }
1288 15 : myActiveRoute = route->getEdgeVector();
1289 : } else {
1290 : myActiveRoute.clear();
1291 300 : parseEdges(attrs.get<std::string>(SUMO_ATTR_EDGES, myVehicleParameter->id.c_str(), ok), myActiveRoute, " walk for person '" + myVehicleParameter->id + "'", ok);
1292 : }
1293 90 : const char* const objId = myVehicleParameter->id.c_str();
1294 90 : const double duration = attrs.getOpt<double>(SUMO_ATTR_DURATION, objId, ok, -1);
1295 90 : if (attrs.hasAttribute(SUMO_ATTR_DURATION) && duration <= 0) {
1296 0 : throw ProcessError(TLF("Non-positive walking duration for '%'.", myVehicleParameter->id));
1297 : }
1298 90 : const double speed = attrs.getOpt<double>(SUMO_ATTR_SPEED, objId, ok, -1.);
1299 90 : if (attrs.hasAttribute(SUMO_ATTR_SPEED) && speed <= 0) {
1300 0 : throw ProcessError(TLF("Non-positive walking speed for '%'.", myVehicleParameter->id));
1301 : }
1302 : double departPos = 0.;
1303 : double arrivalPos = std::numeric_limits<double>::infinity();
1304 90 : if (attrs.hasAttribute(SUMO_ATTR_DEPARTPOS)) {
1305 0 : WRITE_WARNING(TL("The attribute departPos is no longer supported for walks, please use the person attribute, the arrivalPos of the previous step or explicit stops."));
1306 : }
1307 90 : if (attrs.hasAttribute(SUMO_ATTR_ARRIVALPOS)) {
1308 40 : arrivalPos = SUMOVehicleParserHelper::parseWalkPos(SUMO_ATTR_ARRIVALPOS, myHardFail, objId, myActiveRoute.back()->getLength(), attrs.get<std::string>(SUMO_ATTR_ARRIVALPOS, objId, ok));
1309 : }
1310 : std::string stoppingPlaceID;
1311 90 : const std::string errorSuffix = " for walk of person '" + myVehicleParameter->id + "'";
1312 90 : retrieveStoppingPlace(attrs, errorSuffix, stoppingPlaceID);
1313 90 : if (ok) {
1314 90 : ROPerson::addWalk(*myActivePlan, myActiveRoute, duration, speed, departPos, arrivalPos, stoppingPlaceID);
1315 90 : myParamStack.push_back(myActivePlan->back());
1316 : }
1317 : } else {
1318 1234 : addPersonTrip(attrs);
1319 : }
1320 1324 : }
1321 :
1322 :
1323 : void
1324 95 : RORouteHandler::initLaneTree(NamedRTree* tree) {
1325 7571 : for (const auto& edgeItem : myNet.getEdgeMap()) {
1326 14099 : for (ROLane* lane : edgeItem.second->getLanes()) {
1327 6623 : Boundary b = lane->getShape().getBoxBoundary();
1328 6623 : const float cmin[2] = {(float) b.xmin(), (float) b.ymin()};
1329 6623 : const float cmax[2] = {(float) b.xmax(), (float) b.ymax()};
1330 6623 : tree->Insert(cmin, cmax, lane);
1331 : }
1332 : }
1333 95 : }
1334 :
1335 :
1336 : ROEdge*
1337 620 : RORouteHandler::retrieveEdge(const std::string& id) {
1338 620 : return myNet.getEdge(id);
1339 : }
1340 :
1341 :
1342 : const SUMOVTypeParameter*
1343 2606 : RORouteHandler::getVTypeParameter(const std::string& refid) {
1344 2606 : if (refid == "") {
1345 : return nullptr;
1346 : }
1347 20 : if (!myNet.knowsVType(refid)) {
1348 0 : myErrorOutput->inform(TLF("Unknown vehicle type '%'.", refid));
1349 0 : return nullptr;
1350 : }
1351 20 : return myNet.getVehicleTypeSecure(refid);
1352 : }
1353 :
1354 :
1355 : bool
1356 288747 : RORouteHandler::checkLastDepart() {
1357 288747 : if (!myUnsortedInput) {
1358 287735 : return SUMORouteHandler::checkLastDepart();
1359 : }
1360 : return true;
1361 : }
1362 :
1363 :
1364 : /****************************************************************************/
|