Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/dsf/dsf.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

static constexpr uint8_t DSF_VERSION_MAJOR = 4;
static constexpr uint8_t DSF_VERSION_MINOR = 6;
static constexpr uint8_t DSF_VERSION_PATCH = 1;
static constexpr uint8_t DSF_VERSION_PATCH = 2;

static auto const DSF_VERSION =
std::format("{}.{}.{}", DSF_VERSION_MAJOR, DSF_VERSION_MINOR, DSF_VERSION_PATCH);
Expand Down
16 changes: 16 additions & 0 deletions src/dsf/mobility/Road.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@
#include <string>

namespace dsf::mobility {
enum class RoadType : std::uint8_t {
HIGHWAY = 0,
PRIMARY = 1,
SECONDARY = 2,
TERTIARY = 3,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
RESIDENTIAL = 4,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note

MISRA 12.3 rule
};

/// @brief The Road class represents a road in the network.
class Road : public Edge {
protected:
static double m_meanVehicleLength;
Expand All @@ -19,6 +28,7 @@
std::string m_name;
int m_priority;
std::set<Id> m_forbiddenTurns; // Stores the forbidden turns (road ids)
std::optional<RoadType> m_roadType{std::nullopt};

public:
/// @brief Construct a new Road object
Expand Down Expand Up @@ -69,6 +79,9 @@
/// @brief Replace the road's forbidden turns with the given set
/// @param forbiddenTurns The set of forbidden turns
void setForbiddenTurns(std::set<Id> const& forbiddenTurns);
/// @brief Set the road type
/// @param roadType The road type
inline void setRoadType(RoadType roadType) { m_roadType = roadType; }

/// @brief Get the length, in meters
/// @return double The length, in meters
Expand Down Expand Up @@ -96,6 +109,9 @@
/// @details The forbidden turns are the road ids that are not allowed to be used by the agents
/// when they are on the road.
inline auto const& forbiddenTurns() const noexcept { return m_forbiddenTurns; }
/// @brief Get the road type
/// @return std::optional<RoadType> The road type
inline auto roadType() const noexcept { return m_roadType; }
/// @brief Get the road's turn direction given the previous road angle
/// @param previousStreetAngle The angle of the previous road
/// @return Direction The turn direction
Expand Down
63 changes: 62 additions & 1 deletion src/dsf/mobility/RoadNetwork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ namespace dsf::mobility {
auto const streetId = csvReader.GetCell<Id>("id", i);
auto const dLength = csvReader.GetCell<double>("length", i);
auto const name = csvReader.GetCell<std::string>("name", i);
auto strType = csvReader.GetCell<std::string>("type", i);
geometry::PolyLine polyline;
if (bHasGeometry) {
polyline = geometry::PolyLine(csvReader.GetCell<std::string>("geometry", i));
Expand Down Expand Up @@ -81,6 +82,24 @@ namespace dsf::mobility {
name,
polyline));

if (!strType.empty()) {
std::transform(
strType.begin(), strType.end(), strType.begin(), [](unsigned char c) {
return std::tolower(c);
});
if (strType.find("motorway") != std::string::npos) {
edge(streetId)->setRoadType(RoadType::HIGHWAY);
} else if (strType.find("primary") != std::string::npos) {
edge(streetId)->setRoadType(RoadType::PRIMARY);
} else if (strType.find("secondary") != std::string::npos) {
edge(streetId)->setRoadType(RoadType::SECONDARY);
} else if (strType.find("tertiary") != std::string::npos) {
edge(streetId)->setRoadType(RoadType::TERTIARY);
} else if (strType.find("residential") != std::string::npos) {
edge(streetId)->setRoadType(RoadType::RESIDENTIAL);
}
}

if (bHasCoilcode) {
auto strCoilCode = csvReader.GetCell<std::string>("coilcode", i);
// Make this lowercase
Expand Down Expand Up @@ -175,7 +194,7 @@ namespace dsf::mobility {
std::istreambuf_iterator<char>());
simdjson::dom::parser parser;
simdjson::dom::element root;
auto error = parser.parse(json_str).get(root);
auto error = parser.parse(simdjson::padded_string(json_str)).get(root);
if (error) {
throw std::runtime_error("Failed to parse JSON: " +
std::string(simdjson::error_message(error)));
Expand All @@ -201,6 +220,31 @@ namespace dsf::mobility {
auto const& edge_length =
static_cast<double>(edge_properties["length"].get_double());

std::string strType{""};
switch (edge_properties["type"].type()) {
case simdjson::dom::element_type::STRING:
strType =
static_cast<std::string>(edge_properties["type"].get_string().value());
break;
case simdjson::dom::element_type::ARRAY: {
auto type_array = edge_properties["type"].get_array().value();
for (auto const& type_elem : type_array) {
if (!type_elem.is_string()) {
spdlog::warn("Edge {} type array contains non-string element", edge_id);
continue;
}
strType += static_cast<std::string>(type_elem.get_string().value()) + '|';
}
if (!strType.empty()) {
strType.pop_back(); // Remove last '|'
}
break;
}
default:
spdlog::warn("Edge {} type is of unexpected type", edge_id);
break;
}

// Robust extraction for maxspeed
double edge_maxspeed = 30.0;
if (!edge_properties["maxspeed"].is_null()) {
Expand Down Expand Up @@ -245,6 +289,23 @@ namespace dsf::mobility {
edge_lanes,
name,
geometry));
if (!strType.empty()) {
std::transform(
strType.begin(), strType.end(), strType.begin(), [](unsigned char c) {
return std::tolower(c);
});
if (strType.find("motorway") != std::string::npos) {
edge(edge_id)->setRoadType(RoadType::HIGHWAY);
} else if (strType.find("primary") != std::string::npos) {
edge(edge_id)->setRoadType(RoadType::PRIMARY);
} else if (strType.find("secondary") != std::string::npos) {
edge(edge_id)->setRoadType(RoadType::SECONDARY);
} else if (strType.find("tertiary") != std::string::npos) {
edge(edge_id)->setRoadType(RoadType::TERTIARY);
} else if (strType.find("residential") != std::string::npos) {
edge(edge_id)->setRoadType(RoadType::RESIDENTIAL);
}
}
// Check if there is coilcode property
if (!edge_properties.at_key("coilcode").error()) {
auto const& epCoilCode = edge_properties["coilcode"];
Expand Down
29 changes: 29 additions & 0 deletions test/mobility/Test_graph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,35 @@
CHECK_EQ(graph.nRoundabouts(), 1);
CHECK_EQ(graph.nTrafficLights(), 0);
}
THEN("Road types are set") {
int nHighways = 0, nPrimary = 0, nSecondary = 0, nTertiary = 0,

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note test

MISRA 12.3 rule
nResidential = 0;
for (auto const& [_, pEdge] : graph.edges()) {

Check notice

Code scanning / Cppcheck (reported by Codacy)

MISRA 12.3 rule Note test

MISRA 12.3 rule
if (!pEdge->roadType().has_value()) {
continue;
}
switch (pEdge->roadType().value()) {
case RoadType::HIGHWAY:
++nHighways;
break;
case RoadType::PRIMARY:
++nPrimary;
break;
case RoadType::SECONDARY:
++nSecondary;
break;
case RoadType::TERTIARY:
++nTertiary;
break;
case RoadType::RESIDENTIAL:
++nResidential;
break;
default:
break;
}
}
CHECK_GT(nHighways + nPrimary + nSecondary + nTertiary + nResidential, 0);
}
RoadNetwork graph2;
graph2.importEdges((DATA_FOLDER / "postua_edges.geojson").string());
THEN("Sizes are correct also with geojson") {
Expand Down
Loading