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