Skip to content

Commit

Permalink
[JuPedSim] Refactored code related to JPS_GeometryBuilder.
Browse files Browse the repository at this point in the history
  • Loading branch information
bcoueraud87 authored and namdre committed Feb 13, 2024
1 parent ee6dc91 commit acc75c4
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 88 deletions.
155 changes: 69 additions & 86 deletions src/microsim/transportables/MSPModel_JuPedSim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ MSPModel_JuPedSim::~MSPModel_JuPedSim() {
JPS_Simulation_Free(myJPSSimulation);
JPS_OperationalModel_Free(myJPSModel);
JPS_Geometry_Free(myJPSGeometry);
JPS_GeometryBuilder_Free(myJPSGeometryBuilder);

if (myJPSGeometryWithTrains != nullptr) {
JPS_Geometry_Free(myJPSGeometryWithTrains);
}

GEOSGeom_destroy(myGEOSPedestrianNetwork);
finishGEOS();
}
Expand Down Expand Up @@ -721,88 +723,62 @@ MSPModel_JuPedSim::getHoleArea(const GEOSGeometry* hole) {
return area;
}


void
MSPModel_JuPedSim::preparePolygonForDrawing(const GEOSGeometry* polygon, const std::string& polygonId) {
const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
PositionVector shape = getCoordinates(exterior);
MSPModel_JuPedSim::preparePolygonForJPS(const GEOSGeometry* polygon, JPS_GeometryBuilder geometryBuilder) {
// Handle the exterior polygon.
const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
std::vector<JPS_Point> exteriorCoordinates = convertToJPSPoints(exterior);
JPS_GeometryBuilder_AddAccessibleArea(geometryBuilder, exteriorCoordinates.data(), exteriorCoordinates.size());

std::vector<PositionVector> holes;
// Handle the interior polygons (holes).
int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
if (nbrInteriorRings != -1) {
for (unsigned int k = 0; k < (unsigned int)nbrInteriorRings; k++) {
const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
double area = getHoleArea(linearRing);
if (area > GEOS_MIN_AREA) {
PositionVector hole = getCoordinates(linearRing);
holes.push_back(hole);
std::vector<JPS_Point> holeCoordinates = convertToJPSPoints(linearRing);
JPS_GeometryBuilder_ExcludeFromAccessibleArea(geometryBuilder, holeCoordinates.data(), holeCoordinates.size());
}
}

ShapeContainer& shapeContainer = myNetwork->getShapeContainer();
shapeContainer.addPolygon(polygonId, std::string("jupedsim.pedestrian_network"), RGBColor(179, 217, 255, 255), 10.0, 0.0, std::string(), false, shape, false, true, 1.0);
shapeContainer.getPolygons().get(polygonId)->setHoles(holes);
}
}


void
MSPModel_JuPedSim::preparePolygonForJPS(const GEOSGeometry* polygon) {
// Handle the exterior polygon.
const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
std::vector<JPS_Point> exteriorCoordinates = convertToJPSPoints(exterior);
JPS_GeometryBuilder_AddAccessibleArea(myJPSGeometryBuilder, exteriorCoordinates.data(), exteriorCoordinates.size());
MSPModel_JuPedSim::preparePolygonForDrawing(const GEOSGeometry* polygon, const std::string& polygonId) {
const GEOSGeometry* exterior = GEOSGetExteriorRing(polygon);
PositionVector shape = getCoordinates(exterior);

// Handle the interior polygons (holes).
std::vector<PositionVector> holes;
int nbrInteriorRings = GEOSGetNumInteriorRings(polygon);
if (nbrInteriorRings != -1) {
for (unsigned int k = 0; k < (unsigned int)nbrInteriorRings; k++) {
const GEOSGeometry* linearRing = GEOSGetInteriorRingN(polygon, k);
double area = getHoleArea(linearRing);
if (area > GEOS_MIN_AREA) {
std::vector<JPS_Point> holeCoordinates = convertToJPSPoints(linearRing);
JPS_GeometryBuilder_ExcludeFromAccessibleArea(myJPSGeometryBuilder, holeCoordinates.data(), holeCoordinates.size());
PositionVector hole = getCoordinates(linearRing);
holes.push_back(hole);
}
}
}
}


void
MSPModel_JuPedSim::dumpGeometry(const GEOSGeometry* polygon, const std::string& filename) {
std::ofstream dumpFile;
dumpFile.open(filename);
GEOSWKTWriter* writer = GEOSWKTWriter_create();
char* wkt = GEOSWKTWriter_write(writer, polygon);
dumpFile << wkt << std::endl;
dumpFile.close();
GEOSFree(wkt);
GEOSWKTWriter_destroy(writer);
ShapeContainer& shapeContainer = myNetwork->getShapeContainer();
shapeContainer.addPolygon(polygonId, std::string("jupedsim.pedestrian_network"), RGBColor(179, 217, 255, 255), 10.0, 0.0, std::string(), false, shape, false, true, 1.0);
shapeContainer.getPolygons().get(polygonId)->setHoles(holes);
}
}


void
MSPModel_JuPedSim::initialize() {
initGEOS(nullptr, nullptr);
myGEOSPedestrianNetwork = buildPedestrianNetwork(myNetwork);
int nbrConnectedComponents = GEOSGetNumGeometries(myGEOSPedestrianNetwork);

// myJPSGeometryBuilder = JPS_GeometryBuilder_Create();
// for (size_t i = 0; i < GEOSGetNumGeometries(myGEOSPedestrianNetwork); i++) {
// const GEOSGeometry* connectedComponentPolygon = GEOSGetGeometryN(myGEOSPedestrianNetwork, i);
// std::string polygonId = std::string("pedestrian_network_connected_component_") + std::to_string(i);
// preparePolygonForDrawing(connectedComponentPolygon, polygonId);
// preparePolygonForJPS(connectedComponentPolygon);
// }
// prepareAdditionalPolygonsForJPS();

JPS_Geometry
MSPModel_JuPedSim::buildJPSGeometryFromGEOSGeometry(const GEOSGeometry* polygon) {
// For the moment, JuPedSim only supports one connected component, select the one with max area.
int nbrConnectedComponents = GEOSGetNumGeometries(polygon);
const GEOSGeometry* maxAreaConnectedComponentPolygon = nullptr;
std::string maxAreaPolygonId;
double maxArea = 0.0;
double totalArea = 0.0;
for (unsigned int i = 0; i < (unsigned int)nbrConnectedComponents; i++) {
const GEOSGeometry* connectedComponentPolygon = GEOSGetGeometryN(myGEOSPedestrianNetwork, i);
const GEOSGeometry* connectedComponentPolygon = GEOSGetGeometryN(polygon, i);
std::string polygonId = std::string("jupedsim.pedestrian_network.") + std::to_string(i);
double area;
GEOSArea(connectedComponentPolygon, &area);
Expand All @@ -814,53 +790,52 @@ MSPModel_JuPedSim::initialize() {
}
}
if (nbrConnectedComponents > 1) {
WRITE_WARNINGF(TL("While generating geometry % connected components were detected, %% of total pedestrian area is covered by the first."),
WRITE_WARNINGF(TL("While generating geometry % connected components were detected, %% of total pedestrian area is covered by the largest."),
nbrConnectedComponents, maxArea / totalArea * 100.0, "%");
}
#ifdef DEBUG_GEOMETRY_GENERATION
dumpGeometry(maxAreaConnectedComponentPolygon, "pedestrianNetwork.wkt");
#endif
myJPSGeometryBuilder = JPS_GeometryBuilder_Create();
preparePolygonForJPS(maxAreaConnectedComponentPolygon);
JPS_GeometryBuilder geometryBuilder = JPS_GeometryBuilder_Create();
preparePolygonForJPS(maxAreaConnectedComponentPolygon, geometryBuilder);
preparePolygonForDrawing(maxAreaConnectedComponentPolygon, maxAreaPolygonId);

for (const auto& polygonWithID : myNetwork->getShapeContainer().getPolygons()) {
if (polygonWithID.second->getShapeType() == "jupedsim.vanishing_area") {
std::vector<JPS_Point> vanishingAreaBoundary = convertToJPSPoints(polygonWithID.second->getShape());
SUMOTime period = string2time(polygonWithID.second->getParameter("period", "1"));
myVanishingAreas.insert(std::make_pair(polygonWithID.second->getID(), VanishingAreaData{vanishingAreaBoundary, period}));
}
}

JPS_ErrorMessage message = nullptr;
myJPSGeometry = JPS_GeometryBuilder_Build(myJPSGeometryBuilder, &message);
if (myJPSGeometry == nullptr) {
const std::string error = TLF("Error creating the geometry: %", JPS_ErrorMessage_GetMessage(message));
JPS_Geometry geometry = JPS_GeometryBuilder_Build(geometryBuilder, &message);
if (geometry == nullptr) {
const std::string error = TLF("Error while generating geometry: %", JPS_ErrorMessage_GetMessage(message));
JPS_ErrorMessage_Free(message);
throw ProcessError(error);
} else {
WRITE_MESSAGE("Geometry generation for JuPedSim done.");
}

std::string model = "CollisionFreeSpeed";
double strengthNeighborRepulsion = 8.;
double rangeNeighborRepulsion = .1;
double strengthGeometryRepulsion = 5.;
double rangeGeometryRepulsion = .02;
for (const MSVehicleType* type : myNetwork->getVehicleControl().getPedestrianTypes()) {
model = type->getParameter().getParameter("jupedsim.model", model);
strengthNeighborRepulsion = type->getParameter().getDouble("jupedsim.strengthNeighborRepulsion", strengthNeighborRepulsion);
rangeNeighborRepulsion = type->getParameter().getDouble("jupedsim.rangeNeighborRepulsion", rangeNeighborRepulsion);
strengthGeometryRepulsion = type->getParameter().getDouble("jupedsim.strengthGeometryRepulsion", strengthGeometryRepulsion);
rangeGeometryRepulsion = type->getParameter().getDouble("jupedsim.rangeGeometryRepulsion", rangeGeometryRepulsion);
}
if (model == "CollisionFreeSpeed") {
JPS_CollisionFreeSpeedModelBuilder modelBuilder = JPS_CollisionFreeSpeedModelBuilder_Create(strengthNeighborRepulsion, rangeNeighborRepulsion, strengthGeometryRepulsion, rangeGeometryRepulsion);
myJPSModel = JPS_CollisionFreeSpeedModelBuilder_Build(modelBuilder, &message);
JPS_CollisionFreeSpeedModelBuilder_Free(modelBuilder);
} else {
throw ProcessError(TLF("Unknown JuPedSim model: %", model));
WRITE_MESSAGE("Geometry generation done.");
}
JPS_GeometryBuilder_Free(geometryBuilder);
return geometry;
}


void
MSPModel_JuPedSim::dumpGeometry(const GEOSGeometry* polygon, const std::string& filename) {
std::ofstream dumpFile;
dumpFile.open(filename);
GEOSWKTWriter* writer = GEOSWKTWriter_create();
char* wkt = GEOSWKTWriter_write(writer, polygon);
dumpFile << wkt << std::endl;
dumpFile.close();
GEOSFree(wkt);
GEOSWKTWriter_destroy(writer);
}


void
MSPModel_JuPedSim::initialize() {
initGEOS(nullptr, nullptr);
WRITE_MESSAGE("Generating initial JuPedSim geometry for pedestrian network...");
myGEOSPedestrianNetwork = buildPedestrianNetwork(myNetwork);
myJPSGeometry = buildJPSGeometryFromGEOSGeometry(myGEOSPedestrianNetwork);
myJPSGeometryWithTrains = nullptr;
myJPSModelBuilder = JPS_CollisionFreeSpeedModelBuilder_Create(8.0, 0.1, 5.0, 0.02);
JPS_ErrorMessage message = nullptr;
myJPSModel = JPS_CollisionFreeSpeedModelBuilder_Build(myJPSModelBuilder, &message);
if (myJPSModel == nullptr) {
const std::string error = TLF("Error creating the pedestrian model: %", JPS_ErrorMessage_GetMessage(message));
JPS_ErrorMessage_Free(message);
Expand All @@ -872,6 +847,14 @@ MSPModel_JuPedSim::initialize() {
JPS_ErrorMessage_Free(message);
throw ProcessError(error);
}
// Polygons that define vanishing areas aren't part of the regular JuPedSim geometry.
for (const auto& polygonWithID : myNetwork->getShapeContainer().getPolygons()) {
if (polygonWithID.second->getShapeType() == "jupedsim.vanishing_area") {
std::vector<JPS_Point> vanishingAreaBoundary = convertToJPSPoints(polygonWithID.second->getShape());
SUMOTime period = (SUMOTime)(1.0 / std::stod(polygonWithID.second->getParameter("frequency", "1.0"))) * 1000; // SUMOTime is in ms.
myVanishingAreas.insert(std::make_pair(polygonWithID.second->getID(), VanishingAreaData{vanishingAreaBoundary, period}));
}
}
}


Expand Down
7 changes: 5 additions & 2 deletions src/microsim/transportables/MSPModel_JuPedSim.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,9 @@ class MSPModel_JuPedSim : public MSPModel {
GEOSGeometry* myGEOSPedestrianNetwork;
bool myHaveAdditionalWalkableAreas;

JPS_GeometryBuilder myJPSGeometryBuilder;
JPS_Geometry myJPSGeometry;
JPS_Geometry myJPSGeometryWithTrains;
JPS_CollisionFreeSpeedModelBuilder myJPSModelBuilder;
JPS_OperationalModel myJPSModel;
JPS_Simulation myJPSSimulation;
struct VanishingAreaData {
Expand All @@ -167,6 +168,7 @@ class MSPModel_JuPedSim : public MSPModel {
};
std::map<std::string, VanishingAreaData> myVanishingAreas;
SUMOTime myLastRemovalTime = 0;
std::vector<SUMOTrafficObject::NumericalID> myAllStoppedTrainIDs;

static const int GEOS_QUADRANT_SEGMENTS;
static const double GEOS_MITRE_LIMIT;
Expand All @@ -188,7 +190,8 @@ class MSPModel_JuPedSim : public MSPModel {
static std::vector<JPS_Point> convertToJPSPoints(const GEOSGeometry* geometry);
static std::vector<JPS_Point> convertToJPSPoints(const PositionVector& coordinates);
static double getHoleArea(const GEOSGeometry* hole);
void preparePolygonForJPS(const GEOSGeometry* polygon, JPS_GeometryBuilder geometryBuilder);
void preparePolygonForDrawing(const GEOSGeometry* polygon, const std::string& polygonId);
void preparePolygonForJPS(const GEOSGeometry* polygon);
JPS_Geometry buildJPSGeometryFromGEOSGeometry(const GEOSGeometry* polygon);
static void dumpGeometry(const GEOSGeometry* polygon, const std::string& filename);
};

0 comments on commit acc75c4

Please sign in to comment.