30 #include <jupedsim/jupedsim.h>
67 myNetwork(net), myShapeContainer(net->getShapeContainer()), myJPSDeltaT(
string2time(oc.getString(
"pedestrian.jupedsim.step-length"))),
68 myExitTolerance(oc.getFloat(
"pedestrian.jupedsim.exit-tolerance")), myGEOSPedestrianNetworkLargestComponent(nullptr),
69 myHaveAdditionalWalkableAreas(false) {
78 (*myPythonScript) <<
"while simulation.agent_count() > 0 and simulation.iteration_count() < 160 * 100: simulation.iterate()\n";
95 JPS_CollisionFreeSpeedModelAgentParameters agent_parameters{};
97 agent_parameters.stageId = state->
getStageId();
98 agent_parameters.position = {p.
x(), p.
y()};
114 agent_parameters.radius =
getRadius(type);
116 JPS_ErrorMessage message =
nullptr;
117 JPS_AgentId agentId = JPS_Simulation_AddCollisionFreeSpeedModelAgent(
myJPSSimulation, agent_parameters, &message);
118 if (message !=
nullptr) {
120 JPS_ErrorMessage_Free(message);
129 JPS_ErrorMessage message =
nullptr;
130 if (predecessor != 0) {
131 const JPS_Transition transition = JPS_Transition_CreateFixedTransition(stage, &message);
132 if (message !=
nullptr) {
133 WRITE_WARNINGF(
TL(
"Error while creating fixed transition for person '%': %"), agentID, JPS_ErrorMessage_GetMessage(message));
134 JPS_ErrorMessage_Free(message);
137 JPS_JourneyDescription_SetTransitionForStage(journey, predecessor, transition, &message);
138 if (message !=
nullptr) {
139 WRITE_WARNINGF(
TL(
"Error while setting transition for person '%': %"), agentID, JPS_ErrorMessage_GetMessage(message));
140 JPS_ErrorMessage_Free(message);
143 JPS_Transition_Free(transition);
145 JPS_JourneyDescription_AddStage(journey, stage);
153 JPS_ErrorMessage message =
nullptr;
154 const Position& coords = std::get<1>(waypoint);
155 const JPS_StageId waypointId = JPS_Simulation_AddStageWaypoint(
myJPSSimulation, {coords.
x(), coords.
y()},
156 std::get<2>(waypoint), &message);
157 if (message !=
nullptr) {
158 WRITE_WARNINGF(
TL(
"Error while adding waypoint for person '%': %"), agentID, JPS_ErrorMessage_GetMessage(message));
159 JPS_ErrorMessage_Free(message);
162 const JPS_StageId waiting = std::get<0>(waypoint);
165 (*myPythonScript) <<
"journey.add(" << waiting <<
")\n";
166 if (predecessor != 0) {
167 (*myPythonScript) <<
"journey.set_transition_for_stage(" << predecessor <<
", jps.Transition.create_fixed_transition(" << waiting <<
"))\n";
170 if (!
addStage(journey, predecessor, agentID, waiting)) {
175 (*myPythonScript) <<
"ws = simulation.add_waypoint_stage((" << coords.
x() <<
"," << coords.
y() <<
"), " << std::get<2>(waypoint) <<
")\n"
177 if (predecessor != 0) {
178 (*myPythonScript) <<
"journey.set_transition_for_stage(" << predecessor <<
", jps.Transition.create_fixed_transition(ws))\n";
181 if (!
addStage(journey, predecessor, agentID, waypointId)) {
193 const MSLane*
const departureLane = getSidewalk<MSEdge, MSLane>(stage->
getRoute().front());
194 if (departureLane ==
nullptr) {
195 const char* error =
TL(
"Person '%' could not find sidewalk on edge '%', time=%.");
208 if (tazShape ==
nullptr) {
221 const double halfDepartureLaneWidth = departureLane->
getWidth() / 2.0;
224 departureRelativePositionY = 0.0;
227 departureRelativePositionY =
RandHelper::rand(-halfDepartureLaneWidth, halfDepartureLaneWidth);
232 std::vector<WaypointDesc> waypoints;
233 const MSEdge* prev =
nullptr;
235 const MSLane*
const lane = getSidewalk<MSEdge, MSLane>(e);
236 JPS_StageId waitingStage = 0;
237 if (prev !=
nullptr) {
247 for (
const MSEdge*
const ce : crossingRoute) {
248 if (ce->isCrossing()) {
249 const MSLane*
const crossing = getSidewalk<MSEdge, MSLane>(ce);
251 const MSLane*
const prevLane = getSidewalk<MSEdge, MSLane>(prev);
254 if (crossing->
getShape().front().distanceSquaredTo(startPos) < crossing->
getShape().back().distanceSquaredTo(startPos)) {
266 waypoints.push_back({waitingStage, lane->
getShape().positionAtOffset(e->getLength() / 2.), lane->
getWidth() / 2.});
269 const JPS_StageId finalWait = std::get<0>(waypoints.back());
270 waypoints.pop_back();
271 if (!waypoints.empty()) {
272 waypoints.erase(waypoints.begin());
278 JPS_JourneyDescription journeyDesc = JPS_JourneyDescription_Create();
280 (*myPythonScript) <<
"\njourney = jps.JourneyDescription()\n";
282 JPS_StageId startingStage = 0;
283 JPS_StageId predecessor = 0;
284 for (
const auto& p : waypoints) {
286 JPS_JourneyDescription_Free(journeyDesc);
289 if (startingStage == 0) {
290 startingStage = std::get<0>(waypoints.front()) == 0 ? predecessor : std::get<0>(waypoints.front());
293 JPS_ErrorMessage message =
nullptr;
294 JPS_JourneyId journeyId = JPS_Simulation_AddJourney(
myJPSSimulation, journeyDesc, &message);
295 JPS_JourneyDescription_Free(journeyDesc);
296 if (message !=
nullptr) {
297 WRITE_WARNINGF(
TL(
"Error while adding a journey for person '%': %"), person->
getID(), JPS_ErrorMessage_GetMessage(message));
298 JPS_ErrorMessage_Free(message);
304 if (pstate->getPerson() == person) {
309 if (state ==
nullptr) {
310 state =
new PState(
static_cast<MSPerson*
>(person), stage, journeyId, startingStage, waypoints);
313 state->
setPosition(departurePosition.
x(), departurePosition.
y());
318 state->
reinit(stage, journeyId, startingStage, waypoints);
323 (*myPythonScript) <<
"journey_id = simulation.add_journey(journey)\n"
324 "simulation.add_agent(jps.CollisionFreeSpeedModelAgentParameters(journey_id=journey_id,stage_id="
325 << startingStage <<
",position=(" << departurePosition.
x() <<
"," << departurePosition.
y()
330 if (message !=
nullptr) {
331 WRITE_WARNINGF(
TL(
"Error while switching to a new journey for person '%': %"), person->
getID(), JPS_ErrorMessage_GetMessage(message));
332 JPS_ErrorMessage_Free(message);
343 if (pstate->
getStage() !=
nullptr) {
353 JPS_ErrorMessage message =
nullptr;
354 for (
int i = 0; i < nbrIterations; ++i) {
358 WRITE_ERRORF(
TL(
"Error during iteration %: %"), i, JPS_ErrorMessage_GetMessage(message));
366 PState*
const state = *stateIt;
380 if (stage ==
nullptr) {
393 const JPS_Point position = JPS_Agent_GetPosition(agent);
397 const JPS_Point orientation = JPS_Agent_GetOrientation(agent);
398 state->
setAngle(atan2(orientation.y, orientation.x));
401 Position newPosition(position.x, position.y);
405 double bestDistance = std::numeric_limits<double>::max();
406 MSLane* candidateLane =
nullptr;
407 double candidateLaneLongitudinalPosition = 0.0;
410 forwardRoute, 0, person->
getVClass(),
true, bestDistance, &candidateLane, candidateLaneLongitudinalPosition, routeOffset);
418 const bool arrived = stage->
moveToNextEdge(person, time, 1,
nullptr);
423 JPS_CollisionFreeSpeedModelState modelState = JPS_Agent_GetCollisionFreeSpeedModelState(agent,
nullptr);
425 if (newMaxSpeed != JPS_CollisionFreeSpeedModelState_GetV0(modelState)) {
426 JPS_CollisionFreeSpeedModelState_SetV0(modelState, newMaxSpeed);
429 for (
int offset = 0; offset < 2; offset++) {
431 if (waypoint !=
nullptr && std::get<0>(*waypoint) != 0) {
433 const double speed = person->
getSpeed();
436 const bool open = ili.viaLink->opened(time -
DELTA_T, speed, speed, person->
getVehicleType().
getLength() + 2 * speed, person->
getImpatience(), speed, 0, 0,
nullptr,
false, person);
437 const auto proxy = JPS_Simulation_GetWaitingSetProxy(
myJPSSimulation, std::get<0>(*waypoint), &message);
438 JPS_WaitingSetProxy_SetWaitingSetState(proxy, open ? JPS_WaitingSet_Inactive : JPS_WaitingSet_Active);
445 const double slack = person->
getMaxSpeed() *
TS / 2. + POSITION_EPS;
451 const JPS_AgentId agentID = state->
getAgentId();
466 const std::vector<JPS_Point>& areaBoundary = area.areaBoundary;
467 JPS_AgentIdIterator agentsInArea = JPS_Simulation_AgentsInPolygon(
myJPSSimulation, areaBoundary.data(), areaBoundary.size());
468 if (area.areaType ==
"vanishing_area") {
469 const SUMOTime period = area.params.count(
"period") > 0 ?
string2time(area.params.at(
"period")) : 1000;
470 const int nbrPeriodsCoveringTimestep = (int)ceil(
TS /
STEPS2TIME(period));
471 if (time - area.lastRemovalTime >= nbrPeriodsCoveringTimestep * period) {
472 for (
int k = 0; k < nbrPeriodsCoveringTimestep; k++) {
473 const JPS_AgentId agentID = JPS_AgentIdIterator_Next(agentsInArea);
475 auto lambda = [agentID](
const PState *
const p) {
476 return p->getAgentId() == agentID;
480 const PState*
const state = *iterator;
485 WRITE_MESSAGEF(
TL(
"Person '%' in vanishing area '%' was removed from the simulation."), person->
getID(), area.id);
490 area.lastRemovalTime = time;
497 for (JPS_AgentId agentID = JPS_AgentIdIterator_Next(agentsInArea); agentID != 0; agentID = JPS_AgentIdIterator_Next(agentsInArea)) {
498 if (area.params.count(
"speed") > 0) {
499 const JPS_Agent agent = JPS_Simulation_GetAgent(
myJPSSimulation, agentID,
nullptr);
500 JPS_CollisionFreeSpeedModelState modelState = JPS_Agent_GetCollisionFreeSpeedModelState(agent,
nullptr);
502 if (newMaxSpeed != JPS_CollisionFreeSpeedModelState_GetV0(modelState)) {
503 JPS_CollisionFreeSpeedModelState_SetV0(modelState, newMaxSpeed);
508 JPS_AgentIdIterator_Free(agentsInArea);
513 std::vector<SUMOTrafficObject::NumericalID> allStoppedTrainIDs;
514 std::vector<const MSVehicle*> allStoppedTrains;
515 for (
const auto& stop : stoppingPlaces) {
516 std::vector<const SUMOVehicle*> stoppedTrains = stop.second->getStoppedVehicles();
518 allStoppedTrainIDs.push_back(train->getNumericalID());
519 allStoppedTrains.push_back(
dynamic_cast<const MSVehicle*
>(train));
524 if (!allStoppedTrainIDs.empty()) {
525 std::vector<GEOSGeometry*> carriagePolygons;
526 std::vector<GEOSGeometry*> rampPolygons;
527 for (
const MSVehicle* train : allStoppedTrains) {
528 if (train->getLeavingPersonNumber() > 0) {
531 const std::vector<MSTrainHelper::Carriage*>& carriages = trainHelper.
getCarriages();
533 Position dir = carriage->front - carriage->back;
542 carriageShape.push_back(carriage->front + perp * p);
543 carriageShape.push_back(carriage->back + perp * p);
544 carriageShape.push_back(carriage->back - perp * p);
545 carriageShape.push_back(carriage->front - perp * p);
550 for (
const Position& door : carriage->doorPositions) {
552 rampShape.push_back(door - perp * p + dir * d);
553 rampShape.push_back(door - perp * p - dir * d);
554 rampShape.push_back(door + perp * p - dir * d);
555 rampShape.push_back(door + perp * p + dir * d);
561 if (!carriagePolygons.empty()) {
562 GEOSGeometry* carriagesCollection = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, carriagePolygons.data(), (
unsigned int)carriagePolygons.size());
563 GEOSGeometry* rampsCollection = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, rampPolygons.data(), (
unsigned int)rampPolygons.size());
564 GEOSGeometry* carriagesAndRampsUnion = GEOSUnion(carriagesCollection, rampsCollection);
565 if (carriagesAndRampsUnion ==
nullptr) {
569 #ifdef DEBUG_GEOMETRY_GENERATION
572 int nbrComponents = 0;
573 double maxArea = 0.0;
574 double totalArea = 0.0;
575 const GEOSGeometry* pedestrianNetworkWithTrainsAndRampsLargestComponent =
getLargestComponent(pedestrianNetworkWithTrainsAndRamps, nbrComponents, maxArea, totalArea);
576 if (nbrComponents > 1) {
577 WRITE_WARNINGF(
TL(
"While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
578 nbrComponents, maxArea / totalArea * 100.0,
"%");
580 #ifdef DEBUG_GEOMETRY_GENERATION
587 GEOSGeom_destroy(pedestrianNetworkWithTrainsAndRamps);
589 GEOSGeom_destroy(rampsCollection);
590 GEOSGeom_destroy(carriagesCollection);
599 JPS_ErrorMessage_Free(message);
630 GEOSGeometry* lineString = GEOSGeom_createLineString(coordinateSequence);
632 GEOSGeom_destroy(lineString);
633 return dilatedLineString;
640 if (shape.size() == 1) {
641 WRITE_WARNINGF(
TL(
"Polygon '%' at junction '%' will be skipped as it is just a point."), shapeID, junctionID);
645 if (shape.back() != shape.front()) {
646 shape.push_back(shape.front());
650 cleanShape.push_back(shape[0]);
652 for (
int i = 1; i < (int)shape.size(); i++) {
653 if (shape[i] != shape[i - 1]) {
654 cleanShape.push_back(shape[i]);
656 duplicates.push_back(shape[i]);
659 if (cleanShape.size() < shape.size()) {
660 WRITE_WARNINGF(
TL(
"Polygon '%' at junction '%' had some equal consecutive points removed: %"), shapeID, junctionID,
toString(duplicates, 9));
663 GEOSGeometry* linearRing = GEOSGeom_createLinearRing(coordinateSequence);
664 GEOSGeometry* polygon = GEOSGeom_createPolygon(linearRing,
nullptr, 0);
666 if (!GEOSisValid(polygon)) {
667 if (cleanShape.size() == 3) {
668 if (isInternalShape) {
669 WRITE_WARNINGF(
TL(
"Polygon '%' at junction '%' has been dilated as it is just a segment."), shapeID, junctionID);
671 WRITE_WARNINGF(
TL(
"Polygon '%' has been dilated as it is just a segment."), shapeID);
673 GEOSGeometry* lineString = GEOSGeom_createLineString(GEOSCoordSeq_clone(coordinateSequence));
674 GEOSGeom_destroy(polygon);
676 GEOSGeom_destroy(lineString);
678 if (isInternalShape) {
679 WRITE_WARNINGF(
TL(
"Polygon '%' at junction '%' has been replaced by its convex hull as it is not simple."), shapeID, junctionID);
680 GEOSGeometry* hull = GEOSConvexHull(polygon);
681 GEOSGeom_destroy(polygon);
684 WRITE_WARNINGF(
TL(
"Polygon '%' at junction '%' will be skipped as it is not simple."), shapeID, junctionID);
693 if (isInternalShape) {
703 std::vector<GEOSGeometry*> walkableAreas;
705 const MSLane*
const lane = getSidewalk<MSEdge, MSLane>(edge);
706 if (lane !=
nullptr) {
707 GEOSGeometry* dilatedLane =
nullptr;
708 if (edge->isWalkingArea()) {
710 }
else if (edge->isCrossing()) {
712 if (outlineShape !=
nullptr) {
715 if (dilatedLane !=
nullptr) {
716 walkableAreas.push_back(dilatedLane);
726 if (dilatedLane !=
nullptr) {
727 walkableAreas.push_back(dilatedLane);
732 const MSJunction*
const junction = junctionWithID.second;
733 int pedEdgeCount = 0;
734 bool hasWalkingArea =
false;
738 for (
const MSEdge*
const edge : edges) {
739 if (edge->isWalkingArea()) {
740 hasWalkingArea =
true;
743 if (getSidewalk<MSEdge, MSLane>(edge) !=
nullptr) {
747 if (hasWalkingArea) {
751 if (!hasWalkingArea && pedEdgeCount > 1) {
754 if (walkingAreaGeom !=
nullptr) {
755 walkableAreas.push_back(walkingAreaGeom);
761 std::vector<GEOSGeometry*> additionalObstacles;
763 if (polygonWithID.second->getShapeType() ==
"jupedsim.walkable_area" || polygonWithID.second->getShapeType() ==
"taz") {
764 GEOSGeometry* walkableArea =
createGeometryFromShape(polygonWithID.second->getShape(), std::string(
""), polygonWithID.first);
765 if (walkableArea !=
nullptr) {
766 walkableAreas.push_back(walkableArea);
769 }
else if (polygonWithID.second->getShapeType() ==
"jupedsim.obstacle") {
770 GEOSGeometry* additionalObstacle =
createGeometryFromShape(polygonWithID.second->getShape(), std::string(
""), polygonWithID.first);
771 if (additionalObstacle !=
nullptr) {
772 additionalObstacles.push_back(additionalObstacle);
778 GEOSGeometry* disjointWalkableAreas = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, walkableAreas.data(), (
unsigned int)walkableAreas.size());
779 #ifdef DEBUG_GEOMETRY_GENERATION
782 GEOSGeometry* initialWalkableAreas = GEOSUnaryUnion(disjointWalkableAreas);
783 #ifdef DEBUG_GEOMETRY_GENERATION
784 dumpGeometry(initialWalkableAreas,
"initialWalkableAreas.wkt");
786 GEOSGeom_destroy(disjointWalkableAreas);
789 GEOSGeometry* disjointAdditionalObstacles = GEOSGeom_createCollection(GEOS_MULTIPOLYGON, additionalObstacles.data(), (
unsigned int)additionalObstacles.size());
790 #ifdef DEBUG_GEOMETRY_GENERATION
793 GEOSGeometry* additionalObstaclesUnion = GEOSUnaryUnion(disjointAdditionalObstacles);
794 #ifdef DEBUG_GEOMETRY_GENERATION
795 dumpGeometry(additionalObstaclesUnion,
"additionalObstaclesUnion.wkt");
797 GEOSGeometry* finalWalkableAreas = GEOSDifference(initialWalkableAreas, additionalObstaclesUnion);
798 #ifdef DEBUG_GEOMETRY_GENERATION
799 dumpGeometry(finalWalkableAreas,
"finalWalkableAreas.wkt");
801 GEOSGeom_destroy(initialWalkableAreas);
802 GEOSGeom_destroy(additionalObstaclesUnion);
803 GEOSGeom_destroy(disjointAdditionalObstacles);
805 if (!GEOSisSimple(finalWalkableAreas)) {
806 throw ProcessError(
TL(
"Union of walkable areas minus union of obstacles is not a simple polygon."));
809 return finalWalkableAreas;
815 GEOSCoordSequence* coordinateSequence = GEOSCoordSeq_create((
unsigned int)shape.size(), 2);
816 for (
int i = 0; i < (int)shape.size(); i++) {
817 GEOSCoordSeq_setXY(coordinateSequence, i, shape[i].x(), shape[i].y());
819 return coordinateSequence;
826 const GEOSCoordSequence* coordinateSequence = GEOSGeom_getCoordSeq(geometry);
827 unsigned int coordinateSequenceSize;
828 GEOSCoordSeq_getSize(coordinateSequence, &coordinateSequenceSize);
831 for (
unsigned int i = 0; i < coordinateSequenceSize; i++) {
832 GEOSCoordSeq_getX(coordinateSequence, i, &x);
833 GEOSCoordSeq_getY(coordinateSequence, i, &y);
834 coordinateVector.push_back(
Position(x, y));
836 return coordinateVector;
840 std::vector<JPS_Point>
842 std::vector<JPS_Point> pointVector;
843 const GEOSCoordSequence* coordinateSequence = GEOSGeom_getCoordSeq(geometry);
844 unsigned int coordinateSequenceSize;
845 GEOSCoordSeq_getSize(coordinateSequence, &coordinateSequenceSize);
849 for (
unsigned int i = 0; i < coordinateSequenceSize - 1; i++) {
850 GEOSCoordSeq_getX(coordinateSequence, i, &x);
851 GEOSCoordSeq_getY(coordinateSequence, i, &y);
852 pointVector.push_back({x, y});
861 GEOSGeometry* linearRingAsPolygon = GEOSGeom_createPolygon(GEOSGeom_clone(linearRing),
nullptr, 0);
862 GEOSArea(linearRingAsPolygon, &area);
863 GEOSGeom_destroy(linearRingAsPolygon);
876 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
880 std::vector<PositionVector> holes;
881 int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
882 if (nbrInteriorRings != -1) {
883 for (
int k = 0; k < nbrInteriorRings; k++) {
884 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
898 nbrComponents = GEOSGetNumGeometries(polygon);
899 const GEOSGeometry* largestComponent =
nullptr;
902 for (
int i = 0; i < nbrComponents; i++) {
903 const GEOSGeometry* componentPolygon = GEOSGetGeometryN(polygon, i);
905 GEOSArea(componentPolygon, &area);
907 if (area > maxArea) {
909 largestComponent = componentPolygon;
912 return largestComponent;
918 JPS_GeometryBuilder geometryBuilder = JPS_GeometryBuilder_Create();
921 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
923 JPS_GeometryBuilder_AddAccessibleArea(geometryBuilder, exteriorCoordinates.data(), exteriorCoordinates.size());
926 int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
927 if (nbrInteriorRings != -1) {
928 for (
int k = 0; k < nbrInteriorRings; k++) {
929 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
933 JPS_GeometryBuilder_ExcludeFromAccessibleArea(geometryBuilder, holeCoordinates.data(), holeCoordinates.size());
938 JPS_ErrorMessage message =
nullptr;
939 JPS_Geometry geometry = JPS_GeometryBuilder_Build(geometryBuilder, &message);
940 if (geometry ==
nullptr) {
941 const std::string error =
TLF(
"Error while generating geometry: %", JPS_ErrorMessage_GetMessage(message));
942 JPS_ErrorMessage_Free(message);
945 JPS_GeometryBuilder_Free(geometryBuilder);
952 GEOSGeometry* polygonGeoCoordinates =
nullptr;
953 if (useGeoCoordinates) {
954 const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
956 for (
Position& position : exteriorPoints) {
959 const int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
960 std::vector<GEOSGeometry*> holeRings;
961 if (nbrInteriorRings != -1) {
962 for (
int k = 0; k < nbrInteriorRings; k++) {
963 const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
965 for (
Position& position : holePoints) {
969 GEOSGeometry* holeRing = GEOSGeom_createLinearRing(holeRingCoords);
970 holeRings.push_back(holeRing);
974 GEOSGeometry* exteriorRing = GEOSGeom_createLinearRing(exteriorRingCoords);
975 polygonGeoCoordinates = GEOSGeom_createPolygon(exteriorRing, holeRings.data(), nbrInteriorRings);
977 std::ofstream dumpFile;
978 dumpFile.open(filename);
979 GEOSWKTWriter* writer = GEOSWKTWriter_create();
980 char* wkt = GEOSWKTWriter_write(writer, polygonGeoCoordinates ==
nullptr ? polygon : polygonGeoCoordinates);
981 dumpFile << wkt << std::endl;
984 GEOSWKTWriter_destroy(writer);
985 GEOSGeom_destroy(polygonGeoCoordinates);
997 JPS_ErrorMessage message =
nullptr;
998 JPS_StageId waitingStage = 0;
1001 const double offset = 2 * radius + POSITION_EPS;
1002 const double lonOffset = entry ? radius + NUMERICAL_EPS : shape.
length() - radius - NUMERICAL_EPS;
1004 std::vector<JPS_Point> points{{wPos.
x(), wPos.
y()}};
1005 for (
double latOff = offset; latOff < crossing->
getWidth() / 2. - offset; latOff += offset) {
1009 points.push_back({wPosOff.
x(), wPosOff.
y()});
1012 points.push_back({wPosOff2.
x(), wPosOff2.
y()});
1016 center = crossing->
getIncomingLanes().front().lane->getShape().getCentroid();
1018 if (!entry && crossing->
getLinkCont().size() == 1 && crossing->
getLinkCont().front()->getLane()->isWalkingArea()) {
1019 center = crossing->
getLinkCont().front()->getLane()->getShape().getCentroid();
1022 GEOSGeometry* point = GEOSGeom_createPointFromXY(center.
x(), center.
y());
1024 points.push_back({center.
x(), center.
y()});
1026 GEOSGeom_destroy(point);
1028 waitingStage = JPS_Simulation_AddStageWaitingSet(
myJPSSimulation, points.data(), points.size(), &message);
1029 if (message !=
nullptr) {
1030 const std::string error =
TLF(
"Error while adding waiting set for % on '%': %",
1031 entry ?
"entry" :
"exit", crossing->
getID(), JPS_ErrorMessage_GetMessage(message));
1032 JPS_ErrorMessage_Free(message);
1035 const auto proxy = JPS_Simulation_GetWaitingSetProxy(
myJPSSimulation, waitingStage, &message);
1036 JPS_WaitingSetProxy_SetWaitingSetState(proxy, JPS_WaitingSet_Inactive);
1039 (*myPythonScript) <<
"ws = simulation.add_waiting_set_stage([";
1040 for (
const JPS_Point& p : points) {
1041 (*myPythonScript) <<
"(" << p.x <<
"," << p.y <<
"),";
1043 (*myPythonScript) <<
"])\nsimulation.get_stage(ws).state = jps.stages.WaitingSetState.INACTIVE\n";
1045 return waitingStage;
1051 initGEOS(
nullptr,
nullptr);
1054 int nbrComponents = 0;
1055 double maxArea = 0.0;
1056 double totalArea = 0.0;
1058 if (nbrComponents > 1) {
1059 WRITE_WARNINGF(
TL(
"While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
1060 nbrComponents, maxArea / totalArea * 100.0,
"%");
1062 #ifdef DEBUG_GEOMETRY_GENERATION
1065 const std::string filename = oc.
getString(
"pedestrian.jupedsim.wkt");
1066 if (!filename.empty()) {
1074 JPS_ErrorMessage message =
nullptr;
1076 double strengthGeometryRepulsion = oc.
getFloat(
"pedestrian.jupedsim.strength-geometry-repulsion");
1077 double rangeGeometryRepulsion = oc.
getFloat(
"pedestrian.jupedsim.range-geometry-repulsion");
1079 if (oc.
isDefault(
"pedestrian.jupedsim.strength-geometry-repulsion") && oc.
isDefault(
"pedestrian.jupedsim.range-geometry-repulsion")) {
1080 WRITE_MESSAGE(
TL(
"Adapting geometry repulsion default values for jupedsim timestep of 0.02."));
1081 strengthGeometryRepulsion = 35.;
1082 rangeGeometryRepulsion = 0.019;
1085 if (oc.
getString(
"pedestrian.jupedsim.model") ==
"CollisionFreeSpeed") {
1086 JPS_CollisionFreeSpeedModelBuilder modelBuilder = JPS_CollisionFreeSpeedModelBuilder_Create(oc.
getFloat(
"pedestrian.jupedsim.strength-neighbor-repulsion"),
1087 oc.
getFloat(
"pedestrian.jupedsim.range-neighbor-repulsion"),
1088 strengthGeometryRepulsion, rangeGeometryRepulsion);
1089 myJPSModel = JPS_CollisionFreeSpeedModelBuilder_Build(modelBuilder, &message);
1090 JPS_CollisionFreeSpeedModelBuilder_Free(modelBuilder);
1096 const std::string error =
TLF(
"Error creating the pedestrian model: %", JPS_ErrorMessage_GetMessage(message));
1097 JPS_ErrorMessage_Free(message);
1102 const std::string error =
TLF(
"Error creating the simulation: %", JPS_ErrorMessage_GetMessage(message));
1103 JPS_ErrorMessage_Free(message);
1108 const SUMOPolygon*
const poly = polygonWithID.second;
1110 std::vector<JPS_Point> areaBoundary;
1112 areaBoundary.push_back({p.x(), p.y()});
1115 if (areaBoundary.back().x == areaBoundary.front().x && areaBoundary.back().y == areaBoundary.front().y) {
1116 areaBoundary.pop_back();
1125 (*myPythonScript) <<
"import jupedsim as jps\nimport shapely\n\n"
1126 "with open('" << filename <<
"') as f: geom = shapely.from_wkt(f.read())\n"
1127 "simulation = jps.Simulation(dt=" <<
STEPS2TIME(
myJPSDeltaT) <<
", model=jps.CollisionFreeSpeedModel(), geometry=geom,\n"
1128 "trajectory_writer=jps.SqliteTrajectoryWriter(output_file='out.sql'))\n";
1132 crossing.second.first =
addWaitingSet(crossing.first,
true);
1133 crossing.second.second =
addWaitingSet(crossing.first,
false);
1142 JPS_JourneyId journeyId, JPS_StageId stageId,
1143 const std::vector<WaypointDesc>& waypoints)
1144 : myPerson(person), myStage(stage), myJourneyId(journeyId), myStageId(stageId), myWaypoints(waypoints),
1145 myAgentId(0), myPosition(0, 0), myAngle(0), myWaitingToEnter(true) {
1151 const std::vector<WaypointDesc>& waypoints) {
1152 if (myStage !=
nullptr) {
1153 myStage->setPState(
nullptr);
1156 myJourneyId = journeyId;
1157 myStageId = stageId;
1158 myWaypoints = waypoints;
1172 myPosition.set(x, y);
1177 myPreviousPosition = previousPosition;
1208 myLanePosition = lanePosition;
1213 return myLanePosition;
1239 return offset < (int)myWaypoints.size() ? &myWaypoints[offset] :
nullptr;
std::vector< const MSEdge * > ConstMSEdgeVector
#define WRITE_WARNINGF(...)
#define WRITE_MESSAGEF(...)
#define WRITE_ERRORF(...)
#define WRITE_MESSAGE(msg)
#define WRITE_WARNING(msg)
#define PROGRESS_DONE_MESSAGE()
#define PROGRESS_BEGIN_MESSAGE(msg)
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
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.
const double SUMO_const_laneWidth
#define UNUSED_PARAMETER(x)
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
A class that stores a 2D geometrical boundary.
double ymin() const
Returns minimum y-coordinate.
double xmin() const
Returns minimum x-coordinate.
double ymax() const
Returns maximum y-coordinate.
double xmax() const
Returns maximum x-coordinate.
void cartesian2geo(Position &cartesian) const
Converts the given cartesian (shifted) position to its geo (lat/long) representation.
static const GeoConvHelper & getFinal()
the coordinate transformation for writing the location element and for tracking the original coordina...
const MSEdgeVector & getEdges() const
Returns loaded edges.
A road/street connecting two junctions.
bool isNormal() const
return whether this edge is an internal edge
const MSJunction * getFromJunction() const
bool isTazConnector() const
const MSJunction * getToJunction() const
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
The base class for an intersection.
const ConstMSEdgeVector & getIncoming() const
const PositionVector & getShape() const
Returns this junction's shape.
const ConstMSEdgeVector & getOutgoing() const
Representation of a lane in the micro simulation.
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
double getSpeedLimit() const
Returns the lane's maximum allowed speed.
const PositionVector * getOutlineShape() const
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
MSEdge & getEdge() const
Returns the lane's edge.
double getWidth() const
Returns the lane's width.
virtual const PositionVector & getShape(bool) const
The simulated network and simulation perfomer.
MSPedestrianRouter & getPedestrianRouter(const int rngIndex, const MSEdgeVector &prohibited=MSEdgeVector()) const
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
ShapeContainer & getShapeContainer()
Returns the shapes container.
MSJunctionControl & getJunctionControl()
Returns the junctions control.
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
MSEdgeControl & getEdgeControl()
Returns the edge control.
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
bool hasInternalLinks() const
return whether the network contains internal links
const NamedObjectCont< MSStoppingPlace * > & getStoppingPlaces(SumoXMLTag category) const
Holds pedestrian state and performs updates.
JPS_StageId getStageId() const
first stage of the journey
void setPosition(double x, double y)
void setAngle(double angle)
JPS_AgentId getAgentId() const
MSPerson * getPerson() const
void setStage(MSStageMoving *const stage)
SUMOTime getWaitingTime(const MSStageMoving &stage, SUMOTime now) const override
return the time the transportable spent standing
double getEdgePos(const MSStageMoving &stage, SUMOTime now) const override
return the offset from the start of the current edge measured in its natural direction
double getSpeed(const MSStageMoving &stage) const override
return the current speed of the transportable
bool isWaitingToEnter() const
void setAgentId(JPS_AgentId id)
const MSPModel_JuPedSim::WaypointDesc * getNextWaypoint(const int offset=0) const
void setPreviousPosition(Position previousPosition)
bool advanceNextWaypoint()
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
int getDirection(const MSStageMoving &stage, SUMOTime now) const override
return the walking direction (FORWARD, BACKWARD)
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 &stage, SUMOTime now) const override
return the network coordinate of the transportable
double getAngle(const MSStageMoving &stage, SUMOTime now) const override
return the direction in which the transportable faces in degrees
MSStageMoving * getStage() const
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)
JPS_OperationalModel myJPSModel
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)
int myNumActivePedestrians
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.
bool myHaveAdditionalWalkableAreas
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
static const int GEOS_QUADRANT_SEGMENTS
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
int getActiveNumber() override
return the number of active objects
bool usingInternalLanes() override
whether movements on intersections are modelled
static const int BACKWARD
static const double RANDOM_POS_LAT
magic value to encode randomized lateral offset for persons when starting a walk
static const int UNDEFINED_DIRECTION
static const double UNSPECIFIED_POS_LAT
the default lateral offset for persons when starting a walk
double getImpatience() const
const MSEdge * getDestination() const
returns the destination edge
virtual double getArrivalPos() const
virtual const MSEdge * getEdge() const
Returns the current edge.
ConstMSEdgeVector getEdges() const
the edges of the current stage
void setPState(MSTransportableStateAdapter *pstate)
const std::vector< const MSEdge * >::iterator getRouteStep() const
double getDepartPosLat() const
const MSEdge * getEdge() const
Returns the current edge.
virtual const MSEdge * getNextRouteEdge() const =0
const std::vector< const MSEdge * > & getRoute() const
double getDepartPos() 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.
const std::vector< Carriage * > & getCarriages() const
void computeDoorPositions()
compute door positions on demand and fills the carriage structures
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
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
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.
MSStage * getCurrentStage() const
Return the current stage.
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
Representation of a vehicle in the micro simulation.
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.
T get(const std::string &id) const
Retrieves an item.
A storage for options typed value containers)
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.
void setx(double x)
set position x
static const Position INVALID
used to indicate that a position is valid
double distanceTo2D(const Position &p2) const
returns the euclidean distance in the x-y-plane
void norm2D()
Normalizes the given vector.
double x() const
Returns the x-position.
double length2D() const
Computes the length of the given vector.
void sety(double y)
set position y
double y() const
Returns the y-position.
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.
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.
Representation of a vehicle.
DepartPosDefinition departPosProcedure
Information how the vehicle shall choose the departure position.
const Polygons & getPolygons() const
Returns all polygons.
virtual bool removePolygon(const std::string &id, bool useLock=true)
Removes a polygon from the container.
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.
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 ¤tRoute, int routeIndex, SUMOVehicleClass vClass, bool setLateralPos, double &bestDistance, MSLane **lane, double &lanePos, int &routeOffset)
Structure that keeps data related to vanishing areas (and other types of areas).