27 #include <etsi_its_msgs_utils/spatem_ts_access.hpp>
29 #include <OgreSceneNode.h>
30 #include <OgreSceneManager.h>
31 #include <OgreBillboardSet.h>
32 #include <OgreMaterialManager.h>
33 #include <OgreTechnique.h>
35 #include "rviz_common/display_context.hpp"
36 #include "rviz_common/frame_manager_iface.hpp"
37 #include "rviz_common/logging.hpp"
38 #include "rviz_common/properties/color_property.hpp"
39 #include "rviz_common/properties/float_property.hpp"
40 #include "rviz_common/properties/bool_property.hpp"
41 #include "rviz_common/properties/ros_topic_property.hpp"
42 #include "rviz_common/properties/qos_profile_property.hpp"
44 #include "rviz_common/properties/parse_color.hpp"
51 const Ogre::ColourValue
color_grey(0.5, 0.5, 0.5, 1.0);
52 const Ogre::ColourValue
color_green(0.18, 0.79, 0.21, 1.0);
53 const Ogre::ColourValue
color_orange(0.9, 0.7, 0.09, 1.0);
54 const Ogre::ColourValue
color_red(0.8, 0.2, 0.2, 1.0);
58 spatem_topic_property_ =
new rviz_common::properties::RosTopicProperty(
"SPATEM Topic",
"/etsi_its_conversion/spatem_ts/out",
59 rosidl_generator_traits::data_type<etsi_its_spatem_ts_msgs::msg::SPATEM>(),
64 viz_mapem_ =
new rviz_common::properties::BoolProperty(
"Visualize MAPEMs",
true,
68 "MAPEM Timeout", 120.0f,
69 "Time (in s) until MAP disappears",
viz_mapem_);
73 "MAPEM Sphere Scale", 1.0f,
74 "Scaling factor to adjuste size of MAPEM spheres",
viz_mapem_);
78 "Ingress Lane Color", QColor(85, 85, 255),
79 "Color to visualize Ingress-Lanes",
viz_mapem_);
81 "Egress Lane Color", QColor(255, 170, 0),
82 "Color to visualize Egress-Lanes",
viz_mapem_);
84 "MAPEM Lane Width", 1.0,
"Width of MAPEM-Lanes",
viz_mapem_);
86 show_meta_mapem_ =
new rviz_common::properties::BoolProperty(
"Metadata",
true,
87 "Show metadata as text next to MAP reference point",
viz_mapem_);
89 "Text Color", QColor(255, 255, 255),
94 viz_spatem_ =
new rviz_common::properties::BoolProperty(
"Visualize SPATEMs",
true,
95 "Show SPATEMs corresponding to received MAPEMs",
this, SLOT(
changedSPATEMViz()));
98 "SPATEM Timeout", 0.1f,
103 "SPATEM Sphere Scale", 1.0f,
104 "Scaling factor to adjuste size of SPATEM spheres",
viz_spatem_);
108 "Show metadata as text next to SPATEM reference point",
viz_spatem_);
111 "Text Color", QColor(255, 255, 255),
139 RTDClass::onInitialize();
141 auto nodeAbstraction = context_->getRosNodeAbstraction().lock();
145 [
this](rclcpp::QoS profile) {
163 deleteStatus(
"SPATEM Topic");
174 rviz_common::properties::StatusProperty::Warn,
176 QString(
"Error subscribing: Empty topic name"));
180 std::map<std::string, std::vector<std::string>> published_topics =
rviz_node_->get_topic_names_and_types();
181 bool topic_available =
false;
182 std::string topic_message_type;
183 for (
const auto & topic : published_topics) {
186 topic_available =
true;
187 for (
const auto & type : topic.second) {
188 topic_message_type = type;
189 if (type ==
"etsi_its_spatem_ts_msgs/msg/SPATEM") {
196 if(!topic_available) {
198 rviz_common::properties::StatusProperty::Warn,
"SPATEM Topic",
200 + QString(
": Topic is not available!"));
204 rviz_common::properties::StatusProperty::Warn,
"SPATEM Topic",
206 + QString(
": Message type ") + QString::fromStdString(topic_message_type) + QString::fromStdString(
" does not equal etsi_its_spatem_ts_msgs::msg::SPATEM!"));
213 for(
size_t i = 0; i<msg->spat.intersections.array.size(); i++) {
214 etsi_its_spatem_ts_msgs::msg::IntersectionState intersection_state = msg->spat.intersections.array[i];
215 unsigned int intersection_id = etsi_its_spatem_ts_msgs::access::getIntersectionID(intersection_state);
220 std_msgs::msg::Header header;
221 if(intersection_state.moy_is_present) {
222 etsi_its_spatem_ts_msgs::msg::MinuteOfTheYear moy = etsi_its_spatem_ts_msgs::access::getMinuteOfTheYear(intersection_state);
223 uint64_t nanosecs = etsi_its_spatem_ts_msgs::access::getUnixNanosecondsFromMinuteOfTheYear(moy, now.nanoseconds());
224 if(intersection_state.time_stamp_is_present) {
225 double secs_in_minute = etsi_its_spatem_ts_msgs::access::getDSecondValue(intersection_state);
226 nanosecs += (uint64_t)(secs_in_minute*1e9);
228 header.stamp = rclcpp::Time(nanosecs);
234 for(
size_t j=0; j<intersection_state.states.array.size(); j++) {
235 etsi_its_spatem_ts_msgs::msg::MovementState spat_mvmt_state = intersection_state.states.array[j];
238 mvmt_state.
signal_group_id = etsi_its_spatem_ts_msgs::access::getSignalGroupID(spat_mvmt_state);
239 mvmt_state.
header = header;
240 if(spat_mvmt_state.state_time_speed.array.size()) {
241 mvmt_state.
phase_state = etsi_its_spatem_ts_msgs::access::getCurrentMovementPhaseState(spat_mvmt_state);
243 auto movement_event = etsi_its_spatem_ts_msgs::access::getCurrentMovementEvent(spat_mvmt_state);
244 if (movement_event.timing_is_present) {
245 mvmt_state.
time_change_details = std::make_shared<etsi_its_spatem_ts_msgs::msg::TimeChangeDetails>(movement_event.timing);
249 auto mvmnt_it = it->second.movement_states.find(mvmt_state.
signal_group_id);
250 if (mvmnt_it != it->second.movement_states.end()) mvmnt_it->second = mvmt_state;
251 else it->second.movement_states.insert(std::make_pair(mvmt_state.
signal_group_id, mvmt_state));
257 rviz_common::properties::StatusProperty::Ok,
"SPATEM Topic", QString::number(
received_spats_) +
" messages received");
264 if(!msg->map.intersections_is_present)
return;
265 etsi_its_mapem_ts_msgs::msg::MinuteOfTheYear moy = msg->map.time_stamp;
266 for(
size_t i = 0; i<msg->map.intersections.array.size(); i++)
272 rviz_common::properties::StatusProperty::Error,
"Topic",
273 "Message contained invalid floating point values (nans or infs)");
291 std::shared_ptr<rviz_rendering::Shape> sphere = std::make_shared<rviz_rendering::Shape>(rviz_rendering::Shape::Sphere, scene_manager_, child_scene_node);
296 dims.x = 1.0 * scale;
297 dims.y = 1.0 * scale;
298 dims.z = 1.0 * scale;
299 sphere->setScale(dims);
308 std::shared_ptr<rviz_rendering::BillboardLine> line = std::make_shared<rviz_rendering::BillboardLine>(scene_manager_, child_scene_node);
309 Ogre::ColourValue lane_color;
313 line->setColor(lane_color.r, lane_color.g, lane_color.b, lane_color.a);
315 line->setLineWidth(line_width);
316 for(
size_t j = 0; j<lane.
nodes.size(); j++) {
318 p.x = lane.
nodes[j].x;
319 p.y = lane.
nodes[j].y;
320 p.z = lane.
nodes[j].z;
329 std::shared_ptr<rviz_rendering::MovableText> text_render = std::make_shared<rviz_rendering::MovableText>(text,
"Liberation Sans",
char_height_mapem_->getFloat());
331 height+=text_render->getBoundingRadius();
333 Ogre::Vector3 offs(0.0, 0.0, height);
334 text_render->setGlobalTranslation(offs);
336 text_render->setColor(text_color);
337 child_scene_node->attachObject(text_render.get());
338 texts_.push_back(text_render);
346 std::shared_ptr<rviz_rendering::Shape> sg = std::make_shared<rviz_rendering::Shape>(rviz_rendering::Shape::Sphere, scene_manager_, child_scene_node);
351 dims.x = 1.0 * scale;
352 dims.y = 1.0 * scale;
353 dims.z = 1.0 * scale;
358 if(intersection_movement_state !=
nullptr) {
359 std::array<float, 4> color = etsi_its_spatem_ts_msgs::access::interpretMovementPhaseStateAsColor(intersection_movement_state->
phase_state.value);
360 sg->setColor(color.at(0), color.at(1), color.at(2), color.at(3));
367 p.x = lane.
nodes.front().x;
368 p.y = lane.
nodes.front().y;
369 p.z = lane.
nodes.front().z;
376 std::string text_content;
378 if (intersection_movement_state !=
nullptr) {
380 etsi_its_spatem_ts_msgs::msg::TimeChangeDetails::SharedPtr time_change_details = intersection_movement_state->
time_change_details;
381 std_msgs::msg::Header& header = intersection_movement_state->
header;
384 text_content =
"Start time: "
385 + (time_change_details->start_time_is_present
386 ? etsi_its_spatem_ts_msgs::access::parseTimeMarkValueToString(time_change_details->start_time.value, header.stamp.sec, header.stamp.nanosec)
393 text_content +=
"Min end time: "
394 + etsi_its_spatem_ts_msgs::access::parseTimeMarkValueToString(time_change_details->min_end_time.value, header.stamp.sec, header.stamp.nanosec)
399 text_content +=
"Max end time: "
400 + (time_change_details->max_end_time_is_present
401 ? etsi_its_spatem_ts_msgs::access::parseTimeMarkValueToString(time_change_details->max_end_time.value, header.stamp.sec, header.stamp.nanosec)
406 text_content +=
"Likely time: "
407 + (time_change_details->likely_time_is_present
408 ? etsi_its_spatem_ts_msgs::access::parseTimeMarkValueToString(time_change_details->likely_time.value, header.stamp.sec, header.stamp.nanosec)
413 text_content +=
"Confidence: "
414 + (time_change_details->confidence_is_present
415 ? std::to_string((
int)(etsi_its_spatem_ts_msgs::access::interpretTimeIntervalConfidenceAsFloat(time_change_details->confidence.value) * 100)) +
"%"
420 text_content +=
"Next time: "
421 + (time_change_details->next_time_is_present
422 ? etsi_its_spatem_ts_msgs::access::parseTimeMarkValueToString(time_change_details->next_time.value, header.stamp.sec, header.stamp.nanosec)
426 text_content =
"no time info";
432 std::shared_ptr<rviz_rendering::MovableText> text_render = std::make_shared<rviz_rendering::MovableText>(text_content,
"Liberation Sans",
char_height_spatem_->getFloat());
433 Ogre::Vector3 halfSize = text_render->getBoundingBox().getHalfSize();
434 Ogre::Vector3 offset(
435 offset.x = lane.
nodes.front().x - halfSize.x * 0.5,
436 offset.y = lane.
nodes.front().y + halfSize.y,
437 offset.z = lane.
nodes.front().z + 2);
439 text_render->setGlobalTranslation(offset);
441 text_render->setColor(text_color);
442 child_scene_node->attachObject(text_render.get());
443 texts_.push_back(text_render);
452 it->second.removeOutdatedMovemenStates(now,
spatem_timeout_->getFloat());
463 std::string utm_frame_key = intsctn.
getHeader().frame_id;
464 Ogre::Vector3 sn_position;
465 Ogre::Quaternion sn_orientation;
466 if (!context_->getFrameManager()->getTransform(intsctn.
getHeader(), sn_position, sn_orientation)) {
467 setMissingTransformToFixedFrame(utm_frame_key);
474 Ogre::SceneNode* scene_node = scene_node_->createChildSceneNode(utm_frame_key);
485 Ogre::SceneNode* scene_node =
scene_nodes_utm_[utm_frame_key]->createChildSceneNode(std::string(
"Junction: ") + std::to_string(intersection_id));
491 geometry_msgs::msg::Point ref_position = intsctn.
getRefPosition();
492 Ogre::Vector3 position(ref_position.x, ref_position.y, ref_position.z);
494 Ogre::Quaternion orientation(rot_offset.w(), rot_offset.x(), rot_offset.y(), rot_offset.z());
497 child_scene_node->setPosition(position);
498 child_scene_node->setOrientation(orientation);
506 for(
size_t i = 0; i<intsctn.
lanes.size(); i++) {
515 std::unordered_map<int, IntersectionMovementState>::iterator mvmnt_it;
518 for(
size_t j=0; j<intsctn.
lanes[i].signal_group_ids.size(); j++) {
522 mvmnt_ptr = &mvmnt_it->second;
545 #include <pluginlib/class_list_macros.hpp>