Skip to content

Commit 953ae8d

Browse files
authored
Merge pull request #390 from physycom/roadtype
Add `RoadType` as Road attribute
2 parents 3db4ecb + 42221a5 commit 953ae8d

File tree

4 files changed

+108
-2
lines changed

4 files changed

+108
-2
lines changed

src/dsf/dsf.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
static constexpr uint8_t DSF_VERSION_MAJOR = 4;
88
static constexpr uint8_t DSF_VERSION_MINOR = 6;
9-
static constexpr uint8_t DSF_VERSION_PATCH = 1;
9+
static constexpr uint8_t DSF_VERSION_PATCH = 2;
1010

1111
static auto const DSF_VERSION =
1212
std::format("{}.{}.{}", DSF_VERSION_MAJOR, DSF_VERSION_MINOR, DSF_VERSION_PATCH);

src/dsf/mobility/Road.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
#include <string>
99

1010
namespace dsf::mobility {
11+
enum class RoadType : std::uint8_t {
12+
HIGHWAY = 0,
13+
PRIMARY = 1,
14+
SECONDARY = 2,
15+
TERTIARY = 3,
16+
RESIDENTIAL = 4,
17+
};
18+
19+
/// @brief The Road class represents a road in the network.
1120
class Road : public Edge {
1221
protected:
1322
static double m_meanVehicleLength;
@@ -19,6 +28,7 @@ namespace dsf::mobility {
1928
std::string m_name;
2029
int m_priority;
2130
std::set<Id> m_forbiddenTurns; // Stores the forbidden turns (road ids)
31+
std::optional<RoadType> m_roadType{std::nullopt};
2232

2333
public:
2434
/// @brief Construct a new Road object
@@ -69,6 +79,9 @@ namespace dsf::mobility {
6979
/// @brief Replace the road's forbidden turns with the given set
7080
/// @param forbiddenTurns The set of forbidden turns
7181
void setForbiddenTurns(std::set<Id> const& forbiddenTurns);
82+
/// @brief Set the road type
83+
/// @param roadType The road type
84+
inline void setRoadType(RoadType roadType) { m_roadType = roadType; }
7285

7386
/// @brief Get the length, in meters
7487
/// @return double The length, in meters
@@ -96,6 +109,9 @@ namespace dsf::mobility {
96109
/// @details The forbidden turns are the road ids that are not allowed to be used by the agents
97110
/// when they are on the road.
98111
inline auto const& forbiddenTurns() const noexcept { return m_forbiddenTurns; }
112+
/// @brief Get the road type
113+
/// @return std::optional<RoadType> The road type
114+
inline auto roadType() const noexcept { return m_roadType; }
99115
/// @brief Get the road's turn direction given the previous road angle
100116
/// @param previousStreetAngle The angle of the previous road
101117
/// @return Direction The turn direction

src/dsf/mobility/RoadNetwork.cpp

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ namespace dsf::mobility {
4646
auto const streetId = csvReader.GetCell<Id>("id", i);
4747
auto const dLength = csvReader.GetCell<double>("length", i);
4848
auto const name = csvReader.GetCell<std::string>("name", i);
49+
auto strType = csvReader.GetCell<std::string>("type", i);
4950
geometry::PolyLine polyline;
5051
if (bHasGeometry) {
5152
polyline = geometry::PolyLine(csvReader.GetCell<std::string>("geometry", i));
@@ -81,6 +82,24 @@ namespace dsf::mobility {
8182
name,
8283
polyline));
8384

85+
if (!strType.empty()) {
86+
std::transform(
87+
strType.begin(), strType.end(), strType.begin(), [](unsigned char c) {
88+
return std::tolower(c);
89+
});
90+
if (strType.find("motorway") != std::string::npos) {
91+
edge(streetId)->setRoadType(RoadType::HIGHWAY);
92+
} else if (strType.find("primary") != std::string::npos) {
93+
edge(streetId)->setRoadType(RoadType::PRIMARY);
94+
} else if (strType.find("secondary") != std::string::npos) {
95+
edge(streetId)->setRoadType(RoadType::SECONDARY);
96+
} else if (strType.find("tertiary") != std::string::npos) {
97+
edge(streetId)->setRoadType(RoadType::TERTIARY);
98+
} else if (strType.find("residential") != std::string::npos) {
99+
edge(streetId)->setRoadType(RoadType::RESIDENTIAL);
100+
}
101+
}
102+
84103
if (bHasCoilcode) {
85104
auto strCoilCode = csvReader.GetCell<std::string>("coilcode", i);
86105
// Make this lowercase
@@ -175,7 +194,7 @@ namespace dsf::mobility {
175194
std::istreambuf_iterator<char>());
176195
simdjson::dom::parser parser;
177196
simdjson::dom::element root;
178-
auto error = parser.parse(json_str).get(root);
197+
auto error = parser.parse(simdjson::padded_string(json_str)).get(root);
179198
if (error) {
180199
throw std::runtime_error("Failed to parse JSON: " +
181200
std::string(simdjson::error_message(error)));
@@ -201,6 +220,31 @@ namespace dsf::mobility {
201220
auto const& edge_length =
202221
static_cast<double>(edge_properties["length"].get_double());
203222

223+
std::string strType{""};
224+
switch (edge_properties["type"].type()) {
225+
case simdjson::dom::element_type::STRING:
226+
strType =
227+
static_cast<std::string>(edge_properties["type"].get_string().value());
228+
break;
229+
case simdjson::dom::element_type::ARRAY: {
230+
auto type_array = edge_properties["type"].get_array().value();
231+
for (auto const& type_elem : type_array) {
232+
if (!type_elem.is_string()) {
233+
spdlog::warn("Edge {} type array contains non-string element", edge_id);
234+
continue;
235+
}
236+
strType += static_cast<std::string>(type_elem.get_string().value()) + '|';
237+
}
238+
if (!strType.empty()) {
239+
strType.pop_back(); // Remove last '|'
240+
}
241+
break;
242+
}
243+
default:
244+
spdlog::warn("Edge {} type is of unexpected type", edge_id);
245+
break;
246+
}
247+
204248
// Robust extraction for maxspeed
205249
double edge_maxspeed = 30.0;
206250
if (!edge_properties["maxspeed"].is_null()) {
@@ -245,6 +289,23 @@ namespace dsf::mobility {
245289
edge_lanes,
246290
name,
247291
geometry));
292+
if (!strType.empty()) {
293+
std::transform(
294+
strType.begin(), strType.end(), strType.begin(), [](unsigned char c) {
295+
return std::tolower(c);
296+
});
297+
if (strType.find("motorway") != std::string::npos) {
298+
edge(edge_id)->setRoadType(RoadType::HIGHWAY);
299+
} else if (strType.find("primary") != std::string::npos) {
300+
edge(edge_id)->setRoadType(RoadType::PRIMARY);
301+
} else if (strType.find("secondary") != std::string::npos) {
302+
edge(edge_id)->setRoadType(RoadType::SECONDARY);
303+
} else if (strType.find("tertiary") != std::string::npos) {
304+
edge(edge_id)->setRoadType(RoadType::TERTIARY);
305+
} else if (strType.find("residential") != std::string::npos) {
306+
edge(edge_id)->setRoadType(RoadType::RESIDENTIAL);
307+
}
308+
}
248309
// Check if there is coilcode property
249310
if (!edge_properties.at_key("coilcode").error()) {
250311
auto const& epCoilCode = edge_properties["coilcode"];

test/mobility/Test_graph.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,35 @@ TEST_CASE("RoadNetwork") {
159159
CHECK_EQ(graph.nRoundabouts(), 1);
160160
CHECK_EQ(graph.nTrafficLights(), 0);
161161
}
162+
THEN("Road types are set") {
163+
int nHighways = 0, nPrimary = 0, nSecondary = 0, nTertiary = 0,
164+
nResidential = 0;
165+
for (auto const& [_, pEdge] : graph.edges()) {
166+
if (!pEdge->roadType().has_value()) {
167+
continue;
168+
}
169+
switch (pEdge->roadType().value()) {
170+
case RoadType::HIGHWAY:
171+
++nHighways;
172+
break;
173+
case RoadType::PRIMARY:
174+
++nPrimary;
175+
break;
176+
case RoadType::SECONDARY:
177+
++nSecondary;
178+
break;
179+
case RoadType::TERTIARY:
180+
++nTertiary;
181+
break;
182+
case RoadType::RESIDENTIAL:
183+
++nResidential;
184+
break;
185+
default:
186+
break;
187+
}
188+
}
189+
CHECK_GT(nHighways + nPrimary + nSecondary + nTertiary + nResidential, 0);
190+
}
162191
RoadNetwork graph2;
163192
graph2.importEdges((DATA_FOLDER / "postua_edges.geojson").string());
164193
THEN("Sizes are correct also with geojson") {

0 commit comments

Comments
 (0)