Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSPModel_JuPedSim_legacy.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2014-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
21// The pedestrian following model that can instantiate different pedestrian models
22// that come with the JuPedSim third-party simulation framework.
23/****************************************************************************/
24
25#include <config.h>
26
27#include <algorithm>
28#include <fstream>
29#include <geos_c.h>
30#include <jupedsim/jupedsim.h>
31#include <microsim/MSEdge.h>
32#include <microsim/MSLane.h>
33#include <microsim/MSLink.h>
40#include <libsumo/Helper.h>
41#include <utils/geom/Position.h>
45#include "MSPerson.h"
46#include "MSStageWalking.h"
48
49
50// #define DEBUG_GEOMETRY_GENERATION
51
52
59const std::string MSPModel_JuPedSim_legacy::PEDESTRIAN_NETWORK_ID = "jupedsim.pedestrian_network";
60const std::string MSPModel_JuPedSim_legacy::PEDESTRIAN_NETWORK_CARRIAGES_AND_RAMPS_ID = "jupedsim.pedestrian_network.carriages_and_ramps";
61
62const std::vector<MSPModel_JuPedSim_legacy::PState*> MSPModel_JuPedSim_legacy::noPedestrians;
63
64// ===========================================================================
65// method definitions
66// ===========================================================================
68 myRNG("JuPedSim_legacy"), myNetwork(net), myShapeContainer(net->getShapeContainer()), myJPSDeltaT(string2time(oc.getString("pedestrian.jupedsim.step-length"))),
69 myExitTolerance(oc.getFloat("pedestrian.jupedsim.exit-tolerance")), myGEOSPedestrianNetworkLargestComponent(nullptr),
70 myHaveAdditionalWalkableAreas(false) {
72 const std::string model = oc.getString("pedestrian.jupedsim.model");
73 if (model == "CollisionFreeSpeed" || model == "CollisionFreeSpeedModel") {
75 } else if (model == "CollisionFreeSpeedV2" || model == "CollisionFreeSpeedModelV2") {
77 } else if (model == "GeneralizedCentrifugalForce" || model == "GeneralizedCentrifugalForceModel") {
79 } else if (model == "SocialForce" || model == "SocialForceModel") {
81 } else {
82 throw ProcessError(TLF("Unknown JuPedSim model '%'.", model));
83 }
84 initialize(oc);
86}
87
88
90 clearState();
91 if (myPythonScript != nullptr) {
92 (*myPythonScript) << "while simulation.agent_count() > 0 and simulation.iteration_count() < 160 * 100: simulation.iterate()\n";
93 }
94
95 JPS_Simulation_Free(myJPSSimulation);
96 JPS_OperationalModel_Free(myJPSOperationalModel);
97 JPS_Geometry_Free(myJPSGeometry);
98 if (myJPSGeometryWithTrainsAndRamps != nullptr) {
99 JPS_Geometry_Free(myJPSGeometryWithTrainsAndRamps);
100 }
101
102 GEOSGeom_destroy(myGEOSPedestrianNetwork);
103 finishGEOS();
104}
105
106
107void
109 const MSVehicleType& type = state->getPerson()->getVehicleType();
110
111 const double angle = state->getAngle(*state->getStage(), 0);
112 JPS_Point orientation;
113 if (fabs(angle - M_PI / 2) < NUMERICAL_EPS) {
114 orientation = JPS_Point{0., 1.};
115 } else if (fabs(angle + M_PI / 2) < NUMERICAL_EPS) {
116 orientation = JPS_Point{0., -1.};
117 } else {
118 orientation = JPS_Point{1., tan(angle)};
119 }
120
121 JPS_AgentId agentId = 0;
122 JPS_ErrorMessage message = nullptr;
123
124 switch (myJPSModel) {
126 JPS_CollisionFreeSpeedModelAgentParameters agentParameters{};
127 agentParameters.position = {p.x(), p.y()};
128 agentParameters.journeyId = state->getJourneyId();
129 agentParameters.stageId = state->getStageId();
130 agentParameters.v0 = state->getPerson()->getMaxSpeed();
131 agentParameters.radius = getRadius(type);
132 agentId = JPS_Simulation_AddCollisionFreeSpeedModelAgent(myJPSSimulation, agentParameters, &message);
133 break;
134 }
136 JPS_CollisionFreeSpeedModelV2AgentParameters agentParameters{};
137 agentParameters.position = {p.x(), p.y()};
138 agentParameters.journeyId = state->getJourneyId();
139 agentParameters.stageId = state->getStageId();
140 agentParameters.v0 = state->getPerson()->getMaxSpeed();
141 agentParameters.radius = getRadius(type);
142 agentId = JPS_Simulation_AddCollisionFreeSpeedModelV2Agent(myJPSSimulation, agentParameters, &message);
143 break;
144 }
146 JPS_GeneralizedCentrifugalForceModelAgentParameters agentParameters{};
147 agentParameters.position = {p.x(), p.y()};
148 agentParameters.orientation = orientation;
149 agentParameters.journeyId = state->getJourneyId();
150 agentParameters.stageId = state->getStageId();
151 agentParameters.v0 = state->getPerson()->getMaxSpeed();
152 agentId = JPS_Simulation_AddGeneralizedCentrifugalForceModelAgent(myJPSSimulation, agentParameters, &message);
153 break;
154 }
156 JPS_SocialForceModelAgentParameters agentParameters{};
157 agentParameters.position = {p.x(), p.y()};
158 agentParameters.orientation = orientation;
159 agentParameters.journeyId = state->getJourneyId();
160 agentParameters.stageId = state->getStageId();
161 agentParameters.desiredSpeed = state->getPerson()->getMaxSpeed();
162 agentParameters.radius = getRadius(type);
163 agentId = JPS_Simulation_AddSocialForceModelAgent(myJPSSimulation, agentParameters, &message);
164 break;
165 }
166 }
167 if (message != nullptr) {
168 WRITE_WARNINGF(TL("Error while adding person '%' as JuPedSim agent: %"), state->getPerson()->getID(), JPS_ErrorMessage_GetMessage(message));
169 JPS_ErrorMessage_Free(message);
170 } else {
171 state->setAgentId(agentId);
172 }
173}
174
175
176bool
177MSPModel_JuPedSim_legacy::addStage(JPS_JourneyDescription journey, JPS_StageId& predecessor, const std::string& agentID, const JPS_StageId stage) {
178 JPS_ErrorMessage message = nullptr;
179 if (predecessor != 0) {
180 const JPS_Transition transition = JPS_Transition_CreateFixedTransition(stage, &message);
181 if (message != nullptr) {
182 WRITE_WARNINGF(TL("Error while creating fixed transition for person '%': %"), agentID, JPS_ErrorMessage_GetMessage(message));
183 JPS_ErrorMessage_Free(message);
184 return false;
185 }
186 JPS_JourneyDescription_SetTransitionForStage(journey, predecessor, transition, &message);
187 if (message != nullptr) {
188 WRITE_WARNINGF(TL("Error while setting transition for person '%': %"), agentID, JPS_ErrorMessage_GetMessage(message));
189 JPS_ErrorMessage_Free(message);
190 return false;
191 }
192 JPS_Transition_Free(transition);
193 }
194 JPS_JourneyDescription_AddStage(journey, stage);
195 predecessor = stage;
196 return true;
197}
198
199
200bool
201MSPModel_JuPedSim_legacy::addWaypoint(JPS_JourneyDescription journey, JPS_StageId& predecessor, const std::string& agentID, const WaypointDesc& waypoint) {
202 JPS_ErrorMessage message = nullptr;
203 const Position& coords = std::get<1>(waypoint);
204 const JPS_StageId waypointId = JPS_Simulation_AddStageWaypoint(myJPSSimulation, {coords.x(), coords.y()},
205 std::get<2>(waypoint), &message);
206 if (message != nullptr) {
207 WRITE_WARNINGF(TL("Error while adding waypoint for person '%': %"), agentID, JPS_ErrorMessage_GetMessage(message));
208 JPS_ErrorMessage_Free(message);
209 return false;
210 }
211 const JPS_StageId waiting = std::get<0>(waypoint);
212 if (waiting != 0) {
213 if (myPythonScript != nullptr) {
214 (*myPythonScript) << "journey.add(" << waiting << ")\n";
215 if (predecessor != 0) {
216 (*myPythonScript) << "journey.set_transition_for_stage(" << predecessor << ", jps.Transition.create_fixed_transition(" << waiting << "))\n";
217 }
218 }
219 if (!addStage(journey, predecessor, agentID, waiting)) {
220 return false;
221 }
222 }
223 if (myPythonScript != nullptr) {
224 (*myPythonScript) << "ws = simulation.add_waypoint_stage((" << coords.x() << "," << coords.y() << "), " << std::get<2>(waypoint) << ")\n"
225 "journey.add(ws)\n";
226 if (predecessor != 0) {
227 (*myPythonScript) << "journey.set_transition_for_stage(" << predecessor << ", jps.Transition.create_fixed_transition(ws))\n";
228 }
229 }
230 if (!addStage(journey, predecessor, agentID, waypointId)) {
231 return false;
232 }
233 return true;
234}
235
236
239 assert(person->getCurrentStageType() == MSStageType::WALKING);
240 const double radius = getRadius(person->getVehicleType());
241 Position departurePosition = Position::INVALID;
242 const MSLane* const departureLane = getSidewalk<MSEdge, MSLane>(stage->getRoute().front());
243 if (departureLane == nullptr) {
244 const char* error = TL("Person '%' could not find sidewalk on edge '%', time=%.");
245 if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
246 WRITE_WARNINGF(error, person->getID(), person->getEdge()->getID(), time2string(SIMSTEP));
247 return nullptr;
248 } else {
249 throw ProcessError(TLF(error, person->getID(), person->getEdge()->getID(), time2string(SIMSTEP)));
250 }
251 }
252 // First real stage, stage 0 is waiting.
254 const MSEdge* const tripOrigin = person->getNextStage(-1)->getEdge();
255 if (tripOrigin->isTazConnector()) {
256 const SUMOPolygon* tazShape = myNetwork->getShapeContainer().getPolygons().get(tripOrigin->getParameter("taz"));
257 if (tazShape == nullptr) {
258 WRITE_WARNINGF(TL("FromTaz '%' for person '%' has no shape information."), tripOrigin->getParameter("taz"), person->getID());
259 } else {
260 const Boundary& bbox = tazShape->getShape().getBoxBoundary();
261 while (!tazShape->getShape().around(departurePosition)) {
262 // TODO: Optimize for speed if necessary or at least abort trying to find a point.
263 departurePosition.setx(RandHelper::rand(bbox.xmin(), bbox.xmax(), &myRNG));
264 departurePosition.sety(RandHelper::rand(bbox.ymin(), bbox.ymax(), &myRNG));
265 }
266 }
267 }
268 }
269 if (departurePosition == Position::INVALID) {
270 const double halfDepartureLaneWidth = departureLane->getWidth() / 2.0;
271 double departureRelativePositionY = stage->getDepartPosLat();
272 if (departureRelativePositionY == UNSPECIFIED_POS_LAT) {
273 departureRelativePositionY = 0.0;
274 }
275 if (departureRelativePositionY == MSPModel::RANDOM_POS_LAT) {
276 departureRelativePositionY = RandHelper::rand(-halfDepartureLaneWidth, halfDepartureLaneWidth, &myRNG);
277 }
278 departurePosition = departureLane->getShape().positionAtOffset(stage->getDepartPos() + radius + POSITION_EPS, -departureRelativePositionY); // Minus sign is here for legacy reasons.
279 }
280
281 std::vector<WaypointDesc> waypoints;
282 const MSEdge* prev = nullptr;
283 for (const MSEdge* const e : stage->getEdges()) {
284 const MSLane* const lane = getSidewalk<MSEdge, MSLane>(e);
285 JPS_StageId waitingStage = 0;
286 if (prev != nullptr) {
287 int dir = UNDEFINED_DIRECTION;
288 if (prev->getToJunction() == e->getFromJunction() || prev->getToJunction() == e->getToJunction()) {
289 dir = FORWARD;
290 } else if (prev->getFromJunction() == e->getFromJunction() || prev->getFromJunction() == e->getToJunction()) {
291 dir = BACKWARD;
292 }
293 if (dir != UNDEFINED_DIRECTION) {
294 ConstMSEdgeVector crossingRoute;
295 MSNet::getInstance()->getPedestrianRouter(0).compute(prev, e, 0, 0, stage->getMaxSpeed(person), 0,
296 dir == FORWARD ? prev->getToJunction() : prev->getFromJunction(),
297 person->getVTypeParameter(), crossingRoute, true);
298 const MSEdge* wa = nullptr;
299 for (const MSEdge* const ce : crossingRoute) {
300 if (ce->isCrossing()) {
301 const MSLane* const crossing = getSidewalk<MSEdge, MSLane>(ce);
302 auto crossingWait = myCrossingWaits.find(crossing);
303 if (crossingWait != myCrossingWaits.end()) {
304 if (waitingStage != 0 && wa != nullptr) {
305 // we already have a waiting stage we need an intermediate waypoint
306 waypoints.push_back({waitingStage, wa->getLanes()[0]->getShape().getCentroid(), wa->getWidth() / 2.});
307 }
308 const MSLane* const prevLane = getSidewalk<MSEdge, MSLane>(prev);
309 const Position& startPos = dir == FORWARD ? prevLane->getShape().back() : prevLane->getShape().front();
310 // choose the waiting set closer to the lane "end"
311 if (crossing->getShape().front().distanceSquaredTo(startPos) < crossing->getShape().back().distanceSquaredTo(startPos)) {
312 if (crossingWait->second.first == 0) {
313 crossingWait->second.first = addWaitingSet(crossing, true);
314 }
315 waitingStage = crossingWait->second.first;
316 } else {
317 if (crossingWait->second.second == 0) {
318 crossingWait->second.second = addWaitingSet(crossing, false);
319 }
320 waitingStage = crossingWait->second.second;
321 }
322 } else {
323 throw ProcessError(TLF("No waiting set for crossing at %.", ce->getID()));
324 }
325 }
326 if (ce->isWalkingArea()) {
327 wa = ce;
328 }
329 }
330 }
331 }
332 waypoints.push_back({waitingStage, lane->getShape().positionAtOffset(e->getLength() / 2.), lane->getWidth() / 2.});
333 prev = e;
334 }
335 const JPS_StageId finalWait = std::get<0>(waypoints.back());
336 waypoints.pop_back(); // arrival waypoint comes later
337 if (!waypoints.empty()) {
338 waypoints.erase(waypoints.begin()); // departure edge also does not need a waypoint
339 }
340 const MSLane* const arrivalLane = getSidewalk<MSEdge, MSLane>(stage->getDestination());
341 const Position arrivalPosition = arrivalLane->getShape().positionAtOffset(stage->getArrivalPos());
342 waypoints.push_back({finalWait, arrivalPosition, stage->getDouble("jupedsim.waypoint.radius", myExitTolerance)});
343
344 JPS_JourneyDescription journeyDesc = JPS_JourneyDescription_Create();
345 if (myPythonScript != nullptr) {
346 (*myPythonScript) << "\njourney = jps.JourneyDescription()\n";
347 }
348 JPS_StageId startingStage = 0;
349 JPS_StageId predecessor = 0;
350 for (const auto& p : waypoints) {
351 if (!addWaypoint(journeyDesc, predecessor, person->getID(), p)) {
352 JPS_JourneyDescription_Free(journeyDesc);
353 return nullptr;
354 }
355 if (startingStage == 0) {
356 startingStage = std::get<0>(waypoints.front()) == 0 ? predecessor : std::get<0>(waypoints.front());
357 }
358 }
359 JPS_ErrorMessage message = nullptr;
360 JPS_JourneyId journeyId = JPS_Simulation_AddJourney(myJPSSimulation, journeyDesc, &message);
361 JPS_JourneyDescription_Free(journeyDesc);
362 if (message != nullptr) {
363 WRITE_WARNINGF(TL("Error while adding a journey for person '%': %"), person->getID(), JPS_ErrorMessage_GetMessage(message));
364 JPS_ErrorMessage_Free(message);
365 return nullptr;
366 }
367
368 PState* state = nullptr;
369 for (PState* const pstate : myPedestrianStates) { // TODO transform myPedestrianStates into a map for faster lookup
370 if (pstate->getPerson() == person) {
371 state = pstate;
372 break;
373 }
374 }
375 if (state == nullptr) {
376 state = new PState(static_cast<MSPerson*>(person), stage, journeyId, startingStage, waypoints);
377 state->setLanePosition(stage->getDepartPos() + radius + POSITION_EPS);
378 state->setPosition(departurePosition.x(), departurePosition.y());
379 state->setAngle(departureLane->getShape().rotationAtOffset(stage->getDepartPos()));
380 myPedestrianStates.push_back(state);
382 } else {
383 state->reinit(stage, journeyId, startingStage, waypoints);
384 }
385 if (state->isWaitingToEnter()) {
386 const Position p = state->getPosition(*state->getStage(), now);
387 tryPedestrianInsertion(state, p);
388 if (myPythonScript != nullptr) {
389 (*myPythonScript) << "journey_id = simulation.add_journey(journey)\n"
390 "simulation.add_agent(jps.CollisionFreeSpeedModelAgentParameters(journey_id=journey_id,stage_id="
391 << startingStage << ",position=(" << departurePosition.x() << "," << departurePosition.y()
392 << "),radius=" << getRadius(person->getVehicleType()) << ",v0=" << person->getMaxSpeed() << "))\n";
393 }
394 } else {
395 JPS_Simulation_SwitchAgentJourney(myJPSSimulation, state->getAgentId(), journeyId, startingStage, &message);
396 if (message != nullptr) {
397 WRITE_WARNINGF(TL("Error while switching to a new journey for person '%': %"), person->getID(), JPS_ErrorMessage_GetMessage(message));
398 JPS_ErrorMessage_Free(message);
399 return nullptr;
400 }
401 }
402 return state;
403}
404
405
406void
408 PState* pstate = static_cast<PState*>(state);
409 if (pstate->getLane() != nullptr) {
410 auto& peds = myActiveLanes[pstate->getLane()];
411 peds.erase(std::find(peds.begin(), peds.end(), pstate));
412 pstate->setLane(nullptr);
413 }
414 if (pstate->getStage() != nullptr) {
415 pstate->getStage()->setPState(nullptr); // we need to remove the old state reference to avoid double deletion
416 }
417 pstate->setStage(nullptr);
418}
419
420
423 const int nbrIterations = (int)(DELTA_T / myJPSDeltaT);
424 JPS_ErrorMessage message = nullptr;
425 for (int i = 0; i < nbrIterations; ++i) {
426 // Perform one JuPedSim iteration.
427 bool ok = JPS_Simulation_Iterate(myJPSSimulation, &message);
428 if (!ok) {
429 WRITE_ERRORF(TL("Error during iteration %: %"), i, JPS_ErrorMessage_GetMessage(message));
430 }
431 }
432
433 // Update the state of all pedestrians.
434 // If necessary, this could be done more often in the loop above but the more precise positions are probably never visible.
435 // If it is needed for model correctness (precise stopping / arrivals) we should rather reduce SUMO's step-length.
436 for (auto stateIt = myPedestrianStates.begin(); stateIt != myPedestrianStates.end();) {
437 PState* const state = *stateIt;
438
439 if (state->isWaitingToEnter()) {
440 // insertion failed at first try so we retry with some noise
441 Position p = state->getPosition(*state->getStage(), time);
442 p.setx(p.x() + RandHelper::rand(-.5, .5, &myRNG)); // we do this separately to avoid evaluation order problems
443 p.sety(p.y() + RandHelper::rand(-.5, .5, &myRNG));
444 tryPedestrianInsertion(state, p);
445 ++stateIt;
446 continue;
447 }
448
449 MSPerson* const person = state->getPerson();
450 MSStageWalking* const stage = dynamic_cast<MSStageWalking*>(person->getCurrentStage());
451 if (stage == nullptr) {
452 // It seems we kept the state for another stage but the new stage is not a walk.
453 // So let's remove the state because after the new stage we will be elsewhere and need to be reinserted for JuPedSim anyway.
454 // We cannot check this earlier because when the old stage ends the next stage might not know yet whether it will be a walk.
455 registerArrived(state->getAgentId());
456 stateIt = myPedestrianStates.erase(stateIt);
457 continue;
458 }
459
460 // Updates the agent position.
461 const JPS_Agent agent = JPS_Simulation_GetAgent(myJPSSimulation, state->getAgentId(), nullptr);
462 const JPS_Point position = JPS_Agent_GetPosition(agent);
463 state->setPosition(position.x, position.y);
464
465 // Updates the agent direction.
466 const JPS_Point orientation = JPS_Agent_GetOrientation(agent);
467 state->setAngle(atan2(orientation.y, orientation.x));
468
469 // Find on which edge the pedestrian is, using route's forward-looking edges because of how moveToXY is written.
470 Position newPosition(position.x, position.y);
471 ConstMSEdgeVector route = stage->getEdges();
472 const int routeIndex = (int)(stage->getRouteStep() - stage->getRoute().begin());
473 const double oldLanePos = state->getEdgePos(time);
474 ConstMSEdgeVector forwardRoute = ConstMSEdgeVector(route.begin() + routeIndex, route.end());
475 double bestDistance = std::numeric_limits<double>::max();
476 MSLane* candidateLane = nullptr;
477 double candidateLaneLongitudinalPosition = 0.0;
478 int routeOffset = 0;
479 const bool found = libsumo::Helper::moveToXYMap_matchingRoutePosition(newPosition, "",
480 forwardRoute, 0, person->getVClass(), true, bestDistance, &candidateLane, candidateLaneLongitudinalPosition, routeOffset);
481
482 if (found) {
483 if (candidateLane != state->getLane()) {
484 if (state->getLane() != nullptr) {
485 auto& peds = myActiveLanes[state->getLane()];
486 peds.erase(std::find(peds.begin(), peds.end(), state));
487 }
488 myActiveLanes[candidateLane].push_back(state);
489 state->setLane(candidateLane);
490 }
491 state->setLanePosition(candidateLaneLongitudinalPosition);
492 }
493
494 const MSEdge* const expectedEdge = stage->getEdge();
495 if (found && expectedEdge->isNormal() && candidateLane->getEdge().isNormal() && &candidateLane->getEdge() != expectedEdge) {
496 const bool arrived = stage->moveToNextEdge(person, time, 1, nullptr);
497 UNUSED_PARAMETER(arrived);
498 assert(!arrived); // The person has not arrived yet.
499 stage->activateEntryReminders(person);
500 // Adapt speed to lane's speed limit.
501 const double newMaxSpeed = MIN2(candidateLane->getSpeedLimit(), person->getMaxSpeed());
502 switch (myJPSModel) {
504 JPS_CollisionFreeSpeedModelState modelState = JPS_Agent_GetCollisionFreeSpeedModelState(agent, nullptr);
505 if (newMaxSpeed != JPS_CollisionFreeSpeedModelState_GetV0(modelState)) {
506 JPS_CollisionFreeSpeedModelState_SetV0(modelState, newMaxSpeed);
507 }
508 break;
509 }
511 JPS_CollisionFreeSpeedModelV2State modelState = JPS_Agent_GetCollisionFreeSpeedModelV2State(agent, nullptr);
512 if (newMaxSpeed != JPS_CollisionFreeSpeedModelV2State_GetV0(modelState)) {
513 JPS_CollisionFreeSpeedModelV2State_SetV0(modelState, newMaxSpeed);
514 }
515 break;
516 }
518 JPS_GeneralizedCentrifugalForceModelState modelState = JPS_Agent_GetGeneralizedCentrifugalForceModelState(agent, nullptr);
519 if (newMaxSpeed != JPS_GeneralizedCentrifugalForceModelState_GetV0(modelState)) {
520 JPS_GeneralizedCentrifugalForceModelState_SetV0(modelState, newMaxSpeed);
521 }
522 break;
523 }
525 JPS_SocialForceModelState modelState = JPS_Agent_GetSocialForceModelState(agent, nullptr);
526 if (newMaxSpeed != JPS_SocialForceModelState_GetDesiredSpeed(modelState)) {
527 JPS_SocialForceModelState_SetDesiredSpeed(modelState, newMaxSpeed);
528 }
529 break;
530 }
531 }
532 }
533 const double speed = person->getSpeed();
534 for (int offset = 0; offset < 2; offset++) {
535 const WaypointDesc* const waypoint = state->getNextWaypoint(offset);
536 if (waypoint != nullptr && std::get<0>(*waypoint) != 0) {
537 const JPS_StageId waitingStage = std::get<0>(*waypoint);
538 const MSLane* const crossing = myCrossings[waitingStage];
539 const MSLink* link = crossing->getIncomingLanes().front().viaLink;
540 if (waitingStage == myCrossingWaits[crossing].second && link->getTLLogic() != nullptr) {
541 // we are walking backwards on a traffic light, there are different links to check
542 link = crossing->getLinkCont().front();
543 if (link->getTLLogic() == nullptr) {
544 link = crossing->getLogicalPredecessorLane()->getLinkTo(crossing);
545 }
546 }
547 // compare to and maybe adapt for MSPModel_Striping.cpp:1264
548 const double passingClearanceTime = person->getFloatParam("pedestrian.timegap-crossing");
549 const bool open = link->opened(time - DELTA_T, speed, speed, person->getVehicleType().getLength() + passingClearanceTime * speed,
550 person->getImpatience(), speed, 0, 0, nullptr, false, person);
551 const auto proxy = JPS_Simulation_GetWaitingSetProxy(myJPSSimulation, waitingStage, &message);
552 JPS_WaitingSetProxy_SetWaitingSetState(proxy, open ? JPS_WaitingSet_Inactive : JPS_WaitingSet_Active);
553 }
554 }
555 stage->activateMoveReminders(person, oldLanePos, state->getEdgePos(time), state->getSpeed(*stage));
556 // In the worst case during one SUMO step the person touches the waypoint radius and walks immediately into a different direction,
557 // but at some simstep it should have a maximum distance of v * delta_t / 2 to the waypoint circle.
558 const double slack = person->getMaxSpeed() * TS / 2. + POSITION_EPS;
559 if (newPosition.distanceTo2D(std::get<1>(*state->getNextWaypoint())) < std::get<2>(*state->getNextWaypoint()) + slack) {
560 // If near the last waypoint, remove the agent.
561 if (state->advanceNextWaypoint()) {
562 // TODO this only works if the final stage is actually a walk
563 const bool finalStage = person->getNumRemainingStages() == 1;
564 const JPS_AgentId agentID = state->getAgentId();
565 while (!stage->moveToNextEdge(person, time, 1, nullptr));
566 if (finalStage) {
567 registerArrived(agentID);
568 stateIt = myPedestrianStates.erase(stateIt);
569 continue;
570 }
571 }
572 }
573 ++stateIt;
574 }
575
576 // Remove pedestrians that are in a predefined area, at a predefined rate.
577 for (const auto& area : myAreas) {
578 const std::vector<JPS_Point>& areaBoundary = area->areaBoundary;
579 JPS_AgentIdIterator agentsInArea = JPS_Simulation_AgentsInPolygon(myJPSSimulation, areaBoundary.data(), areaBoundary.size());
580 if (area->areaType == "vanishing_area") {
581 const SUMOTime period = area->params.count("period") > 0 ? string2time(area->params.at("period")) : 1000;
582 const int nbrPeriodsCoveringTimestep = (int)ceil(TS / STEPS2TIME(period));
583 if (time - area->lastRemovalTime >= nbrPeriodsCoveringTimestep * period) {
584 for (int k = 0; k < nbrPeriodsCoveringTimestep; k++) {
585 const JPS_AgentId agentID = JPS_AgentIdIterator_Next(agentsInArea);
586 if (agentID != 0) {
587 auto lambda = [agentID](const PState * const p) {
588 return p->getAgentId() == agentID;
589 };
590 std::vector<PState*>::const_iterator iterator = std::find_if(myPedestrianStates.begin(), myPedestrianStates.end(), lambda);
591 if (iterator != myPedestrianStates.end()) {
592 const PState* const state = *iterator;
593 MSPerson* const person = state->getPerson();
594 // Code below only works if the removal happens at the last stage.
595 const bool finalStage = person->getNumRemainingStages() == 1;
596 if (finalStage) {
597 WRITE_MESSAGEF(TL("Person '%' in vanishing area '%' was removed from the simulation."), person->getID(), area->id);
598 while (!state->getStage()->moveToNextEdge(person, time, 1, nullptr));
599 registerArrived(agentID);
600 myPedestrianStates.erase(iterator);
601 area->lastRemovalTime = time;
602 }
603 }
604 }
605 }
606 }
607 } else { // areaType == "influencer"
608 for (JPS_AgentId agentID = JPS_AgentIdIterator_Next(agentsInArea); agentID != 0; agentID = JPS_AgentIdIterator_Next(agentsInArea)) {
609 if (area->params.count("speed") > 0) {
610 const JPS_Agent agent = JPS_Simulation_GetAgent(myJPSSimulation, agentID, nullptr);
611 const double newMaxSpeed = StringUtils::toDouble(area->params.at("speed"));
612 switch (myJPSModel) {
614 JPS_CollisionFreeSpeedModelState modelState = JPS_Agent_GetCollisionFreeSpeedModelState(agent, nullptr);
615 if (newMaxSpeed != JPS_CollisionFreeSpeedModelState_GetV0(modelState)) {
616 JPS_CollisionFreeSpeedModelState_SetV0(modelState, newMaxSpeed);
617 }
618 break;
619 }
621 JPS_CollisionFreeSpeedModelV2State modelState = JPS_Agent_GetCollisionFreeSpeedModelV2State(agent, nullptr);
622 if (newMaxSpeed != JPS_CollisionFreeSpeedModelV2State_GetV0(modelState)) {
623 JPS_CollisionFreeSpeedModelV2State_SetV0(modelState, newMaxSpeed);
624 }
625 break;
626 }
628 JPS_GeneralizedCentrifugalForceModelState modelState = JPS_Agent_GetGeneralizedCentrifugalForceModelState(agent, nullptr);
629 if (newMaxSpeed != JPS_GeneralizedCentrifugalForceModelState_GetV0(modelState)) {
630 JPS_GeneralizedCentrifugalForceModelState_SetV0(modelState, newMaxSpeed);
631 }
632 break;
633 }
635 JPS_SocialForceModelState modelState = JPS_Agent_GetSocialForceModelState(agent, nullptr);
636 if (newMaxSpeed != JPS_SocialForceModelState_GetDesiredSpeed(modelState)) {
637 JPS_SocialForceModelState_SetDesiredSpeed(modelState, newMaxSpeed);
638 }
639 break;
640 }
641 }
642 }
643 }
644 }
645 JPS_AgentIdIterator_Free(agentsInArea);
646 }
647
648 // Add dynamically additional geometry from train carriages that are stopped.
649 const auto& stoppingPlaces = myNetwork->getStoppingPlaces(SumoXMLTag::SUMO_TAG_BUS_STOP);
650 std::vector<SUMOTrafficObject::NumericalID> allStoppedTrainIDs;
651 std::vector<const MSVehicle*> allStoppedTrains;
652 for (const auto& stop : stoppingPlaces) {
653 std::vector<const SUMOVehicle*> stoppedTrains = stop.second->getStoppedVehicles();
654 for (const SUMOVehicle* train : stoppedTrains) {
655 allStoppedTrainIDs.push_back(train->getNumericalID());
656 allStoppedTrains.push_back(dynamic_cast<const MSVehicle*>(train));
657 }
658 }
659 if (allStoppedTrainIDs != myAllStoppedTrainIDs) {
661 if (!allStoppedTrainIDs.empty()) {
662 std::vector<GEOSGeometry*> carriagePolygons;
663 std::vector<GEOSGeometry*> rampPolygons;
664 for (const MSVehicle* train : allStoppedTrains) {
665 if (train->getLeavingPersonNumber() > 0) {
666 const SUMOVTypeParameter& vTypeParam = train->getVehicleType().getParameter();
667 MSTrainHelper trainHelper = MSTrainHelper(train);
668 trainHelper.computeDoorPositions();
669 const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
670 for (const MSTrainHelper::Carriage* carriage : carriages) {
671 Position dir = carriage->front - carriage->back;
672 if (dir.length2D() == 0.0) {
673 continue;
674 }
675 dir.norm2D();
676 Position perp = Position(-dir.y(), dir.x());
677 // Create carriages geometry.
678 double p = trainHelper.getHalfWidth();
679 PositionVector carriageShape;
680 carriageShape.push_back(carriage->front + perp * p);
681 carriageShape.push_back(carriage->back + perp * p);
682 carriageShape.push_back(carriage->back - perp * p);
683 carriageShape.push_back(carriage->front - perp * p);
684 carriagePolygons.push_back(createGeometryFromShape(carriageShape));
685 // Create ramps geometry.
686 p += vTypeParam.maxPlatformDistance;
687 const double d = 0.5 * vTypeParam.carriageDoorWidth;
688 for (const Position& door : carriage->doorPositions) {
689 PositionVector rampShape;
690 rampShape.push_back(door - perp * p + dir * d);
691 rampShape.push_back(door - perp * p - dir * d);
692 rampShape.push_back(door + perp * p - dir * d);
693 rampShape.push_back(door + perp * p + dir * d);
694 rampPolygons.push_back(createGeometryFromShape(rampShape));
695 }
696 }
697 }
698 }
699 if (!carriagePolygons.empty()) {
700 GEOSGeometry* carriagesCollection = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, carriagePolygons.data(), (unsigned int)carriagePolygons.size());
701 GEOSGeometry* rampsCollection = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, rampPolygons.data(), (unsigned int)rampPolygons.size());
702 GEOSGeometry* carriagesAndRampsUnion = GEOSUnion(carriagesCollection, rampsCollection);
703 if (carriagesAndRampsUnion == nullptr) {
704 WRITE_WARNING(TL("Error while generating geometry for carriages."));
705 } else {
706 GEOSGeometry* pedestrianNetworkWithTrainsAndRamps = GEOSUnion(carriagesAndRampsUnion, myGEOSPedestrianNetworkLargestComponent);
707#ifdef DEBUG_GEOMETRY_GENERATION
708 //dumpGeometry(pedestrianNetworkWithTrainsAndRamps, "pedestrianNetworkWithTrainsAndRamps.wkt");
709#endif
710 int nbrComponents = 0;
711 double maxArea = 0.0;
712 double totalArea = 0.0;
713 const GEOSGeometry* pedestrianNetworkWithTrainsAndRampsLargestComponent = getLargestComponent(pedestrianNetworkWithTrainsAndRamps, nbrComponents, maxArea, totalArea);
714 if (nbrComponents > 1) {
715 WRITE_WARNINGF(TL("While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
716 nbrComponents, maxArea / totalArea * 100.0, "%");
717 }
718#ifdef DEBUG_GEOMETRY_GENERATION
719 //dumpGeometry(pedestrianNetworkWithTrainsAndRampsLargestComponent, "pedestrianNetworkWithTrainsAndRamps.wkt");
720#endif
721 myJPSGeometryWithTrainsAndRamps = buildJPSGeometryFromGEOSGeometry(pedestrianNetworkWithTrainsAndRampsLargestComponent);
722 const bool ok = JPS_Simulation_SwitchGeometry(myJPSSimulation, myJPSGeometryWithTrainsAndRamps, nullptr, &message);
723 if (!ok) {
724 WRITE_WARNINGF(TL("While switching to train geometry: %"), JPS_ErrorMessage_GetMessage(message));
725 }
728 GEOSGeom_destroy(pedestrianNetworkWithTrainsAndRamps);
729 }
730 GEOSGeom_destroy(rampsCollection);
731 GEOSGeom_destroy(carriagesCollection);
732 }
733 } else {
734 if (myJPSGeometryWithTrainsAndRamps != nullptr) {
735 const bool ok = JPS_Simulation_SwitchGeometry(myJPSSimulation, myJPSGeometry, nullptr, &message);
736 if (!ok) {
737 WRITE_WARNINGF(TL("While switching to default geometry: %"), JPS_ErrorMessage_GetMessage(message));
738 }
741 }
742 }
743 myAllStoppedTrainIDs = allStoppedTrainIDs;
744 }
745
746 JPS_ErrorMessage_Free(message);
747
748 return DELTA_T;
749}
750
751
752void MSPModel_JuPedSim_legacy::registerArrived(const JPS_AgentId agentID) {
754 JPS_Simulation_MarkAgentForRemoval(myJPSSimulation, agentID, nullptr);
755}
756
757
762
763
764GEOSGeometry*
766 GEOSCoordSequence* coordinateSequence = convertToGEOSPoints(centerLine);
767 GEOSGeometry* lineString = GEOSGeom_createLineString(coordinateSequence);
768 GEOSGeometry* dilatedLineString = GEOSBufferWithStyle(lineString, width, GEOS_QUADRANT_SEGMENTS, capStyle, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);
769 GEOSGeom_destroy(lineString);
770 return dilatedLineString;
771}
772
773
774GEOSGeometry*
775MSPModel_JuPedSim_legacy::createGeometryFromShape(PositionVector shape, std::string junctionID, std::string shapeID, bool isInternalShape) {
776 // Corner case.
777 if (shape.size() == 1) {
778 WRITE_WARNINGF(TL("Polygon '%' at junction '%' will be skipped as it is just a point."), shapeID, junctionID);
779 return nullptr;
780 }
781 // Make sure the shape is closed.
782 if (shape.back() != shape.front()) {
783 shape.push_back(shape.front());
784 }
785 // Replace consecutive points that are equal with just one.
786 PositionVector cleanShape;
787 cleanShape.push_back(shape[0]);
788 PositionVector duplicates;
789 for (int i = 1; i < (int)shape.size(); i++) {
790 if (shape[i] != shape[i - 1]) {
791 cleanShape.push_back(shape[i]);
792 } else {
793 duplicates.push_back(shape[i]);
794 }
795 }
796 if (cleanShape.size() < shape.size()) {
797 WRITE_WARNINGF(TL("Polygon '%' at junction '%' had some equal consecutive points removed: %"), shapeID, junctionID, toString(duplicates, 9));
798 }
799 GEOSCoordSequence* coordinateSequence = convertToGEOSPoints(cleanShape);
800 GEOSGeometry* linearRing = GEOSGeom_createLinearRing(coordinateSequence);
801 GEOSGeometry* polygon = GEOSGeom_createPolygon(linearRing, nullptr, 0);
802
803 if (!GEOSisValid(polygon)) {
804 if (cleanShape.size() == 3) {
805 if (isInternalShape) {
806 WRITE_WARNINGF(TL("Polygon '%' at junction '%' has been dilated as it is just a segment."), shapeID, junctionID);
807 } else {
808 WRITE_WARNINGF(TL("Polygon '%' has been dilated as it is just a segment."), shapeID);
809 }
810 GEOSGeometry* lineString = GEOSGeom_createLineString(GEOSCoordSeq_clone(coordinateSequence));
811 GEOSGeom_destroy(polygon);
812 polygon = GEOSBufferWithStyle(lineString, GEOS_BUFFERED_SEGMENT_WIDTH, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_BEVEL, GEOS_MITRE_LIMIT);
813 GEOSGeom_destroy(lineString);
814 } else {
815 if (isInternalShape) {
816 WRITE_WARNINGF(TL("Polygon '%' at junction '%' has been replaced by its convex hull as it is not simple."), shapeID, junctionID);
817 GEOSGeometry* hull = GEOSConvexHull(polygon);
818 GEOSGeom_destroy(polygon);
819 polygon = GEOSBufferWithStyle(hull, POSITION_EPS, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);;
820 } else {
821 WRITE_WARNINGF(TL("Polygon '%' at junction '%' will be skipped as it is not simple."), shapeID, junctionID);
822 polygon = nullptr;
823 }
824 }
825
826 return polygon;
827 }
828
829 // Some junctions need to be buffered a little so that edges are properly connected.
830 if (isInternalShape) {
831 polygon = GEOSBufferWithStyle(polygon, POSITION_EPS, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);
832 }
833
834 return polygon;
835}
836
837
838GEOSGeometry*
840 std::vector<GEOSGeometry*> walkableAreas;
841 for (const MSEdge* const edge : network->getEdgeControl().getEdges()) {
842 const MSLane* const lane = getSidewalk<MSEdge, MSLane>(edge);
843 if (lane != nullptr) {
844 GEOSGeometry* dilatedLane = nullptr;
845 if (edge->isWalkingArea()) {
846 dilatedLane = createGeometryFromShape(lane->getShape(), edge->getFromJunction()->getID(), edge->getID(), true);
847 } else if (edge->isCrossing()) {
848 const PositionVector* outlineShape = lane->getOutlineShape();
849 if (outlineShape != nullptr) {
850 // this is mainly to ensure that we have at least the "normal" crossing, see #15037
851 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0, GEOSBUF_CAP_FLAT);
852 if (dilatedLane != nullptr) {
853 walkableAreas.push_back(dilatedLane);
854 }
855 dilatedLane = createGeometryFromShape(*outlineShape, edge->getFromJunction()->getID(), edge->getID(), true);
856 } else {
857 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0, GEOSBUF_CAP_ROUND);
858 }
859 myCrossingWaits[lane] = {0, 0};
860 } else { // regular sidewalk
861 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0 + POSITION_EPS, GEOSBUF_CAP_FLAT);
862 }
863 if (dilatedLane != nullptr) {
864 walkableAreas.push_back(dilatedLane);
865 }
866 }
867 }
868 for (const auto& junctionWithID : network->getJunctionControl()) {
869 const MSJunction* const junction = junctionWithID.second;
870 int pedEdgeCount = 0;
871 bool hasWalkingArea = false;
872 for (const ConstMSEdgeVector& edges : {
873 junction->getIncoming(), junction->getOutgoing()
874 }) {
875 for (const MSEdge* const edge : edges) {
876 if (edge->isWalkingArea()) {
877 hasWalkingArea = true;
878 break;
879 }
880 if (getSidewalk<MSEdge, MSLane>(edge) != nullptr) {
881 pedEdgeCount++;
882 }
883 }
884 if (hasWalkingArea) {
885 break;
886 }
887 }
888 if (!hasWalkingArea && pedEdgeCount > 1) {
889 // there is something to connect but no walking area, let's assume peds are allowed everywhere
890 GEOSGeometry* walkingAreaGeom = createGeometryFromShape(junction->getShape(), junction->getID(), junction->getID(), true);
891 if (walkingAreaGeom != nullptr) {
892 walkableAreas.push_back(walkingAreaGeom);
893 }
894 }
895 }
896
897 // Retrieve additional walkable areas and obstacles (walkable areas and obstacles in the sense of JuPedSim).
898 std::vector<GEOSGeometry*> additionalObstacles;
899 for (const auto& polygonWithID : myNetwork->getShapeContainer().getPolygons()) {
900 if (polygonWithID.second->getShapeType() == "jupedsim.walkable_area" || polygonWithID.second->getShapeType() == "taz") {
901 GEOSGeometry* walkableArea = createGeometryFromShape(polygonWithID.second->getShape(), std::string(""), polygonWithID.first);
902 if (walkableArea != nullptr) {
903 walkableAreas.push_back(walkableArea);
905 }
906 } else if (polygonWithID.second->getShapeType() == "jupedsim.obstacle") {
907 GEOSGeometry* additionalObstacle = createGeometryFromShape(polygonWithID.second->getShape(), std::string(""), polygonWithID.first);
908 if (additionalObstacle != nullptr) {
909 additionalObstacles.push_back(additionalObstacle);
910 }
911 }
912 }
913
914 // Take the union of all walkable areas.
915 GEOSGeometry* disjointWalkableAreas = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, walkableAreas.data(), (unsigned int)walkableAreas.size());
916#ifdef DEBUG_GEOMETRY_GENERATION
917 // dumpGeometry(disjointWalkableAreas, "disjointWalkableAreas.wkt");
918#endif
919 GEOSGeometry* initialWalkableAreas = GEOSUnaryUnion(disjointWalkableAreas);
920#ifdef DEBUG_GEOMETRY_GENERATION
921 dumpGeometry(initialWalkableAreas, "initialWalkableAreas.wkt");
922#endif
923 GEOSGeom_destroy(disjointWalkableAreas);
924
925 // At last, remove additional obstacles from the merged walkable areas.
926 GEOSGeometry* disjointAdditionalObstacles = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, additionalObstacles.data(), (unsigned int)additionalObstacles.size());
927#ifdef DEBUG_GEOMETRY_GENERATION
928 // dumpGeometry(disjointAdditionalObstacles, "disjointAdditionalObstacles.wkt");
929#endif
930 GEOSGeometry* additionalObstaclesUnion = GEOSUnaryUnion(disjointAdditionalObstacles); // Obstacles may overlap, e.g. if they were loaded from separate files.
931#ifdef DEBUG_GEOMETRY_GENERATION
932 dumpGeometry(additionalObstaclesUnion, "additionalObstaclesUnion.wkt");
933#endif
934 GEOSGeometry* finalWalkableAreas = GEOSDifference(initialWalkableAreas, additionalObstaclesUnion);
935#ifdef DEBUG_GEOMETRY_GENERATION
936 dumpGeometry(finalWalkableAreas, "finalWalkableAreas.wkt");
937#endif
938 GEOSGeom_destroy(initialWalkableAreas);
939 GEOSGeom_destroy(additionalObstaclesUnion);
940 GEOSGeom_destroy(disjointAdditionalObstacles);
941
942 if (!GEOSisSimple(finalWalkableAreas)) {
943 throw ProcessError(TL("Union of walkable areas minus union of obstacles is not a simple polygon."));
944 }
945
946 return finalWalkableAreas;
947}
948
949
950GEOSCoordSequence*
952 GEOSCoordSequence* coordinateSequence = GEOSCoordSeq_create((unsigned int)shape.size(), 2);
953 for (int i = 0; i < (int)shape.size(); i++) {
954 GEOSCoordSeq_setX(coordinateSequence, i, shape[i].x());
955 GEOSCoordSeq_setY(coordinateSequence, i, shape[i].y());
956 }
957 return coordinateSequence;
958}
959
960
963 PositionVector coordinateVector;
964 const GEOSCoordSequence* coordinateSequence = GEOSGeom_getCoordSeq(geometry);
965 unsigned int coordinateSequenceSize;
966 GEOSCoordSeq_getSize(coordinateSequence, &coordinateSequenceSize);
967 double x;
968 double y;
969 for (unsigned int i = 0; i < coordinateSequenceSize; i++) {
970 GEOSCoordSeq_getX(coordinateSequence, i, &x);
971 GEOSCoordSeq_getY(coordinateSequence, i, &y);
972 coordinateVector.push_back(Position(x, y));
973 }
974 return coordinateVector;
975}
976
977
978std::vector<JPS_Point>
979MSPModel_JuPedSim_legacy::convertToJPSPoints(const GEOSGeometry* geometry) {
980 std::vector<JPS_Point> pointVector;
981 const GEOSCoordSequence* coordinateSequence = GEOSGeom_getCoordSeq(geometry);
982 unsigned int coordinateSequenceSize;
983 GEOSCoordSeq_getSize(coordinateSequence, &coordinateSequenceSize);
984 double x;
985 double y;
986 // Remove the last point so that CGAL doesn't complain about the simplicity of the polygon downstream.
987 for (unsigned int i = 0; i < coordinateSequenceSize - 1; i++) {
988 GEOSCoordSeq_getX(coordinateSequence, i, &x);
989 GEOSCoordSeq_getY(coordinateSequence, i, &y);
990 pointVector.push_back({x, y});
991 }
992 return pointVector;
993}
994
995
996double
997MSPModel_JuPedSim_legacy::getLinearRingArea(const GEOSGeometry* linearRing) {
998 double area;
999 GEOSGeometry* linearRingAsPolygon = GEOSGeom_createPolygon(GEOSGeom_clone(linearRing), nullptr, 0);
1000 GEOSArea(linearRingAsPolygon, &area);
1001 GEOSGeom_destroy(linearRingAsPolygon);
1002 return area;
1003}
1004
1005
1006void
1009}
1010
1011
1012void
1013MSPModel_JuPedSim_legacy::preparePolygonForDrawing(const GEOSGeometry* polygon, const std::string& polygonId, const RGBColor& color) {
1014 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
1015 bool added = myShapeContainer.addPolygon(polygonId, std::string("jupedsim.pedestrian_network"), color, 10.0, 0.0,
1016 std::string(), convertToSUMOPoints(exterior), false, true, 1.0);
1017 if (added) {
1018 std::vector<PositionVector> holes;
1019 int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
1020 if (nbrInteriorRings != -1) {
1021 for (int k = 0; k < nbrInteriorRings; k++) {
1022 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
1023 double area = getLinearRingArea(linearRing);
1024 if (area > GEOS_MIN_AREA) {
1025 holes.push_back(convertToSUMOPoints(linearRing));
1026 }
1027 }
1028 myShapeContainer.getPolygons().get(polygonId)->setHoles(holes);
1029 }
1030 }
1031}
1032
1033
1034const GEOSGeometry*
1035MSPModel_JuPedSim_legacy::getLargestComponent(const GEOSGeometry* polygon, int& nbrComponents, double& maxArea, double& totalArea) {
1036 nbrComponents = GEOSGetNumGeometries(polygon);
1037 const GEOSGeometry* largestComponent = nullptr;
1038 maxArea = 0.0;
1039 totalArea = 0.0;
1040 for (int i = 0; i < nbrComponents; i++) {
1041 const GEOSGeometry* componentPolygon = GEOSGetGeometryN(polygon, i);
1042 double area;
1043 GEOSArea(componentPolygon, &area);
1044 totalArea += area;
1045 if (area > maxArea) {
1046 maxArea = area;
1047 largestComponent = componentPolygon;
1048 }
1049 }
1050 return largestComponent;
1051}
1052
1053
1054JPS_Geometry
1056 JPS_GeometryBuilder geometryBuilder = JPS_GeometryBuilder_Create();
1057
1058 // Handle the exterior polygon.
1059 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
1060 std::vector<JPS_Point> exteriorCoordinates = convertToJPSPoints(exterior);
1061 JPS_GeometryBuilder_AddAccessibleArea(geometryBuilder, exteriorCoordinates.data(), exteriorCoordinates.size());
1062
1063 // Handle the interior polygons (holes).
1064 int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
1065 if (nbrInteriorRings != -1) {
1066 for (int k = 0; k < nbrInteriorRings; k++) {
1067 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
1068 double area = getLinearRingArea(linearRing);
1069 if (area > GEOS_MIN_AREA) {
1070 std::vector<JPS_Point> holeCoordinates = convertToJPSPoints(linearRing);
1071 JPS_GeometryBuilder_ExcludeFromAccessibleArea(geometryBuilder, holeCoordinates.data(), holeCoordinates.size());
1072 }
1073 }
1074 }
1075
1076 JPS_ErrorMessage message = nullptr;
1077 JPS_Geometry geometry = JPS_GeometryBuilder_Build(geometryBuilder, &message);
1078 if (geometry == nullptr) {
1079 const std::string error = TLF("Error while generating geometry: %", JPS_ErrorMessage_GetMessage(message));
1080 JPS_ErrorMessage_Free(message);
1081 throw ProcessError(error);
1082 }
1083 JPS_GeometryBuilder_Free(geometryBuilder);
1084 return geometry;
1085}
1086
1087
1088void
1089MSPModel_JuPedSim_legacy::dumpGeometry(const GEOSGeometry* polygon, const std::string& filename, bool useGeoCoordinates) {
1090 GEOSGeometry* polygonGeoCoordinates = nullptr;
1091 if (useGeoCoordinates) {
1092 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
1093 PositionVector exteriorPoints = convertToSUMOPoints(exterior);
1094 for (Position& position : exteriorPoints) {
1096 }
1097 const int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
1098 std::vector<GEOSGeometry*> holeRings;
1099 if (nbrInteriorRings != -1) {
1100 for (int k = 0; k < nbrInteriorRings; k++) {
1101 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
1102 PositionVector holePoints = convertToSUMOPoints(linearRing);
1103 for (Position& position : holePoints) {
1105 }
1106 GEOSCoordSequence* holeRingCoords = convertToGEOSPoints(holePoints);
1107 GEOSGeometry* holeRing = GEOSGeom_createLinearRing(holeRingCoords);
1108 holeRings.push_back(holeRing);
1109 }
1110 }
1111 GEOSCoordSequence* exteriorRingCoords = convertToGEOSPoints(exteriorPoints);
1112 GEOSGeometry* exteriorRing = GEOSGeom_createLinearRing(exteriorRingCoords);
1113 polygonGeoCoordinates = GEOSGeom_createPolygon(exteriorRing, holeRings.data(), nbrInteriorRings);
1114 }
1115 std::ofstream dumpFile;
1116 dumpFile.open(filename);
1117 GEOSWKTWriter* writer = GEOSWKTWriter_create();
1118 GEOSWKTWriter_setRoundingPrecision(writer, gPrecisionGeo);
1119 char* wkt = GEOSWKTWriter_write(writer, polygonGeoCoordinates == nullptr ? polygon : polygonGeoCoordinates);
1120 dumpFile << wkt << std::endl;
1121 dumpFile.close();
1122 GEOSFree(wkt);
1123 GEOSWKTWriter_destroy(writer);
1124 GEOSGeom_destroy(polygonGeoCoordinates);
1125}
1126
1127
1128double
1130 return 0.5 * MAX2(vehType.getLength(), vehType.getWidth());
1131}
1132
1133
1134JPS_StageId
1135MSPModel_JuPedSim_legacy::addWaitingSet(const MSLane* const crossing, const bool entry) {
1136 JPS_ErrorMessage message = nullptr;
1137 JPS_StageId waitingStage = 0;
1138 PositionVector shape = crossing->getShape();
1139 const double radius = getRadius(*MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true));
1140 shape.extrapolate2D((shape.length() + radius) / shape.length());
1141 const double offset = 2 * radius + POSITION_EPS;
1142 const double lonOffset = entry ? NUMERICAL_EPS : shape.length() - NUMERICAL_EPS;
1143 PositionVector pv;
1144 pv.push_back(shape.positionAtOffset(lonOffset));
1145 for (double latOff = offset; latOff < crossing->getWidth() / 2. - offset; latOff += offset) {
1146 PositionVector moved(shape);
1147 moved.move2side(latOff);
1148 pv.push_back(moved.positionAtOffset(lonOffset));
1149 moved.move2side(-2. * latOff);
1150 pv.push_back(moved.positionAtOffset(lonOffset));
1151 }
1152 if (entry && crossing->getIncomingLanes().size() == 1 && crossing->getIncomingLanes().front().lane->isWalkingArea()) {
1153 pv.push_back(crossing->getIncomingLanes().front().lane->getShape().getCentroid());
1154 }
1155 if (!entry && crossing->getLinkCont().size() == 1 && crossing->getLinkCont().front()->getLane()->isWalkingArea()) {
1156 pv.push_back(crossing->getLinkCont().front()->getLane()->getShape().getCentroid());
1157 }
1158 std::vector<JPS_Point> points;
1159 for (const Position& p : pv) {
1160 GEOSCoordSequence* seq = GEOSCoordSeq_create(1, 2); // 1 point, 2 dimensions
1161 GEOSCoordSeq_setX(seq, 0, p.x());
1162 GEOSCoordSeq_setY(seq, 0, p.y());
1163 GEOSGeometry* point = GEOSGeom_createPoint(seq);
1164 if (GEOSContains(myGEOSPedestrianNetworkLargestComponent, point)) {
1165 points.push_back({p.x(), p.y()});
1166 } else {
1167 WRITE_WARNINGF("Waiting point %,% is not in the geometry for % on '%'.", p.x(), p.y(), entry ? "entry" : "exit", crossing->getID())
1168 }
1169 GEOSGeom_destroy(point);
1170 }
1171 waitingStage = JPS_Simulation_AddStageWaitingSet(myJPSSimulation, points.data(), points.size(), &message);
1172 if (message != nullptr) {
1173 const std::string error = TLF("Error while adding waiting set for % on '%': %",
1174 entry ? "entry" : "exit", crossing->getID(), JPS_ErrorMessage_GetMessage(message));
1175 JPS_ErrorMessage_Free(message);
1176 throw ProcessError(error);
1177 }
1178 const auto proxy = JPS_Simulation_GetWaitingSetProxy(myJPSSimulation, waitingStage, &message);
1179 JPS_WaitingSetProxy_SetWaitingSetState(proxy, JPS_WaitingSet_Inactive);
1180 myCrossings[waitingStage] = crossing;
1181 if (myPythonScript != nullptr) {
1182 (*myPythonScript) << "ws = simulation.add_waiting_set_stage([";
1183 for (const JPS_Point& p : points) {
1184 (*myPythonScript) << "(" << p.x << "," << p.y << "),";
1185 }
1186 (*myPythonScript) << "])\nsimulation.get_stage(ws).state = jps.stages.WaitingSetState.INACTIVE\n";
1187 }
1188 return waitingStage;
1189}
1190
1191
1192void
1194 initGEOS(nullptr, nullptr);
1195 PROGRESS_BEGIN_MESSAGE("Generating initial JuPedSim geometry for pedestrian network");
1197 int nbrComponents = 0;
1198 double maxArea = 0.0;
1199 double totalArea = 0.0;
1201 if (nbrComponents > 1) {
1202 WRITE_WARNINGF(TL("While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
1203 nbrComponents, maxArea / totalArea * 100.0, "%");
1204 }
1205#ifdef DEBUG_GEOMETRY_GENERATION
1206 dumpGeometry(myGEOSPedestrianNetworkLargestComponent, "pedestrianNetwork.wkt");
1207#endif
1208 const std::string filename = oc.getString("pedestrian.jupedsim.wkt");
1209 if (!filename.empty()) {
1210 dumpGeometry(myGEOSPedestrianNetworkLargestComponent, filename, oc.getBool("pedestrian.jupedsim.wkt.geo"));
1211 }
1212 // For the moment, only one connected component is supported.
1217 JPS_ErrorMessage message = nullptr;
1218
1219 double strengthGeometryRepulsion = oc.getFloat("pedestrian.jupedsim.strength-geometry-repulsion");
1220 double rangeGeometryRepulsion = oc.getFloat("pedestrian.jupedsim.range-geometry-repulsion");
1221 if (myJPSDeltaT == 20) {
1222 if (oc.isDefault("pedestrian.jupedsim.strength-geometry-repulsion") && oc.isDefault("pedestrian.jupedsim.range-geometry-repulsion")) {
1223 WRITE_MESSAGE(TL("Adapting geometry repulsion default values for jupedsim timestep of 0.02."));
1224 strengthGeometryRepulsion = 35.;
1225 rangeGeometryRepulsion = 0.019;
1226 }
1227 }
1228
1229 switch (myJPSModel) {
1231 JPS_CollisionFreeSpeedModelBuilder modelBuilder = JPS_CollisionFreeSpeedModelBuilder_Create(
1232 oc.getFloat("pedestrian.jupedsim.strength-neighbor-repulsion"),
1233 oc.getFloat("pedestrian.jupedsim.range-neighbor-repulsion"),
1234 strengthGeometryRepulsion,
1235 rangeGeometryRepulsion);
1236 myJPSOperationalModel = JPS_CollisionFreeSpeedModelBuilder_Build(modelBuilder, &message);
1237 JPS_CollisionFreeSpeedModelBuilder_Free(modelBuilder);
1238 break;
1239 }
1241 JPS_CollisionFreeSpeedModelV2Builder modelBuilder = JPS_CollisionFreeSpeedModelV2Builder_Create();
1242 myJPSOperationalModel = JPS_CollisionFreeSpeedModelV2Builder_Build(modelBuilder, &message);
1243 JPS_CollisionFreeSpeedModelV2Builder_Free(modelBuilder);
1244 break;
1245 }
1247 JPS_GeneralizedCentrifugalForceModelBuilder modelBuilder = JPS_GeneralizedCentrifugalForceModelBuilder_Create(
1248 oc.getFloat("pedestrian.jupedsim.strength-neighbor-repulsion"),
1249 strengthGeometryRepulsion,
1250 2.0,
1251 2.0,
1252 0.1,
1253 0.1,
1254 9.0,
1255 3.0);
1256 myJPSOperationalModel = JPS_GeneralizedCentrifugalForceModelBuilder_Build(modelBuilder, &message);
1257 JPS_GeneralizedCentrifugalForceModelBuilder_Free(modelBuilder);
1258 break;
1259 }
1261 JPS_SocialForceModelBuilder modelBuilder = JPS_SocialForceModelBuilder_Create(120000.0, 240000.0);
1262 myJPSOperationalModel = JPS_SocialForceModelBuilder_Build(modelBuilder, &message);
1263 JPS_SocialForceModelBuilder_Free(modelBuilder);
1264 break;
1265 }
1266 }
1267
1268 if (myJPSOperationalModel == nullptr) {
1269 const std::string error = TLF("Error creating the pedestrian model: %", JPS_ErrorMessage_GetMessage(message));
1270 JPS_ErrorMessage_Free(message);
1271 throw ProcessError(error);
1272 }
1273 myJPSSimulation = JPS_Simulation_Create(myJPSOperationalModel, myJPSGeometry, STEPS2TIME(myJPSDeltaT), &message);
1274 if (myJPSSimulation == nullptr) {
1275 const std::string error = TLF("Error creating the simulation: %", JPS_ErrorMessage_GetMessage(message));
1276 JPS_ErrorMessage_Free(message);
1277 throw ProcessError(error);
1278 }
1279 // Polygons that define vanishing areas aren't part of the regular JuPedSim geometry.
1280 for (const auto& polygonWithID : myNetwork->getShapeContainer().getPolygons()) {
1281 polygonChanged(polygonWithID.second, true, false);
1282 }
1283 if (OutputDevice::createDeviceByOption("pedestrian.jupedsim.py")) {
1284 myPythonScript = &OutputDevice::getDeviceByOption("pedestrian.jupedsim.py");
1286 (*myPythonScript) << "import jupedsim as jps\nimport shapely\n\n"
1287 "with open('" << filename << "') as f: geom = shapely.from_wkt(f.read())\n"
1288 "simulation = jps.Simulation(dt=" << STEPS2TIME(myJPSDeltaT) << ", model=jps.CollisionFreeSpeedModel(), geometry=geom,\n"
1289 "trajectory_writer=jps.SqliteTrajectoryWriter(output_file='out.sql'))\n";
1290 }
1292}
1293
1294
1295void
1296MSPModel_JuPedSim_legacy::polygonChanged(const SUMOPolygon* const poly, const bool added, const bool removed) {
1297 if (poly->getShapeType() == "jupedsim.vanishing_area" || poly->getShapeType() == "jupedsim.influencer") {
1298 SUMOTime lastRemovalTime = 0;
1299 if (!added) {
1300 for (auto areaIt = myAreas.begin(); areaIt != myAreas.end(); ++areaIt) {
1301 if (poly->getID() == (*areaIt)->id) {
1302 lastRemovalTime = (*areaIt)->lastRemovalTime;
1303 myAreas.erase(areaIt);
1304 break;
1305 }
1306 }
1307 }
1308 if (!removed) {
1309 std::vector<JPS_Point> areaBoundary;
1310 for (const Position& p : poly->getShape()) {
1311 areaBoundary.push_back({p.x(), p.y()});
1312 }
1313 // Make sure the shape is not repeating the first point.
1314 if (areaBoundary.back().x == areaBoundary.front().x && areaBoundary.back().y == areaBoundary.front().y) {
1315 areaBoundary.pop_back();
1316 }
1317 const std::string type = StringTokenizer(poly->getShapeType(), ".").getVector()[1];
1318 myAreas.emplace_back(std::unique_ptr<AreaData>(new AreaData{poly->getID(), type, areaBoundary, poly->getParametersMap(), lastRemovalTime}));
1319 }
1320 }
1321}
1322
1323
1324// ===========================================================================
1325// MSPModel_Remote::PState method definitions
1326// ===========================================================================
1328 JPS_JourneyId journeyId, JPS_StageId stageId,
1329 const std::vector<WaypointDesc>& waypoints) :
1330 MSPModel_InteractingState(person, stage, nullptr),
1331 myJourneyId(journeyId), myStageId(stageId), myWaypoints(waypoints), myAgentId(0) {
1332 myDir = FORWARD;
1333}
1334
1335
1336void
1337MSPModel_JuPedSim_legacy::PState::reinit(MSStageMoving* stage, JPS_JourneyId journeyId, JPS_StageId stageId,
1338 const std::vector<WaypointDesc>& waypoints) {
1339 if (myStage != nullptr) {
1340 myStage->setPState(nullptr); // we need to remove the old state reference to avoid double deletion
1341 }
1342 myStage = stage;
1343 myJourneyId = journeyId;
1344 myStageId = stageId;
1345 myWaypoints = waypoints;
1346}
1347
1348
1351
1352
1353void MSPModel_JuPedSim_legacy::PState::setPosition(const double x, const double y, const double z) {
1354 if (myRemoteXYPos != Position::INVALID) {
1355 mySpeed = myRemoteXYPos.distanceTo2D(Position(x, y, z)) / STEPS2TIME(DELTA_T);
1356 } else {
1357 mySpeed = 0.;
1358 }
1359 myRemoteXYPos.set(x, y, z);
1360}
1361
1362
1364 return stage.getNextRouteEdge();
1365}
1366
1367
1370 return offset < (int)myWaypoints.size() ? &myWaypoints[offset] : nullptr;
1371}
1372
1373
1374/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:75
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_MESSAGEF(...)
Definition MsgHandler.h:289
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define WRITE_MESSAGE(msg)
Definition MsgHandler.h:288
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
#define PROGRESS_DONE_MESSAGE()
Definition MsgHandler.h:291
#define TLF(string,...)
Definition MsgHandler.h:306
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition MsgHandler.h:290
SUMOTime DELTA_T
Definition SUMOTime.cpp:39
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:47
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:107
#define STEPS2TIME(x)
Definition SUMOTime.h:58
#define SIMSTEP
Definition SUMOTime.h:69
#define TS
Definition SUMOTime.h:45
const std::string DEFAULT_PEDTYPE_ID
@ RANDOM_LOCATION
The position may be chosen freely in a polygon defined by a taz.
@ SUMO_TAG_BUS_STOP
A bus stop.
int gPrecisionGeo
Definition StdDefs.cpp:29
const double SUMO_const_laneWidth
Definition StdDefs.h:52
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:57
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition Boundary.cpp:127
double xmin() const
Returns minimum x-coordinate.
Definition Boundary.cpp:115
double ymax() const
Returns maximum y-coordinate.
Definition Boundary.cpp:133
double xmax() const
Returns maximum x-coordinate.
Definition Boundary.cpp:121
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
const MSEdgeVector & getEdges() const
Returns loaded edges.
A road/street connecting two junctions.
Definition MSEdge.h:78
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:169
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:265
const MSJunction * getToJunction() const
Definition MSEdge.h:428
const MSJunction * getFromJunction() const
Definition MSEdge.h:424
bool isTazConnector() const
Definition MSEdge.h:293
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:666
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
The base class for an intersection.
Definition MSJunction.h:58
const ConstMSEdgeVector & getOutgoing() const
Definition MSJunction.h:114
const PositionVector & getShape() const
Returns this junction's shape.
Definition MSJunction.h:91
const ConstMSEdgeVector & getIncoming() const
Definition MSJunction.h:108
Representation of a lane in the micro simulation.
Definition MSLane.h:84
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2801
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:602
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:984
MSLane * getLogicalPredecessorLane() const
get the most likely predecessor lane (sorted using by_connections_to_sorter). The result is cached in...
Definition MSLane.cpp:3271
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:790
const PositionVector * getOutlineShape() const
Definition MSLane.h:1384
double getWidth() const
Returns the lane's width.
Definition MSLane.h:661
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:750
The simulated network and simulation perfomer.
Definition MSNet.h:89
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:201
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition MSNet.h:495
MSJunctionControl & getJunctionControl()
Returns the junctions control.
Definition MSNet.h:485
MSPedestrianRouter & getPedestrianRouter(int rngIndex, const Prohibitions &prohibited={}) const
Definition MSNet.cpp:1703
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
ShapeContainer & getShapeContainer()
Returns the shapes container.
Definition MSNet.h:525
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition MSNet.h:445
const NamedObjectCont< MSStoppingPlace * > & getStoppingPlaces(SumoXMLTag category) const
Definition MSNet.cpp:1578
ActiveLanes myActiveLanes
store of all lanes which have pedestrians on them
int myNumActivePedestrians
the total number of active pedestrians
Container for pedestrian state and individual position update function.
MSStageMoving * getStage() const
return the current stage
int myDir
the walking direction on the current lane (1 forward, -1 backward)
virtual double getAngle(const MSStageMoving &, SUMOTime) const
return the current orientation in degrees
double getEdgePos(SUMOTime) const
abstract methods inherited from MSTransportableStateAdapter
MSPerson * getPerson() const
return the represented person
bool isWaitingToEnter() const
whether the person still waits to entere the network
const MSLane * getLane() const
the current lane of the transportable
double getSpeed() const
return the current speed of the transportable, we need to be able to do this for vehicles as well,...
Holds pedestrian state and performs updates.
void reinit(MSStageMoving *stage, JPS_JourneyId journeyId, JPS_StageId stageId, const std::vector< WaypointDesc > &waypoints)
const MSPModel_JuPedSim_legacy::WaypointDesc * getNextWaypoint(const int offset=0) const
const MSEdge * getNextEdge(const MSStageMoving &stage) const override
return the list of internal edges if the transportable is on an intersection
void setStage(MSStageMoving *const stage)
void setPosition(const double x, const double y, const double z=0.)
JPS_StageId getStageId() const
first stage of the journey
Position getPosition(const MSStageMoving &, SUMOTime) const override
return the network coordinate of the transportable
PState(MSPerson *person, MSStageMoving *stage, JPS_JourneyId journeyId, JPS_StageId stageId, const std::vector< WaypointDesc > &waypoints)
void polygonChanged(const SUMOPolygon *const poly, const bool added, const bool removed) override
JPS_Geometry myJPSGeometryWithTrainsAndRamps
The JPS polygon representing the largest connected component plus carriages and ramps.
JPS_Geometry myJPSGeometry
The JPS polygon representing the largest connected component of the pedestrian network.
static const RGBColor PEDESTRIAN_NETWORK_CARRIAGES_AND_RAMPS_COLOR
void initialize(const OptionsCont &oc)
void clearState() override
Resets pedestrians when quick-loading state.
static JPS_Geometry buildJPSGeometryFromGEOSGeometry(const GEOSGeometry *polygon)
static GEOSCoordSequence * convertToGEOSPoints(PositionVector shape)
static PositionVector convertToSUMOPoints(const GEOSGeometry *geometry)
static double getRadius(const MSVehicleType &vehType)
static const double GEOS_BUFFERED_SEGMENT_WIDTH
GEOSGeometry * buildPedestrianNetwork(MSNet *network)
void registerArrived(const JPS_AgentId agentID)
static void dumpGeometry(const GEOSGeometry *polygon, const std::string &filename, bool useGeoCoordinates=false)
void preparePolygonForDrawing(const GEOSGeometry *polygon, const std::string &polygonId, const RGBColor &color)
std::map< const MSLane *, std::pair< JPS_StageId, JPS_StageId >, ComparatorNumericalIdLess > myCrossingWaits
const SUMOTime myJPSDeltaT
Timestep used in the JuPedSim simulator.
bool addWaypoint(JPS_JourneyDescription journey, JPS_StageId &predecessor, const std::string &agentID, const WaypointDesc &waypoint)
GEOSGeometry * myGEOSPedestrianNetwork
The GEOS polygon containing all computed connected components of the pedestrian network.
JPS_StageId addWaitingSet(const MSLane *const crossing, const bool entry)
MSNet *const myNetwork
The network on which the simulation runs.
void removePolygonFromDrawing(const std::string &polygonId)
JPS_OperationalModel myJPSOperationalModel
static const GEOSGeometry * getLargestComponent(const GEOSGeometry *polygon, int &nbrComponents, double &maxArea, double &totalArea)
static const std::vector< MSPModel_JuPedSim_legacy::PState * > noPedestrians
void tryPedestrianInsertion(PState *state, const Position &p)
static GEOSGeometry * createGeometryFromCenterLine(PositionVector centerLine, double width, int capStyle)
MSTransportableStateAdapter * add(MSTransportable *person, MSStageMoving *stage, SUMOTime now) override
register the given person as a pedestrian
MSPModel_JuPedSim_legacy(const OptionsCont &oc, MSNet *net)
static std::vector< JPS_Point > convertToJPSPoints(const GEOSGeometry *geometry)
ShapeContainer & myShapeContainer
The shape container used to add polygons to the rendering pipeline.
std::vector< std::unique_ptr< AreaData > > myAreas
Array of special areas.
void remove(MSTransportableStateAdapter *state) override
remove the specified person from the pedestrian simulation
bool addStage(JPS_JourneyDescription journey, JPS_StageId &predecessor, const std::string &agentID, const JPS_StageId stage)
static double getLinearRingArea(const GEOSGeometry *linearRing)
std::vector< SUMOTrafficObject::NumericalID > myAllStoppedTrainIDs
Array of stopped trains, used to detect whether to add carriages and ramps to the geometry.
static const std::string PEDESTRIAN_NETWORK_CARRIAGES_AND_RAMPS_ID
static GEOSGeometry * createGeometryFromShape(PositionVector shape, std::string junctionID=std::string(""), std::string shapeID=std::string(""), bool isInternalShape=false)
std::vector< PState * > myPedestrianStates
SumoRNG myRNG
The random number generator for fluctuations on insertion.
static const std::string PEDESTRIAN_NETWORK_ID
const double myExitTolerance
Threshold to decide if a pedestrian has ended its journey or not.
std::map< JPS_StageId, const MSLane * > myCrossings
const GEOSGeometry * myGEOSPedestrianNetworkLargestComponent
The GEOS polygon representing the largest (by area) connected component of the pedestrian network.
static const RGBColor PEDESTRIAN_NETWORK_COLOR
std::tuple< JPS_StageId, Position, double > WaypointDesc
static const int BACKWARD
Definition MSPModel.h:55
static const int FORWARD
Definition MSPModel.h:54
static const double RANDOM_POS_LAT
magic value to encode randomized lateral offset for persons when starting a walk
Definition MSPModel.h:68
static const int UNDEFINED_DIRECTION
Definition MSPModel.h:56
static const double UNSPECIFIED_POS_LAT
the default lateral offset for persons when starting a walk
Definition MSPModel.h:65
double getImpatience() const
Definition MSPerson.cpp:245
const MSEdge * getDestination() const
returns the destination edge
Definition MSStage.cpp:65
virtual double getArrivalPos() const
Definition MSStage.h:97
virtual const MSEdge * getEdge() const
Returns the current edge.
Definition MSStage.cpp:71
virtual const MSEdge * getNextRouteEdge() const =0
ConstMSEdgeVector getEdges() const
the edges of the current stage
const std::vector< const MSEdge * > & getRoute() const
void setPState(MSTransportableStateAdapter *pstate)
double getDepartPosLat() const
const MSEdge * getEdge() const
Returns the current edge.
double getDepartPos() const
const std::vector< constMSEdge * >::iterator getRouteStep() const
virtual bool moveToNextEdge(MSTransportable *transportable, SUMOTime currentTime, int prevDir, MSEdge *nextInternal=nullptr, const bool isReplay=false)=0
move forward and return whether the transportable arrived
virtual double getMaxSpeed(const MSTransportable *const transportable=nullptr) const =0
the maximum speed of the transportable
bool moveToNextEdge(MSTransportable *person, SUMOTime currentTime, int prevDir, MSEdge *nextInternal=nullptr, const bool isReplay=false)
move forward and return whether the person arrived
void activateMoveReminders(MSTransportable *person, double oldPos, double newPos, double newSpeed)
void activateEntryReminders(MSTransportable *person, const bool isDepart=false)
add the move reminders for the current lane on entry
A class that helps computing positions of a train's carriages and additional structures.
void computeDoorPositions()
compute door positions on demand and fills the carriage structures
const std::vector< Carriage * > & getCarriages() const
double getHalfWidth() const
virtual double getSpeed() const override
the current speed of the transportable
MSStage * getNextStage(int offset) const
Return the next (or previous) stage denoted by the offset.
int getNumRemainingStages() const
Return the number of remaining stages (including the current)
MSStage * getCurrentStage() const
Return the current stage.
SUMOVehicleClass getVClass() const override
Returns the object's access class.
double getMaxSpeed() const override
Returns the maximum speed (the minimum of desired and physical maximum speed)
const SUMOVTypeParameter & getVTypeParameter() const override
Returns the object's "vehicle" type parameter.
int getCurrentStageIndex() const
Return the index of the current stage.
MSStageType getCurrentStageType() const
the current stage type of the transportable
const SUMOVehicleParameter & getParameter() const override
Returns the vehicle's parameter (including departure definition)
const MSVehicleType & getVehicleType() const override
Returns the object's "vehicle" type.
const MSEdge * getEdge() const override
Returns the current edge.
abstract base class for managing callbacks to retrieve various state information from the model
Definition MSPModel.h:159
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
The car-following model and parameter.
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getLength() const
Get vehicle's length [m].
const std::string & getID() const
Returns the id.
Definition Named.h:73
T get(const std::string &id) const
Retrieves an item.
A storage for options typed value containers)
Definition OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static OptionsCont & getOptions()
Retrieves the options.
static OutputDevice & getDeviceByOption(const std::string &name)
Returns the device described by the option.
void setPrecision(int precision=gPrecision)
Sets the precision or resets it to default.
static bool createDeviceByOption(const std::string &optionName, const std::string &rootElement="", const std::string &schemaFile="", const int maximumDepth=2)
Creates the device using the output definition stored in the named option.
double getDouble(const std::string &key, const double defaultValue) const
Returns the value for a given key converted to a double.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
double compute(const E *from, const E *to, double departPos, double arrivalPos, double speed, SUMOTime msTime, const N *onlyNode, const SUMOVTypeParameter &pars, std::vector< const E * > &into, bool allEdges=false) const
Builds the route between the given edges using the minimum effort at the given time The definition of...
A point in 2D or 3D with translation and scaling methods.
Definition Position.h:37
void setx(double x)
set position x
Definition Position.h:67
static const Position INVALID
used to indicate that a position is valid
Definition Position.h:323
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
Definition Position.h:273
void norm2D()
Normalizes the given vector.
Definition Position.h:179
double x() const
Returns the x-position.
Definition Position.h:52
double length2D() const
Computes the length of the given vector neglecting the z coordinate.
Definition Position.h:174
void sety(double y)
set position y
Definition Position.h:72
double y() const
Returns the y-position.
Definition Position.h:57
A list of positions.
double length() const
Returns the length.
double rotationAtOffset(double pos) const
Returns the rotation at the given length.
Position positionAtOffset(double pos, double lateralOffset=0) const
Returns the position at the given length.
void move2side(double amount, double maxExtension=100)
move position vector to side using certain amount
Boundary getBoxBoundary() const
Returns a boundary enclosing this list of lines.
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point.
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
static void initRandGlobal(SumoRNG *which=nullptr)
Reads the given random number options and initialises the random number generator in accordance.
const PositionVector & getShape() const
Returns the shape of the polygon.
virtual void setHoles(const std::vector< PositionVector > &holes)
Sets the holes of the polygon.
double getFloatParam(const std::string &paramName, const bool required=false, const double deflt=INVALID_DOUBLE, bool checkDist=true) const
Retrieve a floating point parameter for the traffic object.
Structure representing possible vehicle parameter.
double maxPlatformDistance
the maximum distance between platform and train
double carriageDoorWidth
the width of the carriage doors
Representation of a vehicle.
Definition SUMOVehicle.h:63
DepartPosDefinition departPosProcedure
Information how the vehicle shall choose the departure position.
void addShapeListener(ShapeListener *listener)
virtual bool removePolygon(const std::string &id, bool useLock=true)
Removes a polygon from the container.
const Polygons & getPolygons() const
Returns all polygons.
virtual bool addPolygon(const std::string &id, const std::string &type, const RGBColor &color, double layer, double angle, const std::string &imgFile, const PositionVector &shape, bool geo, bool fill, double lineWidth, bool ignorePruning=false, const std::string &name=Shape::DEFAULT_NAME)
Builds a polygon using the given values and adds it to the container.
const std::string & getShapeType() const
Returns the (abstract) type of the Shape.
Definition Shape.cpp:99
std::vector< std::string > getVector()
return vector of strings
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool moveToXYMap_matchingRoutePosition(const Position &pos, const std::string &origID, const ConstMSEdgeVector &currentRoute, int routeIndex, SUMOVehicleClass vClass, bool setLateralPos, double &bestDistance, MSLane **lane, double &lanePos, int &routeOffset)
Definition Helper.cpp:1759
#define UNUSED_PARAMETER(x)
#define M_PI
Definition odrSpiral.cpp:45
Structure that keeps data related to vanishing areas (and other types of areas).