Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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,
293 dir == FORWARD ? prev->getToJunction() : prev->getFromJunction(),
294 person->getVTypeParameter(), crossingRoute, true);
295 const MSEdge* wa = nullptr;
296 for (const MSEdge* const ce : crossingRoute) {
297 if (ce->isCrossing()) {
298 const MSLane* const crossing = getSidewalk<MSEdge, MSLane>(ce);
299 if (myCrossingWaits.count(crossing) > 0) {
300 if (waitingStage != 0 && wa != nullptr) {
301 // we already have a waiting stage we need an intermediate waypoint
302 waypoints.push_back({waitingStage, wa->getLanes()[0]->getShape().getCentroid(), wa->getWidth() / 2.});
303 }
304 const MSLane* const prevLane = getSidewalk<MSEdge, MSLane>(prev);
305 const Position& startPos = dir == FORWARD ? prevLane->getShape().back() : prevLane->getShape().front();
306 // choose the waiting set closer to the lane "end"
307 if (crossing->getShape().front().distanceSquaredTo(startPos) < crossing->getShape().back().distanceSquaredTo(startPos)) {
308 waitingStage = myCrossingWaits[crossing].first;
309 } else {
310 waitingStage = myCrossingWaits[crossing].second;
311 }
312 } else {
313 throw ProcessError(TLF("No waiting set for crossing at %.", ce->getID()));
314 }
315 }
316 if (ce->isWalkingArea()) {
317 wa = ce;
318 }
319 }
320 }
321 }
322 waypoints.push_back({waitingStage, lane->getShape().positionAtOffset(e->getLength() / 2.), lane->getWidth() / 2.});
323 prev = e;
324 }
325 const JPS_StageId finalWait = std::get<0>(waypoints.back());
326 waypoints.pop_back(); // arrival waypoint comes later
327 if (!waypoints.empty()) {
328 waypoints.erase(waypoints.begin()); // departure edge also does not need a waypoint
329 }
330 const MSLane* const arrivalLane = getSidewalk<MSEdge, MSLane>(stage->getDestination());
331 const Position arrivalPosition = arrivalLane->getShape().positionAtOffset(stage->getArrivalPos());
332 waypoints.push_back({finalWait, arrivalPosition, stage->getDouble("jupedsim.waypoint.radius", myExitTolerance)});
333
334 JPS_JourneyDescription journeyDesc = JPS_JourneyDescription_Create();
335 if (myPythonScript != nullptr) {
336 (*myPythonScript) << "\njourney = jps.JourneyDescription()\n";
337 }
338 JPS_StageId startingStage = 0;
339 JPS_StageId predecessor = 0;
340 for (const auto& p : waypoints) {
341 if (!addWaypoint(journeyDesc, predecessor, person->getID(), p)) {
342 JPS_JourneyDescription_Free(journeyDesc);
343 return nullptr;
344 }
345 if (startingStage == 0) {
346 startingStage = std::get<0>(waypoints.front()) == 0 ? predecessor : std::get<0>(waypoints.front());
347 }
348 }
349 JPS_ErrorMessage message = nullptr;
350 JPS_JourneyId journeyId = JPS_Simulation_AddJourney(myJPSSimulation, journeyDesc, &message);
351 JPS_JourneyDescription_Free(journeyDesc);
352 if (message != nullptr) {
353 WRITE_WARNINGF(TL("Error while adding a journey for person '%': %"), person->getID(), JPS_ErrorMessage_GetMessage(message));
354 JPS_ErrorMessage_Free(message);
355 return nullptr;
356 }
357
358 PState* state = nullptr;
359 for (PState* const pstate : myPedestrianStates) { // TODO transform myPedestrianStates into a map for faster lookup
360 if (pstate->getPerson() == person) {
361 state = pstate;
362 break;
363 }
364 }
365 if (state == nullptr) {
366 state = new PState(static_cast<MSPerson*>(person), stage, journeyId, startingStage, waypoints);
367 state->setLanePosition(stage->getDepartPos() + radius + POSITION_EPS);
368 state->setPosition(departurePosition.x(), departurePosition.y());
369 state->setAngle(departureLane->getShape().rotationAtOffset(stage->getDepartPos()));
370 myPedestrianStates.push_back(state);
372 } else {
373 state->reinit(stage, journeyId, startingStage, waypoints);
374 }
375 if (state->isWaitingToEnter()) {
376 const Position p = state->getPosition(*state->getStage(), now);
377 tryPedestrianInsertion(state, p);
378 if (myPythonScript != nullptr) {
379 (*myPythonScript) << "journey_id = simulation.add_journey(journey)\n"
380 "simulation.add_agent(jps.CollisionFreeSpeedModelAgentParameters(journey_id=journey_id,stage_id="
381 << startingStage << ",position=(" << departurePosition.x() << "," << departurePosition.y()
382 << "),radius=" << getRadius(person->getVehicleType()) << ",v0=" << person->getMaxSpeed() << "))\n";
383 }
384 } else {
385 JPS_Simulation_SwitchAgentJourney(myJPSSimulation, state->getAgentId(), journeyId, startingStage, &message);
386 if (message != nullptr) {
387 WRITE_WARNINGF(TL("Error while switching to a new journey for person '%': %"), person->getID(), JPS_ErrorMessage_GetMessage(message));
388 JPS_ErrorMessage_Free(message);
389 return nullptr;
390 }
391 }
392 return state;
393}
394
395
396void
398 PState* pstate = static_cast<PState*>(state);
399 if (pstate->getLane() != nullptr) {
400 auto& peds = myActiveLanes[pstate->getLane()];
401 peds.erase(std::find(peds.begin(), peds.end(), pstate));
402 pstate->setLane(nullptr);
403 }
404 if (pstate->getStage() != nullptr) {
405 pstate->getStage()->setPState(nullptr); // we need to remove the old state reference to avoid double deletion
406 }
407 pstate->setStage(nullptr);
408}
409
410
413 const int nbrIterations = (int)(DELTA_T / myJPSDeltaT);
414 JPS_ErrorMessage message = nullptr;
415 for (int i = 0; i < nbrIterations; ++i) {
416 // Perform one JuPedSim iteration.
417 bool ok = JPS_Simulation_Iterate(myJPSSimulation, &message);
418 if (!ok) {
419 WRITE_ERRORF(TL("Error during iteration %: %"), i, JPS_ErrorMessage_GetMessage(message));
420 }
421 }
422
423 // Update the state of all pedestrians.
424 // If necessary, this could be done more often in the loop above but the more precise positions are probably never visible.
425 // If it is needed for model correctness (precise stopping / arrivals) we should rather reduce SUMO's step-length.
426 for (auto stateIt = myPedestrianStates.begin(); stateIt != myPedestrianStates.end();) {
427 PState* const state = *stateIt;
428
429 if (state->isWaitingToEnter()) {
430 // insertion failed at first try so we retry with some noise
431 Position p = state->getPosition(*state->getStage(), time);
432 p.setx(p.x() + RandHelper::rand(-.5, .5)); // we do this separately to avoid evaluation order problems
433 p.sety(p.y() + RandHelper::rand(-.5, .5));
434 tryPedestrianInsertion(state, p);
435 ++stateIt;
436 continue;
437 }
438
439 MSPerson* const person = state->getPerson();
440 MSStageWalking* const stage = dynamic_cast<MSStageWalking*>(person->getCurrentStage());
441 if (stage == nullptr) {
442 // It seems we kept the state for another stage but the new stage is not a walk.
443 // So let's remove the state because after the new stage we will be elsewhere and need to be reinserted for JuPedSim anyway.
444 // We cannot check this earlier because when the old stage ends the next stage might not know yet whether it will be a walk.
445 registerArrived(state->getAgentId());
446 stateIt = myPedestrianStates.erase(stateIt);
447 continue;
448 }
449
450 // Updates the agent position.
451 const JPS_Agent agent = JPS_Simulation_GetAgent(myJPSSimulation, state->getAgentId(), nullptr);
452 const JPS_Point position = JPS_Agent_GetPosition(agent);
453 state->setPosition(position.x, position.y);
454
455 // Updates the agent direction.
456 const JPS_Point orientation = JPS_Agent_GetOrientation(agent);
457 state->setAngle(atan2(orientation.y, orientation.x));
458
459 // Find on which edge the pedestrian is, using route's forward-looking edges because of how moveToXY is written.
460 Position newPosition(position.x, position.y);
461 ConstMSEdgeVector route = stage->getEdges();
462 const int routeIndex = (int)(stage->getRouteStep() - stage->getRoute().begin());
463 const double oldLanePos = state->getEdgePos(time);
464 ConstMSEdgeVector forwardRoute = ConstMSEdgeVector(route.begin() + routeIndex, route.end());
465 double bestDistance = std::numeric_limits<double>::max();
466 MSLane* candidateLane = nullptr;
467 double candidateLaneLongitudinalPosition = 0.0;
468 int routeOffset = 0;
469 const bool found = libsumo::Helper::moveToXYMap_matchingRoutePosition(newPosition, "",
470 forwardRoute, 0, person->getVClass(), true, bestDistance, &candidateLane, candidateLaneLongitudinalPosition, routeOffset);
471
472 if (found) {
473 if (candidateLane != state->getLane()) {
474 if (state->getLane() != nullptr) {
475 auto& peds = myActiveLanes[state->getLane()];
476 peds.erase(std::find(peds.begin(), peds.end(), state));
477 }
478 myActiveLanes[candidateLane].push_back(state);
479 state->setLane(candidateLane);
480 }
481 state->setLanePosition(candidateLaneLongitudinalPosition);
482 }
483
484 const MSEdge* const expectedEdge = stage->getEdge();
485 if (found && expectedEdge->isNormal() && candidateLane->getEdge().isNormal() && &candidateLane->getEdge() != expectedEdge) {
486 const bool arrived = stage->moveToNextEdge(person, time, 1, nullptr);
487 UNUSED_PARAMETER(arrived);
488 assert(!arrived); // The person has not arrived yet.
489 stage->activateEntryReminders(person);
490 // Adapt speed to lane's speed limit.
491 const double newMaxSpeed = MIN2(candidateLane->getSpeedLimit(), person->getMaxSpeed());
492 switch (myJPSModel) {
494 JPS_CollisionFreeSpeedModelState modelState = JPS_Agent_GetCollisionFreeSpeedModelState(agent, nullptr);
495 if (newMaxSpeed != JPS_CollisionFreeSpeedModelState_GetV0(modelState)) {
496 JPS_CollisionFreeSpeedModelState_SetV0(modelState, newMaxSpeed);
497 }
498 break;
499 }
501 JPS_CollisionFreeSpeedModelV2State modelState = JPS_Agent_GetCollisionFreeSpeedModelV2State(agent, nullptr);
502 if (newMaxSpeed != JPS_CollisionFreeSpeedModelV2State_GetV0(modelState)) {
503 JPS_CollisionFreeSpeedModelV2State_SetV0(modelState, newMaxSpeed);
504 }
505 break;
506 }
508 JPS_GeneralizedCentrifugalForceModelState modelState = JPS_Agent_GetGeneralizedCentrifugalForceModelState(agent, nullptr);
509 if (newMaxSpeed != JPS_GeneralizedCentrifugalForceModelState_GetV0(modelState)) {
510 JPS_GeneralizedCentrifugalForceModelState_SetV0(modelState, newMaxSpeed);
511 }
512 break;
513 }
515 JPS_SocialForceModelState modelState = JPS_Agent_GetSocialForceModelState(agent, nullptr);
516 if (newMaxSpeed != JPS_SocialForceModelState_GetDesiredSpeed(modelState)) {
517 JPS_SocialForceModelState_SetDesiredSpeed(modelState, newMaxSpeed);
518 }
519 break;
520 }
521 }
522 }
523 const double speed = person->getSpeed();
524 for (int offset = 0; offset < 2; offset++) {
525 const WaypointDesc* const waypoint = state->getNextWaypoint(offset);
526 if (waypoint != nullptr && std::get<0>(*waypoint) != 0) {
527 const JPS_StageId waitingStage = std::get<0>(*waypoint);
528 const MSLane* const crossing = myCrossings[waitingStage];
529 const MSLink* link = crossing->getIncomingLanes().front().viaLink;
530 if (waitingStage == myCrossingWaits[crossing].second && link->getTLLogic() != nullptr) {
531 // we are walking backwards on a traffic light, there are different links to check
532 link = crossing->getLinkCont().front();
533 if (link->getTLLogic() == nullptr) {
534 link = crossing->getLogicalPredecessorLane()->getLinkTo(crossing);
535 }
536 }
537 // compare to and maybe adapt for MSPModel_Striping.cpp:1264
538 const double passingClearanceTime = person->getFloatParam("pedestrian.timegap-crossing");
539 const bool open = link->opened(time - DELTA_T, speed, speed, person->getVehicleType().getLength() + passingClearanceTime * speed,
540 person->getImpatience(), speed, 0, 0, nullptr, false, person);
541 const auto proxy = JPS_Simulation_GetWaitingSetProxy(myJPSSimulation, waitingStage, &message);
542 JPS_WaitingSetProxy_SetWaitingSetState(proxy, open ? JPS_WaitingSet_Inactive : JPS_WaitingSet_Active);
543 }
544 }
545 stage->activateMoveReminders(person, oldLanePos, state->getEdgePos(time), state->getSpeed(*stage));
546 // In the worst case during one SUMO step the person touches the waypoint radius and walks immediately into a different direction,
547 // but at some simstep it should have a maximum distance of v * delta_t / 2 to the waypoint circle.
548 const double slack = person->getMaxSpeed() * TS / 2. + POSITION_EPS;
549 if (newPosition.distanceTo2D(std::get<1>(*state->getNextWaypoint())) < std::get<2>(*state->getNextWaypoint()) + slack) {
550 // If near the last waypoint, remove the agent.
551 if (state->advanceNextWaypoint()) {
552 // TODO this only works if the final stage is actually a walk
553 const bool finalStage = person->getNumRemainingStages() == 1;
554 const JPS_AgentId agentID = state->getAgentId();
555 while (!stage->moveToNextEdge(person, time, 1, nullptr));
556 if (finalStage) {
557 registerArrived(agentID);
558 stateIt = myPedestrianStates.erase(stateIt);
559 continue;
560 }
561 }
562 }
563 ++stateIt;
564 }
565
566 // Remove pedestrians that are in a predefined area, at a predefined rate.
567 for (AreaData& area : myAreas) {
568 const std::vector<JPS_Point>& areaBoundary = area.areaBoundary;
569 JPS_AgentIdIterator agentsInArea = JPS_Simulation_AgentsInPolygon(myJPSSimulation, areaBoundary.data(), areaBoundary.size());
570 if (area.areaType == "vanishing_area") {
571 const SUMOTime period = area.params.count("period") > 0 ? string2time(area.params.at("period")) : 1000;
572 const int nbrPeriodsCoveringTimestep = (int)ceil(TS / STEPS2TIME(period));
573 if (time - area.lastRemovalTime >= nbrPeriodsCoveringTimestep * period) {
574 for (int k = 0; k < nbrPeriodsCoveringTimestep; k++) {
575 const JPS_AgentId agentID = JPS_AgentIdIterator_Next(agentsInArea);
576 if (agentID != 0) {
577 auto lambda = [agentID](const PState * const p) {
578 return p->getAgentId() == agentID;
579 };
580 std::vector<PState*>::const_iterator iterator = std::find_if(myPedestrianStates.begin(), myPedestrianStates.end(), lambda);
581 if (iterator != myPedestrianStates.end()) {
582 const PState* const state = *iterator;
583 MSPerson* const person = state->getPerson();
584 // Code below only works if the removal happens at the last stage.
585 const bool finalStage = person->getNumRemainingStages() == 1;
586 if (finalStage) {
587 WRITE_MESSAGEF(TL("Person '%' in vanishing area '%' was removed from the simulation."), person->getID(), area.id);
588 while (!state->getStage()->moveToNextEdge(person, time, 1, nullptr));
589 registerArrived(agentID);
590 myPedestrianStates.erase(iterator);
591 area.lastRemovalTime = time;
592 }
593 }
594 }
595 }
596 }
597 } else { // areaType == "influencer"
598 for (JPS_AgentId agentID = JPS_AgentIdIterator_Next(agentsInArea); agentID != 0; agentID = JPS_AgentIdIterator_Next(agentsInArea)) {
599 if (area.params.count("speed") > 0) {
600 const JPS_Agent agent = JPS_Simulation_GetAgent(myJPSSimulation, agentID, nullptr);
601 const double newMaxSpeed = StringUtils::toDouble(area.params.at("speed"));
602 switch (myJPSModel) {
604 JPS_CollisionFreeSpeedModelState modelState = JPS_Agent_GetCollisionFreeSpeedModelState(agent, nullptr);
605 if (newMaxSpeed != JPS_CollisionFreeSpeedModelState_GetV0(modelState)) {
606 JPS_CollisionFreeSpeedModelState_SetV0(modelState, newMaxSpeed);
607 }
608 break;
609 }
611 JPS_CollisionFreeSpeedModelV2State modelState = JPS_Agent_GetCollisionFreeSpeedModelV2State(agent, nullptr);
612 if (newMaxSpeed != JPS_CollisionFreeSpeedModelV2State_GetV0(modelState)) {
613 JPS_CollisionFreeSpeedModelV2State_SetV0(modelState, newMaxSpeed);
614 }
615 break;
616 }
618 JPS_GeneralizedCentrifugalForceModelState modelState = JPS_Agent_GetGeneralizedCentrifugalForceModelState(agent, nullptr);
619 if (newMaxSpeed != JPS_GeneralizedCentrifugalForceModelState_GetV0(modelState)) {
620 JPS_GeneralizedCentrifugalForceModelState_SetV0(modelState, newMaxSpeed);
621 }
622 break;
623 }
625 JPS_SocialForceModelState modelState = JPS_Agent_GetSocialForceModelState(agent, nullptr);
626 if (newMaxSpeed != JPS_SocialForceModelState_GetDesiredSpeed(modelState)) {
627 JPS_SocialForceModelState_SetDesiredSpeed(modelState, newMaxSpeed);
628 }
629 break;
630 }
631 }
632 }
633 }
634 }
635 JPS_AgentIdIterator_Free(agentsInArea);
636 }
637
638 // Add dynamically additional geometry from train carriages that are stopped.
639 const auto& stoppingPlaces = myNetwork->getStoppingPlaces(SumoXMLTag::SUMO_TAG_BUS_STOP);
640 std::vector<SUMOTrafficObject::NumericalID> allStoppedTrainIDs;
641 std::vector<const MSVehicle*> allStoppedTrains;
642 for (const auto& stop : stoppingPlaces) {
643 std::vector<const SUMOVehicle*> stoppedTrains = stop.second->getStoppedVehicles();
644 for (const SUMOVehicle* train : stoppedTrains) {
645 allStoppedTrainIDs.push_back(train->getNumericalID());
646 allStoppedTrains.push_back(dynamic_cast<const MSVehicle*>(train));
647 }
648 }
649 if (allStoppedTrainIDs != myAllStoppedTrainIDs) {
651 if (!allStoppedTrainIDs.empty()) {
652 std::vector<GEOSGeometry*> carriagePolygons;
653 std::vector<GEOSGeometry*> rampPolygons;
654 for (const MSVehicle* train : allStoppedTrains) {
655 if (train->getLeavingPersonNumber() > 0) {
656 const SUMOVTypeParameter& vTypeParam = train->getVehicleType().getParameter();
657 MSTrainHelper trainHelper = MSTrainHelper(train);
658 trainHelper.computeDoorPositions();
659 const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
660 for (const MSTrainHelper::Carriage* carriage : carriages) {
661 Position dir = carriage->front - carriage->back;
662 if (dir.length2D() == 0.0) {
663 continue;
664 }
665 dir.norm2D();
666 Position perp = Position(-dir.y(), dir.x());
667 // Create carriages geometry.
668 double p = trainHelper.getHalfWidth();
669 PositionVector carriageShape;
670 carriageShape.push_back(carriage->front + perp * p);
671 carriageShape.push_back(carriage->back + perp * p);
672 carriageShape.push_back(carriage->back - perp * p);
673 carriageShape.push_back(carriage->front - perp * p);
674 carriagePolygons.push_back(createGeometryFromShape(carriageShape));
675 // Create ramps geometry.
676 p += vTypeParam.maxPlatformDistance;
677 const double d = 0.5 * vTypeParam.carriageDoorWidth;
678 for (const Position& door : carriage->doorPositions) {
679 PositionVector rampShape;
680 rampShape.push_back(door - perp * p + dir * d);
681 rampShape.push_back(door - perp * p - dir * d);
682 rampShape.push_back(door + perp * p - dir * d);
683 rampShape.push_back(door + perp * p + dir * d);
684 rampPolygons.push_back(createGeometryFromShape(rampShape));
685 }
686 }
687 }
688 }
689 if (!carriagePolygons.empty()) {
690 GEOSGeometry* carriagesCollection = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, carriagePolygons.data(), (unsigned int)carriagePolygons.size());
691 GEOSGeometry* rampsCollection = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, rampPolygons.data(), (unsigned int)rampPolygons.size());
692 GEOSGeometry* carriagesAndRampsUnion = GEOSUnion(carriagesCollection, rampsCollection);
693 if (carriagesAndRampsUnion == nullptr) {
694 WRITE_WARNING(TL("Error while generating geometry for carriages."));
695 } else {
696 GEOSGeometry* pedestrianNetworkWithTrainsAndRamps = GEOSUnion(carriagesAndRampsUnion, myGEOSPedestrianNetworkLargestComponent);
697#ifdef DEBUG_GEOMETRY_GENERATION
698 //dumpGeometry(pedestrianNetworkWithTrainsAndRamps, "pedestrianNetworkWithTrainsAndRamps.wkt");
699#endif
700 int nbrComponents = 0;
701 double maxArea = 0.0;
702 double totalArea = 0.0;
703 const GEOSGeometry* pedestrianNetworkWithTrainsAndRampsLargestComponent = getLargestComponent(pedestrianNetworkWithTrainsAndRamps, nbrComponents, maxArea, totalArea);
704 if (nbrComponents > 1) {
705 WRITE_WARNINGF(TL("While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
706 nbrComponents, maxArea / totalArea * 100.0, "%");
707 }
708#ifdef DEBUG_GEOMETRY_GENERATION
709 //dumpGeometry(pedestrianNetworkWithTrainsAndRampsLargestComponent, "pedestrianNetworkWithTrainsAndRamps.wkt");
710#endif
711 myJPSGeometryWithTrainsAndRamps = buildJPSGeometryFromGEOSGeometry(pedestrianNetworkWithTrainsAndRampsLargestComponent);
712 JPS_Simulation_SwitchGeometry(myJPSSimulation, myJPSGeometryWithTrainsAndRamps, nullptr, nullptr);
715 GEOSGeom_destroy(pedestrianNetworkWithTrainsAndRamps);
716 }
717 GEOSGeom_destroy(rampsCollection);
718 GEOSGeom_destroy(carriagesCollection);
719 }
720 } else {
721 JPS_Simulation_SwitchGeometry(myJPSSimulation, myJPSGeometry, nullptr, nullptr);
723 }
724 myAllStoppedTrainIDs = allStoppedTrainIDs;
725 }
726
727 JPS_ErrorMessage_Free(message);
728
729 return DELTA_T;
730}
731
732
733void MSPModel_JuPedSim::registerArrived(const JPS_AgentId agentID) {
735 JPS_Simulation_MarkAgentForRemoval(myJPSSimulation, agentID, nullptr);
736}
737
738
743
744
745GEOSGeometry*
747 GEOSCoordSequence* coordinateSequence = convertToGEOSPoints(centerLine);
748 GEOSGeometry* lineString = GEOSGeom_createLineString(coordinateSequence);
749 GEOSGeometry* dilatedLineString = GEOSBufferWithStyle(lineString, width, GEOS_QUADRANT_SEGMENTS, capStyle, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);
750 GEOSGeom_destroy(lineString);
751 return dilatedLineString;
752}
753
754
755GEOSGeometry*
756MSPModel_JuPedSim::createGeometryFromShape(PositionVector shape, std::string junctionID, std::string shapeID, bool isInternalShape) {
757 // Corner case.
758 if (shape.size() == 1) {
759 WRITE_WARNINGF(TL("Polygon '%' at junction '%' will be skipped as it is just a point."), shapeID, junctionID);
760 return nullptr;
761 }
762 // Make sure the shape is closed.
763 if (shape.back() != shape.front()) {
764 shape.push_back(shape.front());
765 }
766 // Replace consecutive points that are equal with just one.
767 PositionVector cleanShape;
768 cleanShape.push_back(shape[0]);
769 PositionVector duplicates;
770 for (int i = 1; i < (int)shape.size(); i++) {
771 if (shape[i] != shape[i - 1]) {
772 cleanShape.push_back(shape[i]);
773 } else {
774 duplicates.push_back(shape[i]);
775 }
776 }
777 if (cleanShape.size() < shape.size()) {
778 WRITE_WARNINGF(TL("Polygon '%' at junction '%' had some equal consecutive points removed: %"), shapeID, junctionID, toString(duplicates, 9));
779 }
780 GEOSCoordSequence* coordinateSequence = convertToGEOSPoints(cleanShape);
781 GEOSGeometry* linearRing = GEOSGeom_createLinearRing(coordinateSequence);
782 GEOSGeometry* polygon = GEOSGeom_createPolygon(linearRing, nullptr, 0);
783
784 if (!GEOSisValid(polygon)) {
785 if (cleanShape.size() == 3) {
786 if (isInternalShape) {
787 WRITE_WARNINGF(TL("Polygon '%' at junction '%' has been dilated as it is just a segment."), shapeID, junctionID);
788 } else {
789 WRITE_WARNINGF(TL("Polygon '%' has been dilated as it is just a segment."), shapeID);
790 }
791 GEOSGeometry* lineString = GEOSGeom_createLineString(GEOSCoordSeq_clone(coordinateSequence));
792 GEOSGeom_destroy(polygon);
793 polygon = GEOSBufferWithStyle(lineString, GEOS_BUFFERED_SEGMENT_WIDTH, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_BEVEL, GEOS_MITRE_LIMIT);
794 GEOSGeom_destroy(lineString);
795 } else {
796 if (isInternalShape) {
797 WRITE_WARNINGF(TL("Polygon '%' at junction '%' has been replaced by its convex hull as it is not simple."), shapeID, junctionID);
798 GEOSGeometry* hull = GEOSConvexHull(polygon);
799 GEOSGeom_destroy(polygon);
800 polygon = GEOSBufferWithStyle(hull, POSITION_EPS, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);;
801 } else {
802 WRITE_WARNINGF(TL("Polygon '%' at junction '%' will be skipped as it is not simple."), shapeID, junctionID);
803 polygon = nullptr;
804 }
805 }
806
807 return polygon;
808 }
809
810 // Some junctions need to be buffered a little so that edges are properly connected.
811 if (isInternalShape) {
812 polygon = GEOSBufferWithStyle(polygon, POSITION_EPS, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);
813 }
814
815 return polygon;
816}
817
818
819GEOSGeometry*
821 std::vector<GEOSGeometry*> walkableAreas;
822 for (const MSEdge* const edge : network->getEdgeControl().getEdges()) {
823 const MSLane* const lane = getSidewalk<MSEdge, MSLane>(edge);
824 if (lane != nullptr) {
825 GEOSGeometry* dilatedLane = nullptr;
826 if (edge->isWalkingArea()) {
827 dilatedLane = createGeometryFromShape(lane->getShape(), edge->getFromJunction()->getID(), edge->getID(), true);
828 } else if (edge->isCrossing()) {
829 const PositionVector* outlineShape = lane->getOutlineShape();
830 if (outlineShape != nullptr) {
831 // this is mainly to ensure that we have at least the "normal" crossing, see #15037
832 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0, GEOSBUF_CAP_FLAT);
833 if (dilatedLane != nullptr) {
834 walkableAreas.push_back(dilatedLane);
835 }
836 dilatedLane = createGeometryFromShape(*outlineShape, edge->getFromJunction()->getID(), edge->getID(), true);
837 } else {
838 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0, GEOSBUF_CAP_ROUND);
839 }
840 myCrossingWaits[lane] = {0, 0};
841 } else { // regular sidewalk
842 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0 + POSITION_EPS, GEOSBUF_CAP_FLAT);
843 }
844 if (dilatedLane != nullptr) {
845 walkableAreas.push_back(dilatedLane);
846 }
847 }
848 }
849 for (const auto& junctionWithID : network->getJunctionControl()) {
850 const MSJunction* const junction = junctionWithID.second;
851 int pedEdgeCount = 0;
852 bool hasWalkingArea = false;
853 for (const ConstMSEdgeVector& edges : {
854 junction->getIncoming(), junction->getOutgoing()
855 }) {
856 for (const MSEdge* const edge : edges) {
857 if (edge->isWalkingArea()) {
858 hasWalkingArea = true;
859 break;
860 }
861 if (getSidewalk<MSEdge, MSLane>(edge) != nullptr) {
862 pedEdgeCount++;
863 }
864 }
865 if (hasWalkingArea) {
866 break;
867 }
868 }
869 if (!hasWalkingArea && pedEdgeCount > 1) {
870 // there is something to connect but no walking area, let's assume peds are allowed everywhere
871 GEOSGeometry* walkingAreaGeom = createGeometryFromShape(junction->getShape(), junction->getID(), junction->getID(), true);
872 if (walkingAreaGeom != nullptr) {
873 walkableAreas.push_back(walkingAreaGeom);
874 }
875 }
876 }
877
878 // Retrieve additional walkable areas and obstacles (walkable areas and obstacles in the sense of JuPedSim).
879 std::vector<GEOSGeometry*> additionalObstacles;
880 for (const auto& polygonWithID : myNetwork->getShapeContainer().getPolygons()) {
881 if (polygonWithID.second->getShapeType() == "jupedsim.walkable_area" || polygonWithID.second->getShapeType() == "taz") {
882 GEOSGeometry* walkableArea = createGeometryFromShape(polygonWithID.second->getShape(), std::string(""), polygonWithID.first);
883 if (walkableArea != nullptr) {
884 walkableAreas.push_back(walkableArea);
886 }
887 } else if (polygonWithID.second->getShapeType() == "jupedsim.obstacle") {
888 GEOSGeometry* additionalObstacle = createGeometryFromShape(polygonWithID.second->getShape(), std::string(""), polygonWithID.first);
889 if (additionalObstacle != nullptr) {
890 additionalObstacles.push_back(additionalObstacle);
891 }
892 }
893 }
894
895 // Take the union of all walkable areas.
896 GEOSGeometry* disjointWalkableAreas = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, walkableAreas.data(), (unsigned int)walkableAreas.size());
897#ifdef DEBUG_GEOMETRY_GENERATION
898 // dumpGeometry(disjointWalkableAreas, "disjointWalkableAreas.wkt");
899#endif
900 GEOSGeometry* initialWalkableAreas = GEOSUnaryUnion(disjointWalkableAreas);
901#ifdef DEBUG_GEOMETRY_GENERATION
902 dumpGeometry(initialWalkableAreas, "initialWalkableAreas.wkt");
903#endif
904 GEOSGeom_destroy(disjointWalkableAreas);
905
906 // At last, remove additional obstacles from the merged walkable areas.
907 GEOSGeometry* disjointAdditionalObstacles = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, additionalObstacles.data(), (unsigned int)additionalObstacles.size());
908#ifdef DEBUG_GEOMETRY_GENERATION
909 // dumpGeometry(disjointAdditionalObstacles, "disjointAdditionalObstacles.wkt");
910#endif
911 GEOSGeometry* additionalObstaclesUnion = GEOSUnaryUnion(disjointAdditionalObstacles); // Obstacles may overlap, e.g. if they were loaded from separate files.
912#ifdef DEBUG_GEOMETRY_GENERATION
913 dumpGeometry(additionalObstaclesUnion, "additionalObstaclesUnion.wkt");
914#endif
915 GEOSGeometry* finalWalkableAreas = GEOSDifference(initialWalkableAreas, additionalObstaclesUnion);
916#ifdef DEBUG_GEOMETRY_GENERATION
917 dumpGeometry(finalWalkableAreas, "finalWalkableAreas.wkt");
918#endif
919 GEOSGeom_destroy(initialWalkableAreas);
920 GEOSGeom_destroy(additionalObstaclesUnion);
921 GEOSGeom_destroy(disjointAdditionalObstacles);
922
923 if (!GEOSisSimple(finalWalkableAreas)) {
924 throw ProcessError(TL("Union of walkable areas minus union of obstacles is not a simple polygon."));
925 }
926
927 return finalWalkableAreas;
928}
929
930
931GEOSCoordSequence*
933 GEOSCoordSequence* coordinateSequence = GEOSCoordSeq_create((unsigned int)shape.size(), 2);
934 for (int i = 0; i < (int)shape.size(); i++) {
935 GEOSCoordSeq_setXY(coordinateSequence, i, shape[i].x(), shape[i].y());
936 }
937 return coordinateSequence;
938}
939
940
942MSPModel_JuPedSim::convertToSUMOPoints(const GEOSGeometry* geometry) {
943 PositionVector coordinateVector;
944 const GEOSCoordSequence* coordinateSequence = GEOSGeom_getCoordSeq(geometry);
945 unsigned int coordinateSequenceSize;
946 GEOSCoordSeq_getSize(coordinateSequence, &coordinateSequenceSize);
947 double x;
948 double y;
949 for (unsigned int i = 0; i < coordinateSequenceSize; i++) {
950 GEOSCoordSeq_getX(coordinateSequence, i, &x);
951 GEOSCoordSeq_getY(coordinateSequence, i, &y);
952 coordinateVector.push_back(Position(x, y));
953 }
954 return coordinateVector;
955}
956
957
958std::vector<JPS_Point>
959MSPModel_JuPedSim::convertToJPSPoints(const GEOSGeometry* geometry) {
960 std::vector<JPS_Point> pointVector;
961 const GEOSCoordSequence* coordinateSequence = GEOSGeom_getCoordSeq(geometry);
962 unsigned int coordinateSequenceSize;
963 GEOSCoordSeq_getSize(coordinateSequence, &coordinateSequenceSize);
964 double x;
965 double y;
966 // Remove the last point so that CGAL doesn't complain about the simplicity of the polygon downstream.
967 for (unsigned int i = 0; i < coordinateSequenceSize - 1; i++) {
968 GEOSCoordSeq_getX(coordinateSequence, i, &x);
969 GEOSCoordSeq_getY(coordinateSequence, i, &y);
970 pointVector.push_back({x, y});
971 }
972 return pointVector;
973}
974
975
976double
977MSPModel_JuPedSim::getLinearRingArea(const GEOSGeometry* linearRing) {
978 double area;
979 GEOSGeometry* linearRingAsPolygon = GEOSGeom_createPolygon(GEOSGeom_clone(linearRing), nullptr, 0);
980 GEOSArea(linearRingAsPolygon, &area);
981 GEOSGeom_destroy(linearRingAsPolygon);
982 return area;
983}
984
985
986void
987MSPModel_JuPedSim::removePolygonFromDrawing(const std::string& polygonId) {
989}
990
991
992void
993MSPModel_JuPedSim::preparePolygonForDrawing(const GEOSGeometry* polygon, const std::string& polygonId, const RGBColor& color) {
994 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
995 bool added = myShapeContainer.addPolygon(polygonId, std::string("jupedsim.pedestrian_network"), color, 10.0, 0.0,
996 std::string(), convertToSUMOPoints(exterior), false, true, 1.0);
997 if (added) {
998 std::vector<PositionVector> holes;
999 int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
1000 if (nbrInteriorRings != -1) {
1001 for (int k = 0; k < nbrInteriorRings; k++) {
1002 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
1003 double area = getLinearRingArea(linearRing);
1004 if (area > GEOS_MIN_AREA) {
1005 holes.push_back(convertToSUMOPoints(linearRing));
1006 }
1007 }
1008 myShapeContainer.getPolygons().get(polygonId)->setHoles(holes);
1009 }
1010 }
1011}
1012
1013
1014const GEOSGeometry*
1015MSPModel_JuPedSim::getLargestComponent(const GEOSGeometry* polygon, int& nbrComponents, double& maxArea, double& totalArea) {
1016 nbrComponents = GEOSGetNumGeometries(polygon);
1017 const GEOSGeometry* largestComponent = nullptr;
1018 maxArea = 0.0;
1019 totalArea = 0.0;
1020 for (int i = 0; i < nbrComponents; i++) {
1021 const GEOSGeometry* componentPolygon = GEOSGetGeometryN(polygon, i);
1022 double area;
1023 GEOSArea(componentPolygon, &area);
1024 totalArea += area;
1025 if (area > maxArea) {
1026 maxArea = area;
1027 largestComponent = componentPolygon;
1028 }
1029 }
1030 return largestComponent;
1031}
1032
1033
1034JPS_Geometry
1036 JPS_GeometryBuilder geometryBuilder = JPS_GeometryBuilder_Create();
1037
1038 // Handle the exterior polygon.
1039 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
1040 std::vector<JPS_Point> exteriorCoordinates = convertToJPSPoints(exterior);
1041 JPS_GeometryBuilder_AddAccessibleArea(geometryBuilder, exteriorCoordinates.data(), exteriorCoordinates.size());
1042
1043 // Handle the interior polygons (holes).
1044 int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
1045 if (nbrInteriorRings != -1) {
1046 for (int k = 0; k < nbrInteriorRings; k++) {
1047 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
1048 double area = getLinearRingArea(linearRing);
1049 if (area > GEOS_MIN_AREA) {
1050 std::vector<JPS_Point> holeCoordinates = convertToJPSPoints(linearRing);
1051 JPS_GeometryBuilder_ExcludeFromAccessibleArea(geometryBuilder, holeCoordinates.data(), holeCoordinates.size());
1052 }
1053 }
1054 }
1055
1056 JPS_ErrorMessage message = nullptr;
1057 JPS_Geometry geometry = JPS_GeometryBuilder_Build(geometryBuilder, &message);
1058 if (geometry == nullptr) {
1059 const std::string error = TLF("Error while generating geometry: %", JPS_ErrorMessage_GetMessage(message));
1060 JPS_ErrorMessage_Free(message);
1061 throw ProcessError(error);
1062 }
1063 JPS_GeometryBuilder_Free(geometryBuilder);
1064 return geometry;
1065}
1066
1067
1068void
1069MSPModel_JuPedSim::dumpGeometry(const GEOSGeometry* polygon, const std::string& filename, bool useGeoCoordinates) {
1070 GEOSGeometry* polygonGeoCoordinates = nullptr;
1071 if (useGeoCoordinates) {
1072 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
1073 PositionVector exteriorPoints = convertToSUMOPoints(exterior);
1074 for (Position& position : exteriorPoints) {
1076 }
1077 const int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
1078 std::vector<GEOSGeometry*> holeRings;
1079 if (nbrInteriorRings != -1) {
1080 for (int k = 0; k < nbrInteriorRings; k++) {
1081 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
1082 PositionVector holePoints = convertToSUMOPoints(linearRing);
1083 for (Position& position : holePoints) {
1085 }
1086 GEOSCoordSequence* holeRingCoords = convertToGEOSPoints(holePoints);
1087 GEOSGeometry* holeRing = GEOSGeom_createLinearRing(holeRingCoords);
1088 holeRings.push_back(holeRing);
1089 }
1090 }
1091 GEOSCoordSequence* exteriorRingCoords = convertToGEOSPoints(exteriorPoints);
1092 GEOSGeometry* exteriorRing = GEOSGeom_createLinearRing(exteriorRingCoords);
1093 polygonGeoCoordinates = GEOSGeom_createPolygon(exteriorRing, holeRings.data(), nbrInteriorRings);
1094 }
1095 std::ofstream dumpFile;
1096 dumpFile.open(filename);
1097 GEOSWKTWriter* writer = GEOSWKTWriter_create();
1098 GEOSWKTWriter_setRoundingPrecision(writer, gPrecisionGeo);
1099 char* wkt = GEOSWKTWriter_write(writer, polygonGeoCoordinates == nullptr ? polygon : polygonGeoCoordinates);
1100 dumpFile << wkt << std::endl;
1101 dumpFile.close();
1102 GEOSFree(wkt);
1103 GEOSWKTWriter_destroy(writer);
1104 GEOSGeom_destroy(polygonGeoCoordinates);
1105}
1106
1107
1108double
1110 return 0.5 * MAX2(vehType.getLength(), vehType.getWidth());
1111}
1112
1113
1114JPS_StageId
1115MSPModel_JuPedSim::addWaitingSet(const MSLane* const crossing, const bool entry) {
1116 JPS_ErrorMessage message = nullptr;
1117 JPS_StageId waitingStage = 0;
1118 PositionVector shape = crossing->getShape();
1119 const double radius = getRadius(*MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true));
1120 shape.extrapolate2D((shape.length() + radius) / shape.length());
1121 const double offset = 2 * radius + POSITION_EPS;
1122 const double lonOffset = entry ? NUMERICAL_EPS : shape.length() - NUMERICAL_EPS;
1123 PositionVector pv;
1124 pv.push_back(shape.positionAtOffset(lonOffset));
1125 for (double latOff = offset; latOff < crossing->getWidth() / 2. - offset; latOff += offset) {
1126 PositionVector moved(shape);
1127 moved.move2side(latOff);
1128 pv.push_back(moved.positionAtOffset(lonOffset));
1129 moved.move2side(-2. * latOff);
1130 pv.push_back(moved.positionAtOffset(lonOffset));
1131 }
1132 if (entry && crossing->getIncomingLanes().size() == 1 && crossing->getIncomingLanes().front().lane->isWalkingArea()) {
1133 pv.push_back(crossing->getIncomingLanes().front().lane->getShape().getCentroid());
1134 }
1135 if (!entry && crossing->getLinkCont().size() == 1 && crossing->getLinkCont().front()->getLane()->isWalkingArea()) {
1136 pv.push_back(crossing->getLinkCont().front()->getLane()->getShape().getCentroid());
1137 }
1138 std::vector<JPS_Point> points;
1139 for (const Position& p : pv) {
1140 GEOSGeometry* point = GEOSGeom_createPointFromXY(p.x(), p.y());
1141 if (GEOSContains(myGEOSPedestrianNetworkLargestComponent, point)) {
1142 points.push_back({p.x(), p.y()});
1143 }
1144 GEOSGeom_destroy(point);
1145 }
1146 waitingStage = JPS_Simulation_AddStageWaitingSet(myJPSSimulation, points.data(), points.size(), &message);
1147 if (message != nullptr) {
1148 const std::string error = TLF("Error while adding waiting set for % on '%': %",
1149 entry ? "entry" : "exit", crossing->getID(), JPS_ErrorMessage_GetMessage(message));
1150 JPS_ErrorMessage_Free(message);
1151 throw ProcessError(error);
1152 }
1153 const auto proxy = JPS_Simulation_GetWaitingSetProxy(myJPSSimulation, waitingStage, &message);
1154 JPS_WaitingSetProxy_SetWaitingSetState(proxy, JPS_WaitingSet_Inactive);
1155 myCrossings[waitingStage] = crossing;
1156 if (myPythonScript != nullptr) {
1157 (*myPythonScript) << "ws = simulation.add_waiting_set_stage([";
1158 for (const JPS_Point& p : points) {
1159 (*myPythonScript) << "(" << p.x << "," << p.y << "),";
1160 }
1161 (*myPythonScript) << "])\nsimulation.get_stage(ws).state = jps.stages.WaitingSetState.INACTIVE\n";
1162 }
1163 return waitingStage;
1164}
1165
1166
1167void
1169 initGEOS(nullptr, nullptr);
1170 PROGRESS_BEGIN_MESSAGE("Generating initial JuPedSim geometry for pedestrian network");
1172 int nbrComponents = 0;
1173 double maxArea = 0.0;
1174 double totalArea = 0.0;
1176 if (nbrComponents > 1) {
1177 WRITE_WARNINGF(TL("While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
1178 nbrComponents, maxArea / totalArea * 100.0, "%");
1179 }
1180#ifdef DEBUG_GEOMETRY_GENERATION
1181 dumpGeometry(myGEOSPedestrianNetworkLargestComponent, "pedestrianNetwork.wkt");
1182#endif
1183 const std::string filename = oc.getString("pedestrian.jupedsim.wkt");
1184 if (!filename.empty()) {
1185 dumpGeometry(myGEOSPedestrianNetworkLargestComponent, filename, oc.getBool("pedestrian.jupedsim.wkt.geo"));
1186 }
1187 // For the moment, only one connected component is supported.
1192 JPS_ErrorMessage message = nullptr;
1193
1194 double strengthGeometryRepulsion = oc.getFloat("pedestrian.jupedsim.strength-geometry-repulsion");
1195 double rangeGeometryRepulsion = oc.getFloat("pedestrian.jupedsim.range-geometry-repulsion");
1196 if (myJPSDeltaT == 20) {
1197 if (oc.isDefault("pedestrian.jupedsim.strength-geometry-repulsion") && oc.isDefault("pedestrian.jupedsim.range-geometry-repulsion")) {
1198 WRITE_MESSAGE(TL("Adapting geometry repulsion default values for jupedsim timestep of 0.02."));
1199 strengthGeometryRepulsion = 35.;
1200 rangeGeometryRepulsion = 0.019;
1201 }
1202 }
1203
1204 switch (myJPSModel) {
1206 JPS_CollisionFreeSpeedModelBuilder modelBuilder = JPS_CollisionFreeSpeedModelBuilder_Create(
1207 oc.getFloat("pedestrian.jupedsim.strength-neighbor-repulsion"),
1208 oc.getFloat("pedestrian.jupedsim.range-neighbor-repulsion"),
1209 strengthGeometryRepulsion,
1210 rangeGeometryRepulsion);
1211 myJPSOperationalModel = JPS_CollisionFreeSpeedModelBuilder_Build(modelBuilder, &message);
1212 JPS_CollisionFreeSpeedModelBuilder_Free(modelBuilder);
1213 break;
1214 }
1216 JPS_CollisionFreeSpeedModelV2Builder modelBuilder = JPS_CollisionFreeSpeedModelV2Builder_Create();
1217 myJPSOperationalModel = JPS_CollisionFreeSpeedModelV2Builder_Build(modelBuilder, &message);
1218 JPS_CollisionFreeSpeedModelV2Builder_Free(modelBuilder);
1219 break;
1220 }
1222 JPS_GeneralizedCentrifugalForceModelBuilder modelBuilder = JPS_GeneralizedCentrifugalForceModelBuilder_Create(
1223 oc.getFloat("pedestrian.jupedsim.strength-neighbor-repulsion"),
1224 strengthGeometryRepulsion,
1225 2.0,
1226 2.0,
1227 0.1,
1228 0.1,
1229 9.0,
1230 3.0);
1231 myJPSOperationalModel = JPS_GeneralizedCentrifugalForceModelBuilder_Build(modelBuilder, &message);
1232 JPS_GeneralizedCentrifugalForceModelBuilder_Free(modelBuilder);
1233 break;
1234 }
1236 JPS_SocialForceModelBuilder modelBuilder = JPS_SocialForceModelBuilder_Create(120000.0, 240000.0);
1237 myJPSOperationalModel = JPS_SocialForceModelBuilder_Build(modelBuilder, &message);
1238 JPS_SocialForceModelBuilder_Free(modelBuilder);
1239 break;
1240 }
1241 }
1242
1243 if (myJPSOperationalModel == nullptr) {
1244 const std::string error = TLF("Error creating the pedestrian model: %", JPS_ErrorMessage_GetMessage(message));
1245 JPS_ErrorMessage_Free(message);
1246 throw ProcessError(error);
1247 }
1248 myJPSSimulation = JPS_Simulation_Create(myJPSOperationalModel, myJPSGeometry, STEPS2TIME(myJPSDeltaT), &message);
1249 if (myJPSSimulation == nullptr) {
1250 const std::string error = TLF("Error creating the simulation: %", JPS_ErrorMessage_GetMessage(message));
1251 JPS_ErrorMessage_Free(message);
1252 throw ProcessError(error);
1253 }
1254 // Polygons that define vanishing areas aren't part of the regular JuPedSim geometry.
1255 for (const auto& polygonWithID : myNetwork->getShapeContainer().getPolygons()) {
1256 const SUMOPolygon* const poly = polygonWithID.second;
1257 if (poly->getShapeType() == "jupedsim.vanishing_area" || poly->getShapeType() == "jupedsim.influencer") {
1258 std::vector<JPS_Point> areaBoundary;
1259 for (const Position& p : poly->getShape()) {
1260 areaBoundary.push_back({p.x(), p.y()});
1261 }
1262 // Make sure the shape is not repeating the first point.
1263 if (areaBoundary.back().x == areaBoundary.front().x && areaBoundary.back().y == areaBoundary.front().y) {
1264 areaBoundary.pop_back();
1265 }
1266 const std::string type = StringTokenizer(poly->getShapeType(), ".").getVector()[1];
1267 myAreas.push_back({poly->getID(), type, areaBoundary, poly->getParametersMap(), 0});
1268 }
1269 }
1270 if (OutputDevice::createDeviceByOption("pedestrian.jupedsim.py")) {
1271 myPythonScript = &OutputDevice::getDeviceByOption("pedestrian.jupedsim.py");
1273 (*myPythonScript) << "import jupedsim as jps\nimport shapely\n\n"
1274 "with open('" << filename << "') as f: geom = shapely.from_wkt(f.read())\n"
1275 "simulation = jps.Simulation(dt=" << STEPS2TIME(myJPSDeltaT) << ", model=jps.CollisionFreeSpeedModel(), geometry=geom,\n"
1276 "trajectory_writer=jps.SqliteTrajectoryWriter(output_file='out.sql'))\n";
1277 }
1278 // add waiting sets at crossings
1279 for (auto& crossing : myCrossingWaits) {
1280 crossing.second.first = addWaitingSet(crossing.first, true);
1281 crossing.second.second = addWaitingSet(crossing.first, false);
1282 }
1283}
1284
1285
1286// ===========================================================================
1287// MSPModel_Remote::PState method definitions
1288// ===========================================================================
1290 JPS_JourneyId journeyId, JPS_StageId stageId,
1291 const std::vector<WaypointDesc>& waypoints) :
1292 MSPModel_InteractingState(person, stage, nullptr),
1293 myJourneyId(journeyId), myStageId(stageId), myWaypoints(waypoints), myAgentId(0) {
1294 myDir = FORWARD;
1295}
1296
1297
1298void
1299MSPModel_JuPedSim::PState::reinit(MSStageMoving* stage, JPS_JourneyId journeyId, JPS_StageId stageId,
1300 const std::vector<WaypointDesc>& waypoints) {
1301 if (myStage != nullptr) {
1302 myStage->setPState(nullptr); // we need to remove the old state reference to avoid double deletion
1303 }
1304 myStage = stage;
1305 myJourneyId = journeyId;
1306 myStageId = stageId;
1307 myWaypoints = waypoints;
1308}
1309
1310
1313
1314
1315void MSPModel_JuPedSim::PState::setPosition(const double x, const double y, const double z) {
1316 if (myRemoteXYPos != Position::INVALID) {
1317 mySpeed = myRemoteXYPos.distanceTo2D(Position(x, y, z)) / STEPS2TIME(DELTA_T);
1318 } else {
1319 mySpeed = 0.;
1320 }
1321 myRemoteXYPos.set(x, y, z);
1322}
1323
1324
1326 return stage.getNextRouteEdge();
1327}
1328
1329
1332 return offset < (int)myWaypoints.size() ? &myWaypoints[offset] : nullptr;
1333}
1334
1335
1336/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:74
#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: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: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: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:426
const MSJunction * getFromJunction() const
Definition MSEdge.h:422
bool isTazConnector() const
Definition MSEdge.h:291
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:664
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:2746
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:597
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:955
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3217
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:769
const PositionVector * getOutlineShape() const
Definition MSLane.h:1355
double getWidth() const
Returns the lane's width.
Definition MSLane.h:640
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:729
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:485
MSJunctionControl & getJunctionControl()
Returns the junctions control.
Definition MSNet.h:475
MSPedestrianRouter & getPedestrianRouter(int rngIndex, const Prohibitions &prohibited={}) const
Definition MSNet.cpp:1614
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
ShapeContainer & getShapeContainer()
Returns the shapes container.
Definition MSNet.h:515
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition MSNet.h:435
const NamedObjectCont< MSStoppingPlace * > & getStoppingPlaces(SumoXMLTag category) const
Definition MSNet.cpp:1488
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 SUMOVTypeParameter & getVTypeParameter() const
Returns the object's "vehicle" type parameter.
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, 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)
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.cpp:103
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).