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