15 #include "nav2_rviz_plugins/route_tool.hpp"
16 #include <QDesktopServices>
18 #include <sys/types.h>
19 #include <QFileDialog>
20 #include "rviz_common/display_context.hpp"
23 namespace nav2_rviz_plugins
26 : rviz_common::Panel(parent),
27 ui_(std::make_unique<Ui::route_tool>())
31 node_ = std::make_shared<nav2_util::LifecycleNode>(
"route_tool_node",
"", rclcpp::NodeOptions());
33 graph_vis_publisher_ = node_->create_publisher<visualization_msgs::msg::MarkerArray>(
34 "route_graph", rclcpp::QoS(rclcpp::KeepLast(1)).transient_local().reliable());
36 tf_ = std::make_shared<tf2_ros::Buffer>(node_->get_clock());
37 graph_loader_ = std::make_shared<nav2_route::GraphLoader>(node_, tf_,
"map");
38 graph_saver_ = std::make_shared<nav2_route::GraphSaver>(node_, tf_,
"map");
39 ui_->add_node_button->setChecked(
true);
40 ui_->edit_node_button->setChecked(
true);
41 ui_->remove_node_button->setChecked(
true);
47 void RouteTool::onInitialize(
void)
49 auto ros_node_abstraction = getDisplayContext()->getRosNodeAbstraction().lock();
50 if (!ros_node_abstraction) {
52 node_->get_logger(),
"Unable to get ROS node abstraction");
55 auto node = ros_node_abstraction->get_raw_node();
57 clicked_point_subscription_ = node->create_subscription<geometry_msgs::msg::PointStamped>(
58 "clicked_point", 1, [
this](
const geometry_msgs::msg::PointStamped::SharedPtr msg) {
59 ui_->add_field_1->setText(std::to_string(msg->point.x).c_str());
60 ui_->add_field_2->setText(std::to_string(msg->point.y).c_str());
61 ui_->edit_field_1->setText(std::to_string(msg->point.x).c_str());
62 ui_->edit_field_2->setText(std::to_string(msg->point.y).c_str());
66 void RouteTool::on_load_button_clicked(
void)
68 QString filename = QFileDialog::getOpenFileName(
70 tr(
"Open Address Book"),
"",
71 tr(
"Address Book (*.geojson);;All Files (*)"));
72 if (filename.isEmpty()) {
73 RCLCPP_INFO(node_->get_logger(),
"Load operation cancelled by user");
76 graph_to_id_map_.clear();
77 edge_to_node_map_.clear();
78 graph_to_incoming_edges_map_.clear();
80 graph_loader_->loadGraphFromFile(graph_, graph_to_id_map_, filename.toStdString());
81 unsigned int max_node_id = 0;
82 for (
const auto & node : graph_) {
83 max_node_id = std::max(node.nodeid, max_node_id);
84 for (
const auto & edge : node.neighbors) {
85 max_node_id = std::max(edge.edgeid, max_node_id);
86 edge_to_node_map_[edge.edgeid] = node.nodeid;
87 if (graph_to_incoming_edges_map_.find(edge.end->nodeid) !=
88 graph_to_incoming_edges_map_.end())
90 graph_to_incoming_edges_map_[edge.end->nodeid].push_back(edge.edgeid);
92 graph_to_incoming_edges_map_[edge.end->nodeid] = std::vector<unsigned int> {edge.edgeid};
96 next_node_id_ = max_node_id + 1;
100 void RouteTool::on_save_button_clicked(
void)
102 QString filename = QFileDialog::getSaveFileName(
104 tr(
"Open Address Book"),
"",
105 tr(
"Address Book (*.geojson);;All Files (*)"));
106 RCLCPP_INFO(node_->get_logger(),
"Save graph to: %s", filename.toStdString().c_str());
107 graph_saver_->saveGraphToFile(graph_, filename.toStdString());
110 void RouteTool::on_create_button_clicked(
void)
112 if (
ui_->add_field_1->toPlainText() ==
"" ||
ui_->add_field_2->toPlainText() ==
"") {
return;}
113 if (
ui_->add_node_button->isChecked()) {
114 auto longitude =
ui_->add_field_1->toPlainText().toFloat();
115 auto latitude =
ui_->add_field_2->toPlainText().toFloat();
117 new_node.nodeid = next_node_id_;
118 new_node.coords.x = longitude;
119 new_node.coords.y = latitude;
120 graph_.push_back(new_node);
121 graph_to_id_map_[next_node_id_++] = graph_.size() - 1;
122 RCLCPP_INFO(node_->get_logger(),
"Adding node at: (%f, %f)", longitude, latitude);
123 update_route_graph();
124 }
else if (
ui_->add_edge_button->isChecked()) {
125 auto start_node =
ui_->add_field_1->toPlainText().toInt();
126 auto end_node =
ui_->add_field_2->toPlainText().toInt();
128 graph_[graph_to_id_map_[start_node]].addEdge(
129 edge_cost, &(graph_[graph_to_id_map_[end_node]]),
131 if (graph_to_incoming_edges_map_.find(end_node) != graph_to_incoming_edges_map_.end()) {
132 graph_to_incoming_edges_map_[end_node].push_back(next_node_id_);
134 graph_to_incoming_edges_map_[end_node] = std::vector<unsigned int> {next_node_id_};
136 edge_to_node_map_[next_node_id_++] = start_node;
137 RCLCPP_INFO(node_->get_logger(),
"Adding edge from %d to %d", start_node, end_node);
138 update_route_graph();
140 ui_->add_field_1->setText(
"");
141 ui_->add_field_2->setText(
"");
144 void RouteTool::on_confirm_button_clicked(
void)
146 if (
ui_->edit_id->toPlainText() ==
"" ||
ui_->edit_field_1->toPlainText() ==
"" ||
147 ui_->edit_field_2->toPlainText() ==
"") {
return;}
148 if (
ui_->edit_node_button->isChecked()) {
149 auto node_id =
ui_->edit_id->toPlainText().toInt();
150 auto new_longitude =
ui_->edit_field_1->toPlainText().toFloat();
151 auto new_latitude =
ui_->edit_field_2->toPlainText().toFloat();
152 if (graph_to_id_map_.find(node_id) != graph_to_id_map_.end()) {
153 graph_[graph_to_id_map_[node_id]].coords.x = new_longitude;
154 graph_[graph_to_id_map_[node_id]].coords.y = new_latitude;
155 update_route_graph();
157 }
else if (
ui_->edit_edge_button->isChecked()) {
158 auto edge_id = (
unsigned int)
ui_->edit_id->toPlainText().toInt();
159 auto new_start =
ui_->edit_field_1->toPlainText().toInt();
160 auto new_end =
ui_->edit_field_2->toPlainText().toInt();
162 auto current_start_node = &graph_[graph_to_id_map_[edge_to_node_map_[edge_id]]];
163 for (
auto itr = current_start_node->neighbors.begin();
164 itr != current_start_node->neighbors.end(); itr++)
166 if (itr->edgeid == edge_id) {
167 current_start_node->neighbors.erase(itr);
173 graph_[graph_to_id_map_[new_start]].addEdge(
174 edge_cost, &(graph_[graph_to_id_map_[new_end]]),
176 edge_to_node_map_[edge_id] = new_start;
177 if (graph_to_incoming_edges_map_.find(new_end) != graph_to_incoming_edges_map_.end()) {
178 graph_to_incoming_edges_map_[new_end].push_back(edge_id);
180 graph_to_incoming_edges_map_[new_end] = std::vector<unsigned int> {edge_id};
182 update_route_graph();
184 ui_->edit_id->setText(
"");
185 ui_->edit_field_1->setText(
"");
186 ui_->edit_field_2->setText(
"");
189 void RouteTool::on_delete_button_clicked(
void)
191 if (
ui_->remove_id->toPlainText() ==
"") {
return;}
192 if (
ui_->remove_node_button->isChecked()) {
193 unsigned int node_id =
ui_->remove_id->toPlainText().toInt();
195 for (
auto edge_id : graph_to_incoming_edges_map_[node_id]) {
196 auto start_node = &graph_[graph_to_id_map_[edge_to_node_map_[edge_id]]];
197 for (
auto itr = start_node->neighbors.begin(); itr != start_node->neighbors.end(); itr++) {
198 if (itr->edgeid == edge_id) {
199 start_node->neighbors.erase(itr);
200 edge_to_node_map_.erase(edge_id);
205 if (graph_[graph_to_id_map_[node_id]].nodeid == node_id) {
207 graph_[graph_to_id_map_[node_id]].nodeid = std::numeric_limits<int>::max();
208 graph_to_id_map_.erase(node_id);
209 graph_to_incoming_edges_map_.erase(node_id);
210 RCLCPP_INFO(node_->get_logger(),
"Removed node %d", node_id);
212 update_route_graph();
213 }
else if (
ui_->remove_edge_button->isChecked()) {
214 auto edge_id = (
unsigned int)
ui_->remove_id->toPlainText().toInt();
215 auto start_node = &graph_[graph_to_id_map_[edge_to_node_map_[edge_id]]];
216 for (
auto itr = start_node->neighbors.begin(); itr != start_node->neighbors.end(); itr++) {
217 if (itr->edgeid == edge_id) {
218 RCLCPP_INFO(node_->get_logger(),
"Removed edge %d", edge_id);
219 start_node->neighbors.erase(itr);
220 edge_to_node_map_.erase(edge_id);
224 update_route_graph();
226 ui_->remove_id->setText(
"");
229 void RouteTool::on_add_node_button_toggled(
void)
231 if (
ui_->add_node_button->isChecked()) {
232 ui_->add_text->setText(
"Position:");
233 ui_->add_label_1->setText(
"X:");
234 ui_->add_label_2->setText(
"Y:");
236 ui_->add_text->setText(
"Connections:");
237 ui_->add_label_1->setText(
"Start Node ID:");
238 ui_->add_label_2->setText(
"End Node ID:");
242 void RouteTool::on_edit_node_button_toggled(
void)
244 if (
ui_->edit_node_button->isChecked()) {
245 ui_->edit_text->setText(
"Position:");
246 ui_->edit_label_1->setText(
"X:");
247 ui_->edit_label_2->setText(
"Y:");
249 ui_->edit_text->setText(
"Connections:");
250 ui_->edit_label_1->setText(
"Start Node ID:");
251 ui_->edit_label_2->setText(
"End Node ID:");
255 void RouteTool::update_route_graph(
void)
257 graph_vis_publisher_->publish(nav2_route::utils::toMsg(graph_,
"map", node_->now()));
262 rviz_common::Panel::save(config);
265 void RouteTool::load(
const rviz_common::Config & config)
267 rviz_common::Panel::load(config);
271 #include <pluginlib/class_list_macros.hpp>
An object to store edge cost or cost metadata for scoring.
An object to store the nodes in the graph file.