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