22 std::string MakeId(
const char *prefix, std::size_t index) {
23 std::ostringstream out;
24 out << prefix << index;
31 int ClassRank(
const std::string &
highway) {
35 if (
highway ==
"secondary" ||
highway ==
"secondary_link")
return 4;
37 if (
highway ==
"unclassified" ||
highway ==
"residential")
return 2;
38 if (
highway ==
"living_street")
return 1;
45 double limit,
double &out_s,
double &out_t) {
46 const Road *best =
nullptr;
47 double best_distance = limit;
48 for (
const Road &
road : model.roads) {
49 if (
road.junction_id.has_value() ||
road.reference_line.size() < 2u) {
62 const double dx = geom::bg::get<0>(
point) - geom::bg::get<0>(on);
63 const double dy = geom::bg::get<1>(
point) - geom::bg::get<1>(on);
70 void AddSignal(TwinModelData &model,
SignalKind kind,
const Road &
road,
72 std::optional<double> value,
long long node_id) {
74 signal.id = MakeId(
"signal_", model.signals.size());
76 signal.road_id =
road.id;
79 signal.position = position;
82 signal.osm_node_id = node_id;
83 signal.orientation = (t < 0.0) ?
"-" :
"+";
84 model.signals.push_back(std::move(signal));
100 for (
const auto &entry : osm.
nodes) {
108 if (*
highway ==
"traffic_signals") {
113 }
else if (*
highway ==
"stop") {
116 }
else if (*
highway ==
"give_way") {
119 }
else if (*
highway ==
"crossing") {
130 if (
road ==
nullptr) {
135 std::nullopt,
node.id);
139 std::set<std::string> signed_roads;
141 if (
road.junction_id.has_value() ||
road.lanes.empty()) {
144 const std::string *maxspeed =
FindTag(
road.tags,
"maxspeed");
145 if (maxspeed ==
nullptr) {
148 const std::optional<double> speed =
ParseMaxSpeed(*maxspeed);
149 if (!speed.has_value() || signed_roads.count(
road.id) != 0u) {
152 signed_roads.insert(
road.id);
163 std::set<std::string> approaches;
165 approaches.insert(connection.incoming_road);
167 for (
const std::string &
road_id : approaches) {
169 if (
road ==
nullptr ||
road->reference_line.size() < 2u) {
184 std::set<std::string> signalised;
188 signalised.insert(signal.road_id);
192 std::set<std::string> approaches;
194 approaches.insert(connection.incoming_road);
196 if (approaches.size() < 2u) {
200 bool any_signalised =
false;
201 for (
const std::string &
road_id : approaches) {
203 if (
road ==
nullptr) {
206 best = std::max(best, ClassRank(
road->highway));
207 any_signalised = any_signalised || (signalised.count(
road_id) != 0u);
209 if (any_signalised || best < 0) {
213 for (
const std::string &
road_id : approaches) {
215 if (
road !=
nullptr && ClassRank(
road->highway) != best) {
219 for (
const std::string &
road_id : approaches) {
221 if (
road ==
nullptr ||
road->reference_line.size() < 2u) {
226 const bool major = mixed && ClassRank(
road->highway) == best;
229 const double at = std::max(0.0, total - 1.0);
238 std::map<std::string, std::vector<std::string>> by_junction;
245 bool touches =
false;
247 if (connection.incoming_road == signal.road_id) {
253 by_junction[
junction.id].push_back(signal.id);
258 for (
const auto &entry : by_junction) {
260 controller.
id = MakeId(
"controller_", model.
controllers.size());
265 if (std::find(entry.second.begin(), entry.second.end(), signal.id) !=
266 entry.second.end()) {
267 signal.controller_id = controller.
id;
270 model.
controllers.push_back(std::move(controller));
std::map< std::string, unsigned int > road
std::map< std::string, unsigned int > junction
WGS84 <-> local ENU metres, a transverse Mercator centred on the origin.
void ToLocal(double lon, double lat, double &x, double &y) const
double Length(const LineString &line)
Point Interpolate(const LineString &line, double s)
Point at distance s along line, shapely's LineString.interpolate.
double HeadingAt(const LineString &line, double s)
Heading of line at distance s, in radians.
bg::model::linestring< Point > LineString
double Hypot(const Point &a, const Point &b)
bg::model::d2::point_xy< double > Point
Point To2D(const Point3 &p)
double Project(const LineString &line, const Point &p)
Distance along line of the projection of p, shapely's LineString.project.
SignalKind
OpenDRIVE type/subtype follow road/SignalType.h; the crosswalk is not a signal in CARLA but an <objec...
std::optional< double > ParseMaxSpeed(const std::string &value)
Parse an OSM maxspeed value into m/s; "50", "50 km/h" and "30 mph".
const std::string * FindTag(const Tags &tags, const std::string &key)
void BuildSignals(const OsmData &osm, const LocalFrame &frame, TwinModelData &model, const SignalOptions &options)
Read traffic lights, stop and give-way signs, speed limits and crossings out of the OSM tags and atta...
std::vector< std::string > signal_ids
std::map< long long, OsmNode > nodes
bool generate_traffic_lights
bool all_junctions_traffic_lights
double snap_m
A signal node is bound to the nearest road end within this distance.
Everything the OpenDRIVE writer reads.
std::vector< Signal > signals
std::vector< Road > roads
const Road * FindRoad(const std::string &id) const
std::vector< Controller > controllers
std::vector< Junction > junctions