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-2026 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
21// The pedestrian following model that can instantiate different pedestrian models
22// that come with the JuPedSim third-party simulation framework.
23/****************************************************************************/
24
25#include <config.h>
26
27#include <algorithm>
28#include <fstream>
29#include <geos_c.h>
31#include <microsim/MSEdge.h>
32#include <microsim/MSLane.h>
33#include <microsim/MSLink.h>
41#include <libsumo/Helper.h>
42#include <utils/geom/Position.h>
46#include "MSPerson.h"
47#include "MSStageWalking.h"
48#include "MSPModel_JuPedSim.h"
49
50
51// #define DEBUG_GEOMETRY_GENERATION
52// #define DEBUG_GRPC_TIMING
53
54
61const std::string MSPModel_JuPedSim::PEDESTRIAN_NETWORK_ID = "jupedsim.pedestrian_network";
62const std::string MSPModel_JuPedSim::PEDESTRIAN_NETWORK_CARRIAGES_AND_RAMPS_ID = "jupedsim.pedestrian_network.carriages_and_ramps";
63
64const std::vector<MSPModel_JuPedSim::PState*> MSPModel_JuPedSim::noPedestrians;
65
66// ===========================================================================
67// method definitions
68// ===========================================================================
70 myStopWatch(10), myRNG("JuPedSim"), myNetwork(net), myShapeContainer(net->getShapeContainer()), myJPSDeltaT(string2time(oc.getString("pedestrian.jupedsim.step-length"))),
71 myExitTolerance(oc.getFloat("pedestrian.jupedsim.exit-tolerance")), myGEOSPedestrianNetworkLargestComponent(nullptr),
72 myHaveAdditionalWalkableAreas(false) {
74 myJPSModel = oc.getString("pedestrian.jupedsim.model");
75 if (myJPSModel.find("Model") == std::string::npos) {
76 // TODO warn about outdated model name
77 myJPSModel += "Model";
78 if (myJPSModel == "CollisionFreeSpeedV2Model") {
79 myJPSModel = "CollisionFreeSpeedModelV2";
80 }
81 }
82 std::string command;
83 std::string address = oc.getString("pedestrian.jupedsim.address");
84 // address = "localhost:50051"; // for debugging
85 if (address == "") {
86 const char* pythonEnv = getenv("PYTHON");
87 const std::string python = (pythonEnv == nullptr) ? "python" : pythonEnv;
88 const char* sumoHomeEnv = getenv("SUMO_HOME");
89 const std::string sumoHome = (sumoHomeEnv == nullptr) ? "." : sumoHomeEnv;
90 command = python + " " + sumoHome + "/tools/jupedsim_grpc/servicer.py";
91 if (oc.isSet("pedestrian.jupedsim.py")) {
92 command += " --debug " + oc.getString("pedestrian.jupedsim.py");
93 }
94 }
95 for (int i = 0; i < 2; i++) { // try twice: initial attempt + one restart
96 if (command != "") {
97#ifdef HAVE_BOOST
98 const std::string port = toString(tcpip::Socket::getFreeSocketPort());
99 myJuPedSimServer = std::unique_ptr<bp::child>(new bp::child(command + " --port " + port));
100 address = "localhost:" + port;
101#else
102 WRITE_WARNINGF(TL("No boost process support, you will need to start the JuPedSim server manually using %."), command);
103#endif
104 }
105
106 myGrpcChannel = grpc::CreateChannel(address, grpc::InsecureChannelCredentials());
107 if (myGrpcChannel->WaitForConnected(std::chrono::system_clock::now() + std::chrono::seconds(5))) {
108 WRITE_MESSAGEF(TL("Connected to JuPedSim gRPC server on '%'."), address);
109 break;
110 } else {
111 WRITE_WARNINGF(TL("Could not connect to JuPedSim gRPC server on '%' (will retry on demand)."), address);
112#ifdef HAVE_BOOST
113 if (myJuPedSimServer == nullptr || myJuPedSimServer->running()) {
114 break;
115 }
116#else
117 break;
118#endif
119 }
120 }
121 myGrpcStub = sumo_jupedsim_api::JuPedSimService::NewStub(myGrpcChannel);
122 initialize(oc);
124}
125
126
128 clearState();
129#ifdef HAVE_BOOST
130 if (myJuPedSimServer != nullptr) {
131 myJuPedSimServer->terminate();
132 }
133#endif
134
135 // TODO: clear simulation, operational model and geometries?
136
137 GEOSGeom_destroy(myGEOSPedestrianNetwork);
138 finishGEOS();
139#ifdef DEBUG_GRPC_TIMING
140 std::cout << myStopWatch[0].getTotal() / (1e6) << "ms, iteration: "
141 << myStopWatch[1].getTotal() / (1e6) << "ms, agent data retrieval: "
142 << myStopWatch[2].getTotal() / (1e6) << "ms, journey creation: "
143 << myStopWatch[3].getTotal() / (1e6) << "ms, insertion: "
144 << myStopWatch[4].getTotal() / (1e6) << "ms, removal: "
145 << myStopWatch[5].getTotal() / (1e6) << "ms, add waiting set: "
146 << myStopWatch[6].getTotal() / (1e6) << "ms, speed: "
147 << myStopWatch[7].getTotal() / (1e6) << "ms " << std::endl;
148#endif
149}
150
151
152void
154#ifdef DEBUG_GRPC_TIMING
155 myStopWatch[4].start();
156#endif
157 const MSVehicleType& type = state->getPerson()->getVehicleType();
158 sumo_jupedsim_api::CreateAgentRequest agentRequest;
159 agentRequest.set_simulation_id(myJPSSimulation);
160 agentRequest.set_agent_model_class(myJPSModel);
161 auto& agentParams = *agentRequest.mutable_agent_model_parameters()->mutable_fields();
162 agentParams["journey_id"].set_number_value(static_cast<double>(state->getJourneyId()));
163 agentParams["stage_id"].set_number_value(static_cast<double>(state->getStageId()));
164 agentParams["desired_speed"].set_number_value(state->getPerson()->getMaxSpeed());
165 if (myJPSModel != "GeneralizedCentrifugalForceModel") {
166 agentParams["radius"].set_number_value(getRadius(type));
167 }
168 google::protobuf::ListValue* position = agentParams["position"].mutable_list_value();
169 position->add_values()->set_number_value(p.x());
170 position->add_values()->set_number_value(p.y());
171 if (myJPSModel == "GeneralizedCentrifugalForceModel" || myJPSModel == "SocialForceModel") {
172 const double angle = state->getAngle(*state->getStage(), 0);
173 double orientation_x = 0.;
174 double orientation_y = 0.;
175 if (fabs(angle - M_PI / 2) < NUMERICAL_EPS) {
176 orientation_y = 1.;
177 } else if (fabs(angle + M_PI / 2) < NUMERICAL_EPS) {
178 orientation_y = -1.;
179 } else {
180 orientation_x = 1.;
181 orientation_y = tan(angle);
182 }
183 google::protobuf::ListValue* orientation = agentParams["orientation"].mutable_list_value();
184 orientation->add_values()->set_number_value(orientation_x);
185 orientation->add_values()->set_number_value(orientation_y);
186 }
187 grpc::ClientContext agentContext;
188 sumo_jupedsim_api::CreateAgentResponse agentResponse;
189 const grpc::Status agentStatus = myGrpcStub->CreateAgent(&agentContext, agentRequest, &agentResponse);
190 if (agentStatus.ok()) {
191 state->setAgentId(agentResponse.agent_id());
192 } else {
193 WRITE_WARNINGF(TL("Error while adding person '%' as JuPedSim agent: %"), state->getPerson()->getID(), agentStatus.error_message());
194 }
195#ifdef DEBUG_GRPC_TIMING
196 myStopWatch[4].stop();
197#endif
198}
199
200
202MSPModel_JuPedSim::addWaypoint(const std::string& agentID, WaypointDesc& waypoint, const MSStageMoving* const finalStage) {
203 // Unlike the previous implementation we do not need to set the transitions explicitly anymore,
204 // the intermediate JuPedSim GRPC service handles this for us.
205 const MSLane* const lane = std::get<1>(waypoint);
206 Position& coords = std::get<2>(waypoint);
207 double& dist = std::get<3>(waypoint);
208 sumo_jupedsim_api::AddWaypointStageRequest waypointRequest;
209 if (finalStage == nullptr) {
210 if (lane->isWalkingArea()) {
211 coords = lane->getShape().getCentroid();
212 dist = lane->getEdge().getWidth() / 2.;
213 } else {
214 coords = lane->getShape().positionAtOffset(lane->getEdge().getLength() / 2.);
215 dist = lane->getWidth() / 2.;
216 }
217 const auto& centerIt = myLaneCenters.find(lane);
218 if (centerIt != myLaneCenters.end()) {
219 return centerIt->second;
220 }
221 } else {
222 coords = lane->getShape().positionAtOffset(finalStage->getArrivalPos());
223 dist = finalStage->getDouble("jupedsim.waypoint.radius", myExitTolerance);
224 }
225 waypointRequest.mutable_point()->set_x(coords.x());
226 waypointRequest.mutable_point()->set_y(coords.y());
227 waypointRequest.set_distance(dist);
228 sumo_jupedsim_api::StageResponse waypointResponse = callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::AddWaypointStage, waypointRequest,
229 TLF("Error while adding waypoint for person '%': ", agentID), true);
230 if (waypointResponse.stage_id() != 0 && finalStage == nullptr) {
231 myLaneCenters[lane] = waypointResponse.stage_id();
232 }
233 return waypointResponse.stage_id();
234}
235
236
239 assert(person->getCurrentStageType() == MSStageType::WALKING);
240 const double radius = getRadius(person->getVehicleType());
241 Position departurePosition = Position::INVALID;
242 const MSLane* const departureLane = getSidewalk<MSEdge, MSLane>(stage->getRoute().front());
243 if (departureLane == nullptr) {
244 const char* error = TL("Person '%' could not find sidewalk on edge '%', time=%.");
245 if (OptionsCont::getOptions().getBool("ignore-route-errors")) {
246 WRITE_WARNINGF(error, person->getID(), person->getEdge()->getID(), time2string(SIMSTEP));
247 return nullptr;
248 } else {
249 throw ProcessError(TLF(error, person->getID(), person->getEdge()->getID(), time2string(SIMSTEP)));
250 }
251 }
252 // First real stage, stage 0 is waiting.
254 const MSEdge* const tripOrigin = person->getNextStage(-1)->getEdge();
255 if (tripOrigin->isTazConnector()) {
256 const SUMOPolygon* tazShape = myNetwork->getShapeContainer().getPolygons().get(tripOrigin->getParameter("taz"));
257 if (tazShape == nullptr) {
258 WRITE_WARNINGF(TL("FromTaz '%' for person '%' has no shape information."), tripOrigin->getParameter("taz"), person->getID());
259 } else {
260 const Boundary& bbox = tazShape->getShape().getBoxBoundary();
261 while (!tazShape->getShape().around(departurePosition)) {
262 // TODO: Optimize for speed if necessary or at least abort trying to find a point.
263 departurePosition.setx(RandHelper::rand(bbox.xmin(), bbox.xmax(), &myRNG));
264 departurePosition.sety(RandHelper::rand(bbox.ymin(), bbox.ymax(), &myRNG));
265 }
266 }
267 }
268 }
269 if (departurePosition == Position::INVALID) {
270 const double halfDepartureLaneWidth = departureLane->getWidth() / 2.0;
271 double departureRelativePositionY = stage->getDepartPosLat();
272 if (departureRelativePositionY == UNSPECIFIED_POS_LAT) {
273 departureRelativePositionY = 0.0;
274 }
275 if (departureRelativePositionY == MSPModel::RANDOM_POS_LAT) {
276 departureRelativePositionY = RandHelper::rand(-halfDepartureLaneWidth, halfDepartureLaneWidth, &myRNG);
277 }
278 departurePosition = departureLane->getShape().positionAtOffset(stage->getDepartPos() + radius + POSITION_EPS, -departureRelativePositionY); // Minus sign is here for legacy reasons.
279 }
280
281 std::vector<WaypointDesc> waypoints;
282 const MSEdge* prev = nullptr;
283 for (const MSEdge* const e : stage->getEdges()) {
284 const MSLane* const lane = getSidewalk<MSEdge, MSLane>(e);
285 JPS_StageId waitingStage = 0;
286 if (prev != nullptr) {
287 int dir = UNDEFINED_DIRECTION;
288 if (prev->getToJunction() == e->getFromJunction() || prev->getToJunction() == e->getToJunction()) {
289 dir = FORWARD;
290 } else if (prev->getFromJunction() == e->getFromJunction() || prev->getFromJunction() == e->getToJunction()) {
291 dir = BACKWARD;
292 }
293 if (dir != UNDEFINED_DIRECTION) {
294 ConstMSEdgeVector crossingRoute;
295 MSNet::getInstance()->getPedestrianRouter(0).compute(prev, e, 0, 0, stage->getMaxSpeed(person), 0,
296 dir == FORWARD ? prev->getToJunction() : prev->getFromJunction(),
297 person->getVTypeParameter(), crossingRoute, true);
298 const MSEdge* wa = nullptr;
299 for (const MSEdge* const ce : crossingRoute) {
300 if (ce->isCrossing()) {
301 const MSLane* const crossing = getSidewalk<MSEdge, MSLane>(ce);
302 auto crossingWait = myCrossingWaits.find(crossing);
303 if (crossingWait != myCrossingWaits.end()) {
304 if (waitingStage != 0 && wa != nullptr) {
305 // we already have a waiting stage we need an intermediate waypoint
306 waypoints.push_back({waitingStage, wa->getLanes()[0], {}, {}});
307 }
308 const MSLane* const prevLane = getSidewalk<MSEdge, MSLane>(prev);
309 const Position& startPos = dir == FORWARD ? prevLane->getShape().back() : prevLane->getShape().front();
310 // choose the waiting set closer to the lane "end"
311 if (crossing->getShape().front().distanceSquaredTo(startPos) < crossing->getShape().back().distanceSquaredTo(startPos)) {
312 if (crossingWait->second.first == 0) {
313 crossingWait->second.first = addWaitingSet(crossing, true);
314 }
315 waitingStage = crossingWait->second.first;
316 } else {
317 if (crossingWait->second.second == 0) {
318 crossingWait->second.second = addWaitingSet(crossing, false);
319 }
320 waitingStage = crossingWait->second.second;
321 }
322 } else {
323 throw ProcessError(TLF("No waiting set for crossing at %.", ce->getID()));
324 }
325 }
326 if (ce->isWalkingArea()) {
327 wa = ce;
328 }
329 }
330 }
331 }
332 waypoints.push_back({waitingStage, lane, {}, {}});
333 prev = e;
334 }
335 const JPS_StageId finalWait = std::get<0>(waypoints.back());
336 waypoints.pop_back(); // arrival waypoint comes later
337 if (!waypoints.empty()) {
338 waypoints.erase(waypoints.begin()); // departure edge also does not need a waypoint
339 }
340 waypoints.push_back({finalWait, getSidewalk<MSEdge, MSLane>(stage->getDestination()), {}, {}});
341
342#ifdef DEBUG_GRPC_TIMING
343 myStopWatch[3].start();
344#endif
345 sumo_jupedsim_api::AddJourneyRequest journeyRequest;
346 JPS_StageId startingStage = 0;
347 for (WaypointDesc& p : waypoints) {
348 const JPS_StageId waiting = std::get<0>(p);
349 if (waiting != 0) {
350 journeyRequest.add_stage_ids(waiting);
351 }
352 JPS_StageId waypoint = addWaypoint(person->getID(), p, &p == &waypoints.back() ? stage : nullptr);
353 if (waypoint == 0) {
354 return nullptr;
355 }
356 journeyRequest.add_stage_ids(waypoint);
357 if (startingStage == 0) {
358 startingStage = waiting != 0 ? waiting : waypoint;
359 }
360 }
361 const sumo_jupedsim_api::AddJourneyResponse journeyResponse = callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::AddJourney, journeyRequest,
362 TLF("Error while adding journey for agent '%': ", person->getID()));
363 const JPS_JourneyId journeyId = journeyResponse.journey_id();
364#ifdef DEBUG_GRPC_TIMING
365 myStopWatch[3].stop();
366#endif
367
368 PState* state = nullptr;
369 for (PState* const pstate : myPedestrianStates) { // TODO transform myPedestrianStates into a map for faster lookup
370 if (pstate->getPerson() == person) {
371 state = pstate;
372 break;
373 }
374 }
375 if (state == nullptr) {
376 state = new PState(static_cast<MSPerson*>(person), stage, journeyId, startingStage, waypoints);
377 state->setLanePosition(stage->getDepartPos() + radius + POSITION_EPS);
378 state->setPosition(departurePosition.x(), departurePosition.y());
379 state->setAngle(departureLane->getShape().rotationAtOffset(stage->getDepartPos()));
380 myPedestrianStates.push_back(state);
382 } else {
383 state->reinit(stage, journeyId, startingStage, waypoints);
384 }
385 if (state->isWaitingToEnter()) {
386 const Position p = state->getPosition(*state->getStage(), now);
387 tryPedestrianInsertion(state, p);
388 } else {
389 sumo_jupedsim_api::SwitchAgentJourneyRequest switchRequest;
390 switchRequest.set_agent_id(state->getAgentId());
391 switchRequest.set_journey_id(journeyId);
392 switchRequest.set_stage_id(startingStage);
393 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::SwitchAgentJourney, switchRequest,
394 TLF("Error while switching journey for agent '%': ", person->getID()));
395 }
396 return state;
397}
398
399
400void
402 PState* pstate = static_cast<PState*>(state);
403 if (pstate->getLane() != nullptr) {
404 auto& peds = myActiveLanes[pstate->getLane()];
405 peds.erase(std::find(peds.begin(), peds.end(), pstate));
406 pstate->setLane(nullptr);
407 }
408 if (pstate->getStage() != nullptr) {
409 pstate->getStage()->setPState(nullptr); // we need to remove the old state reference to avoid double deletion
410 }
411 pstate->setStage(nullptr);
412}
413
414
417#ifdef DEBUG_GRPC_TIMING
418 myStopWatch[1].start();
419#endif
420 sumo_jupedsim_api::IterateRequest iterateRequest;
421 iterateRequest.set_count((int)(DELTA_T / myJPSDeltaT));
422 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::Iterate, iterateRequest, TL("JuPedSim gRPC Iterate failed: "));
423#ifdef DEBUG_GRPC_TIMING
424 myStopWatch[1].stop();
425#endif
426
427#ifdef DEBUG_GRPC_TIMING
428 myStopWatch[2].start();
429#endif
430 sumo_jupedsim_api::GetCorePropertiesOfAllAgentsRequest propertiesRequest;
431 sumo_jupedsim_api::GetCorePropertiesOfAllAgentsResponse propertiesResponse =
432 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::GetCorePropertiesOfAllAgents, propertiesRequest, TL("JuPedSim gRPC GetCorePropertiesOfAllAgents failed: "));
433 const auto& properties = propertiesResponse.properties();
434#ifdef DEBUG_GRPC_TIMING
435 myStopWatch[2].stop();
436#endif
437
438 for (auto stateIt = myPedestrianStates.begin(); stateIt != myPedestrianStates.end();) {
439 PState* const state = *stateIt;
440
441 if (state->isWaitingToEnter()) {
442 // insertion failed at first try so we retry with some noise
443 Position p = state->getPosition(*state->getStage(), time);
444 p.setx(p.x() + RandHelper::rand(-.5, .5, &myRNG)); // we do this separately to avoid evaluation order problems
445 p.sety(p.y() + RandHelper::rand(-.5, .5, &myRNG));
446 tryPedestrianInsertion(state, p);
447 ++stateIt;
448 continue;
449 }
450
451 MSPerson* const person = state->getPerson();
452 MSStageWalking* const stage = dynamic_cast<MSStageWalking*>(person->getCurrentStage());
453 if (stage == nullptr) {
454 // It seems we kept the state for another stage but the new stage is not a walk.
455 // So let's remove the state because after the new stage we will be elsewhere and need to be reinserted for JuPedSim anyway.
456 // We cannot check this earlier because when the old stage ends the next stage might not know yet whether it will be a walk.
457 registerArrived(state->getAgentId());
458 stateIt = myPedestrianStates.erase(stateIt);
459 continue;
460 }
461
462 // Updates the agent position.
463 const auto agentIt = properties.find(state->getAgentId());
464 if (agentIt == properties.end()) {
465 WRITE_WARNINGF(TL("JuPedSim gRPC unknown agent: %"), state->getAgentId());
466 continue;
467 }
468 const sumo_jupedsim_api::Point& pos = agentIt->second.position();
469 state->setPosition(pos.x(), pos.y());
470 const sumo_jupedsim_api::Point& orientation = agentIt->second.orientation();
471 state->setAngle(atan2(orientation.y(), orientation.x()));
472
473 // Find on which edge the pedestrian is, using route's forward-looking edges because of how moveToXY is written.
474 Position newPosition(pos.x(), pos.y());
475 ConstMSEdgeVector route = stage->getEdges();
476 const int routeIndex = (int)(stage->getRouteStep() - stage->getRoute().begin());
477 const double oldLanePos = state->getEdgePos(time);
478 ConstMSEdgeVector forwardRoute = ConstMSEdgeVector(route.begin() + routeIndex, route.end());
479 double bestDistance = std::numeric_limits<double>::max();
480 MSLane* candidateLane = nullptr;
481 double candidateLaneLongitudinalPosition = 0.0;
482 int routeOffset = 0;
483 const bool found = libsumo::Helper::moveToXYMap_matchingRoutePosition(newPosition, "",
484 forwardRoute, 0, person->getVClass(), true, bestDistance, &candidateLane, candidateLaneLongitudinalPosition, routeOffset);
485
486 if (found) {
487 if (candidateLane != state->getLane()) {
488 if (state->getLane() != nullptr) {
489 auto& peds = myActiveLanes[state->getLane()];
490 peds.erase(std::find(peds.begin(), peds.end(), state));
491 }
492 myActiveLanes[candidateLane].push_back(state);
493 state->setLane(candidateLane);
494 }
495 state->setLanePosition(candidateLaneLongitudinalPosition);
496 }
497
498 const MSEdge* const expectedEdge = stage->getEdge();
499 if (found && expectedEdge->isNormal() && candidateLane->getEdge().isNormal() && &candidateLane->getEdge() != expectedEdge) {
500 const bool arrived = stage->moveToNextEdge(person, time, 1, nullptr);
501 UNUSED_PARAMETER(arrived);
502 assert(!arrived); // The person has not arrived yet.
503 stage->activateEntryReminders(person);
504 // Adapt speed to lane's speed limit.
505 // TODO make this a bulk request
506 sumo_jupedsim_api::SetDesiredSpeedRequest desiredSpeedRequest;
507 auto speeds = desiredSpeedRequest.mutable_desired_speeds();
508 (*speeds)[state->getAgentId()] = MIN2(candidateLane->getSpeedLimit(), person->getMaxSpeed());
509#ifdef DEBUG_GRPC_TIMING
510 myStopWatch[7].start();
511#endif
512 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::SetDesiredSpeedOfAgents, desiredSpeedRequest,
513 TLF("Error while setting desired speed for %: ", person->getID()));
514#ifdef DEBUG_GRPC_TIMING
515 myStopWatch[7].stop();
516#endif
517 }
518 const double speed = person->getSpeed();
519 for (int offset = 0; offset < 2; offset++) {
520 const WaypointDesc* const waypoint = state->getNextWaypoint(offset);
521 if (waypoint != nullptr && std::get<0>(*waypoint) != 0) {
522 const JPS_StageId waitingStage = std::get<0>(*waypoint);
523 auto& crossingState = myCrossings[waitingStage];
524 const MSLane* const crossing = crossingState.first;
525 const MSLink* link = crossing->getIncomingLanes().front().viaLink;
526 if (waitingStage == myCrossingWaits[crossing].second && link->getTLLogic() != nullptr) {
527 // we are walking backwards on a traffic light, there are different links to check
528 link = crossing->getLinkCont().front();
529 if (link->getTLLogic() == nullptr) {
530 link = crossing->getLogicalPredecessorLane()->getLinkTo(crossing);
531 }
532 }
533 // compare to and maybe adapt for MSPModel_Striping.cpp:1264
534 const double passingClearanceTime = person->getFloatParam("pedestrian.timegap-crossing");
535 const bool open = link->opened(time - DELTA_T, speed, speed, person->getVehicleType().getLength() + passingClearanceTime * speed,
536 person->getImpatience(), speed, 0, 0, nullptr, false, person);
537 if (open != crossingState.second) {
538 sumo_jupedsim_api::SetWaitingSetStateRequest waitingSetStateRequest;
539 waitingSetStateRequest.set_stage_id(waitingStage);
540 waitingSetStateRequest.set_state(open ? sumo_jupedsim_api::INACTIVE : sumo_jupedsim_api::ACTIVE);
541 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::SetWaitingSetState, waitingSetStateRequest,
542 TLF("Error while setting waiting status for %:", crossing->getID()));
543 crossingState.second = open;
544 }
545 }
546 }
547 stage->activateMoveReminders(person, oldLanePos, state->getEdgePos(time), state->getSpeed(*stage));
548 // In the worst case during one SUMO step the person touches the waypoint radius and walks immediately into a different direction,
549 // but at some simstep it should have a maximum distance of v * delta_t / 2 to the waypoint circle.
550 const double slack = person->getMaxSpeed() * TS / 2. + POSITION_EPS;
551 if (newPosition.distanceTo2D(std::get<2>(*state->getNextWaypoint())) < std::get<3>(*state->getNextWaypoint()) + slack) {
552 // If near the last waypoint, remove the agent.
553 if (state->advanceNextWaypoint()) {
554 // TODO this only works if the final stage is actually a walk
555 const bool finalStage = person->getNumRemainingStages() == 1;
556 const JPS_AgentId agentID = state->getAgentId();
557 while (!stage->moveToNextEdge(person, time, 1, nullptr));
558 if (finalStage) {
559 registerArrived(agentID);
560 stateIt = myPedestrianStates.erase(stateIt);
561 continue;
562 }
563 }
564 }
565 ++stateIt;
566 }
567
568 // Remove pedestrians that are in a predefined area, at a predefined rate.
569 for (const auto& area : myAreas) {
570 sumo_jupedsim_api::GetAgentsInRegionRequest agentsRequest;
571 *agentsRequest.mutable_region() = area->areaBoundary;
572 const sumo_jupedsim_api::AgentIdsResponse agentsResponse = callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::GetAgentsInRegion,
573 agentsRequest, TL("Error while retrieving agents in area: "));
574 const int numAgents = agentsResponse.agent_ids_size();
575 if (numAgents == 0) {
576 continue;
577 }
578 if (area->areaType == "vanishing_area") {
579 const SUMOTime period = area->params.count("period") > 0 ? string2time(area->params.at("period")) : 1000;
580 const int nbrPeriodsCoveringTimestep = (int)ceil(TS / STEPS2TIME(period));
581 if (time - area->lastRemovalTime >= nbrPeriodsCoveringTimestep * period) {
582 for (int k = 0; k < MIN2(nbrPeriodsCoveringTimestep, numAgents); k++) {
583 const JPS_AgentId agentID = agentsResponse.agent_ids(k);
584 auto lambda = [agentID](const PState * const p) {
585 return p->getAgentId() == agentID;
586 };
587 std::vector<PState*>::const_iterator iterator = std::find_if(myPedestrianStates.begin(), myPedestrianStates.end(), lambda);
588 if (iterator != myPedestrianStates.end()) {
589 const PState* const state = *iterator;
590 MSPerson* const person = state->getPerson();
591 // Code below only works if the removal happens at the last stage.
592 const bool finalStage = person->getNumRemainingStages() == 1;
593 if (finalStage) {
594 WRITE_MESSAGEF(TL("Person '%' in vanishing area '%' was removed from the simulation."), person->getID(), area->id);
595 while (!state->getStage()->moveToNextEdge(person, time, 1, nullptr));
596 registerArrived(agentID);
597 myPedestrianStates.erase(iterator);
598 area->lastRemovalTime = time;
599 }
600 }
601 }
602 }
603 } else { // areaType == "influencer"
604 if (area->params.count("speed") == 0) {
605 continue;
606 }
607 const double newSpeed = StringUtils::toDouble(area->params.at("speed"));
608 sumo_jupedsim_api::SetDesiredSpeedRequest desiredSpeedRequest;
609 auto speeds = desiredSpeedRequest.mutable_desired_speeds();
610 for (int i = 0; i < numAgents; i++) {
611 (*speeds)[agentsResponse.agent_ids(i)] = newSpeed;
612 }
613 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::SetDesiredSpeedOfAgents, desiredSpeedRequest,
614 TL("Error while setting desired speed for area: "));
615 }
616 }
617
618 // Add dynamically additional geometry from train carriages that are stopped.
619 const auto& stoppingPlaces = myNetwork->getStoppingPlaces(SumoXMLTag::SUMO_TAG_BUS_STOP);
620 std::vector<SUMOTrafficObject::NumericalID> allStoppedTrainIDs;
621 std::vector<const MSVehicle*> allStoppedTrains;
622 for (const auto& stop : stoppingPlaces) {
623 std::vector<const SUMOVehicle*> stoppedTrains = stop.second->getStoppedVehicles();
624 for (const SUMOVehicle* train : stoppedTrains) {
625 allStoppedTrainIDs.push_back(train->getNumericalID());
626 allStoppedTrains.push_back(dynamic_cast<const MSVehicle*>(train));
627 }
628 }
629 if (allStoppedTrainIDs != myAllStoppedTrainIDs) {
631 if (!allStoppedTrainIDs.empty()) {
632 std::vector<GEOSGeometry*> carriagePolygons;
633 std::vector<GEOSGeometry*> rampPolygons;
634 for (const MSVehicle* train : allStoppedTrains) {
635 if (train->getLeavingPersonNumber() > 0) {
636 const SUMOVTypeParameter& vTypeParam = train->getVehicleType().getParameter();
637 MSTrainHelper trainHelper = MSTrainHelper(train);
638 trainHelper.computeDoorPositions();
639 const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.getCarriages();
640 for (const MSTrainHelper::Carriage* carriage : carriages) {
641 Position dir = carriage->front - carriage->back;
642 if (dir.length2D() == 0.0) {
643 continue;
644 }
645 dir.norm2D();
646 Position perp = Position(-dir.y(), dir.x());
647 // Create carriages geometry.
648 double p = trainHelper.getHalfWidth();
649 PositionVector carriageShape;
650 carriageShape.push_back(carriage->front + perp * p);
651 carriageShape.push_back(carriage->back + perp * p);
652 carriageShape.push_back(carriage->back - perp * p);
653 carriageShape.push_back(carriage->front - perp * p);
654 carriagePolygons.push_back(createGeometryFromShape(carriageShape));
655 // Create ramps geometry.
656 p += vTypeParam.maxPlatformDistance;
657 const double d = 0.5 * vTypeParam.carriageDoorWidth;
658 for (const Position& door : carriage->doorPositions) {
659 PositionVector rampShape;
660 rampShape.push_back(door - perp * p + dir * d);
661 rampShape.push_back(door - perp * p - dir * d);
662 rampShape.push_back(door + perp * p - dir * d);
663 rampShape.push_back(door + perp * p + dir * d);
664 rampPolygons.push_back(createGeometryFromShape(rampShape));
665 }
666 }
667 }
668 }
669 if (!carriagePolygons.empty()) {
670 GEOSGeometry* carriagesCollection = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, carriagePolygons.data(), (unsigned int)carriagePolygons.size());
671 GEOSGeometry* rampsCollection = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, rampPolygons.data(), (unsigned int)rampPolygons.size());
672 GEOSGeometry* carriagesAndRampsUnion = GEOSUnion(carriagesCollection, rampsCollection);
673 if (carriagesAndRampsUnion == nullptr) {
674 WRITE_WARNING(TL("Error while generating geometry for carriages."));
675 } else {
676 GEOSGeometry* pedestrianNetworkWithTrainsAndRamps = GEOSUnion(carriagesAndRampsUnion, myGEOSPedestrianNetworkLargestComponent);
677#ifdef DEBUG_GEOMETRY_GENERATION
678 //dumpGeometry(pedestrianNetworkWithTrainsAndRamps, "pedestrianNetworkWithTrainsAndRamps.wkt");
679#endif
680 int nbrComponents = 0;
681 double maxArea = 0.0;
682 double totalArea = 0.0;
683 const GEOSGeometry* pedestrianNetworkWithTrainsAndRampsLargestComponent = getLargestComponent(pedestrianNetworkWithTrainsAndRamps, nbrComponents, maxArea, totalArea);
684 if (nbrComponents > 1) {
685 WRITE_WARNINGF(TL("While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
686 nbrComponents, maxArea / totalArea * 100.0, "%");
687 }
688#ifdef DEBUG_GEOMETRY_GENERATION
689 //dumpGeometry(pedestrianNetworkWithTrainsAndRampsLargestComponent, "pedestrianNetworkWithTrainsAndRamps.wkt");
690#endif
691 myJPSGeometryWithTrainsAndRamps = buildJPSGeometryFromGEOSGeometry(pedestrianNetworkWithTrainsAndRampsLargestComponent);
692 sumo_jupedsim_api::SwitchGeometryRequest switchRequest;
693 switchRequest.set_geometry_id(myJPSGeometryWithTrainsAndRamps);
694 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::SwitchGeometry, switchRequest, TL("While switching to train geometry: "), true);
697 GEOSGeom_destroy(pedestrianNetworkWithTrainsAndRamps);
698 }
699 GEOSGeom_destroy(rampsCollection);
700 GEOSGeom_destroy(carriagesCollection);
701 }
702 } else {
704 sumo_jupedsim_api::SwitchGeometryRequest switchRequest;
705 switchRequest.set_geometry_id(myJPSGeometry);
706 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::SwitchGeometry, switchRequest, TL("While switching to default geometry: "), true);
709 }
710 }
711 myAllStoppedTrainIDs = allStoppedTrainIDs;
712 }
713
714 return DELTA_T;
715}
716
717
720 sumo_jupedsim_api::RemoveAgentsRequest removeRequest;
721 removeRequest.add_agent_ids(agentID);
722#ifdef DEBUG_GRPC_TIMING
723 myStopWatch[5].start();
724#endif
725 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::RemoveAgents, removeRequest, TL("Error while removing agent: "));
726#ifdef DEBUG_GRPC_TIMING
727 myStopWatch[5].stop();
728#endif
729}
730
731
736
737
738GEOSGeometry*
740 GEOSCoordSequence* coordinateSequence = convertToGEOSPoints(centerLine);
741 GEOSGeometry* lineString = GEOSGeom_createLineString(coordinateSequence);
742 GEOSGeometry* dilatedLineString = GEOSBufferWithStyle(lineString, width, GEOS_QUADRANT_SEGMENTS, capStyle, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);
743 GEOSGeom_destroy(lineString);
744 return dilatedLineString;
745}
746
747
748GEOSGeometry*
749MSPModel_JuPedSim::createGeometryFromShape(PositionVector shape, std::string junctionID, std::string shapeID, bool isInternalShape) {
750 // Corner case.
751 if (shape.size() == 1) {
752 WRITE_WARNINGF(TL("Polygon '%' at junction '%' will be skipped as it is just a point."), shapeID, junctionID);
753 return nullptr;
754 }
755 // Make sure the shape is closed.
756 if (shape.back() != shape.front()) {
757 shape.push_back(shape.front());
758 }
759 // Replace consecutive points that are equal with just one.
760 PositionVector cleanShape;
761 cleanShape.push_back(shape[0]);
762 PositionVector duplicates;
763 for (int i = 1; i < (int)shape.size(); i++) {
764 if (shape[i] != shape[i - 1]) {
765 cleanShape.push_back(shape[i]);
766 } else {
767 duplicates.push_back(shape[i]);
768 }
769 }
770 if (cleanShape.size() < shape.size()) {
771 WRITE_WARNINGF(TL("Polygon '%' at junction '%' had some equal consecutive points removed: %"), shapeID, junctionID, toString(duplicates, 9));
772 }
773 GEOSCoordSequence* coordinateSequence = convertToGEOSPoints(cleanShape);
774 GEOSGeometry* linearRing = GEOSGeom_createLinearRing(coordinateSequence);
775 GEOSGeometry* polygon = GEOSGeom_createPolygon(linearRing, nullptr, 0);
776
777 if (!GEOSisValid(polygon)) {
778 if (cleanShape.size() == 3) {
779 if (isInternalShape) {
780 WRITE_WARNINGF(TL("Polygon '%' at junction '%' has been dilated as it is just a segment."), shapeID, junctionID);
781 } else {
782 WRITE_WARNINGF(TL("Polygon '%' has been dilated as it is just a segment."), shapeID);
783 }
784 GEOSGeometry* lineString = GEOSGeom_createLineString(GEOSCoordSeq_clone(coordinateSequence));
785 GEOSGeom_destroy(polygon);
786 polygon = GEOSBufferWithStyle(lineString, GEOS_BUFFERED_SEGMENT_WIDTH, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_BEVEL, GEOS_MITRE_LIMIT);
787 GEOSGeom_destroy(lineString);
788 } else {
789 if (isInternalShape) {
790 WRITE_WARNINGF(TL("Polygon '%' at junction '%' has been replaced by its convex hull as it is not simple."), shapeID, junctionID);
791 GEOSGeometry* hull = GEOSConvexHull(polygon);
792 GEOSGeom_destroy(polygon);
793 polygon = GEOSBufferWithStyle(hull, POSITION_EPS, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);;
794 } else {
795 WRITE_WARNINGF(TL("Polygon '%' at junction '%' will be skipped as it is not simple."), shapeID, junctionID);
796 polygon = nullptr;
797 }
798 }
799
800 return polygon;
801 }
802
803 // Some junctions need to be buffered a little so that edges are properly connected.
804 if (isInternalShape) {
805 polygon = GEOSBufferWithStyle(polygon, POSITION_EPS, GEOS_QUADRANT_SEGMENTS, GEOSBUF_CAP_FLAT, GEOSBUF_JOIN_ROUND, GEOS_MITRE_LIMIT);
806 }
807
808 return polygon;
809}
810
811
812GEOSGeometry*
814 std::vector<GEOSGeometry*> walkableAreas;
815 for (const MSEdge* const edge : network->getEdgeControl().getEdges()) {
816 const MSLane* const lane = getSidewalk<MSEdge, MSLane>(edge);
817 if (lane != nullptr) {
818 GEOSGeometry* dilatedLane = nullptr;
819 if (edge->isWalkingArea()) {
820 dilatedLane = createGeometryFromShape(lane->getShape(), edge->getFromJunction()->getID(), edge->getID(), true);
821 } else if (edge->isCrossing()) {
822 const PositionVector* outlineShape = lane->getOutlineShape();
823 if (outlineShape != nullptr) {
824 // this is mainly to ensure that we have at least the "normal" crossing, see #15037
825 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0, GEOSBUF_CAP_FLAT);
826 if (dilatedLane != nullptr) {
827 walkableAreas.push_back(dilatedLane);
828 }
829 dilatedLane = createGeometryFromShape(*outlineShape, edge->getFromJunction()->getID(), edge->getID(), true);
830 } else {
831 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0, GEOSBUF_CAP_ROUND);
832 }
833 myCrossingWaits[lane] = {0, 0};
834 } else { // regular sidewalk
835 dilatedLane = createGeometryFromCenterLine(lane->getShape(), lane->getWidth() / 2.0 + POSITION_EPS, GEOSBUF_CAP_FLAT);
836 }
837 if (dilatedLane != nullptr) {
838 walkableAreas.push_back(dilatedLane);
839 }
840 }
841 }
842 for (const auto& junctionWithID : network->getJunctionControl()) {
843 const MSJunction* const junction = junctionWithID.second;
844 int pedEdgeCount = 0;
845 bool hasWalkingArea = false;
846 for (const ConstMSEdgeVector& edges : {
847 junction->getIncoming(), junction->getOutgoing()
848 }) {
849 for (const MSEdge* const edge : edges) {
850 if (edge->isWalkingArea()) {
851 hasWalkingArea = true;
852 break;
853 }
854 if (getSidewalk<MSEdge, MSLane>(edge) != nullptr) {
855 pedEdgeCount++;
856 }
857 }
858 if (hasWalkingArea) {
859 break;
860 }
861 }
862 if (!hasWalkingArea && pedEdgeCount > 1) {
863 // there is something to connect but no walking area, let's assume peds are allowed everywhere
864 GEOSGeometry* walkingAreaGeom = createGeometryFromShape(junction->getShape(), junction->getID(), junction->getID(), true);
865 if (walkingAreaGeom != nullptr) {
866 walkableAreas.push_back(walkingAreaGeom);
867 }
868 }
869 }
870
871 // Retrieve additional walkable areas and obstacles (walkable areas and obstacles in the sense of JuPedSim).
872 std::vector<GEOSGeometry*> additionalObstacles;
873 for (const auto& polygonWithID : myNetwork->getShapeContainer().getPolygons()) {
874 if (polygonWithID.second->getShapeType() == "jupedsim.walkable_area" || polygonWithID.second->getShapeType() == "taz") {
875 GEOSGeometry* walkableArea = createGeometryFromShape(polygonWithID.second->getShape(), std::string(""), polygonWithID.first);
876 if (walkableArea != nullptr) {
877 walkableAreas.push_back(walkableArea);
879 }
880 } else if (polygonWithID.second->getShapeType() == "jupedsim.obstacle") {
881 GEOSGeometry* additionalObstacle = createGeometryFromShape(polygonWithID.second->getShape(), std::string(""), polygonWithID.first);
882 if (additionalObstacle != nullptr) {
883 additionalObstacles.push_back(additionalObstacle);
884 }
885 }
886 }
887
888 // Take the union of all walkable areas.
889 GEOSGeometry* disjointWalkableAreas = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, walkableAreas.data(), (unsigned int)walkableAreas.size());
890#ifdef DEBUG_GEOMETRY_GENERATION
891 // dumpGeometry(disjointWalkableAreas, "disjointWalkableAreas.wkt");
892#endif
893 GEOSGeometry* initialWalkableAreas = GEOSUnaryUnion(disjointWalkableAreas);
894#ifdef DEBUG_GEOMETRY_GENERATION
895 dumpGeometry(initialWalkableAreas, "initialWalkableAreas.wkt");
896#endif
897 GEOSGeom_destroy(disjointWalkableAreas);
898
899 // At last, remove additional obstacles from the merged walkable areas.
900 GEOSGeometry* disjointAdditionalObstacles = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, additionalObstacles.data(), (unsigned int)additionalObstacles.size());
901#ifdef DEBUG_GEOMETRY_GENERATION
902 // dumpGeometry(disjointAdditionalObstacles, "disjointAdditionalObstacles.wkt");
903#endif
904 GEOSGeometry* additionalObstaclesUnion = GEOSUnaryUnion(disjointAdditionalObstacles); // Obstacles may overlap, e.g. if they were loaded from separate files.
905#ifdef DEBUG_GEOMETRY_GENERATION
906 dumpGeometry(additionalObstaclesUnion, "additionalObstaclesUnion.wkt");
907#endif
908 GEOSGeometry* finalWalkableAreas = GEOSDifference(initialWalkableAreas, additionalObstaclesUnion);
909#ifdef DEBUG_GEOMETRY_GENERATION
910 dumpGeometry(finalWalkableAreas, "finalWalkableAreas.wkt");
911#endif
912 GEOSGeom_destroy(initialWalkableAreas);
913 GEOSGeom_destroy(additionalObstaclesUnion);
914 GEOSGeom_destroy(disjointAdditionalObstacles);
915
916 if (!GEOSisSimple(finalWalkableAreas)) {
917 throw ProcessError(TL("Union of walkable areas minus union of obstacles is not a simple polygon."));
918 }
919
920 return finalWalkableAreas;
921}
922
923
924GEOSCoordSequence*
926 GEOSCoordSequence* coordinateSequence = GEOSCoordSeq_create((unsigned int)shape.size(), 2);
927 for (int i = 0; i < (int)shape.size(); i++) {
928 GEOSCoordSeq_setX(coordinateSequence, i, shape[i].x());
929 GEOSCoordSeq_setY(coordinateSequence, i, shape[i].y());
930 }
931 return coordinateSequence;
932}
933
934
936MSPModel_JuPedSim::convertToSUMOPoints(const GEOSGeometry* geometry) {
937 PositionVector coordinateVector;
938 const GEOSCoordSequence* coordinateSequence = GEOSGeom_getCoordSeq(geometry);
939 unsigned int coordinateSequenceSize;
940 GEOSCoordSeq_getSize(coordinateSequence, &coordinateSequenceSize);
941 double x;
942 double y;
943 for (unsigned int i = 0; i < coordinateSequenceSize; i++) {
944 GEOSCoordSeq_getX(coordinateSequence, i, &x);
945 GEOSCoordSeq_getY(coordinateSequence, i, &y);
946 coordinateVector.push_back(Position(x, y));
947 }
948 return coordinateVector;
949}
950
951
952void
953MSPModel_JuPedSim::convertToJPSPoints(const GEOSGeometry* geometry, sumo_jupedsim_api::Polygon* into) {
954 const GEOSCoordSequence* coordinateSequence = GEOSGeom_getCoordSeq(geometry);
955 unsigned int coordinateSequenceSize;
956 GEOSCoordSeq_getSize(coordinateSequence, &coordinateSequenceSize);
957 double x;
958 double y;
959 // Remove the last point so that CGAL doesn't complain about the simplicity of the polygon downstream.
960 for (unsigned int i = 0; i < coordinateSequenceSize - 1; i++) {
961 GEOSCoordSeq_getX(coordinateSequence, i, &x);
962 GEOSCoordSeq_getY(coordinateSequence, i, &y);
963 sumo_jupedsim_api::Point* point = into->add_points();
964 point->set_x(x);
965 point->set_y(y);
966 }
967}
968
969
970double
971MSPModel_JuPedSim::getLinearRingArea(const GEOSGeometry* linearRing) {
972 double area;
973 GEOSGeometry* linearRingAsPolygon = GEOSGeom_createPolygon(GEOSGeom_clone(linearRing), nullptr, 0);
974 GEOSArea(linearRingAsPolygon, &area);
975 GEOSGeom_destroy(linearRingAsPolygon);
976 return area;
977}
978
979
980void
981MSPModel_JuPedSim::removePolygonFromDrawing(const std::string& polygonId) {
983}
984
985
986void
987MSPModel_JuPedSim::preparePolygonForDrawing(const GEOSGeometry* polygon, const std::string& polygonId, const RGBColor& color) {
988 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
989 bool added = myShapeContainer.addPolygon(polygonId, std::string("jupedsim.pedestrian_network"), color, 10.0, 0.0,
990 std::string(), convertToSUMOPoints(exterior), false, true, 1.0);
991 if (added) {
992 std::vector<PositionVector> holes;
993 int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
994 if (nbrInteriorRings != -1) {
995 for (int k = 0; k < nbrInteriorRings; k++) {
996 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
997 double area = getLinearRingArea(linearRing);
998 if (area > GEOS_MIN_AREA) {
999 holes.push_back(convertToSUMOPoints(linearRing));
1000 }
1001 }
1002 myShapeContainer.getPolygons().get(polygonId)->setHoles(holes);
1003 }
1004 }
1005}
1006
1007
1008const GEOSGeometry*
1009MSPModel_JuPedSim::getLargestComponent(const GEOSGeometry* polygon, int& nbrComponents, double& maxArea, double& totalArea) {
1010 nbrComponents = GEOSGetNumGeometries(polygon);
1011 const GEOSGeometry* largestComponent = nullptr;
1012 maxArea = 0.0;
1013 totalArea = 0.0;
1014 for (int i = 0; i < nbrComponents; i++) {
1015 const GEOSGeometry* componentPolygon = GEOSGetGeometryN(polygon, i);
1016 double area;
1017 GEOSArea(componentPolygon, &area);
1018 totalArea += area;
1019 if (area > maxArea) {
1020 maxArea = area;
1021 largestComponent = componentPolygon;
1022 }
1023 }
1024 return largestComponent;
1025}
1026
1027
1028int64_t
1030 sumo_jupedsim_api::CreateGeometryRequest geometryRequest;
1031 sumo_jupedsim_api::Polygon* boundary = geometryRequest.mutable_boundary();
1032
1033 // Handle the exterior polygon.
1034 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
1035 convertToJPSPoints(exterior, boundary);
1036
1037 // Handle the interior polygons (holes).
1038 int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
1039 if (nbrInteriorRings != -1) {
1040 for (int k = 0; k < nbrInteriorRings; k++) {
1041 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
1042 double area = getLinearRingArea(linearRing);
1043 if (area > GEOS_MIN_AREA) {
1044 sumo_jupedsim_api::Polygon* hole = geometryRequest.add_obstacles();
1045 convertToJPSPoints(linearRing, hole);
1046 }
1047 }
1048 }
1049 grpc::ClientContext geometryContext;
1050 sumo_jupedsim_api::CreateGeometryResponse geometryResponse;
1051 const grpc::Status geometryStatus = myGrpcStub->CreateGeometry(&geometryContext, geometryRequest, &geometryResponse);
1052 if (!geometryStatus.ok()) {
1053 WRITE_WARNINGF(TL("JuPedSim gRPC CreateGeometry failed: %"), geometryStatus.error_message());
1054 return -1;
1055 }
1056
1057 return geometryResponse.geometry_id();
1058}
1059
1060void
1061MSPModel_JuPedSim::dumpGeometry(const GEOSGeometry* polygon, const std::string& filename, bool useGeoCoordinates) {
1062 GEOSGeometry* polygonGeoCoordinates = nullptr;
1063 if (useGeoCoordinates) {
1064 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
1065 PositionVector exteriorPoints = convertToSUMOPoints(exterior);
1066 for (Position& position : exteriorPoints) {
1068 }
1069 const int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
1070 std::vector<GEOSGeometry*> holeRings;
1071 if (nbrInteriorRings != -1) {
1072 for (int k = 0; k < nbrInteriorRings; k++) {
1073 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
1074 PositionVector holePoints = convertToSUMOPoints(linearRing);
1075 for (Position& position : holePoints) {
1077 }
1078 GEOSCoordSequence* holeRingCoords = convertToGEOSPoints(holePoints);
1079 GEOSGeometry* holeRing = GEOSGeom_createLinearRing(holeRingCoords);
1080 holeRings.push_back(holeRing);
1081 }
1082 }
1083 GEOSCoordSequence* exteriorRingCoords = convertToGEOSPoints(exteriorPoints);
1084 GEOSGeometry* exteriorRing = GEOSGeom_createLinearRing(exteriorRingCoords);
1085 polygonGeoCoordinates = GEOSGeom_createPolygon(exteriorRing, holeRings.data(), nbrInteriorRings);
1086 }
1087 std::ofstream dumpFile;
1088 dumpFile.open(filename);
1089 GEOSWKTWriter* writer = GEOSWKTWriter_create();
1090 GEOSWKTWriter_setRoundingPrecision(writer, gPrecisionGeo);
1091 char* wkt = GEOSWKTWriter_write(writer, polygonGeoCoordinates == nullptr ? polygon : polygonGeoCoordinates);
1092 dumpFile << wkt << std::endl;
1093 dumpFile.close();
1094 GEOSFree(wkt);
1095 GEOSWKTWriter_destroy(writer);
1096 GEOSGeom_destroy(polygonGeoCoordinates);
1097}
1098
1099
1100double
1102 return 0.5 * MAX2(vehType.getLength(), vehType.getWidth());
1103}
1104
1105
1107MSPModel_JuPedSim::addWaitingSet(const MSLane* const crossing, const bool entry) {
1108 PositionVector shape = crossing->getShape();
1109 const double radius = getRadius(*MSNet::getInstance()->getVehicleControl().getVType(DEFAULT_PEDTYPE_ID, nullptr, true));
1110 shape.extrapolate2D((shape.length() + radius) / shape.length());
1111 const double offset = 2 * radius + POSITION_EPS;
1112 const double lonOffset = entry ? NUMERICAL_EPS : shape.length() - NUMERICAL_EPS;
1113 PositionVector pv;
1114 pv.push_back(shape.positionAtOffset(lonOffset));
1115 for (double latOff = offset; latOff < crossing->getWidth() / 2. - offset; latOff += offset) {
1116 PositionVector moved(shape);
1117 moved.move2side(latOff);
1118 pv.push_back(moved.positionAtOffset(lonOffset));
1119 moved.move2side(-2. * latOff);
1120 pv.push_back(moved.positionAtOffset(lonOffset));
1121 }
1122 if (entry && crossing->getIncomingLanes().size() == 1 && crossing->getIncomingLanes().front().lane->isWalkingArea()) {
1123 pv.push_back(crossing->getIncomingLanes().front().lane->getShape().getCentroid());
1124 }
1125 if (!entry && crossing->getLinkCont().size() == 1 && crossing->getLinkCont().front()->getLane()->isWalkingArea()) {
1126 pv.push_back(crossing->getLinkCont().front()->getLane()->getShape().getCentroid());
1127 }
1128
1129 sumo_jupedsim_api::AddWaitingSetStageRequest waitingSetRequest;
1130 for (const Position& p : pv) {
1131 GEOSCoordSequence* seq = GEOSCoordSeq_create(1, 2); // 1 point, 2 dimensions
1132 GEOSCoordSeq_setX(seq, 0, p.x());
1133 GEOSCoordSeq_setY(seq, 0, p.y());
1134 GEOSGeometry* geosPoint = GEOSGeom_createPoint(seq);
1135 if (GEOSContains(myGEOSPedestrianNetworkLargestComponent, geosPoint)) {
1136 sumo_jupedsim_api::Point* point = waitingSetRequest.add_points();
1137 point->set_x(p.x());
1138 point->set_y(p.y());
1139 } else {
1140 WRITE_WARNINGF("Waiting point %,% is not in the geometry for % on '%'.", p.x(), p.y(), entry ? "entry" : "exit", crossing->getID())
1141 }
1142 GEOSGeom_destroy(geosPoint);
1143 }
1144#ifdef DEBUG_GRPC_TIMING
1145 myStopWatch[6].start();
1146#endif
1147 auto waitingSetResponse = callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::AddWaitingSetStage, waitingSetRequest,
1148 TLF("Error while adding waiting set for % on '%':", entry ? "entry" : "exit", crossing->getID()));
1149#ifdef DEBUG_GRPC_TIMING
1150 myStopWatch[6].stop();
1151#endif
1152 JPS_StageId waitingStage = waitingSetResponse.stage_id();
1153
1154 sumo_jupedsim_api::SetWaitingSetStateRequest waitingSetStateRequest;
1155 waitingSetStateRequest.set_stage_id(waitingStage);
1156 waitingSetStateRequest.set_state(sumo_jupedsim_api::INACTIVE);
1157 callGrpc(&sumo_jupedsim_api::JuPedSimService::Stub::SetWaitingSetState, waitingSetStateRequest,
1158 TLF("Error while setting waiting status for % on '%':", entry ? "entry" : "exit", crossing->getID()));
1159
1160 myCrossings[waitingStage] = {crossing, true};
1161 return waitingStage;
1162}
1163
1164
1165void
1167 initGEOS(nullptr, nullptr);
1168 PROGRESS_BEGIN_MESSAGE("Generating initial JuPedSim geometry for pedestrian network");
1170 int nbrComponents = 0;
1171 double maxArea = 0.0;
1172 double totalArea = 0.0;
1174 if (nbrComponents > 1) {
1175 WRITE_WARNINGF(TL("While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
1176 nbrComponents, maxArea / totalArea * 100.0, "%");
1177 }
1178#ifdef DEBUG_GEOMETRY_GENERATION
1179 dumpGeometry(myGEOSPedestrianNetworkLargestComponent, "pedestrianNetwork.wkt");
1180#endif
1181 const std::string filename = oc.getString("pedestrian.jupedsim.wkt");
1182 if (!filename.empty()) {
1183 dumpGeometry(myGEOSPedestrianNetworkLargestComponent, filename, oc.getBool("pedestrian.jupedsim.wkt.geo"));
1184 }
1185 // For the moment, only one connected component is supported.
1190
1191 double strengthGeometryRepulsion = oc.getFloat("pedestrian.jupedsim.strength-geometry-repulsion");
1192 double rangeGeometryRepulsion = oc.getFloat("pedestrian.jupedsim.range-geometry-repulsion");
1193 if (myJPSDeltaT == 20) {
1194 if (oc.isDefault("pedestrian.jupedsim.strength-geometry-repulsion") && oc.isDefault("pedestrian.jupedsim.range-geometry-repulsion")) {
1195 WRITE_MESSAGE(TL("Adapting geometry repulsion default values for jupedsim timestep of 0.02."));
1196 strengthGeometryRepulsion = 35.;
1197 rangeGeometryRepulsion = 0.019;
1198 }
1199 }
1200 sumo_jupedsim_api::CreateSimulationRequest simulationRequest;
1201 simulationRequest.set_geometry_id(myJPSGeometry);
1202 simulationRequest.set_model_class(myJPSModel);
1203 simulationRequest.set_delta_t(STEPS2TIME(myJPSDeltaT));
1204 // Default server side arguments for the models.
1205 // TODO: Better handling of this as this is still hard-coded for each model class.
1206 auto& modelParams = *simulationRequest.mutable_model_parameters()->mutable_fields();
1207 if (myJPSModel == "CollisionFreeSpeedModel") {
1208 modelParams["strength_neighbor_repulsion"].set_number_value(oc.getFloat("pedestrian.jupedsim.strength-neighbor-repulsion"));
1209 modelParams["range_neighbor_repulsion"].set_number_value(oc.getFloat("pedestrian.jupedsim.range-neighbor-repulsion"));
1210 modelParams["strength_geometry_repulsion"].set_number_value(strengthGeometryRepulsion);
1211 modelParams["range_geometry_repulsion"].set_number_value(rangeGeometryRepulsion);
1212 } else if (myJPSModel == "CollisionFreeSpeedModelV2") {
1213 // Empty - did not set any parameters in old implementation
1214 } else if (myJPSModel == "GeneralizedCentrifugalForceModel") {
1215 modelParams["strength_neighbor_repulsion"].set_number_value(oc.getFloat("pedestrian.jupedsim.strength-neighbor-repulsion"));
1216 modelParams["strength_geometry_repulsion"].set_number_value(strengthGeometryRepulsion);
1217 } else if (myJPSModel == "SocialForceModel") {
1218 modelParams["body_force"].set_number_value(120000.0);
1219 modelParams["friction"].set_number_value(240000.0);
1220 }
1221 grpc::ClientContext simulationContext;
1222 sumo_jupedsim_api::CreateSimulationResponse simulationResponse;
1223 const grpc::Status simulationStatus = myGrpcStub->CreateSimulation(&simulationContext, simulationRequest, &simulationResponse);
1224 if (simulationStatus.ok()) {
1225 myJPSSimulation = simulationResponse.simulation_id();
1226 } else {
1227 throw ProcessError(TLF("JuPedSim gRPC CreateSimulation failed: %", simulationStatus.error_message()));
1228 }
1229 // Polygons that define vanishing areas aren't part of the regular JuPedSim geometry.
1230 for (const auto& polygonWithID : myNetwork->getShapeContainer().getPolygons()) {
1231 polygonChanged(polygonWithID.second, true, false);
1232 }
1234}
1235
1236
1237void
1238MSPModel_JuPedSim::polygonChanged(const SUMOPolygon* const poly, const bool added, const bool removed) {
1239 if (poly->getShapeType() == "jupedsim.vanishing_area" || poly->getShapeType() == "jupedsim.influencer") {
1240 SUMOTime lastRemovalTime = 0;
1241 if (!added) {
1242 for (auto areaIt = myAreas.begin(); areaIt != myAreas.end(); ++areaIt) {
1243 if (poly->getID() == (*areaIt)->id) {
1244 lastRemovalTime = (*areaIt)->lastRemovalTime;
1245 myAreas.erase(areaIt);
1246 break;
1247 }
1248 }
1249 }
1250 if (!removed) {
1251 sumo_jupedsim_api::Polygon areaBoundary;
1252 for (const Position& p : poly->getShape()) {
1253 sumo_jupedsim_api::Point* point = areaBoundary.add_points();
1254 point->set_x(p.x());
1255 point->set_y(p.y());
1256 }
1257 // // Make sure the shape is not repeating the first point.
1258 // if (areaBoundary.back().x == areaBoundary.front().x && areaBoundary.back().y == areaBoundary.front().y) {
1259 // areaBoundary.pop_back();
1260 // }
1261 const std::string type = StringTokenizer(poly->getShapeType(), ".").getVector()[1];
1262 myAreas.emplace_back(std::unique_ptr<AreaData>(new AreaData{poly->getID(), type, areaBoundary, poly->getParametersMap(), lastRemovalTime}));
1263 }
1264 }
1265}
1266
1267
1268// ===========================================================================
1269// MSPModel_Remote::PState method definitions
1270// ===========================================================================
1272 JPS_JourneyId journeyId, JPS_StageId stageId,
1273 const std::vector<WaypointDesc>& waypoints) :
1274 MSPModel_InteractingState(person, stage, nullptr),
1275 myJourneyId(journeyId), myStageId(stageId), myWaypoints(waypoints), myAgentId(0) {
1276 myDir = FORWARD;
1277}
1278
1279
1280void
1282 const std::vector<WaypointDesc>& waypoints) {
1283 if (myStage != nullptr) {
1284 myStage->setPState(nullptr); // we need to remove the old state reference to avoid double deletion
1285 }
1286 myStage = stage;
1287 myJourneyId = journeyId;
1288 myStageId = stageId;
1289 myWaypoints = waypoints;
1290}
1291
1292
1295
1296
1297void MSPModel_JuPedSim::PState::setPosition(const double x, const double y, const double z) {
1298 if (myRemoteXYPos != Position::INVALID) {
1299 mySpeed = myRemoteXYPos.distanceTo2D(Position(x, y, z)) / STEPS2TIME(DELTA_T);
1300 } else {
1301 mySpeed = 0.;
1302 }
1303 myRemoteXYPos.set(x, y, z);
1304}
1305
1306
1308 return stage.getNextRouteEdge();
1309}
1310
1311
1314 return offset < (int)myWaypoints.size() ? &myWaypoints[offset] : nullptr;
1315}
1316
1317
1318/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
std::vector< const MSEdge * > ConstMSEdgeVector
Definition MSEdge.h:75
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:287
#define WRITE_MESSAGEF(...)
Definition MsgHandler.h:289
#define WRITE_MESSAGE(msg)
Definition MsgHandler.h:288
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
#define PROGRESS_DONE_MESSAGE()
Definition MsgHandler.h:291
#define TLF(string,...)
Definition MsgHandler.h:306
#define PROGRESS_BEGIN_MESSAGE(msg)
Definition MsgHandler.h:290
SUMOTime DELTA_T
Definition SUMOTime.cpp:39
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:47
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:107
#define STEPS2TIME(x)
Definition SUMOTime.h:58
#define SIMSTEP
Definition SUMOTime.h:69
#define TS
Definition SUMOTime.h:45
const std::string DEFAULT_PEDTYPE_ID
@ RANDOM_LOCATION
The position may be chosen freely in a polygon defined by a taz.
@ SUMO_TAG_BUS_STOP
A bus stop.
int gPrecisionGeo
Definition StdDefs.cpp:29
const double SUMO_const_laneWidth
Definition StdDefs.h:52
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:57
A class that stores a 2D geometrical boundary.
Definition Boundary.h:39
double ymin() const
Returns minimum y-coordinate.
Definition Boundary.cpp:127
double xmin() const
Returns minimum x-coordinate.
Definition Boundary.cpp:115
double ymax() const
Returns maximum y-coordinate.
Definition Boundary.cpp:133
double xmax() const
Returns maximum x-coordinate.
Definition Boundary.cpp:121
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
const MSEdgeVector & getEdges() const
Returns loaded edges.
A road/street connecting two junctions.
Definition MSEdge.h:78
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition MSEdge.h:169
bool isNormal() const
return whether this edge is an internal edge
Definition MSEdge.h:265
const MSJunction * getToJunction() const
Definition MSEdge.h:428
double getLength() const
return the length of the edge
Definition MSEdge.h:695
const MSJunction * getFromJunction() const
Definition MSEdge.h:424
bool isTazConnector() const
Definition MSEdge.h:293
double getWidth() const
Returns the edges's width (sum over all lanes)
Definition MSEdge.h:666
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
The base class for an intersection.
Definition MSJunction.h:58
const ConstMSEdgeVector & getOutgoing() const
Definition MSJunction.h:114
const PositionVector & getShape() const
Returns this junction's shape.
Definition MSJunction.h:91
const ConstMSEdgeVector & getIncoming() const
Definition MSJunction.h:108
Representation of a lane in the micro simulation.
Definition MSLane.h:84
const MSLink * getLinkTo(const MSLane *const) const
returns the link to the given lane or nullptr, if it is not connected
Definition MSLane.cpp:2801
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
Definition MSLane.h:602
bool isWalkingArea() const
Definition MSLane.cpp:2693
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:984
MSLane * getLogicalPredecessorLane() const
get the most likely predecessor lane (sorted using by_connections_to_sorter). The result is cached in...
Definition MSLane.cpp:3271
virtual const PositionVector & getShape(bool) const
Definition MSLane.h:294
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:790
const PositionVector * getOutlineShape() const
Definition MSLane.h:1384
double getWidth() const
Returns the lane's width.
Definition MSLane.h:661
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:750
The simulated network and simulation perfomer.
Definition MSNet.h:89
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:201
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition MSNet.h:495
MSJunctionControl & getJunctionControl()
Returns the junctions control.
Definition MSNet.h:485
MSPedestrianRouter & getPedestrianRouter(int rngIndex, const Prohibitions &prohibited={}) const
Definition MSNet.cpp:1703
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
ShapeContainer & getShapeContainer()
Returns the shapes container.
Definition MSNet.h:525
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition MSNet.h:445
const NamedObjectCont< MSStoppingPlace * > & getStoppingPlaces(SumoXMLTag category) const
Definition MSNet.cpp:1578
ActiveLanes myActiveLanes
store of all lanes which have pedestrians on them
int myNumActivePedestrians
the total number of active pedestrians
Container for pedestrian state and individual position update function.
MSStageMoving * getStage() const
return the current stage
int myDir
the walking direction on the current lane (1 forward, -1 backward)
virtual double getAngle(const MSStageMoving &, SUMOTime) const
return the current orientation in degrees
double getEdgePos(SUMOTime) const
abstract methods inherited from MSTransportableStateAdapter
MSPerson * getPerson() const
return the represented person
bool isWaitingToEnter() const
whether the person still waits to entere the network
const MSLane * getLane() const
the current lane of the transportable
double getSpeed() const
return the current speed of the transportable, we need to be able to do this for vehicles as well,...
Holds pedestrian state and performs updates.
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.)
int64_t buildJPSGeometryFromGEOSGeometry(const GEOSGeometry *polygon)
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.
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
static const std::string PEDESTRIAN_NETWORK_ID
std::map< const MSLane *, JPS_StageId, ComparatorNumericalIdLess > myLaneCenters
static GEOSGeometry * createGeometryFromShape(PositionVector shape, std::string junctionID=std::string(""), std::string shapeID=std::string(""), bool isInternalShape=false)
static GEOSCoordSequence * convertToGEOSPoints(PositionVector shape)
int64_t myJPSGeometry
The JPS polygon representing the largest connected component of the pedestrian network.
GEOSGeometry * myGEOSPedestrianNetwork
The GEOS polygon containing all computed connected components of the pedestrian network.
static void convertToJPSPoints(const GEOSGeometry *geometry, sumo_jupedsim_api::Polygon *into)
static void dumpGeometry(const GEOSGeometry *polygon, const std::string &filename, bool useGeoCoordinates=false)
std::map< const MSLane *, std::pair< JPS_StageId, JPS_StageId >, ComparatorNumericalIdLess > myCrossingWaits
const SUMOTime myJPSDeltaT
Timestep used in the JuPedSim simulator.
MSNet *const myNetwork
The network on which the simulation runs.
std::shared_ptr< grpc::Channel > myGrpcChannel
void polygonChanged(const SUMOPolygon *const poly, const bool added, const bool removed) override
static const double GEOS_MIN_AREA
void initialize(const OptionsCont &oc)
GEOSGeometry * buildPedestrianNetwork(MSNet *network)
void remove(MSTransportableStateAdapter *state) override
remove the specified person from the pedestrian simulation
std::vector< StopWatch< std::chrono::nanoseconds > > myStopWatch
std::vector< std::unique_ptr< AreaData > > myAreas
Array of special areas.
static double getLinearRingArea(const GEOSGeometry *linearRing)
std::unique_ptr< sumo_jupedsim_api::JuPedSimService::Stub > myGrpcStub
SumoRNG myRNG
The random number generator for fluctuations on insertion.
std::tuple< JPS_StageId, const MSLane *, Position, double > WaypointDesc
void clearState() override
Resets pedestrians when quick-loading state.
Response callGrpc(grpc::Status(sumo_jupedsim_api::JuPedSimService::Stub::*method)(grpc::ClientContext *, const Request &, Response *), Request &request, const std::string &what, const bool warnOnly=false)
ShapeContainer & myShapeContainer
The shape container used to add polygons to the rendering pipeline.
std::vector< PState * > myPedestrianStates
JPS_StageId addWaitingSet(const MSLane *const crossing, const bool entry)
int64_t myJPSGeometryWithTrainsAndRamps
The JPS polygon representing the largest connected component plus carriages and ramps.
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)
JPS_StageId addWaypoint(const std::string &agentID, WaypointDesc &waypoint, const MSStageMoving *const finalStage)
void tryPedestrianInsertion(PState *state, const Position &p)
SUMOTime execute(SUMOTime time)
static const double GEOS_BUFFERED_SEGMENT_WIDTH
std::map< JPS_StageId, std::pair< const MSLane *, bool > > myCrossings
static const int BACKWARD
Definition MSPModel.h:55
static const int FORWARD
Definition MSPModel.h:54
static const double RANDOM_POS_LAT
magic value to encode randomized lateral offset for persons when starting a walk
Definition MSPModel.h:68
static const int UNDEFINED_DIRECTION
Definition MSPModel.h:56
static const double UNSPECIFIED_POS_LAT
the default lateral offset for persons when starting a walk
Definition MSPModel.h:65
double getImpatience() const
Definition MSPerson.cpp:245
const MSEdge * getDestination() const
returns the destination edge
Definition MSStage.cpp:65
virtual double getArrivalPos() const
Definition MSStage.h:97
virtual const MSEdge * getEdge() const
Returns the current edge.
Definition MSStage.cpp:71
virtual const MSEdge * getNextRouteEdge() const =0
ConstMSEdgeVector getEdges() const
the edges of the current stage
const std::vector< const MSEdge * > & getRoute() const
void setPState(MSTransportableStateAdapter *pstate)
double getDepartPosLat() const
const MSEdge * getEdge() const
Returns the current edge.
double getDepartPos() const
const std::vector< constMSEdge * >::iterator getRouteStep() const
virtual bool moveToNextEdge(MSTransportable *transportable, SUMOTime currentTime, int prevDir, MSEdge *nextInternal=nullptr, const bool isReplay=false)=0
move forward and return whether the transportable arrived
virtual double getMaxSpeed(const MSTransportable *const transportable=nullptr) const =0
the maximum speed of the transportable
bool moveToNextEdge(MSTransportable *person, SUMOTime currentTime, int prevDir, MSEdge *nextInternal=nullptr, const bool isReplay=false)
move forward and return whether the person arrived
void activateMoveReminders(MSTransportable *person, double oldPos, double newPos, double newSpeed)
void activateEntryReminders(MSTransportable *person, const bool isDepart=false)
add the move reminders for the current lane on entry
A class that helps computing positions of a train's carriages and additional structures.
void computeDoorPositions()
compute door positions on demand and fills the carriage structures
const std::vector< Carriage * > & getCarriages() const
double getHalfWidth() const
virtual double getSpeed() const override
the current speed of the transportable
MSStage * getNextStage(int offset) const
Return the next (or previous) stage denoted by the offset.
int getNumRemainingStages() const
Return the number of remaining stages (including the current)
MSStage * getCurrentStage() const
Return the current stage.
SUMOVehicleClass getVClass() const override
Returns the object's access class.
double getMaxSpeed() const override
Returns the maximum speed (the minimum of desired and physical maximum speed)
const SUMOVTypeParameter & getVTypeParameter() const override
Returns the object's "vehicle" type parameter.
int getCurrentStageIndex() const
Return the index of the current stage.
MSStageType getCurrentStageType() const
the current stage type of the transportable
const SUMOVehicleParameter & getParameter() const override
Returns the vehicle's parameter (including departure definition)
const MSVehicleType & getVehicleType() const override
Returns the object's "vehicle" type.
const MSEdge * getEdge() const override
Returns the current edge.
abstract base class for managing callbacks to retrieve various state information from the model
Definition MSPModel.h:159
Representation of a vehicle in the micro simulation.
Definition MSVehicle.h:77
The car-following model and parameter.
double getWidth() const
Get the width which vehicles of this class shall have when being drawn.
double getLength() const
Get vehicle's length [m].
const std::string & getID() const
Returns the id.
Definition Named.h:73
T get(const std::string &id) const
Retrieves an item.
A storage for options typed value containers)
Definition OptionsCont.h:89
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
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.
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.
Position getCentroid() const
Returns the centroid (closes the polygon if unclosed)
void extrapolate2D(const double val, const bool onlyFirst=false)
extrapolate position vector in two dimensions (Z is ignored)
bool around(const Position &p, double offset=0) const
Returns the information whether the position vector describes a polygon lying around the given point.
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
static void initRandGlobal(SumoRNG *which=nullptr)
Reads the given random number options and initialises the random number generator in accordance.
const PositionVector & getShape() const
Returns the shape of the polygon.
virtual void setHoles(const std::vector< PositionVector > &holes)
Sets the holes of the polygon.
double getFloatParam(const std::string &paramName, const bool required=false, const double deflt=INVALID_DOUBLE, bool checkDist=true) const
Retrieve a floating point parameter for the traffic object.
Structure representing possible vehicle parameter.
double maxPlatformDistance
the maximum distance between platform and train
double carriageDoorWidth
the width of the carriage doors
Representation of a vehicle.
Definition SUMOVehicle.h:63
DepartPosDefinition departPosProcedure
Information how the vehicle shall choose the departure position.
void addShapeListener(ShapeListener *listener)
virtual bool removePolygon(const std::string &id, bool useLock=true)
Removes a polygon from the container.
const Polygons & getPolygons() const
Returns all polygons.
virtual bool addPolygon(const std::string &id, const std::string &type, const RGBColor &color, double layer, double angle, const std::string &imgFile, const PositionVector &shape, bool geo, bool fill, double lineWidth, bool ignorePruning=false, const std::string &name=Shape::DEFAULT_NAME)
Builds a polygon using the given values and adds it to the container.
const std::string & getShapeType() const
Returns the (abstract) type of the Shape.
Definition Shape.cpp:99
std::vector< std::string > getVector()
return vector of strings
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool moveToXYMap_matchingRoutePosition(const Position &pos, const std::string &origID, const ConstMSEdgeVector &currentRoute, int routeIndex, SUMOVehicleClass vClass, bool setLateralPos, double &bestDistance, MSLane **lane, double &lanePos, int &routeOffset)
Definition Helper.cpp:1759
static int getFreeSocketPort()
Returns an free port on the system.
Definition socket.cpp:118
#define UNUSED_PARAMETER(x)
#define M_PI
Definition odrSpiral.cpp:45
Structure that keeps data related to vanishing areas (and other types of areas).