1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file MSTransportable.cpp
11 /// @author Melanie Weber
12 /// @author Andreas Kendziorra
13 /// @author Michael Behrisch
14 /// @date Thu, 12 Jun 2014
15 /// @version $Id$
16 ///
17 // The common superclass for modelling transportable objects like persons and containers
18 /****************************************************************************/
19
20
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25
26 #include <utils/common/StringTokenizer.h>
27 #include <utils/geom/GeomHelper.h>
28 #include <utils/vehicle/SUMOVehicleParameter.h>
29 #include <utils/router/PedestrianRouter.h>
30 #include <utils/router/IntermodalRouter.h>
31 #include "MSEdge.h"
32 #include "MSLane.h"
33 #include "MSNet.h"
34 #include <microsim/pedestrians/MSPerson.h>
35 #include <microsim/devices/MSTransportableDevice.h>
36 #include "MSVehicleControl.h"
37 #include "MSTransportableControl.h"
38 #include "MSTransportable.h"
39
40 /* -------------------------------------------------------------------------
41 * static member definitions
42 * ----------------------------------------------------------------------- */
43 const double MSTransportable::ROADSIDE_OFFSET(3);
44
45
46 // ===========================================================================
47 // method definitions
48 // ===========================================================================
49 /* -------------------------------------------------------------------------
50 * MSTransportable::Stage - methods
51 * ----------------------------------------------------------------------- */
Stage(const MSEdge * destination,MSStoppingPlace * toStop,const double arrivalPos,StageType type)52 MSTransportable::Stage::Stage(const MSEdge* destination, MSStoppingPlace* toStop, const double arrivalPos, StageType type)
53 : myDestination(destination), myDestinationStop(toStop), myArrivalPos(arrivalPos), myDeparted(-1), myArrived(-1), myType(type) {}
54
~Stage()55 MSTransportable::Stage::~Stage() {}
56
57 const MSEdge*
getDestination() const58 MSTransportable::Stage::getDestination() const {
59 return myDestination;
60 }
61
62
63 const MSEdge*
getEdge() const64 MSTransportable::Stage::getEdge() const {
65 return myDestination;
66 }
67
68
69 const MSEdge*
getFromEdge() const70 MSTransportable::Stage::getFromEdge() const {
71 return myDestination;
72 }
73
74
75 double
getEdgePos(SUMOTime) const76 MSTransportable::Stage::getEdgePos(SUMOTime /* now */) const {
77 return myArrivalPos;
78 }
79
80
81 SUMOTime
getWaitingTime(SUMOTime) const82 MSTransportable::Stage::getWaitingTime(SUMOTime /* now */) const {
83 return 0;
84 }
85
86
87 double
getSpeed() const88 MSTransportable::Stage::getSpeed() const {
89 return 0.;
90 }
91
92
93 ConstMSEdgeVector
getEdges() const94 MSTransportable::Stage::getEdges() const {
95 ConstMSEdgeVector result;
96 result.push_back(getDestination());
97 return result;
98 }
99
100
101 void
setDeparted(SUMOTime now)102 MSTransportable::Stage::setDeparted(SUMOTime now) {
103 if (myDeparted < 0) {
104 myDeparted = now;
105 }
106 }
107
108 SUMOTime
getDeparted() const109 MSTransportable::Stage::getDeparted() const {
110 return myDeparted;
111 }
112
113 void
setArrived(MSNet *,MSTransportable *,SUMOTime now)114 MSTransportable::Stage::setArrived(MSNet* /* net */, MSTransportable* /* transportable */, SUMOTime now) {
115 myArrived = now;
116 }
117
118 bool
isWaitingFor(const SUMOVehicle *) const119 MSTransportable::Stage::isWaitingFor(const SUMOVehicle* /*vehicle*/) const {
120 return false;
121 }
122
123 Position
getEdgePosition(const MSEdge * e,double at,double offset) const124 MSTransportable::Stage::getEdgePosition(const MSEdge* e, double at, double offset) const {
125 return getLanePosition(e->getLanes()[0], at, offset);
126 }
127
128 Position
getLanePosition(const MSLane * lane,double at,double offset) const129 MSTransportable::Stage::getLanePosition(const MSLane* lane, double at, double offset) const {
130 return lane->getShape().positionAtOffset(lane->interpolateLanePosToGeometryPos(at), offset);
131 }
132
133 double
getEdgeAngle(const MSEdge * e,double at) const134 MSTransportable::Stage::getEdgeAngle(const MSEdge* e, double at) const {
135 return e->getLanes()[0]->getShape().rotationAtOffset(at);
136 }
137
138
139 void
setDestination(const MSEdge * newDestination,MSStoppingPlace * newDestStop)140 MSTransportable::Stage::setDestination(const MSEdge* newDestination, MSStoppingPlace* newDestStop) {
141 myDestination = newDestination;
142 myDestinationStop = newDestStop;
143 if (newDestStop != nullptr) {
144 myArrivalPos = (newDestStop->getBeginLanePosition() + newDestStop->getEndLanePosition()) / 2;
145 }
146 }
147
148
149
150 /* -------------------------------------------------------------------------
151 * MSTransportable::Stage_Trip - methods
152 * ----------------------------------------------------------------------- */
Stage_Trip(const MSEdge * origin,MSStoppingPlace * fromStop,const MSEdge * destination,MSStoppingPlace * toStop,const SUMOTime duration,const SVCPermissions modeSet,const std::string & vTypes,const double speed,const double walkFactor,const double departPosLat,const bool hasArrivalPos,const double arrivalPos)153 MSTransportable::Stage_Trip::Stage_Trip(const MSEdge* origin, MSStoppingPlace* fromStop,
154 const MSEdge* destination, MSStoppingPlace* toStop,
155 const SUMOTime duration, const SVCPermissions modeSet,
156 const std::string& vTypes, const double speed, const double walkFactor,
157 const double departPosLat, const bool hasArrivalPos, const double arrivalPos):
158 MSTransportable::Stage(destination, toStop, arrivalPos, TRIP),
159 myOrigin(origin),
160 myOriginStop(fromStop),
161 myDuration(duration),
162 myModeSet(modeSet),
163 myVTypes(vTypes),
164 mySpeed(speed),
165 myWalkFactor(walkFactor),
166 myDepartPosLat(departPosLat),
167 myHaveArrivalPos(hasArrivalPos) {
168 }
169
170
~Stage_Trip()171 MSTransportable::Stage_Trip::~Stage_Trip() {}
172
173 MSTransportable::Stage*
clone() const174 MSTransportable::Stage_Trip::clone() const {
175 return new Stage_Trip(myOrigin, const_cast<MSStoppingPlace*>(myOriginStop),
176 myDestination, myDestinationStop, myDuration,
177 myModeSet, myVTypes, mySpeed, myWalkFactor, myDepartPosLat, myHaveArrivalPos, myArrivalPos);
178 }
179
180
181 Position
getPosition(SUMOTime) const182 MSTransportable::Stage_Trip::getPosition(SUMOTime /* now */) const {
183 throw ProcessError("Should not get here!");
184 }
185
186
187 double
getAngle(SUMOTime) const188 MSTransportable::Stage_Trip::getAngle(SUMOTime /* now */) const {
189 throw ProcessError("Should not get here!");
190 }
191
192
193 const MSEdge*
getEdge() const194 MSTransportable::Stage_Trip::getEdge() const {
195 return myOrigin;
196 }
197
198
199 double
getEdgePos(SUMOTime) const200 MSTransportable::Stage_Trip::getEdgePos(SUMOTime /* now */) const {
201 return myDepartPos;
202 }
203
204
205 void
setArrived(MSNet * net,MSTransportable * transportable,SUMOTime now)206 MSTransportable::Stage_Trip::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now) {
207 MSTransportable::Stage::setArrived(net, transportable, now);
208 MSVehicleControl& vehControl = net->getVehicleControl();
209 std::vector<SUMOVehicleParameter*> pars;
210 for (StringTokenizer st(myVTypes); st.hasNext();) {
211 pars.push_back(new SUMOVehicleParameter());
212 pars.back()->vtypeid = st.next();
213 pars.back()->parametersSet |= VEHPARS_VTYPE_SET;
214 pars.back()->departProcedure = DEPART_TRIGGERED;
215 pars.back()->id = transportable->getID() + "_" + toString(pars.size() - 1);
216 }
217 if (pars.empty()) {
218 if ((myModeSet & SVC_PASSENGER) != 0) {
219 pars.push_back(new SUMOVehicleParameter());
220 pars.back()->id = transportable->getID() + "_0";
221 pars.back()->departProcedure = DEPART_TRIGGERED;
222 } else if ((myModeSet & SVC_BICYCLE) != 0) {
223 pars.push_back(new SUMOVehicleParameter());
224 pars.back()->vtypeid = DEFAULT_BIKETYPE_ID;
225 pars.back()->id = transportable->getID() + "_b0";
226 pars.back()->departProcedure = DEPART_TRIGGERED;
227 } else {
228 // allow shortcut via busStop even when not intending to ride
229 pars.push_back(nullptr);
230 }
231 }
232 MSTransportable::Stage* previous;
233 SUMOTime time = MSNet::getInstance()->getCurrentTimeStep();
234 if (transportable->getNumStages() == transportable->getNumRemainingStages()) { // this is a difficult way to check that we are the first stage
235 myDepartPos = transportable->getParameter().departPos;
236 if (transportable->getParameter().departPosProcedure == DEPART_POS_RANDOM) {
237 myDepartPos = RandHelper::rand(myOrigin->getLength());
238 }
239 previous = new MSTransportable::Stage_Waiting(myOrigin, nullptr, -1, transportable->getParameter().depart, myDepartPos, "start", true);
240 time = transportable->getParameter().depart;
241 } else {
242 previous = transportable->getNextStage(-1);
243 myDepartPos = previous->getArrivalPos();
244 }
245 // TODO This works currently only for a single vehicle type
246 for (SUMOVehicleParameter* vehPar : pars) {
247 SUMOVehicle* vehicle = nullptr;
248 if (vehPar != nullptr) {
249 MSVehicleType* type = vehControl.getVType(vehPar->vtypeid);
250 if (type->getVehicleClass() != SVC_IGNORING && (myOrigin->getPermissions() & type->getVehicleClass()) == 0) {
251 WRITE_WARNING("Ignoring vehicle type '" + type->getID() + "' when routing person '" + transportable->getID() + "' because it is not allowed on the start edge.");
252 } else {
253 const MSRoute* const routeDummy = new MSRoute(vehPar->id, ConstMSEdgeVector({ myOrigin }), false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
254 vehicle = vehControl.buildVehicle(vehPar, routeDummy, type, !MSGlobals::gCheckRoutes);
255 }
256 }
257 bool carUsed = false;
258 std::vector<MSNet::MSIntermodalRouter::TripItem> result;
259 int stageIndex = 1;
260 if (net->getIntermodalRouter().compute(myOrigin, myDestination, previous->getArrivalPos(), myArrivalPos, myDestinationStop == nullptr ? "" : myDestinationStop->getID(),
261 transportable->getVehicleType().getMaxSpeed() * myWalkFactor, vehicle, myModeSet, time, result)) {
262 for (std::vector<MSNet::MSIntermodalRouter::TripItem>::iterator it = result.begin(); it != result.end(); ++it) {
263 if (!it->edges.empty()) {
264 MSStoppingPlace* bs = MSNet::getInstance()->getStoppingPlace(it->destStop, SUMO_TAG_BUS_STOP);
265 double localArrivalPos = bs != nullptr ? bs->getAccessPos(it->edges.back()) : it->edges.back()->getLength() / 2.;
266 if (it + 1 == result.end() && myHaveArrivalPos) {
267 localArrivalPos = myArrivalPos;
268 }
269 if (it->line == "") {
270 double depPos = previous->getArrivalPos();
271 if (previous->getDestinationStop() != nullptr) {
272 depPos = previous->getDestinationStop()->getAccessPos(it->edges.front());
273 } else if (previous->getEdge() != it->edges.front()) {
274 // if (previous->getEdge()->getToJunction() == it->edges.front()->getToJunction()) {
275 // depPos = it->edges.front()->getLength();
276 // } else {
277 depPos = 0.;
278 // }
279 }
280 previous = new MSPerson::MSPersonStage_Walking(transportable->getID(), it->edges, bs, myDuration, mySpeed, depPos, localArrivalPos, myDepartPosLat);
281 transportable->appendStage(previous, stageIndex++);
282 } else if (vehicle != nullptr && it->line == vehicle->getID()) {
283 if (bs == nullptr && it + 1 != result.end()) {
284 // we have no defined endpoint and are in the middle of the trip, drive as far as possible
285 localArrivalPos = it->edges.back()->getLength();
286 }
287 previous = new MSPerson::MSPersonStage_Driving(it->edges.back(), bs, localArrivalPos, std::vector<std::string>({ it->line }));
288 transportable->appendStage(previous, stageIndex++);
289 vehicle->replaceRouteEdges(it->edges, -1, 0, "person:" + transportable->getID(), true);
290 vehicle->setArrivalPos(localArrivalPos);
291 vehControl.addVehicle(vehPar->id, vehicle);
292 carUsed = true;
293 } else {
294 previous = new MSPerson::MSPersonStage_Driving(it->edges.back(), bs, localArrivalPos, std::vector<std::string>({ it->line }), it->intended, TIME2STEPS(it->depart));
295 transportable->appendStage(previous, stageIndex++);
296 }
297 }
298 }
299 } else {
300 // append stage so the GUI won't crash due to inconsistent state
301 transportable->appendStage(new MSPerson::MSPersonStage_Walking(transportable->getID(), ConstMSEdgeVector({ myOrigin, myDestination }), myDestinationStop, myDuration, mySpeed, previous->getArrivalPos(), myArrivalPos, myDepartPosLat), stageIndex++);
302 if (MSGlobals::gCheckRoutes) {
303 const std::string error = "No connection found between edge '" + myOrigin->getID() + "' and edge '" + (myDestinationStop != nullptr ? myDestinationStop->getID() : myDestination->getID()) + "' for person '" + transportable->getID() + "'.";
304 transportable->myStep++;
305 throw ProcessError(error);
306 } else {
307 // pedestrian will teleport
308 }
309 }
310 if (vehicle != nullptr && !carUsed) {
311 vehControl.deleteVehicle(vehicle, true);
312 }
313 }
314 }
315
316
317 void
proceed(MSNet * net,MSTransportable * transportable,SUMOTime now,Stage *)318 MSTransportable::Stage_Trip::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, Stage* /* previous */) {
319 // just skip the stage, every interesting happens in setArrived
320 transportable->proceed(net, now);
321 }
322
323
324 void
tripInfoOutput(OutputDevice &,const MSTransportable * const) const325 MSTransportable::Stage_Trip::tripInfoOutput(OutputDevice&, const MSTransportable* const) const {
326 }
327
328
329 void
routeOutput(OutputDevice &,const bool) const330 MSTransportable::Stage_Trip::routeOutput(OutputDevice&, const bool /* withRouteLength */) const {
331 }
332
333
334 void
beginEventOutput(const MSTransportable &,SUMOTime,OutputDevice &) const335 MSTransportable::Stage_Trip::beginEventOutput(const MSTransportable&, SUMOTime, OutputDevice&) const {
336 }
337
338
339 void
endEventOutput(const MSTransportable &,SUMOTime,OutputDevice &) const340 MSTransportable::Stage_Trip::endEventOutput(const MSTransportable&, SUMOTime, OutputDevice&) const {
341 }
342
343
344 std::string
getStageSummary() const345 MSTransportable::Stage_Trip::getStageSummary() const {
346 return "trip from '" + myOrigin->getID() + "' to '" + getDestination()->getID() + "'";
347 }
348
349
350
351 /* -------------------------------------------------------------------------
352 * MSTransportable::Stage_Waiting - methods
353 * ----------------------------------------------------------------------- */
Stage_Waiting(const MSEdge * destination,MSStoppingPlace * toStop,SUMOTime duration,SUMOTime until,double pos,const std::string & actType,const bool initial)354 MSTransportable::Stage_Waiting::Stage_Waiting(const MSEdge* destination, MSStoppingPlace* toStop,
355 SUMOTime duration, SUMOTime until, double pos, const std::string& actType,
356 const bool initial) :
357 MSTransportable::Stage(destination, toStop, SUMOVehicleParameter::interpretEdgePos(
358 pos, destination->getLength(), SUMO_ATTR_DEPARTPOS, "stopping at " + destination->getID()),
359 initial ? WAITING_FOR_DEPART : WAITING),
360 myWaitingDuration(duration),
361 myWaitingUntil(until),
362 myActType(actType) {
363 }
364
365
~Stage_Waiting()366 MSTransportable::Stage_Waiting::~Stage_Waiting() {}
367
368 MSTransportable::Stage*
clone() const369 MSTransportable::Stage_Waiting::clone() const {
370 return new Stage_Waiting(myDestination, myDestinationStop, myWaitingDuration, myWaitingUntil, myArrivalPos, myActType, myType == WAITING_FOR_DEPART);
371 }
372
373 SUMOTime
getUntil() const374 MSTransportable::Stage_Waiting::getUntil() const {
375 return myWaitingUntil;
376 }
377
378
379 Position
getPosition(SUMOTime) const380 MSTransportable::Stage_Waiting::getPosition(SUMOTime /* now */) const {
381 return getEdgePosition(myDestination, myArrivalPos,
382 ROADSIDE_OFFSET * (MSNet::getInstance()->lefthand() ? -1 : 1));
383 }
384
385
386 double
getAngle(SUMOTime) const387 MSTransportable::Stage_Waiting::getAngle(SUMOTime /* now */) const {
388 return getEdgeAngle(myDestination, myArrivalPos) + M_PI / 2 * (MSNet::getInstance()->lefthand() ? -1 : 1);
389 }
390
391
392 void
proceed(MSNet * net,MSTransportable * transportable,SUMOTime now,Stage * previous)393 MSTransportable::Stage_Waiting::proceed(MSNet* net, MSTransportable* transportable, SUMOTime now, Stage* previous) {
394 myDeparted = now;
395 const SUMOTime until = MAX3(now, now + myWaitingDuration, myWaitingUntil);
396 if (myDestinationStop != nullptr) {
397 myDestinationStop->addTransportable(transportable);
398 }
399 if (dynamic_cast<MSPerson*>(transportable) != nullptr) {
400 previous->getEdge()->addPerson(transportable);
401 net->getPersonControl().setWaitEnd(until, transportable);
402 } else {
403 previous->getEdge()->addContainer(transportable);
404 net->getContainerControl().setWaitEnd(until, transportable);
405 }
406 }
407
408
409 void
tripInfoOutput(OutputDevice & os,const MSTransportable * const) const410 MSTransportable::Stage_Waiting::tripInfoOutput(OutputDevice& os, const MSTransportable* const) const {
411 if (myType != WAITING_FOR_DEPART) {
412 os.openTag("stop");
413 os.writeAttr("duration", time2string(myArrived - myDeparted));
414 os.writeAttr("arrival", time2string(myArrived));
415 os.writeAttr("arrivalPos", toString(myArrivalPos));
416 os.writeAttr("actType", toString(myActType));
417 os.closeTag();
418 }
419 }
420
421
422 void
routeOutput(OutputDevice & os,const bool) const423 MSTransportable::Stage_Waiting::routeOutput(OutputDevice& os, const bool /* withRouteLength */) const {
424 if (myType != WAITING_FOR_DEPART) {
425 // lane index is arbitrary
426 os.openTag("stop").writeAttr(SUMO_ATTR_LANE, getDestination()->getID() + "_0");
427 if (myWaitingDuration >= 0) {
428 os.writeAttr(SUMO_ATTR_DURATION, time2string(myWaitingDuration));
429 }
430 if (myWaitingUntil >= 0) {
431 os.writeAttr(SUMO_ATTR_UNTIL, time2string(myWaitingUntil));
432 }
433 os.closeTag();
434 }
435 }
436
437
438 void
beginEventOutput(const MSTransportable & p,SUMOTime t,OutputDevice & os) const439 MSTransportable::Stage_Waiting::beginEventOutput(const MSTransportable& p, SUMOTime t, OutputDevice& os) const {
440 os.openTag("event").writeAttr("time", time2string(t)).writeAttr("type", "actstart " + myActType)
441 .writeAttr("agent", p.getID()).writeAttr("link", getEdge()->getID()).closeTag();
442 }
443
444
445 void
endEventOutput(const MSTransportable & p,SUMOTime t,OutputDevice & os) const446 MSTransportable::Stage_Waiting::endEventOutput(const MSTransportable& p, SUMOTime t, OutputDevice& os) const {
447 os.openTag("event").writeAttr("time", time2string(t)).writeAttr("type", "actend " + myActType).writeAttr("agent", p.getID())
448 .writeAttr("link", getEdge()->getID()).closeTag();
449 }
450
451
452 SUMOTime
getWaitingTime(SUMOTime now) const453 MSTransportable::Stage_Waiting::getWaitingTime(SUMOTime now) const {
454 return now - myDeparted;
455 }
456
457
458 void
abort(MSTransportable * t)459 MSTransportable::Stage_Waiting::abort(MSTransportable* t) {
460 MSTransportableControl& tc = (dynamic_cast<MSPerson*>(t) != nullptr ?
461 MSNet::getInstance()->getPersonControl() :
462 MSNet::getInstance()->getContainerControl());
463 tc.abortWaiting(t);
464 }
465
466
467 std::string
getStageSummary() const468 MSTransportable::Stage_Waiting::getStageSummary() const {
469 std::string timeInfo;
470 if (myWaitingUntil >= 0) {
471 timeInfo += " until " + time2string(myWaitingUntil);
472 }
473 if (myWaitingDuration >= 0) {
474 timeInfo += " duration " + time2string(myWaitingDuration);
475 }
476 return "stopping at edge '" + getDestination()->getID() + "' " + timeInfo + " (" + myActType + ")";
477 }
478
479
480 /* -------------------------------------------------------------------------
481 * MSTransportable::Stage_Driving - methods
482 * ----------------------------------------------------------------------- */
Stage_Driving(const MSEdge * destination,MSStoppingPlace * toStop,const double arrivalPos,const std::vector<std::string> & lines,const std::string & intendedVeh,SUMOTime intendedDepart)483 MSTransportable::Stage_Driving::Stage_Driving(const MSEdge* destination,
484 MSStoppingPlace* toStop, const double arrivalPos, const std::vector<std::string>& lines,
485 const std::string& intendedVeh, SUMOTime intendedDepart) :
486 MSTransportable::Stage(destination, toStop, arrivalPos, DRIVING),
487 myLines(lines.begin(), lines.end()),
488 myVehicle(nullptr),
489 myVehicleID("NULL"),
490 myVehicleDistance(-1.),
491 myWaitingEdge(nullptr),
492 myStopWaitPos(Position::INVALID),
493 myIntendedVehicleID(intendedVeh),
494 myIntendedDepart(intendedDepart) {
495 }
496
497
~Stage_Driving()498 MSTransportable::Stage_Driving::~Stage_Driving() {}
499
500 const MSEdge*
getEdge() const501 MSTransportable::Stage_Driving::getEdge() const {
502 if (myVehicle != nullptr) {
503 if (myVehicle->getLane() != nullptr) {
504 return &myVehicle->getLane()->getEdge();
505 }
506 return myVehicle->getEdge();
507 }
508 return myWaitingEdge;
509 }
510
511
512 const MSEdge*
getFromEdge() const513 MSTransportable::Stage_Driving::getFromEdge() const {
514 return myWaitingEdge;
515 }
516
517
518 double
getEdgePos(SUMOTime) const519 MSTransportable::Stage_Driving::getEdgePos(SUMOTime /* now */) const {
520 if (isWaiting4Vehicle()) {
521 return myWaitingPos;
522 }
523 // vehicle may already have passed the lane (check whether this is correct)
524 return MIN2(myVehicle->getPositionOnLane(), getEdge()->getLength());
525 }
526
527
528 Position
getPosition(SUMOTime) const529 MSTransportable::Stage_Driving::getPosition(SUMOTime /* now */) const {
530 if (isWaiting4Vehicle()) {
531 if (myStopWaitPos != Position::INVALID) {
532 return myStopWaitPos;
533 }
534 return getEdgePosition(myWaitingEdge, myWaitingPos,
535 ROADSIDE_OFFSET * (MSNet::getInstance()->lefthand() ? -1 : 1));
536 }
537 return myVehicle->getPosition();
538 }
539
540
541 double
getAngle(SUMOTime) const542 MSTransportable::Stage_Driving::getAngle(SUMOTime /* now */) const {
543 if (!isWaiting4Vehicle()) {
544 MSVehicle* veh = dynamic_cast<MSVehicle*>(myVehicle);
545 if (veh != nullptr) {
546 return veh->getAngle();
547 } else {
548 return 0;
549 }
550 }
551 return getEdgeAngle(myWaitingEdge, myWaitingPos) + M_PI / 2. * (MSNet::getInstance()->lefthand() ? -1 : 1);
552 }
553
554
555 bool
isWaitingFor(const SUMOVehicle * vehicle) const556 MSTransportable::Stage_Driving::isWaitingFor(const SUMOVehicle* vehicle) const {
557 return (myLines.count(vehicle->getID()) > 0
558 || myLines.count(vehicle->getParameter().line) > 0
559 || (myLines.count("ANY") > 0 && vehicle->stopsAt(myDestinationStop)));
560 }
561
562
563 bool
isWaiting4Vehicle() const564 MSTransportable::Stage_Driving::isWaiting4Vehicle() const {
565 return myVehicle == nullptr;
566 }
567
568
569 SUMOTime
getWaitingTime(SUMOTime now) const570 MSTransportable::Stage_Driving::getWaitingTime(SUMOTime now) const {
571 return isWaiting4Vehicle() ? now - myWaitingSince : 0;
572 }
573
574
575 double
getSpeed() const576 MSTransportable::Stage_Driving::getSpeed() const {
577 return isWaiting4Vehicle() ? 0 : myVehicle->getSpeed();
578 }
579
580
581 ConstMSEdgeVector
getEdges() const582 MSTransportable::Stage_Driving::getEdges() const {
583 ConstMSEdgeVector result;
584 result.push_back(getFromEdge());
585 result.push_back(getDestination());
586 return result;
587 }
588
589 void
setArrived(MSNet * net,MSTransportable * transportable,SUMOTime now)590 MSTransportable::Stage_Driving::setArrived(MSNet* net, MSTransportable* transportable, SUMOTime now) {
591 MSTransportable::Stage::setArrived(net, transportable, now);
592 if (myVehicle != nullptr) {
593 // distance was previously set to driven distance upon embarking
594 myVehicleDistance = myVehicle->getRoute().getDistanceBetween(
595 myVehicle->getDepartPos(), myVehicle->getPositionOnLane(),
596 myVehicle->getRoute().begin(), myVehicle->getCurrentRouteEdge()) - myVehicleDistance;
597 if (myVehicle->isStopped()) {
598 myArrivalPos = myVehicle->getPositionOnLane();
599 }
600 } else {
601 myVehicleDistance = -1.;
602 }
603 }
604
605 void
setVehicle(SUMOVehicle * v)606 MSTransportable::Stage_Driving::setVehicle(SUMOVehicle* v) {
607 myVehicle = v;
608 myVehicleID = v->getID();
609 myVehicleLine = v->getParameter().line;
610 myVehicleVClass = v->getVClass();
611 myVehicleDistance = myVehicle->getRoute().getDistanceBetween(
612 myVehicle->getDepartPos(), myVehicle->getPositionOnLane(),
613 myVehicle->getRoute().begin(), myVehicle->getCurrentRouteEdge());
614 }
615
616 void
abort(MSTransportable * t)617 MSTransportable::Stage_Driving::abort(MSTransportable* t) {
618 if (myVehicle != nullptr) {
619 // jumping out of a moving vehicle!
620 dynamic_cast<MSVehicle*>(myVehicle)->removeTransportable(t);
621 }
622 }
623
624
625 std::string
getWaitingDescription() const626 MSTransportable::Stage_Driving::getWaitingDescription() const {
627 return isWaiting4Vehicle() ? ("waiting for " + joinToString(myLines, ",")
628 + " at " + (myDestinationStop == nullptr
629 ? ("edge '" + myWaitingEdge->getID() + "'")
630 : ("busStop '" + myDestinationStop->getID() + "'"))
631 ) : "";
632 }
633
634
635 void
beginEventOutput(const MSTransportable & p,SUMOTime t,OutputDevice & os) const636 MSTransportable::Stage_Driving::beginEventOutput(const MSTransportable& p, SUMOTime t, OutputDevice& os) const {
637 os.openTag("event").writeAttr("time", time2string(t)).writeAttr("type", "arrival").writeAttr("agent", p.getID()).writeAttr("link", getEdge()->getID()).closeTag();
638 }
639
640
641 void
endEventOutput(const MSTransportable & p,SUMOTime t,OutputDevice & os) const642 MSTransportable::Stage_Driving::endEventOutput(const MSTransportable& p, SUMOTime t, OutputDevice& os) const {
643 os.openTag("event").writeAttr("time", time2string(t)).writeAttr("type", "arrival").writeAttr("agent", p.getID()).writeAttr("link", getEdge()->getID()).closeTag();
644 }
645
646
647
648 /* -------------------------------------------------------------------------
649 * MSTransportable - methods
650 * ----------------------------------------------------------------------- */
MSTransportable(const SUMOVehicleParameter * pars,MSVehicleType * vtype,MSTransportablePlan * plan)651 MSTransportable::MSTransportable(const SUMOVehicleParameter* pars, MSVehicleType* vtype, MSTransportablePlan* plan)
652 : myParameter(pars), myVType(vtype), myPlan(plan) {
653 myStep = myPlan->begin();
654 // init devices
655 MSDevice::buildTransportableDevices(*this, myDevices);
656 }
657
658
~MSTransportable()659 MSTransportable::~MSTransportable() {
660 if (myStep != myPlan->end() && getCurrentStageType() == DRIVING) {
661 Stage_Driving* const stage = dynamic_cast<Stage_Driving*>(*myStep);
662 if (stage->getVehicle() != nullptr) {
663 stage->getVehicle()->removeTransportable(this);
664 }
665 }
666 if (myPlan != nullptr) {
667 for (MSTransportablePlan::const_iterator i = myPlan->begin(); i != myPlan->end(); ++i) {
668 delete *i;
669 }
670 delete myPlan;
671 myPlan = nullptr;
672 }
673 delete myParameter;
674 if (myVType->isVehicleSpecific()) {
675 MSNet::getInstance()->getVehicleControl().removeVType(myVType);
676 }
677 }
678
679 const std::string&
getID() const680 MSTransportable::getID() const {
681 return myParameter->id;
682 }
683
684 SUMOTime
getDesiredDepart() const685 MSTransportable::getDesiredDepart() const {
686 return myParameter->depart;
687 }
688
689 void
setDeparted(SUMOTime now)690 MSTransportable::setDeparted(SUMOTime now) {
691 (*myStep)->setDeparted(now);
692 }
693
694 double
getEdgePos() const695 MSTransportable::getEdgePos() const {
696 return (*myStep)->getEdgePos(MSNet::getInstance()->getCurrentTimeStep());
697 }
698
699 Position
getPosition() const700 MSTransportable::getPosition() const {
701 return (*myStep)->getPosition(MSNet::getInstance()->getCurrentTimeStep());
702 }
703
704 double
getAngle() const705 MSTransportable::getAngle() const {
706 return (*myStep)->getAngle(MSNet::getInstance()->getCurrentTimeStep());
707 }
708
709 double
getWaitingSeconds() const710 MSTransportable::getWaitingSeconds() const {
711 return STEPS2TIME((*myStep)->getWaitingTime(MSNet::getInstance()->getCurrentTimeStep()));
712 }
713
714 double
getSpeed() const715 MSTransportable::getSpeed() const {
716 return (*myStep)->getSpeed();
717 }
718
719
720 int
getNumRemainingStages() const721 MSTransportable::getNumRemainingStages() const {
722 return (int)(myPlan->end() - myStep);
723 }
724
725 int
getNumStages() const726 MSTransportable::getNumStages() const {
727 return (int)myPlan->size();
728 }
729
730 void
appendStage(Stage * stage,int next)731 MSTransportable::appendStage(Stage* stage, int next) {
732 // myStep is invalidated upon modifying myPlan
733 const int stepIndex = (int)(myStep - myPlan->begin());
734 if (next < 0) {
735 myPlan->push_back(stage);
736 } else {
737 if (stepIndex + next > (int)myPlan->size()) {
738 throw ProcessError("invalid index '" + toString(next) + "' for inserting new stage into plan of '" + getID() + "'");
739 }
740 myPlan->insert(myPlan->begin() + stepIndex + next, stage);
741 }
742 myStep = myPlan->begin() + stepIndex;
743 }
744
745
746 void
removeStage(int next)747 MSTransportable::removeStage(int next) {
748 assert(myStep + next < myPlan->end());
749 assert(next >= 0);
750 if (next > 0) {
751 // myStep is invalidated upon modifying myPlan
752 int stepIndex = (int)(myStep - myPlan->begin());
753 delete *(myStep + next);
754 myPlan->erase(myStep + next);
755 myStep = myPlan->begin() + stepIndex;
756 } else {
757 if (myStep + 1 == myPlan->end()) {
758 // stay in the simulation until the start of simStep to allow appending new stages (at the correct position)
759 appendStage(new Stage_Waiting(getEdge(), nullptr, 0, 0, getEdgePos(), "last stage removed", false));
760 }
761 (*myStep)->abort(this);
762 proceed(MSNet::getInstance(), MSNet::getInstance()->getCurrentTimeStep());
763 }
764 }
765
766
767 void
setSpeed(double speed)768 MSTransportable::setSpeed(double speed) {
769 for (MSTransportablePlan::const_iterator i = myPlan->begin(); i != myPlan->end(); ++i) {
770 (*i)->setSpeed(speed);
771 }
772 }
773
774
775 void
replaceVehicleType(MSVehicleType * type)776 MSTransportable::replaceVehicleType(MSVehicleType* type) {
777 if (myVType->isVehicleSpecific()) {
778 MSNet::getInstance()->getVehicleControl().removeVType(myVType);
779 }
780 myVType = type;
781 }
782
783
784 MSVehicleType&
getSingularType()785 MSTransportable::getSingularType() {
786 if (myVType->isVehicleSpecific()) {
787 return *myVType;
788 }
789 MSVehicleType* type = myVType->buildSingularType(myVType->getID() + "@" + getID());
790 replaceVehicleType(type);
791 return *type;
792 }
793
794
795 PositionVector
getBoundingBox() const796 MSTransportable::getBoundingBox() const {
797 PositionVector centerLine;
798 const Position p = getPosition();
799 const double angle = getAngle();
800 const double length = getVehicleType().getLength();
801 const Position back = p + Position(-cos(angle) * length, -sin(angle) * length);
802 centerLine.push_back(p);
803 centerLine.push_back(back);
804 centerLine.move2side(0.5 * getVehicleType().getWidth());
805 PositionVector result = centerLine;
806 centerLine.move2side(-getVehicleType().getWidth());
807 result.append(centerLine.reverse(), POSITION_EPS);
808 //std::cout << " transp=" << getID() << " p=" << p << " angle=" << GeomHelper::naviDegree(angle) << " back=" << back << " result=" << result << "\n";
809 return result;
810 }
811
812
813 std::string
getStageSummary(int stageIndex) const814 MSTransportable::getStageSummary(int stageIndex) const {
815 assert(stageIndex < (int)myPlan->size());
816 assert(stageIndex >= 0);
817 return (*myPlan)[stageIndex]->getStageSummary();
818 }
819
820
821 bool
hasArrived() const822 MSTransportable::hasArrived() const {
823 return myStep == myPlan->end();
824 }
825
826 bool
hasDeparted() const827 MSTransportable::hasDeparted() const {
828 return myPlan->size() > 0 && myPlan->front()->getDeparted() >= 0;
829 }
830
831
832 void
rerouteParkingArea(MSStoppingPlace * orig,MSStoppingPlace * replacement)833 MSTransportable::rerouteParkingArea(MSStoppingPlace* orig, MSStoppingPlace* replacement) {
834 // check whether the transportable was riding to the orignal stop
835 // @note: parkingArea can currently not be set as myDestinationStop so we
836 // check for stops on the edge instead
837 assert(getCurrentStageType() == DRIVING);
838 if (dynamic_cast<MSPerson*>(this) == nullptr) {
839 WRITE_WARNING("parkingAreaReroute not support for containers");
840 return;
841 }
842 if (getDestination() == &orig->getLane().getEdge()) {
843 Stage_Driving* const stage = dynamic_cast<Stage_Driving*>(*myStep);
844 assert(stage != 0);
845 assert(stage->getVehicle() != 0);
846 // adapt plan
847 stage->setDestination(&replacement->getLane().getEdge(), replacement);
848 if (myStep + 1 == myPlan->end()) {
849 return;
850 }
851 // if the next step is a walk, adapt the route
852 Stage* nextStage = *(myStep + 1);
853 if (nextStage->getStageType() == TRIP) {
854 dynamic_cast<MSTransportable::Stage_Trip*>(nextStage)->setOrigin(stage->getDestination());
855 } else if (nextStage->getStageType() == MOVING_WITHOUT_VEHICLE) {
856 Stage_Trip* newStage = new Stage_Trip(stage->getDestination(), nullptr, nextStage->getDestination(),
857 nextStage->getDestinationStop(), -1, 0, "", -1, 1, 0, true, nextStage->getArrivalPos());
858 removeStage(1);
859 appendStage(newStage, 1);
860 }
861 // if the plan contains another ride with the same vehicle from the same
862 // parking area, adapt the preceeding walk to end at the replacement
863 // (ride origin is set implicitly from the walk destination)
864 for (auto it = myStep + 2; it != myPlan->end(); it++) {
865 const Stage* const futureStage = *it;
866 Stage* const prevStage = *(it - 1);
867 if (futureStage->getStageType() == DRIVING) {
868 const MSPerson::MSPersonStage_Driving* const ds = dynamic_cast<const MSPerson::MSPersonStage_Driving* const>(futureStage);
869 if (ds->getLines() == stage->getLines()
870 && prevStage->getDestination() == &orig->getLane().getEdge()) {
871 if (prevStage->getStageType() == TRIP) {
872 dynamic_cast<MSTransportable::Stage_Trip*>(prevStage)->setDestination(stage->getDestination(), replacement);
873 } else if (prevStage->getStageType() == MOVING_WITHOUT_VEHICLE) {
874 Stage_Trip* newStage = new Stage_Trip(prevStage->getFromEdge(), nullptr, stage->getDestination(),
875 replacement, -1, 0, "", -1, 1, 0, true, stage->getArrivalPos());
876 int prevStageRelIndex = (int)(it - 1 - myStep);
877 removeStage(prevStageRelIndex);
878 appendStage(newStage, prevStageRelIndex);
879 }
880 break;
881 }
882 }
883 }
884 }
885 }
886
887 MSTransportableDevice*
getDevice(const std::type_info & type) const888 MSTransportable::getDevice(const std::type_info& type) const {
889 for (MSTransportableDevice* const dev : myDevices) {
890 if (typeid(*dev) == type) {
891 return dev;
892 }
893 }
894 return nullptr;
895 }
896
897 double
getSlope() const898 MSTransportable::getSlope() const {
899 const MSEdge* edge = getEdge();
900 const double ep = getEdgePos();
901 const double gp = edge->getLanes()[0]->interpolateLanePosToGeometryPos(ep);
902 return edge->getLanes()[0]->getShape().slopeDegreeAtOffset(gp);
903 }
904
905 SUMOTime
getWaitingTime() const906 MSTransportable::getWaitingTime() const {
907 return (*myStep)->getWaitingTime(MSNet::getInstance()->getCurrentTimeStep());
908 }
909
910 double
getMaxSpeed() const911 MSTransportable::getMaxSpeed() const {
912 return getVehicleType().getMaxSpeed();
913 }
914
915 SUMOVehicleClass
getVClass() const916 MSTransportable::getVClass() const {
917 return getVehicleType().getVehicleClass();
918 }
919
920 /****************************************************************************/
921