scenario_simulator_v2 C++ API
traffic_light.hpp
Go to the documentation of this file.
1 // Copyright 2015 TIER IV, Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef TRAFFIC_SIMULATOR__TRAFFIC_LIGHTS__TRAFFIC_LIGHT_HPP_
16 #define TRAFFIC_SIMULATOR__TRAFFIC_LIGHTS__TRAFFIC_LIGHT_HPP_
17 
18 #include <color_names/color_names.hpp>
19 #include <cstdint>
20 #include <geometry_msgs/msg/point.hpp>
21 #include <iostream>
22 #include <limits>
23 #include <memory>
24 #include <optional>
25 #include <regex>
27 #include <set>
29 #include <stdexcept>
31 #include <tuple>
32 #include <type_traits>
33 #include <unordered_map>
34 #include <utility>
35 #include <vector>
36 
37 namespace traffic_simulator
38 {
40 {
41  struct Color
42  {
43  enum Value : std::uint8_t {
46  red,
48  } value;
49 
50  // clang-format off
51  static_assert(static_cast<std::uint8_t>(green ) == 0b0000'0000);
52  static_assert(static_cast<std::uint8_t>(yellow) == 0b0000'0001);
53  static_assert(static_cast<std::uint8_t>(red ) == 0b0000'0010);
54  static_assert(static_cast<std::uint8_t>(white ) == 0b0000'0011);
55  // clang-format on
56 
57  constexpr Color(const Value value = green) : value(value) {}
58 
59  Color(const std::string & name) : value(make(name)) {}
60 
61  static inline const std::unordered_map<std::string, Value> table{
62  std::make_pair("amber", yellow),
63  std::make_pair("green", green),
64  std::make_pair("red", red),
65  std::make_pair("white", white),
66  std::make_pair("yellow", yellow),
67 
68  // BACKWARD COMPATIBILITY
69  std::make_pair("Green", green),
70  std::make_pair("Red", red),
71  std::make_pair("Yellow", yellow),
72  };
73 
74  static auto make(const std::string & name) -> Color;
75 
76  constexpr auto is(const Color given) const { return value == given; }
77 
78  constexpr operator Value() const noexcept { return value; }
79 
80  friend auto operator>>(std::istream & is, Color & color) -> std::istream &;
81 
82  friend auto operator<<(std::ostream & os, const Color & color) -> std::ostream &;
83  };
84 
85  struct Status
86  {
87  enum Value : std::uint8_t {
92  } value;
93 
94  // clang-format off
95  static_assert(static_cast<std::uint8_t>(solid_on ) == 0b0000'0000);
96  static_assert(static_cast<std::uint8_t>(solid_off) == 0b0000'0001);
97  static_assert(static_cast<std::uint8_t>(flashing ) == 0b0000'0010);
98  static_assert(static_cast<std::uint8_t>(unknown ) == 0b0000'0011);
99  // clang-format on
100 
101  constexpr Status(const Value value = solid_on) : value(value) {}
102 
103  Status(const std::string & name) : value(make(name)) {}
104 
105  static inline const std::unordered_map<std::string, Value> table{
106  std::make_pair("solidOn", solid_on),
107  std::make_pair("solidOff", solid_off),
108  std::make_pair("flashing", flashing),
109  std::make_pair("unknown", unknown),
110 
111  // BACKWARD COMPATIBILITY
112  std::make_pair("Blank", solid_off),
113  std::make_pair("none", solid_off),
114  };
115 
116  static auto make(const std::string & name) -> Status;
117 
118  constexpr auto is(const Value given) const { return value == given; }
119 
120  constexpr operator bool() const { return value == solid_on or value == flashing; }
121 
122  constexpr operator Value() const noexcept { return value; }
123 
124  friend auto operator>>(std::istream & is, Status & status) -> std::istream &;
125 
126  friend auto operator<<(std::ostream & os, const Status & status) -> std::ostream &;
127  };
128 
129  struct Shape
130  {
131  enum class Category : std::uint8_t {
132  circle,
133  cross,
134  arrow,
135  };
136 
137  // clang-format off
138  static_assert(static_cast<std::uint8_t>(Category::circle) == 0b0000'0000);
139  static_assert(static_cast<std::uint8_t>(Category::cross ) == 0b0000'0001);
140  static_assert(static_cast<std::uint8_t>(Category::arrow ) == 0b0000'0010);
141  // clang-format on
142 
143  enum Value : std::uint16_t {
144  // clang-format off
145  circle = static_cast<std::uint8_t>(Category::circle),
146  cross = static_cast<std::uint8_t>(Category::cross ),
147  left = (0b0000'1000 << 8) | static_cast<std::uint8_t>(Category::arrow ),
148  down = (0b0000'0100 << 8) | static_cast<std::uint8_t>(Category::arrow ),
149  up = (0b0000'0010 << 8) | static_cast<std::uint8_t>(Category::arrow ),
150  right = (0b0000'0001 << 8) | static_cast<std::uint8_t>(Category::arrow ),
151  lower_left = (0b0000'1100 << 8) | static_cast<std::uint8_t>(Category::arrow ),
152  upper_left = (0b0000'1010 << 8) | static_cast<std::uint8_t>(Category::arrow ),
153  lower_right = (0b0000'0101 << 8) | static_cast<std::uint8_t>(Category::arrow ),
154  upper_right = (0b0000'0011 << 8) | static_cast<std::uint8_t>(Category::arrow ),
155  // clang-format on
156  } value;
157 
158  // clang-format off
159  static_assert(static_cast<std::uint16_t>(circle ) == 0b0000'0000'0000'0000);
160  static_assert(static_cast<std::uint16_t>(cross ) == 0b0000'0000'0000'0001);
161  static_assert(static_cast<std::uint16_t>(left ) == 0b0000'1000'0000'0010);
162  static_assert(static_cast<std::uint16_t>(down ) == 0b0000'0100'0000'0010);
163  static_assert(static_cast<std::uint16_t>(up ) == 0b0000'0010'0000'0010);
164  static_assert(static_cast<std::uint16_t>(right ) == 0b0000'0001'0000'0010);
165  static_assert(static_cast<std::uint16_t>(lower_left ) == 0b0000'1100'0000'0010);
166  static_assert(static_cast<std::uint16_t>(upper_left ) == 0b0000'1010'0000'0010);
167  static_assert(static_cast<std::uint16_t>(lower_right) == 0b0000'0101'0000'0010);
168  static_assert(static_cast<std::uint16_t>(upper_right) == 0b0000'0011'0000'0010);
169  // clang-format on
170 
171  constexpr Shape(const Value value = circle) : value(value) {}
172 
173  Shape(const std::string & name) : value(make(name)) {}
174 
175  static inline const std::unordered_map<std::string, Shape::Value> table{
176  std::make_pair("circle", Shape::circle),
177  std::make_pair("cross", Shape::cross),
178  std::make_pair("left", Shape::left),
179  std::make_pair("down", Shape::down),
180  std::make_pair("up", Shape::up),
181  std::make_pair("right", Shape::right),
182  std::make_pair("lowerLeft", Shape::lower_left),
183  std::make_pair("upperLeft", Shape::upper_left),
184  std::make_pair("lowerRight", Shape::lower_right),
185  std::make_pair("upperRight", Shape::upper_right),
186 
187  // BACKWARD COMPATIBILITY
188  std::make_pair("straight", Shape::up),
189  };
190 
191  static auto make(const std::string & name) -> Shape;
192 
193  constexpr auto category() const
194  {
195  return static_cast<Category>(static_cast<std::uint16_t>(value) & 0b1111'1111);
196  }
197 
198  constexpr auto is(const Value given) const { return value == given; }
199 
200  constexpr auto is(const Category given) const { return category() == given; }
201 
202  constexpr operator Value() const noexcept { return value; }
203 
204  friend auto operator>>(std::istream & is, Shape & shape) -> std::istream &;
205 
206  friend auto operator<<(std::ostream & os, const Shape & shape) -> std::ostream &;
207  };
208 
209  struct Bulb
210  {
211  using Value = std::tuple<Color, Status, Shape>;
212 
213  const Value value;
214 
215  using Hash = std::uint32_t; // (Color::Value << 8 + 16) | (Status::Value << 16) | Shape::Value
216 
217  constexpr Bulb(const Value value) : value(value) {}
218 
219  constexpr Bulb(const Color color = {}, const Status status = {}, const Shape shape = {})
220  : Bulb(std::forward_as_tuple(color, status, shape))
221  {
222  }
223 
224  Bulb(const std::string & name) : Bulb(make(name)) {}
225 
226  auto make(const std::string & s) -> Value;
227 
228  constexpr auto is(const Color color) const { return std::get<Color>(value).is(color); }
229 
230  constexpr auto is(const Status status) const { return std::get<Status>(value).is(status); }
231 
232  constexpr auto is(const Shape shape) const { return std::get<Shape>(value).is(shape); }
233 
234  constexpr auto is(const Shape::Category category) const
235  {
236  return std::get<Shape>(value).is(category);
237  }
238 
239  constexpr auto hash() const -> Hash
240  {
241  return (static_cast<Hash>(std::get<Color>(value).value) << 24) |
242  (static_cast<Hash>(std::get<Status>(value).value) << 16) |
243  static_cast<Hash>(std::get<Shape>(value).value);
244  }
245 
246  friend constexpr auto operator<(const Bulb & lhs, const Bulb & rhs) -> bool
247  {
248  return lhs.hash() < rhs.hash();
249  }
250 
251  friend auto operator<<(std::ostream & os, const Bulb & bulb) -> std::ostream &;
252 
253  explicit operator simulation_api_schema::TrafficLight() const
254  {
255  auto color = [this]() {
256  switch (std::get<Color>(value).value) {
257  case Color::green:
258  return simulation_api_schema::TrafficLight_Color_GREEN;
259  case Color::yellow:
260  return simulation_api_schema::TrafficLight_Color_AMBER;
261  case Color::red:
262  return simulation_api_schema::TrafficLight_Color_RED;
263  case Color::white:
264  return simulation_api_schema::TrafficLight_Color_WHITE;
265  default:
266  throw common::SyntaxError(std::get<Color>(value), " is not supported color.");
267  }
268  };
269 
270  auto status = [this]() {
271  switch (std::get<Status>(value).value) {
272  case Status::solid_on:
273  return simulation_api_schema::TrafficLight_Status_SOLID_ON;
274  case Status::solid_off:
275  return simulation_api_schema::TrafficLight_Status_SOLID_OFF;
276  case Status::flashing:
277  return simulation_api_schema::TrafficLight_Status_FLASHING;
278  case Status::unknown:
279  return simulation_api_schema::TrafficLight_Status_UNKNOWN_STATUS;
280  default:
281  throw common::SyntaxError(std::get<Status>(value), " is not supported as a status.");
282  }
283  };
284 
285  auto shape = [this]() {
286  switch (std::get<Shape>(value).value) {
287  case Shape::circle:
288  return simulation_api_schema::TrafficLight_Shape_CIRCLE;
289  case Shape::cross:
290  return simulation_api_schema::TrafficLight_Shape_CROSS;
291  case Shape::left:
292  return simulation_api_schema::TrafficLight_Shape_LEFT_ARROW;
293  case Shape::down:
294  return simulation_api_schema::TrafficLight_Shape_DOWN_ARROW;
295  case Shape::up:
296  return simulation_api_schema::TrafficLight_Shape_UP_ARROW;
297  case Shape::right:
298  return simulation_api_schema::TrafficLight_Shape_RIGHT_ARROW;
299  case Shape::lower_left:
300  return simulation_api_schema::TrafficLight_Shape_DOWN_LEFT_ARROW;
301  case Shape::lower_right:
302  return simulation_api_schema::TrafficLight_Shape_DOWN_RIGHT_ARROW;
303  case Shape::upper_left:
304  return simulation_api_schema::TrafficLight_Shape_UP_LEFT_ARROW;
305  case Shape::upper_right:
306  return simulation_api_schema::TrafficLight_Shape_UP_RIGHT_ARROW;
307  default:
308  throw common::SyntaxError(std::get<Shape>(value), " is not supported as a shape.");
309  }
310  };
311 
312  simulation_api_schema::TrafficLight traffic_light_bulb_proto;
313  traffic_light_bulb_proto.set_status(status());
314  traffic_light_bulb_proto.set_shape(shape());
315  traffic_light_bulb_proto.set_color(color());
316  // NOTE: confidence will be overwritten in TrafficLight::operator simulation_api_schema::TrafficSignal()
317  traffic_light_bulb_proto.set_confidence(1.0);
318 
319  return traffic_light_bulb_proto;
320  }
321  };
322 
323  const lanelet::Id way_id;
324 
325  double confidence = 1.0;
326 
327  std::set<Bulb> bulbs;
328 
329  const std::map<Bulb::Hash, std::optional<geometry_msgs::msg::Point>> positions;
330 
331  explicit TrafficLight(const lanelet::Id, hdmap_utils::HdMapUtils &);
332 
333  auto clear() { bulbs.clear(); }
334 
335  auto contains(const Bulb & bulb) const { return bulbs.find(bulb) != std::end(bulbs); }
336 
337  auto contains(const Color & color, const Status & status, const Shape & shape) const
338  {
339  return contains(Bulb(color, status, shape));
340  }
341 
342  auto contains(const std::string & name) const { return contains(Bulb(name)); }
343 
344  template <typename Markers, typename Now>
345  auto draw(Markers & markers, const Now & now, const std::string & frame_id) const
346  {
347  auto optional_position = [this](auto && bulb) {
348  try {
349  return positions.at(bulb.hash() & 0b1111'0000'1111'1111); // NOTE: Ignore status
350  } catch (const std::out_of_range &) {
351  return std::optional<geometry_msgs::msg::Point>(std::nullopt);
352  }
353  };
354 
355  for (const auto & bulb : bulbs) {
356  if (optional_position(bulb).has_value() and bulb.is(Shape::Category::circle)) {
357  visualization_msgs::msg::Marker marker;
358  marker.header.stamp = now;
359  marker.header.frame_id = frame_id;
360  marker.action = marker.ADD;
361  marker.ns = "bulb";
362  marker.id = way_id;
363  marker.type = marker.SPHERE;
364  marker.pose.position = optional_position(bulb).value();
365  marker.pose.orientation = geometry_msgs::msg::Quaternion();
366  marker.scale.x = 0.3;
367  marker.scale.y = 0.3;
368  marker.scale.z = 0.3;
369  marker.color =
370  color_names::makeColorMsg(boost::lexical_cast<std::string>(std::get<Color>(bulb.value)));
371  markers.push_back(marker);
372  }
373  }
374  }
375 
376  template <typename... Ts>
377  auto emplace(Ts &&... xs)
378  {
379  bulbs.emplace(std::forward<decltype(xs)>(xs)...);
380  }
381 
382  auto empty() const { return bulbs.empty(); }
383 
384  auto set(const std::string & states) -> void;
385 
386  friend auto operator<<(std::ostream & os, const TrafficLight & traffic_light) -> std::ostream &;
387 
388  explicit operator simulation_api_schema::TrafficSignal() const
389  {
390  simulation_api_schema::TrafficSignal traffic_signal_proto;
391 
392  traffic_signal_proto.set_id(way_id);
393  for (const auto & bulb : bulbs) {
394  auto traffic_light_bulb_proto = static_cast<simulation_api_schema::TrafficLight>(bulb);
395  traffic_light_bulb_proto.set_confidence(confidence);
396  *traffic_signal_proto.add_traffic_light_status() = traffic_light_bulb_proto;
397  }
398  return traffic_signal_proto;
399  }
400 };
401 } // namespace traffic_simulator
402 
403 #endif // TRAFFIC_SIMULATOR__TRAFFIC_LIGHTS__TRAFFIC_LIGHT_HPP_
Definition: hdmap_utils.hpp:62
Definition: api.hpp:48
Definition: junit5.hpp:25
std::string string
Definition: junit5.hpp:26
There is a syntactic error in the description of the scenario. Or you are using a feature that is not...
Definition: exception.hpp:53
Definition: traffic_light.hpp:210
constexpr auto is(const Shape shape) const
Definition: traffic_light.hpp:232
std::tuple< Color, Status, Shape > Value
Definition: traffic_light.hpp:211
constexpr auto hash() const -> Hash
Definition: traffic_light.hpp:239
constexpr Bulb(const Value value)
Definition: traffic_light.hpp:217
constexpr Bulb(const Color color={}, const Status status={}, const Shape shape={})
Definition: traffic_light.hpp:219
Bulb(const std::string &name)
Definition: traffic_light.hpp:224
constexpr friend auto operator<(const Bulb &lhs, const Bulb &rhs) -> bool
Definition: traffic_light.hpp:246
constexpr auto is(const Color color) const
Definition: traffic_light.hpp:228
friend auto operator<<(std::ostream &os, const Bulb &bulb) -> std::ostream &
Definition: traffic_light.cpp:162
auto make(const std::string &s) -> Value
Definition: traffic_light.cpp:136
constexpr auto is(const Shape::Category category) const
Definition: traffic_light.hpp:234
const Value value
Definition: traffic_light.hpp:213
std::uint32_t Hash
Definition: traffic_light.hpp:215
constexpr auto is(const Status status) const
Definition: traffic_light.hpp:230
Definition: traffic_light.hpp:42
Value
Definition: traffic_light.hpp:43
@ white
Definition: traffic_light.hpp:47
@ green
Definition: traffic_light.hpp:44
@ red
Definition: traffic_light.hpp:46
@ yellow
Definition: traffic_light.hpp:45
friend auto operator<<(std::ostream &os, const Color &color) -> std::ostream &
Definition: traffic_light.cpp:43
constexpr Color(const Value value=green)
Definition: traffic_light.hpp:57
Color(const std::string &name)
Definition: traffic_light.hpp:59
static const std::unordered_map< std::string, Value > table
Definition: traffic_light.hpp:61
enum traffic_simulator::TrafficLight::Color::Value value
friend auto operator>>(std::istream &is, Color &color) -> std::istream &
Definition: traffic_light.cpp:35
static auto make(const std::string &name) -> Color
Definition: traffic_light.cpp:26
constexpr auto is(const Color given) const
Definition: traffic_light.hpp:76
Definition: traffic_light.hpp:130
Value
Definition: traffic_light.hpp:143
@ up
Definition: traffic_light.hpp:149
@ upper_right
Definition: traffic_light.hpp:154
@ left
Definition: traffic_light.hpp:147
@ cross
Definition: traffic_light.hpp:146
@ lower_right
Definition: traffic_light.hpp:153
@ upper_left
Definition: traffic_light.hpp:152
@ lower_left
Definition: traffic_light.hpp:151
@ down
Definition: traffic_light.hpp:148
@ circle
Definition: traffic_light.hpp:145
@ right
Definition: traffic_light.hpp:150
constexpr auto category() const
Definition: traffic_light.hpp:193
enum traffic_simulator::TrafficLight::Shape::Value value
static auto make(const std::string &name) -> Shape
Definition: traffic_light.cpp:91
constexpr auto is(const Category given) const
Definition: traffic_light.hpp:200
friend auto operator>>(std::istream &is, Shape &shape) -> std::istream &
Definition: traffic_light.cpp:100
Category
Definition: traffic_light.hpp:131
friend auto operator<<(std::ostream &os, const Shape &shape) -> std::ostream &
Definition: traffic_light.cpp:108
constexpr auto is(const Value given) const
Definition: traffic_light.hpp:198
constexpr Shape(const Value value=circle)
Definition: traffic_light.hpp:171
static const std::unordered_map< std::string, Shape::Value > table
Definition: traffic_light.hpp:175
Shape(const std::string &name)
Definition: traffic_light.hpp:173
Definition: traffic_light.hpp:86
constexpr auto is(const Value given) const
Definition: traffic_light.hpp:118
constexpr Status(const Value value=solid_on)
Definition: traffic_light.hpp:101
static const std::unordered_map< std::string, Value > table
Definition: traffic_light.hpp:105
Status(const std::string &name)
Definition: traffic_light.hpp:103
Value
Definition: traffic_light.hpp:87
@ solid_off
Definition: traffic_light.hpp:89
@ unknown
Definition: traffic_light.hpp:91
@ solid_on
Definition: traffic_light.hpp:88
@ flashing
Definition: traffic_light.hpp:90
friend auto operator<<(std::ostream &os, const Status &status) -> std::ostream &
Definition: traffic_light.cpp:76
enum traffic_simulator::TrafficLight::Status::Value value
static auto make(const std::string &name) -> Status
Definition: traffic_light.cpp:59
friend auto operator>>(std::istream &is, Status &status) -> std::istream &
Definition: traffic_light.cpp:68
Definition: traffic_light.hpp:40
auto clear()
Definition: traffic_light.hpp:333
double confidence
Definition: traffic_light.hpp:325
const lanelet::Id way_id
Definition: traffic_light.hpp:323
TrafficLight(const lanelet::Id, hdmap_utils::HdMapUtils &)
Definition: traffic_light.cpp:169
const std::map< Bulb::Hash, std::optional< geometry_msgs::msg::Point > > positions
Definition: traffic_light.hpp:329
auto empty() const
Definition: traffic_light.hpp:382
auto contains(const Color &color, const Status &status, const Shape &shape) const
Definition: traffic_light.hpp:337
std::set< Bulb > bulbs
Definition: traffic_light.hpp:327
auto set(const std::string &states) -> void
Definition: traffic_light.cpp:201
auto contains(const std::string &name) const
Definition: traffic_light.hpp:342
auto draw(Markers &markers, const Now &now, const std::string &frame_id) const
Definition: traffic_light.hpp:345
friend auto operator<<(std::ostream &os, const TrafficLight &traffic_light) -> std::ostream &
Definition: traffic_light.cpp:219
auto contains(const Bulb &bulb) const
Definition: traffic_light.hpp:335
auto emplace(Ts &&... xs)
Definition: traffic_light.hpp:377