Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2017-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 Person.cpp
15 : /// @author Leonhard Luecken
16 : /// @date 15.09.2017
17 : ///
18 : // C++ TraCI client API implementation
19 : /****************************************************************************/
20 : #include <config.h>
21 :
22 : #include <microsim/transportables/MSTransportableControl.h>
23 : #include <microsim/MSVehicleControl.h>
24 : #include <microsim/MSEdge.h>
25 : #include <microsim/MSLane.h>
26 : #include <microsim/MSNet.h>
27 : #include <microsim/MSStoppingPlace.h>
28 : #include <microsim/transportables/MSPModel.h>
29 : #include <microsim/transportables/MSPerson.h>
30 : #include <microsim/transportables/MSStageDriving.h>
31 : #include <microsim/transportables/MSStageWaiting.h>
32 : #include <microsim/transportables/MSStageWalking.h>
33 : #include <microsim/transportables/MSStageTrip.h>
34 : #include <microsim/devices/MSDevice_Taxi.h>
35 : #include <microsim/devices/MSDispatch_TraCI.h>
36 : #include <libsumo/TraCIConstants.h>
37 : #include <utils/geom/GeomHelper.h>
38 : #include <utils/common/StringTokenizer.h>
39 : #include <utils/common/SUMOTime.h>
40 : #include <utils/emissions/PollutantsInterface.h>
41 : #include <utils/router/PedestrianRouter.h>
42 : #include <utils/vehicle/SUMOVehicleParserHelper.h>
43 : #include "Helper.h"
44 : #include "StorageHelper.h"
45 : #include "VehicleType.h"
46 : #include "Person.h"
47 :
48 : #define FAR_AWAY 1000.0
49 :
50 : //#define DEBUG_MOVEXY
51 : //#define DEBUG_MOVEXY_ANGLE
52 :
53 : namespace libsumo {
54 : // ===========================================================================
55 : // static member initializations
56 : // ===========================================================================
57 : SubscriptionResults Person::mySubscriptionResults;
58 : ContextSubscriptionResults Person::myContextSubscriptionResults;
59 :
60 :
61 : // ===========================================================================
62 : // static member definitions
63 : // ===========================================================================
64 : std::vector<std::string>
65 59208 : Person::getIDList() {
66 59208 : MSTransportableControl& c = MSNet::getInstance()->getPersonControl();
67 : std::vector<std::string> ids;
68 158474 : for (MSTransportableControl::constVehIt i = c.loadedBegin(); i != c.loadedEnd(); ++i) {
69 99268 : if (i->second->getCurrentStageType() != MSStageType::WAITING_FOR_DEPART) {
70 99251 : ids.push_back(i->first);
71 : }
72 : }
73 59206 : return ids;
74 0 : }
75 :
76 :
77 : int
78 30 : Person::getIDCount() {
79 30 : return MSNet::getInstance()->getPersonControl().size();
80 : }
81 :
82 :
83 : TraCIPosition
84 127146 : Person::getPosition(const std::string& personID, const bool includeZ) {
85 127146 : return Helper::makeTraCIPosition(getPerson(personID)->getPosition(), includeZ);
86 : }
87 :
88 :
89 : TraCIPosition
90 4 : Person::getPosition3D(const std::string& personID) {
91 4 : return Helper::makeTraCIPosition(getPerson(personID)->getPosition(), true);
92 : }
93 :
94 :
95 : double
96 121 : Person::getAngle(const std::string& personID) {
97 121 : return GeomHelper::naviDegree(getPerson(personID)->getAngle());
98 : }
99 :
100 :
101 : double
102 19 : Person::getSlope(const std::string& personID) {
103 19 : MSPerson* person = getPerson(personID);
104 19 : const double ep = person->getEdgePos();
105 19 : const MSLane* lane = getSidewalk<MSEdge, MSLane>(person->getEdge());
106 19 : if (lane == nullptr) {
107 0 : lane = person->getEdge()->getLanes()[0];
108 : }
109 : const double gp = lane->interpolateLanePosToGeometryPos(ep);
110 19 : return lane->getShape().slopeDegreeAtOffset(gp);
111 : }
112 :
113 :
114 : double
115 43 : Person::getSpeed(const std::string& personID) {
116 43 : return getPerson(personID)->getSpeed();
117 : }
118 :
119 :
120 : std::string
121 1242 : Person::getRoadID(const std::string& personID) {
122 1242 : return getPerson(personID)->getEdge()->getID();
123 : }
124 :
125 :
126 : std::string
127 261 : Person::getLaneID(const std::string& personID) {
128 522 : return Named::getIDSecure(getPerson(personID)->getLane(), "");
129 : }
130 :
131 :
132 : double
133 121 : Person::getLanePosition(const std::string& personID) {
134 121 : return getPerson(personID)->getEdgePos();
135 : }
136 :
137 :
138 : double
139 28 : Person::getWalkingDistance(const std::string& personID, const std::string& edgeID, double pos, int laneIndex) {
140 28 : MSPerson* p = getPerson(personID);
141 28 : if (p->getCurrentStageType() == MSStageType::WALKING) {
142 24 : const MSStageWalking* walk = dynamic_cast<const MSStageWalking*>(p->getCurrentStage());
143 24 : ConstMSEdgeVector edges = walk->getEdges();
144 24 : edges.erase(edges.begin(), edges.begin() + walk->getRoutePosition());
145 24 : const MSLane* lane = Helper::getLaneChecking(edgeID, laneIndex, pos);
146 24 : auto it = std::find(edges.begin(), edges.end(), &lane->getEdge());
147 24 : if (it == edges.end()) {
148 : // Vehicle would return INVALID_DOUBLE_VALUE;
149 0 : throw TraCIException(TLF("Edge '%' does not occur within the remaining walk of person '%'.", edgeID, personID));
150 :
151 : }
152 : edges.erase(it + 1, edges.end());
153 24 : double distance = 0;
154 24 : MSPedestrianRouter& router = MSNet::getInstance()->getPedestrianRouter(0);
155 24 : router.recomputeWalkCosts(edges, p->getMaxSpeed(), p->getEdgePos(), pos, SIMSTEP, p->getVTypeParameter(), distance);
156 24 : if (distance == std::numeric_limits<double>::max()) {
157 : return INVALID_DOUBLE_VALUE;
158 : }
159 24 : return distance;
160 24 : } else {
161 : // Vehicle would return INVALID_DOUBLE_VALUE;
162 12 : throw TraCIException(TLF("Person '%' is not walking", personID));
163 : }
164 : }
165 :
166 :
167 : double
168 12 : Person::getWalkingDistance2D(const std::string& personID, double x, double y) {
169 12 : MSPerson* p = getPerson(personID);
170 12 : std::pair<MSLane*, double> roadPos = Helper::convertCartesianToRoadMap(Position(x, y), p->getVehicleType().getVehicleClass());
171 12 : return getWalkingDistance(personID, roadPos.first->getEdge().getID(), roadPos.second, roadPos.first->getIndex());
172 : }
173 :
174 :
175 :
176 : std::vector<TraCIReservation>
177 4849 : Person::getTaxiReservations(int onlyNew) {
178 : std::vector<TraCIReservation> result;
179 : MSDispatch* dispatcher = MSDevice_Taxi::getDispatchAlgorithm();
180 4849 : if (dispatcher != nullptr) {
181 8463 : for (Reservation* res : dispatcher->getReservations()) {
182 3622 : if (filterReservation(onlyNew, res, result)) {
183 2900 : if (res->state == Reservation::NEW) {
184 358 : res->state = Reservation::RETRIEVED;
185 : }
186 : }
187 4841 : }
188 4841 : const bool includeRunning = onlyNew == 0 || (onlyNew & (Reservation::ASSIGNED | Reservation::ONBOARD)) != 0;
189 : if (includeRunning) {
190 9551 : for (const Reservation* res : dispatcher->getRunningReservations()) {
191 5337 : filterReservation(onlyNew, res, result);
192 4214 : }
193 : }
194 : }
195 4849 : std::sort(result.begin(), result.end(), reservation_by_id_sorter());
196 4849 : return result;
197 0 : }
198 :
199 : int
200 8698 : Person::reservation_by_id_sorter::operator()(const TraCIReservation& r1, const TraCIReservation& r2) const {
201 8698 : return r1.id < r2.id;
202 : }
203 :
204 :
205 : std::string
206 5 : Person::splitTaxiReservation(std::string reservationID, const std::vector<std::string>& personIDs) {
207 : MSDispatch* dispatcher = MSDevice_Taxi::getDispatchAlgorithm();
208 5 : if (dispatcher != nullptr) {
209 5 : MSDispatch_TraCI* traciDispatcher = dynamic_cast<MSDispatch_TraCI*>(dispatcher);
210 5 : if (traciDispatcher != nullptr) {
211 15 : return traciDispatcher->splitReservation(reservationID, personIDs);
212 : }
213 : }
214 0 : throw TraCIException("device.taxi.dispatch-algorithm 'traci' has not been loaded");
215 : }
216 :
217 : bool
218 8959 : Person::filterReservation(int onlyNew, const Reservation* res, std::vector<libsumo::TraCIReservation>& reservations) {
219 8959 : if (onlyNew != 0 && (onlyNew & res->state) == 0) {
220 : return false;
221 : }
222 : std::vector<std::string> personIDs;
223 16225 : for (const MSTransportable* p : res->persons) {
224 8125 : personIDs.push_back(p->getID());
225 : }
226 8100 : std::sort(personIDs.begin(), personIDs.end());
227 8100 : reservations.push_back(TraCIReservation(res->id,
228 : personIDs,
229 8100 : res->group,
230 8100 : res->from->getID(),
231 8100 : res->to->getID(),
232 8100 : res->fromPos,
233 8100 : res->toPos,
234 8100 : STEPS2TIME(res->pickupTime),
235 8100 : STEPS2TIME(res->reservationTime),
236 8100 : res->state
237 : ));
238 : return true;
239 8100 : }
240 :
241 :
242 : TraCIColor
243 21 : Person::getColor(const std::string& personID) {
244 21 : const RGBColor& col = getPerson(personID)->getParameter().color;
245 : TraCIColor tcol;
246 21 : tcol.r = col.red();
247 21 : tcol.g = col.green();
248 21 : tcol.b = col.blue();
249 21 : tcol.a = col.alpha();
250 21 : return tcol;
251 : }
252 :
253 :
254 : std::string
255 235 : Person::getTypeID(const std::string& personID) {
256 235 : return getPerson(personID)->getVehicleType().getID();
257 : }
258 :
259 :
260 : double
261 612 : Person::getWaitingTime(const std::string& personID) {
262 612 : return getPerson(personID)->getWaitingSeconds();
263 : }
264 :
265 :
266 : std::string
267 84 : Person::getNextEdge(const std::string& personID) {
268 84 : return getPerson(personID)->getNextEdge();
269 : }
270 :
271 :
272 : std::vector<std::string>
273 1151 : Person::getEdges(const std::string& personID, int nextStageIndex) {
274 1151 : MSTransportable* p = getPerson(personID);
275 1151 : if (nextStageIndex >= p->getNumRemainingStages()) {
276 0 : throw TraCIException("The stage index must be lower than the number of remaining stages.");
277 : }
278 1151 : if (nextStageIndex < (p->getNumRemainingStages() - p->getNumStages())) {
279 0 : throw TraCIException("The negative stage index must refer to a valid previous stage.");
280 : }
281 : std::vector<std::string> edgeIDs;
282 3047 : for (auto& e : p->getNextStage(nextStageIndex)->getEdges()) {
283 1896 : if (e != nullptr) {
284 1896 : edgeIDs.push_back(e->getID());
285 : }
286 1151 : }
287 1151 : return edgeIDs;
288 0 : }
289 :
290 :
291 : TraCIStage
292 797 : Person::getStage(const std::string& personID, int nextStageIndex) {
293 797 : MSTransportable* p = getPerson(personID);
294 1586 : TraCIStage result;
295 793 : if (nextStageIndex >= p->getNumRemainingStages()) {
296 10 : throw TraCIException("The stage index must be lower than the number of remaining stages.");
297 : }
298 788 : if (nextStageIndex < (p->getNumRemainingStages() - p->getNumStages())) {
299 106 : throw TraCIException("The negative stage index " + toString(nextStageIndex) + " must refer to a valid previous stage.");
300 : }
301 : //stageType, arrivalPos, edges, destStop, vType, and description can be retrieved directly from the base Stage class.
302 : MSStage* stage = p->getNextStage(nextStageIndex);
303 735 : result.type = (int)stage->getStageType();
304 735 : result.arrivalPos = stage->getArrivalPos();
305 2105 : for (auto e : stage->getEdges()) {
306 1370 : if (e != nullptr) {
307 1360 : result.edges.push_back(e->getID());
308 : }
309 735 : }
310 : MSStoppingPlace* destinationStop = stage->getDestinationStop();
311 735 : if (destinationStop != nullptr) {
312 470 : result.destStop = destinationStop->getID();
313 : }
314 735 : result.description = stage->getStageDescription(p->isPerson());
315 735 : result.length = stage->getDistance();
316 735 : if (result.length == -1.) {
317 63 : result.length = INVALID_DOUBLE_VALUE;
318 : }
319 735 : result.departPos = INVALID_DOUBLE_VALUE;
320 735 : result.cost = INVALID_DOUBLE_VALUE;
321 735 : result.depart = stage->getDeparted() >= 0 ? STEPS2TIME(stage->getDeparted()) : INVALID_DOUBLE_VALUE;
322 735 : result.travelTime = INVALID_DOUBLE_VALUE;
323 735 : if (stage->getArrived() >= 0) {
324 141 : result.travelTime = STEPS2TIME(stage->getArrived() - stage->getDeparted());
325 594 : } else if (stage->getDeparted() >= 0) {
326 457 : result.travelTime = STEPS2TIME(SIMSTEP - stage->getDeparted());
327 : }
328 :
329 : // Some stage type dependant attributes
330 735 : switch (stage->getStageType()) {
331 525 : case MSStageType::DRIVING: {
332 : MSStageDriving* const drivingStage = static_cast<MSStageDriving*>(stage);
333 1050 : result.vType = drivingStage->getVehicleType();
334 525 : result.intended = drivingStage->getIntendedVehicleID();
335 525 : if (result.depart < 0 && drivingStage->getIntendedDepart() >= 0) {
336 0 : result.depart = STEPS2TIME(drivingStage->getIntendedDepart());
337 : }
338 : const std::set<std::string> lines = drivingStage->getLines();
339 1050 : for (auto line = lines.begin(); line != lines.end(); line++) {
340 525 : if (line != lines.begin()) {
341 0 : result.line += " ";
342 : }
343 525 : result.line += *line;
344 : }
345 : break;
346 : }
347 83 : case MSStageType::WALKING: {
348 : auto* walkingStage = (MSStageWalking*) stage;
349 83 : result.departPos = walkingStage->getDepartPos();
350 83 : break;
351 : }
352 21 : case MSStageType::WAITING: {
353 : auto* waitingStage = (MSStageWaiting*) stage;
354 21 : if (waitingStage->getPlannedDuration() > 0) {
355 10 : result.travelTime = STEPS2TIME(waitingStage->getPlannedDuration());
356 : }
357 : break;
358 : }
359 : default:
360 : break;
361 : }
362 735 : return result;
363 58 : }
364 :
365 :
366 : int
367 162 : Person::getRemainingStages(const std::string& personID) {
368 162 : return getPerson(personID)->getNumRemainingStages();
369 : }
370 :
371 :
372 : std::string
373 19 : Person::getVehicle(const std::string& personID) {
374 19 : const SUMOVehicle* veh = getPerson(personID)->getVehicle();
375 19 : if (veh == nullptr) {
376 19 : return "";
377 : } else {
378 : return veh->getID();
379 : }
380 : }
381 :
382 :
383 : std::string
384 475 : Person::getParameter(const std::string& personID, const std::string& param) {
385 949 : return getPerson(personID)->getParameter().getParameter(param, "");
386 : }
387 :
388 :
389 102 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Person)
390 :
391 :
392 : std::string
393 0 : Person::getEmissionClass(const std::string& personID) {
394 0 : return PollutantsInterface::getName(getPerson(personID)->getVehicleType().getEmissionClass());
395 : }
396 :
397 :
398 : std::string
399 0 : Person::getShapeClass(const std::string& personID) {
400 0 : return getVehicleShapeName(getPerson(personID)->getVehicleType().getGuiShape());
401 : }
402 :
403 :
404 : double
405 4 : Person::getLength(const std::string& personID) {
406 4 : return getPerson(personID)->getVehicleType().getLength();
407 : }
408 :
409 :
410 : double
411 18 : Person::getSpeedFactor(const std::string& personID) {
412 18 : return getPerson(personID)->getChosenSpeedFactor();
413 : }
414 :
415 :
416 : double
417 0 : Person::getAccel(const std::string& personID) {
418 0 : return getPerson(personID)->getVehicleType().getCarFollowModel().getMaxAccel();
419 : }
420 :
421 :
422 : double
423 0 : Person::getDecel(const std::string& personID) {
424 0 : return getPerson(personID)->getVehicleType().getCarFollowModel().getMaxDecel();
425 : }
426 :
427 :
428 0 : double Person::getEmergencyDecel(const std::string& personID) {
429 0 : return getPerson(personID)->getVehicleType().getCarFollowModel().getEmergencyDecel();
430 : }
431 :
432 :
433 0 : double Person::getApparentDecel(const std::string& personID) {
434 0 : return getPerson(personID)->getVehicleType().getCarFollowModel().getApparentDecel();
435 : }
436 :
437 :
438 0 : double Person::getActionStepLength(const std::string& personID) {
439 0 : return getPerson(personID)->getVehicleType().getActionStepLengthSecs();
440 : }
441 :
442 :
443 : double
444 0 : Person::getTau(const std::string& personID) {
445 0 : return getPerson(personID)->getVehicleType().getCarFollowModel().getHeadwayTime();
446 : }
447 :
448 :
449 : double
450 0 : Person::getImperfection(const std::string& personID) {
451 0 : return getPerson(personID)->getVehicleType().getCarFollowModel().getImperfection();
452 : }
453 :
454 :
455 : double
456 0 : Person::getSpeedDeviation(const std::string& personID) {
457 0 : return getPerson(personID)->getVehicleType().getSpeedFactor().getParameter(1);
458 : }
459 :
460 :
461 : std::string
462 0 : Person::getVehicleClass(const std::string& personID) {
463 0 : return toString(getPerson(personID)->getVehicleType().getVehicleClass());
464 : }
465 :
466 :
467 : double
468 4 : Person::getMinGap(const std::string& personID) {
469 4 : return getPerson(personID)->getVehicleType().getMinGap();
470 : }
471 :
472 :
473 : double
474 0 : Person::getMinGapLat(const std::string& personID) {
475 0 : return getPerson(personID)->getVehicleType().getMinGapLat();
476 : }
477 :
478 :
479 : double
480 18 : Person::getMaxSpeed(const std::string& personID) {
481 18 : return getPerson(personID)->getMaxSpeed();
482 : }
483 :
484 :
485 : double
486 0 : Person::getMaxSpeedLat(const std::string& personID) {
487 0 : return getPerson(personID)->getVehicleType().getMaxSpeedLat();
488 : }
489 :
490 :
491 : std::string
492 0 : Person::getLateralAlignment(const std::string& personID) {
493 0 : return toString(getPerson(personID)->getVehicleType().getPreferredLateralAlignment());
494 : }
495 :
496 :
497 : double
498 4 : Person::getWidth(const std::string& personID) {
499 4 : return getPerson(personID)->getVehicleType().getWidth();
500 : }
501 :
502 :
503 : double
504 0 : Person::getHeight(const std::string& personID) {
505 0 : return getPerson(personID)->getVehicleType().getHeight();
506 : }
507 :
508 :
509 : double
510 0 : Person::getMass(const std::string& personID) {
511 0 : return getPerson(personID)->getVehicleType().getMass();
512 : }
513 :
514 :
515 : int
516 0 : Person::getPersonCapacity(const std::string& personID) {
517 0 : return getPerson(personID)->getVehicleType().getPersonCapacity();
518 : }
519 :
520 :
521 : double
522 4 : Person::getBoardingDuration(const std::string& personID) {
523 4 : return STEPS2TIME(getPerson(personID)->getVehicleType().getBoardingDuration(true));
524 : }
525 :
526 :
527 : double
528 8 : Person::getImpatience(const std::string& personID) {
529 8 : return getPerson(personID)->getImpatience();
530 : }
531 :
532 :
533 : void
534 14 : Person::setSpeed(const std::string& personID, double speed) {
535 14 : getPerson(personID)->setSpeed(speed);
536 14 : }
537 :
538 :
539 : void
540 16 : Person::setType(const std::string& personID, const std::string& typeID) {
541 16 : MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
542 16 : if (vehicleType == nullptr) {
543 0 : throw TraCIException("The vehicle type '" + typeID + "' is not known.");
544 : }
545 16 : getPerson(personID)->replaceVehicleType(vehicleType);
546 16 : }
547 :
548 :
549 : void
550 211 : Person::add(const std::string& personID, const std::string& edgeID, double pos, double departInSecs, const std::string typeID) {
551 : MSTransportable* p;
552 : try {
553 211 : p = getPerson(personID);
554 211 : } catch (TraCIException&) {
555 : p = nullptr;
556 211 : }
557 :
558 0 : if (p != nullptr) {
559 0 : throw TraCIException("The person " + personID + " to add already exists.");
560 : }
561 :
562 211 : SUMOTime depart = TIME2STEPS(departInSecs);
563 211 : SUMOVehicleParameter vehicleParams;
564 : vehicleParams.id = personID;
565 :
566 211 : MSVehicleType* vehicleType = MSNet::getInstance()->getVehicleControl().getVType(typeID);
567 211 : if (!vehicleType) {
568 0 : throw TraCIException("Invalid type '" + typeID + "' for person '" + personID + "'");
569 : }
570 :
571 211 : const MSEdge* edge = MSEdge::dictionary(edgeID);
572 211 : if (!edge) {
573 0 : throw TraCIException("Invalid edge '" + edgeID + "' for person: '" + personID + "'");
574 : }
575 :
576 211 : if (departInSecs < 0.) {
577 165 : const int proc = (int) - departInSecs;
578 165 : if (proc >= static_cast<int>(DepartDefinition::DEF_MAX)) {
579 0 : throw TraCIException("Invalid departure time." + toString(depart) + " " + toString(proc));
580 : }
581 165 : vehicleParams.departProcedure = (DepartDefinition)proc;
582 165 : vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
583 46 : } else if (depart < MSNet::getInstance()->getCurrentTimeStep()) {
584 36 : vehicleParams.depart = MSNet::getInstance()->getCurrentTimeStep();
585 108 : WRITE_WARNINGF(TL("Departure time=% for person '%' is in the past; using current time=% instead."),
586 : toString(departInSecs), personID, time2string(vehicleParams.depart));
587 : } else {
588 10 : vehicleParams.depart = depart;
589 : }
590 :
591 211 : vehicleParams.departPosProcedure = DepartPosDefinition::GIVEN;
592 211 : if (fabs(pos) > edge->getLength()) {
593 0 : throw TraCIException("Invalid departure position.");
594 : }
595 211 : if (pos < 0) {
596 19 : pos += edge->getLength();
597 : }
598 211 : vehicleParams.departPos = pos;
599 :
600 211 : SUMOVehicleParameter* params = new SUMOVehicleParameter(vehicleParams);
601 211 : MSTransportable::MSTransportablePlan* plan = new MSTransportable::MSTransportablePlan();
602 211 : plan->push_back(new MSStageWaiting(edge, nullptr, 0, depart, pos, "awaiting departure", true));
603 :
604 : try {
605 211 : MSTransportable* person = MSNet::getInstance()->getPersonControl().buildPerson(params, vehicleType, plan, nullptr);
606 211 : MSNet::getInstance()->getPersonControl().add(person);
607 0 : } catch (ProcessError& e) {
608 0 : delete params;
609 0 : delete plan;
610 0 : throw TraCIException(e.what());
611 0 : }
612 211 : }
613 :
614 : MSStage*
615 44 : Person::convertTraCIStage(const TraCIStage& stage, const std::string personID) {
616 : MSStoppingPlace* bs = nullptr;
617 44 : if (!stage.destStop.empty()) {
618 18 : bs = MSNet::getInstance()->getStoppingPlace(stage.destStop);
619 18 : if (bs == nullptr) {
620 0 : throw TraCIException("Invalid stopping place id '" + stage.destStop + "' for person: '" + personID + "'");
621 : }
622 : }
623 44 : switch (stage.type) {
624 10 : case STAGE_DRIVING: {
625 10 : if (stage.edges.empty()) {
626 0 : throw TraCIException("The stage should have at least one edge");
627 : }
628 : std::string toId = stage.edges.back();
629 10 : MSEdge* to = MSEdge::dictionary(toId);
630 10 : if (!to) {
631 0 : throw TraCIException("Invalid edge '" + toId + "' for person: '" + personID + "'");
632 : }
633 : //std::string fromId = stage.edges.front();
634 : //MSEdge* from = MSEdge::dictionary(fromId);
635 : //if (!from) {
636 : // throw TraCIException("Invalid edge '" + fromId + "' for person: '" + personID + "'");
637 : //}
638 10 : if (stage.line.empty()) {
639 0 : throw TraCIException("Empty lines parameter for person: '" + personID + "'");
640 : }
641 10 : double arrivalPos = stage.arrivalPos;
642 10 : if (arrivalPos == INVALID_DOUBLE_VALUE) {
643 5 : if (bs != nullptr) {
644 5 : arrivalPos = bs->getEndLanePosition();
645 : } else {
646 : arrivalPos = to->getLength();
647 : }
648 : }
649 30 : return new MSStageDriving(nullptr, to, bs, arrivalPos, 0.0, StringTokenizer(stage.line).getVector());
650 : }
651 :
652 26 : case STAGE_WALKING: {
653 26 : MSTransportable* p = getPerson(personID);
654 : ConstMSEdgeVector edges;
655 : try {
656 52 : MSEdge::parseEdgesList(stage.edges, edges, "<unknown>");
657 0 : } catch (ProcessError& e) {
658 0 : throw TraCIException(e.what());
659 0 : }
660 26 : if (edges.empty()) {
661 0 : throw TraCIException("Empty edge list for walking stage of person '" + personID + "'.");
662 : }
663 26 : double arrivalPos = stage.arrivalPos;
664 26 : if (fabs(arrivalPos) > edges.back()->getLength()) {
665 0 : throw TraCIException("Invalid arrivalPos for walking stage of person '" + personID + "'.");
666 : }
667 26 : if (arrivalPos < 0) {
668 1 : arrivalPos += edges.back()->getLength();
669 : }
670 26 : return new MSStageWalking(p->getID(), edges, bs, -1, -1, p->getArrivalPos(), arrivalPos, MSPModel::UNSPECIFIED_POS_LAT);
671 26 : }
672 :
673 0 : case STAGE_WAITING: {
674 0 : MSTransportable* p = getPerson(personID);
675 0 : if (stage.travelTime < 0) {
676 0 : throw TraCIException("Duration for person: '" + personID + "' must not be negative");
677 : }
678 0 : return new MSStageWaiting(p->getArrivalEdge(), nullptr, TIME2STEPS(stage.travelTime), 0, p->getArrivalPos(), stage.description, false);
679 : }
680 8 : case STAGE_TRIP: {
681 8 : MSTransportable* p = getPerson(personID);
682 : ConstMSEdgeVector edges;
683 : try {
684 16 : MSEdge::parseEdgesList(stage.edges, edges, "<unknown>");
685 0 : } catch (ProcessError& e) {
686 0 : throw TraCIException(e.what());
687 0 : }
688 8 : if ((edges.size() == 0 && bs == nullptr) || edges.size() > 1) {
689 0 : throw TraCIException("A trip should be defined with a destination edge or a destination stop for person '" + personID + "'.");
690 : }
691 : const MSEdge* to = nullptr;
692 8 : if (bs != nullptr) {
693 8 : to = &bs->getLane().getEdge();
694 8 : if (edges.size() > 0 && to != edges.back()) {
695 0 : throw TraCIException("Mismatching destination edge and destination stop edge for person '" + personID + "'.");
696 : }
697 : } else {
698 0 : to = edges.back();
699 : }
700 8 : SVCPermissions modeSet = 0;
701 8 : MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
702 24 : for (std::string vtypeid : StringTokenizer(stage.vType).getVector()) {
703 8 : const MSVehicleType* const vType = vehControl.getVType(vtypeid);
704 8 : if (vType == nullptr) {
705 0 : throw TraCIException("The vehicle type '" + vtypeid + "' in a trip for person '" + personID + "' is not known.");
706 : }
707 12 : modeSet |= (vType->getVehicleClass() == SVC_BICYCLE) ? SVC_BICYCLE : SVC_PASSENGER;
708 8 : }
709 8 : if (stage.line.empty()) {
710 0 : modeSet = p->getParameter().modes;
711 : } else {
712 : std::string errorMsg;
713 16 : if (!SUMOVehicleParameter::parsePersonModes(stage.line, "person", personID, modeSet, errorMsg)) {
714 0 : throw TraCIException(errorMsg);
715 : }
716 : }
717 8 : bool hasArrivalPos = stage.arrivalPos != INVALID_DOUBLE_VALUE;
718 : double arrivalPos = stage.arrivalPos;
719 8 : if (hasArrivalPos) {
720 8 : if (fabs(arrivalPos) > to->getLength()) {
721 0 : throw TraCIException("Invalid arrivalPos for walking stage of person '" + personID + "'.");
722 : }
723 8 : if (arrivalPos < 0) {
724 0 : arrivalPos += to->getLength();
725 : }
726 : }
727 : const MSStage* cur = p->getCurrentStage();
728 16 : double walkfactor = OptionsCont::getOptions().getFloat("persontrip.walkfactor");
729 : std::string group = stage.intended; //OptionsCont::getOptions().getString("persontrip.default.group");
730 : const SUMOTime duration = -1;
731 : const double speed = -1;
732 : return new MSStageTrip(cur->getDestination(), cur->getDestinationStop(), to, bs,
733 8 : duration, modeSet, stage.vType, speed, walkfactor, group,
734 8 : MSPModel::UNSPECIFIED_POS_LAT, hasArrivalPos, arrivalPos);
735 8 : }
736 : default:
737 : return nullptr;
738 : }
739 : }
740 :
741 :
742 : void
743 34 : Person::appendStage(const std::string& personID, const TraCIStage& stage) {
744 34 : MSTransportable* p = getPerson(personID);
745 34 : MSStage* personStage = convertTraCIStage(stage, personID);
746 34 : p->appendStage(personStage);
747 34 : }
748 :
749 :
750 : void
751 10 : Person::replaceStage(const std::string& personID, const int stageIndex, const TraCIStage& stage) {
752 10 : MSTransportable* p = getPerson(personID);
753 10 : if (stageIndex >= p->getNumRemainingStages()) {
754 0 : throw TraCIException("Specified stage index: is not valid for person " + personID);
755 : }
756 10 : MSStage* personStage = convertTraCIStage(stage, personID);
757 : // removing the current stage triggers abort+proceed so the replacement
758 : // stage must be ready beforehand
759 10 : p->appendStage(personStage, stageIndex + 1);
760 10 : p->removeStage(stageIndex);
761 10 : }
762 :
763 :
764 : void
765 36 : Person::appendDrivingStage(const std::string& personID, const std::string& toEdge, const std::string& lines, const std::string& stopID) {
766 36 : MSTransportable* p = getPerson(personID);
767 36 : const MSEdge* edge = MSEdge::dictionary(toEdge);
768 36 : if (!edge) {
769 0 : throw TraCIException("Invalid edge '" + toEdge + "' for person: '" + personID + "'");
770 : }
771 36 : if (lines.size() == 0) {
772 0 : throw TraCIException("Empty lines parameter for person: '" + personID + "'");
773 : }
774 : MSStoppingPlace* bs = nullptr;
775 36 : if (stopID != "") {
776 20 : bs = MSNet::getInstance()->getStoppingPlace(stopID);
777 20 : if (bs == nullptr) {
778 0 : throw TraCIException("Invalid stopping place id '" + stopID + "' for person: '" + personID + "'");
779 : }
780 : }
781 108 : p->appendStage(new MSStageDriving(nullptr, edge, bs, edge->getLength() - NUMERICAL_EPS, 0.0, StringTokenizer(lines).getVector()));
782 36 : }
783 :
784 :
785 : void
786 26 : Person::appendWaitingStage(const std::string& personID, double duration, const std::string& description, const std::string& stopID) {
787 26 : MSTransportable* p = getPerson(personID);
788 26 : if (duration < 0) {
789 0 : throw TraCIException("Duration for person: '" + personID + "' must not be negative");
790 : }
791 : MSStoppingPlace* bs = nullptr;
792 26 : if (stopID != "") {
793 10 : bs = MSNet::getInstance()->getStoppingPlace(stopID, SUMO_TAG_BUS_STOP);
794 10 : if (bs == nullptr) {
795 0 : throw TraCIException("Invalid stopping place id '" + stopID + "' for person: '" + personID + "'");
796 : }
797 : }
798 52 : p->appendStage(new MSStageWaiting(p->getArrivalEdge(), nullptr, TIME2STEPS(duration), 0, p->getArrivalPos(), description, false));
799 26 : }
800 :
801 :
802 : void
803 189 : Person::appendWalkingStage(const std::string& personID, const std::vector<std::string>& edgeIDs, double arrivalPos, double duration, double speed, const std::string& stopID) {
804 189 : MSTransportable* p = getPerson(personID);
805 : ConstMSEdgeVector edges;
806 : try {
807 378 : MSEdge::parseEdgesList(edgeIDs, edges, "<unknown>");
808 0 : } catch (ProcessError& e) {
809 0 : throw TraCIException(e.what());
810 0 : }
811 189 : if (edges.empty()) {
812 0 : throw TraCIException("Empty edge list for walking stage of person '" + personID + "'.");
813 : }
814 189 : if (fabs(arrivalPos) > edges.back()->getLength()) {
815 0 : throw TraCIException("Invalid arrivalPos for walking stage of person '" + personID + "'.");
816 : }
817 189 : if (arrivalPos < 0) {
818 31 : arrivalPos += edges.back()->getLength();
819 : }
820 : MSStoppingPlace* bs = nullptr;
821 189 : if (stopID != "") {
822 0 : bs = MSNet::getInstance()->getStoppingPlace(stopID, SUMO_TAG_BUS_STOP);
823 0 : if (bs == nullptr) {
824 0 : throw TraCIException("Invalid stopping place id '" + stopID + "' for person: '" + personID + "'");
825 : }
826 : }
827 378 : p->appendStage(new MSStageWalking(p->getID(), edges, bs, TIME2STEPS(duration), speed, p->getArrivalPos(), arrivalPos, MSPModel::UNSPECIFIED_POS_LAT));
828 189 : }
829 :
830 :
831 : void
832 139 : Person::removeStage(const std::string& personID, int nextStageIndex) {
833 139 : MSTransportable* p = getPerson(personID);
834 138 : if (nextStageIndex >= p->getNumRemainingStages()) {
835 0 : throw TraCIException("The stage index must be lower than the number of remaining stages.");
836 : }
837 138 : if (nextStageIndex < 0) {
838 0 : throw TraCIException("The stage index may not be negative.");
839 : }
840 138 : p->removeStage(nextStageIndex);
841 138 : }
842 :
843 :
844 : void
845 986 : Person::rerouteTraveltime(const std::string& personID) {
846 986 : MSPerson* p = getPerson(personID);
847 986 : if (p->getNumRemainingStages() == 0) {
848 0 : throw TraCIException("Person '" + personID + "' has no remaining stages.");
849 : }
850 986 : const MSEdge* from = p->getEdge();
851 986 : double departPos = p->getEdgePos();
852 : // reroute to the start of the next-non-walking stage
853 : int firstIndex;
854 986 : if (p->getCurrentStageType() == MSStageType::WALKING) {
855 : firstIndex = 0;
856 5 : } else if (p->getCurrentStageType() == MSStageType::WAITING) {
857 5 : if (p->getNumRemainingStages() < 2 || p->getStageType(1) != MSStageType::WALKING) {
858 0 : throw TraCIException("Person '" + personID + "' cannot reroute after the current stop.");
859 : }
860 : firstIndex = 1;
861 : } else {
862 0 : throw TraCIException("Person '" + personID + "' cannot reroute in stage type '" + toString((int)p->getCurrentStageType()) + "'.");
863 : }
864 986 : int nextIndex = firstIndex + 1;
865 991 : for (; nextIndex < p->getNumRemainingStages(); nextIndex++) {
866 20 : if (p->getStageType(nextIndex) != MSStageType::WALKING) {
867 : break;
868 : }
869 : }
870 986 : MSStage* destStage = p->getNextStage(nextIndex - 1);
871 986 : const MSEdge* to = destStage->getEdges().back();
872 986 : double arrivalPos = destStage->getArrivalPos();
873 986 : double speed = p->getMaxSpeed();
874 : ConstMSEdgeVector newEdges;
875 1972 : MSNet::getInstance()->getPedestrianRouter(0).compute(from, to, departPos, arrivalPos, speed, 0, nullptr, p->getVTypeParameter(), newEdges);
876 986 : if (newEdges.empty()) {
877 0 : throw TraCIException("Could not find new route for person '" + personID + "'.");
878 : }
879 986 : ConstMSEdgeVector oldEdges = p->getNextStage(firstIndex)->getEdges();
880 : assert(!oldEdges.empty());
881 986 : if (oldEdges.front()->getFunction() != SumoXMLEdgeFunc::NORMAL) {
882 : oldEdges.erase(oldEdges.begin());
883 : }
884 : //std::cout << " remainingStages=" << p->getNumRemainingStages() << " oldEdges=" << toString(oldEdges) << " newEdges=" << toString(newEdges) << " firstIndex=" << firstIndex << " nextIndex=" << nextIndex << "\n";
885 986 : if (newEdges == oldEdges && (firstIndex + 1 == nextIndex)) {
886 : return;
887 : }
888 37 : if (newEdges.front() != from) {
889 : // @note: maybe this should be done automatically by the router
890 4 : newEdges.insert(newEdges.begin(), from);
891 : }
892 37 : p->replaceWalk(newEdges, departPos, firstIndex, nextIndex);
893 986 : }
894 :
895 :
896 : void
897 18 : Person::moveTo(const std::string& personID, const std::string& laneID, double pos, double posLat) {
898 18 : MSPerson* p = getPerson(personID);
899 18 : MSLane* l = MSLane::dictionary(laneID);
900 18 : if (l == nullptr) {
901 0 : throw TraCIException("Unknown lane '" + laneID + "'.");
902 : }
903 18 : if (posLat == INVALID_DOUBLE_VALUE) {
904 18 : posLat = 0;
905 0 : } else if (fabs(posLat) >= (0.5 * (l->getWidth() + p->getVehicleType().getWidth()) + MSPModel::SIDEWALK_OFFSET)) {
906 : // see MSPModel_Striping::moveToXY
907 0 : throw TraCIException("Invalid lateral position " + toString(posLat) + " on lane '" + laneID + "'.");
908 : }
909 18 : switch (p->getStageType(0)) {
910 : case MSStageType::WALKING: {
911 18 : MSStageWalking* s = dynamic_cast<MSStageWalking*>(p->getCurrentStage());
912 : assert(s != 0);
913 18 : s->getPState()->moveTo(p, l, pos, posLat, SIMSTEP);
914 : break;
915 : }
916 0 : default:
917 0 : throw TraCIException("Command moveTo is not supported for person '" + personID + "' while " + p->getCurrentStageDescription() + ".");
918 : }
919 18 : }
920 :
921 :
922 : void
923 14121 : Person::moveToXY(const std::string& personID, const std::string& edgeID, const double x, const double y, double angle, const int keepRoute, double matchThreshold) {
924 14121 : MSPerson* p = getPerson(personID);
925 14121 : const bool doKeepRoute = (keepRoute & 1) != 0;
926 14121 : const bool mayLeaveNetwork = (keepRoute & 2) != 0;
927 14121 : const bool ignorePermissions = (keepRoute & 4) != 0;
928 14121 : SUMOVehicleClass vClass = ignorePermissions ? SVC_IGNORING : p->getVClass();
929 : Position pos(x, y);
930 : #ifdef DEBUG_MOVEXY
931 : const double origAngle = angle;
932 : #endif
933 : // angle must be in [0,360] because it will be compared against those returned by naviDegree()
934 : // angle set to INVALID_DOUBLE_VALUE is ignored in the evaluated and later set to the angle of the matched lane
935 14121 : if (angle != INVALID_DOUBLE_VALUE) {
936 11682 : while (angle >= 360.) {
937 0 : angle -= 360.;
938 : }
939 11682 : while (angle < 0.) {
940 0 : angle += 360.;
941 : }
942 : }
943 : #ifdef DEBUG_MOVEXY
944 : std::cout << std::endl << "begin person " << p->getID() << " lanePos:" << p->getEdgePos() << " edge:" << Named::getIDSecure(p->getEdge()) << "\n";
945 : std::cout << " want pos:" << pos << " edgeID:" << edgeID << " origAngle:" << origAngle << " angle:" << angle << " keepRoute:" << keepRoute << std::endl;
946 : #endif
947 :
948 : ConstMSEdgeVector edges;
949 14121 : MSLane* lane = nullptr;
950 : double lanePos;
951 : double lanePosLat = 0;
952 14121 : double bestDistance = std::numeric_limits<double>::max();
953 14121 : int routeOffset = 0;
954 : bool found = false;
955 14121 : double maxRouteDistance = matchThreshold;
956 :
957 : ConstMSEdgeVector ev;
958 14121 : ev.push_back(p->getEdge());
959 : int routeIndex = 0;
960 14121 : MSLane* currentLane = const_cast<MSLane*>(getSidewalk<MSEdge, MSLane>(p->getEdge()));
961 14121 : switch (p->getStageType(0)) {
962 : case MSStageType::WALKING: {
963 14104 : MSStageWalking* s = dynamic_cast<MSStageWalking*>(p->getCurrentStage());
964 : assert(s != 0);
965 14104 : ev = s->getEdges();
966 14104 : routeIndex = (int)(s->getRouteStep() - s->getRoute().begin());
967 : }
968 14104 : break;
969 : default:
970 : break;
971 : }
972 14121 : if (doKeepRoute) {
973 : // case a): vehicle is on its earlier route
974 : // we additionally assume it is moving forward (SUMO-limit);
975 : // note that the route ("edges") is not changed in this case
976 12010 : found = Helper::moveToXYMap_matchingRoutePosition(pos, edgeID,
977 : ev, routeIndex, vClass, true,
978 : bestDistance, &lane, lanePos, routeOffset);
979 12010 : if (bestDistance > maxRouteDistance) {
980 : found = false;
981 3137 : lane = nullptr;
982 : }
983 : } else {
984 2111 : double speed = pos.distanceTo2D(p->getPosition()); // !!!veh->getSpeed();
985 4222 : found = Helper::moveToXYMap(pos, maxRouteDistance, mayLeaveNetwork, edgeID, angle,
986 2111 : speed, ev, routeIndex, currentLane, p->getEdgePos(), currentLane != nullptr,
987 2111 : vClass, GeomHelper::naviDegree(p->getAngle()), true,
988 : bestDistance, &lane, lanePos, routeOffset, edges);
989 2111 : if (edges.size() != 0 && ev.size() > 1) {
990 : // try to rebuild the route
991 24 : const MSEdge* origEdge = p->getEdge();
992 : assert(lane != nullptr);
993 : const MSJunction* originalTarget = nullptr;
994 24 : if (origEdge->isNormal()) {
995 24 : if (routeIndex == 0) {
996 24 : if (origEdge->getToJunction() == ev[1]->getToJunction() || origEdge->getToJunction() == ev[1]->getFromJunction()) {
997 : originalTarget = origEdge->getToJunction();
998 : } else {
999 : originalTarget = origEdge->getFromJunction();
1000 : }
1001 : } else {
1002 0 : if (origEdge->getToJunction() == ev[routeIndex - 1]->getToJunction() || origEdge->getToJunction() == ev[routeIndex - 1]->getFromJunction()) {
1003 : originalTarget = origEdge->getFromJunction();
1004 : } else {
1005 : originalTarget = origEdge->getToJunction();
1006 : }
1007 : }
1008 : } else {
1009 : originalTarget = origEdge->getToJunction();
1010 : assert(originalTarget == origEdge->getFromJunction());
1011 : }
1012 24 : const MSEdge* newEdge = edges[0];
1013 24 : if (edges[0]->getFromJunction() == originalTarget || edges[0]->getToJunction() == originalTarget) {
1014 19 : edges = ev;
1015 19 : edges[routeIndex] = newEdge;
1016 : }
1017 : }
1018 : }
1019 14121 : if (found || mayLeaveNetwork) {
1020 : // compute lateral offset
1021 14116 : if (found) {
1022 10984 : const double perpDist = lane->getShape().distance2D(pos, false);
1023 10984 : if (perpDist != GeomHelper::INVALID_OFFSET) {
1024 : lanePosLat = perpDist;
1025 10984 : if (!mayLeaveNetwork) {
1026 1633 : lanePosLat = MIN2(lanePosLat, 0.5 * (lane->getWidth() + p->getVehicleType().getWidth()));
1027 : }
1028 : // figure out whether the offset is to the left or to the right
1029 10984 : PositionVector tmp = lane->getShape();
1030 : try {
1031 10984 : tmp.move2side(-lanePosLat); // moved to left
1032 0 : } catch (ProcessError&) {
1033 0 : WRITE_WARNINGF(TL("Could not determine position on lane '%' at lateral position %."), lane->getID(), toString(-lanePosLat));
1034 0 : }
1035 : //std::cout << " lane=" << lane->getID() << " posLat=" << lanePosLat << " shape=" << lane->getShape() << " tmp=" << tmp << " tmpDist=" << tmp.distance2D(pos) << "\n";
1036 10984 : if (tmp.distance2D(pos) > perpDist) {
1037 : lanePosLat = -lanePosLat;
1038 : }
1039 10984 : }
1040 : }
1041 14116 : if (found && !mayLeaveNetwork && MSGlobals::gLateralResolution < 0) {
1042 : // mapped position may differ from pos
1043 1633 : pos = lane->geometryPositionAtOffset(lanePos, -lanePosLat);
1044 : }
1045 : assert((found && lane != nullptr) || (!found && lane == nullptr));
1046 14116 : switch (p->getStageType(0)) {
1047 14099 : case MSStageType::WALKING: {
1048 14099 : if (angle == INVALID_DOUBLE_VALUE) {
1049 : // walking angle cannot be deduced from road angle so we always use the last pos
1050 2417 : angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
1051 : }
1052 : break;
1053 : }
1054 17 : case MSStageType::WAITING_FOR_DEPART:
1055 : case MSStageType::WAITING: {
1056 17 : if (p->getNumRemainingStages() <= 1 || p->getStageType(1) != MSStageType::WALKING) {
1057 : // insert walking stage after the current stage
1058 4 : ConstMSEdgeVector route({p->getEdge()});
1059 4 : const double departPos = p->getCurrentStage()->getArrivalPos();
1060 4 : p->appendStage(new MSStageWalking(p->getID(), route, nullptr, -1, -1, departPos, departPos, MSPModel::UNSPECIFIED_POS_LAT), 1);
1061 4 : }
1062 : // abort waiting stage and proceed to walking stage
1063 17 : p->removeStage(0);
1064 : assert(p->getStageType(0) == MSStageType::WALKING);
1065 17 : if (angle == INVALID_DOUBLE_VALUE) {
1066 17 : if (lane != nullptr && !lane->getEdge().isWalkingArea()) {
1067 17 : angle = GeomHelper::naviDegree(lane->getShape().rotationAtOffset(lanePos));
1068 : } else {
1069 : // compute angle outside road network or on walkingarea from old and new position
1070 0 : angle = GeomHelper::naviDegree(p->getPosition().angleTo2D(pos));
1071 : }
1072 : }
1073 : break;
1074 : }
1075 0 : default:
1076 0 : throw TraCIException("Command moveToXY is not supported for person '" + personID + "' while " + p->getCurrentStageDescription() + ".");
1077 : }
1078 14116 : Helper::setRemoteControlled(p, pos, lane, lanePos, lanePosLat, angle, routeOffset, edges, MSNet::getInstance()->getCurrentTimeStep());
1079 : } else {
1080 5 : if (lane == nullptr) {
1081 15 : throw TraCIException("Could not map person '" + personID + "' no road found within " + toString(maxRouteDistance) + "m.");
1082 : } else {
1083 0 : throw TraCIException("Could not map person '" + personID + "' distance to road is " + toString(bestDistance) + ".");
1084 : }
1085 : }
1086 14126 : }
1087 :
1088 :
1089 : /** untested setter functions which alter the person's vtype ***/
1090 :
1091 : void
1092 109 : Person::setParameter(const std::string& personID, const std::string& key, const std::string& value) {
1093 109 : MSTransportable* p = getPerson(personID);
1094 218 : if (StringUtils::startsWith(key, "device.")) {
1095 0 : throw TraCIException("Person '" + personID + "' does not support device parameters\n");
1096 218 : } else if (StringUtils::startsWith(key, "laneChangeModel.")) {
1097 0 : throw TraCIException("Person '" + personID + "' does not support laneChangeModel parameters\n");
1098 218 : } else if (StringUtils::startsWith(key, "carFollowModel.")) {
1099 0 : throw TraCIException("Person '" + personID + "' does not support carFollowModel parameters\n");
1100 218 : } else if (StringUtils::startsWith(key, "junctionModel.")) {
1101 : try {
1102 : // use the whole key (including junctionModel prefix)
1103 10 : p->setJunctionModelParameter(key, value);
1104 5 : } catch (InvalidArgument& e) {
1105 : // error message includes id since it is also used for xml input
1106 10 : throw TraCIException(e.what());
1107 5 : }
1108 99 : } else if (StringUtils::startsWith(key, "has.") && StringUtils::endsWith(key, ".device")) {
1109 0 : throw TraCIException("Person '" + personID + "' does not support chanigng device status\n");
1110 : } else {
1111 99 : ((SUMOVehicleParameter&)p->getParameter()).setParameter(key, value);
1112 : }
1113 104 : }
1114 :
1115 :
1116 : void
1117 2 : Person::setLength(const std::string& personID, double length) {
1118 2 : getPerson(personID)->getSingularType().setLength(length);
1119 2 : }
1120 :
1121 :
1122 : void
1123 0 : Person::setMaxSpeed(const std::string& personID, double speed) {
1124 0 : getPerson(personID)->getSingularType().setMaxSpeed(speed);
1125 0 : }
1126 :
1127 :
1128 : void
1129 0 : Person::setVehicleClass(const std::string& personID, const std::string& clazz) {
1130 0 : getPerson(personID)->getSingularType().setVClass(getVehicleClassID(clazz));
1131 0 : }
1132 :
1133 :
1134 : void
1135 0 : Person::setShapeClass(const std::string& personID, const std::string& clazz) {
1136 0 : getPerson(personID)->getSingularType().setShape(getVehicleShapeID(clazz));
1137 0 : }
1138 :
1139 :
1140 : void
1141 0 : Person::setEmissionClass(const std::string& personID, const std::string& clazz) {
1142 0 : getPerson(personID)->getSingularType().setEmissionClass(PollutantsInterface::getClassByName(clazz));
1143 0 : }
1144 :
1145 :
1146 : void
1147 2 : Person::setWidth(const std::string& personID, double width) {
1148 2 : getPerson(personID)->getSingularType().setWidth(width);
1149 2 : }
1150 :
1151 :
1152 : void
1153 2 : Person::setHeight(const std::string& personID, double height) {
1154 2 : getPerson(personID)->getSingularType().setHeight(height);
1155 2 : }
1156 :
1157 :
1158 : void
1159 0 : Person::setMass(const std::string& personID, double mass) {
1160 0 : getPerson(personID)->getSingularType().setMass(mass);
1161 0 : }
1162 :
1163 :
1164 : void
1165 2 : Person::setMinGap(const std::string& personID, double minGap) {
1166 2 : getPerson(personID)->getSingularType().setMinGap(minGap);
1167 2 : }
1168 :
1169 :
1170 : void
1171 0 : Person::setAccel(const std::string& personID, double accel) {
1172 0 : getPerson(personID)->getSingularType().setAccel(accel);
1173 0 : }
1174 :
1175 :
1176 : void
1177 0 : Person::setDecel(const std::string& personID, double decel) {
1178 0 : getPerson(personID)->getSingularType().setDecel(decel);
1179 0 : }
1180 :
1181 :
1182 : void
1183 0 : Person::setEmergencyDecel(const std::string& personID, double decel) {
1184 0 : getPerson(personID)->getSingularType().setEmergencyDecel(decel);
1185 0 : }
1186 :
1187 :
1188 : void
1189 0 : Person::setApparentDecel(const std::string& personID, double decel) {
1190 0 : getPerson(personID)->getSingularType().setApparentDecel(decel);
1191 0 : }
1192 :
1193 :
1194 : void
1195 0 : Person::setImperfection(const std::string& personID, double imperfection) {
1196 0 : getPerson(personID)->getSingularType().setImperfection(imperfection);
1197 0 : }
1198 :
1199 :
1200 : void
1201 0 : Person::setBoardingDuration(const std::string& personID, double boardingDuration) {
1202 0 : Helper::getPerson(personID)->getSingularType().setBoardingDuration(TIME2STEPS(boardingDuration));
1203 0 : }
1204 :
1205 :
1206 : void
1207 0 : Person::setImpatience(const std::string& personID, double impatience) {
1208 0 : Helper::getVehicle(personID)->getSingularType().setImpatience(impatience);
1209 0 : }
1210 :
1211 :
1212 :
1213 : void
1214 0 : Person::setTau(const std::string& personID, double tau) {
1215 0 : getPerson(personID)->getSingularType().setTau(tau);
1216 0 : }
1217 :
1218 :
1219 : void
1220 0 : Person::setMinGapLat(const std::string& personID, double minGapLat) {
1221 0 : getPerson(personID)->getSingularType().setMinGapLat(minGapLat);
1222 0 : }
1223 :
1224 :
1225 : void
1226 0 : Person::setMaxSpeedLat(const std::string& personID, double speed) {
1227 0 : getPerson(personID)->getSingularType().setMaxSpeedLat(speed);
1228 0 : }
1229 :
1230 :
1231 : void
1232 0 : Person::setLateralAlignment(const std::string& personID, const std::string& latAlignment) {
1233 : double lao;
1234 : LatAlignmentDefinition lad;
1235 0 : if (SUMOVTypeParameter::parseLatAlignment(latAlignment, lao, lad)) {
1236 0 : getPerson(personID)->getSingularType().setPreferredLateralAlignment(lad, lao);
1237 : } else {
1238 0 : throw TraCIException("Unknown value '" + latAlignment + "' when setting latAlignment for person '" + personID + "';\n must be one of (\"right\", \"center\", \"arbitrary\", \"nice\", \"compact\", \"left\" or a float)");
1239 : }
1240 0 : }
1241 :
1242 :
1243 : void
1244 30 : Person::setSpeedFactor(const std::string& personID, double factor) {
1245 30 : getPerson(personID)->setChosenSpeedFactor(factor);
1246 30 : }
1247 :
1248 :
1249 : void
1250 0 : Person::setActionStepLength(const std::string& personID, double actionStepLength, bool resetActionOffset) {
1251 0 : getPerson(personID)->getSingularType().setActionStepLength(SUMOVehicleParserHelper::processActionStepLength(actionStepLength), resetActionOffset);
1252 0 : }
1253 :
1254 : void
1255 23 : Person::remove(const std::string& personID, char /*reason*/) {
1256 23 : MSPerson* person = getPerson(personID);
1257 : // remove all stages after the current and then abort the current stage
1258 : // (without adding a zero-length waiting stage)
1259 32 : while (person->getNumRemainingStages() > 1) {
1260 9 : person->removeStage(1);
1261 : }
1262 23 : person->removeStage(0, false);
1263 23 : }
1264 :
1265 : void
1266 6 : Person::setColor(const std::string& personID, const TraCIColor& c) {
1267 6 : const SUMOVehicleParameter& p = getPerson(personID)->getParameter();
1268 6 : p.color.set((unsigned char)c.r, (unsigned char)c.g, (unsigned char)c.b, (unsigned char)c.a);
1269 6 : p.parametersSet |= VEHPARS_COLOR_SET;
1270 6 : }
1271 :
1272 :
1273 8387 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Person, PERSON)
1274 :
1275 :
1276 : MSPerson*
1277 164983 : Person::getPerson(const std::string& personID) {
1278 164983 : return Helper::getPerson(personID);
1279 : }
1280 :
1281 :
1282 : void
1283 16360 : Person::storeShape(const std::string& id, PositionVector& shape) {
1284 16360 : shape.push_back(getPerson(id)->getPosition());
1285 16360 : }
1286 :
1287 :
1288 : std::shared_ptr<VariableWrapper>
1289 270 : Person::makeWrapper() {
1290 270 : return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
1291 : }
1292 :
1293 :
1294 : bool
1295 115117 : Person::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
1296 115117 : switch (variable) {
1297 30424 : case TRACI_ID_LIST:
1298 30424 : return wrapper->wrapStringList(objID, variable, getIDList());
1299 22 : case ID_COUNT:
1300 22 : return wrapper->wrapInt(objID, variable, getIDCount());
1301 77632 : case VAR_POSITION:
1302 77632 : return wrapper->wrapPosition(objID, variable, getPosition(objID));
1303 17 : case VAR_POSITION3D:
1304 17 : return wrapper->wrapPosition(objID, variable, getPosition(objID, true));
1305 77 : case VAR_ANGLE:
1306 77 : return wrapper->wrapDouble(objID, variable, getAngle(objID));
1307 15 : case VAR_SLOPE:
1308 15 : return wrapper->wrapDouble(objID, variable, getSlope(objID));
1309 31 : case VAR_SPEED:
1310 31 : return wrapper->wrapDouble(objID, variable, getSpeed(objID));
1311 752 : case VAR_ROAD_ID:
1312 1504 : return wrapper->wrapString(objID, variable, getRoadID(objID));
1313 192 : case VAR_LANE_ID:
1314 384 : return wrapper->wrapString(objID, variable, getLaneID(objID));
1315 80 : case VAR_LANEPOSITION:
1316 80 : return wrapper->wrapDouble(objID, variable, getLanePosition(objID));
1317 17 : case VAR_COLOR:
1318 17 : return wrapper->wrapColor(objID, variable, getColor(objID));
1319 608 : case VAR_WAITING_TIME:
1320 608 : return wrapper->wrapDouble(objID, variable, getWaitingTime(objID));
1321 8 : case VAR_IMPATIENCE:
1322 8 : return wrapper->wrapDouble(objID, variable, getImpatience(objID));
1323 26 : case VAR_TYPE:
1324 52 : return wrapper->wrapString(objID, variable, getTypeID(objID));
1325 14 : case VAR_SPEED_FACTOR:
1326 14 : return wrapper->wrapDouble(objID, variable, getSpeedFactor(objID));
1327 82 : case VAR_NEXT_EDGE:
1328 164 : return wrapper->wrapString(objID, variable, getNextEdge(objID));
1329 695 : case VAR_EDGES:
1330 1390 : return wrapper->wrapStringList(objID, variable, getEdges(objID, StoHelp::readTypedInt(*paramData)));
1331 464 : case VAR_STAGE:
1332 884 : return wrapper->wrapStage(objID, variable, getStage(objID, StoHelp::readTypedInt(*paramData)));
1333 124 : case VAR_STAGES_REMAINING:
1334 124 : return wrapper->wrapInt(objID, variable, getRemainingStages(objID));
1335 15 : case VAR_VEHICLE:
1336 30 : return wrapper->wrapString(objID, variable, getVehicle(objID));
1337 14 : case VAR_MAXSPEED:
1338 : // integrate desiredMaxSpeed and individual speedFactor
1339 14 : return wrapper->wrapDouble(objID, variable, getMaxSpeed(objID));
1340 : case DISTANCE_REQUEST: {
1341 50 : TraCIRoadPosition roadPos;
1342 : Position pos;
1343 25 : if (Helper::readDistanceRequest(*paramData, roadPos, pos) == libsumo::POSITION_ROADMAP) {
1344 14 : return wrapper->wrapDouble(objID, variable, getWalkingDistance(objID, roadPos.edgeID, roadPos.pos, roadPos.laneIndex));
1345 : }
1346 11 : return wrapper->wrapDouble(objID, variable, getWalkingDistance2D(objID, pos.x(), pos.y()));
1347 : }
1348 399 : case VAR_PARAMETER:
1349 798 : return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
1350 47 : case VAR_PARAMETER_WITH_KEY:
1351 94 : return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
1352 3134 : case VAR_TAXI_RESERVATIONS:
1353 6268 : return wrapper->wrapReservationVector(objID, variable, getTaxiReservations(StoHelp::readTypedInt(*paramData)));
1354 4 : case SPLIT_TAXI_RESERVATIONS:
1355 13 : return wrapper->wrapString(objID, variable, splitTaxiReservation(objID, StoHelp::readTypedStringList(*paramData)));
1356 199 : default:
1357 398 : return libsumo::VehicleType::handleVariable(getTypeID(objID), variable, wrapper, paramData);
1358 : }
1359 : }
1360 :
1361 :
1362 : }
1363 :
1364 :
1365 : /****************************************************************************/
|