moveit2
The MoveIt Motion Planning Framework for ROS 2.
motion_planning_frame_scenes.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Ioan Sucan */
39 
45 
46 #include <interactive_markers/tools.hpp>
47 
48 #include <rviz_common/display_context.hpp>
49 #include <rviz_common/window_manager_interface.hpp>
50 
51 #include <QMessageBox>
52 #include <QInputDialog>
53 
54 #include "ui_motion_planning_rviz_plugin_frame.h"
55 
56 #include <boost/math/constants/constants.hpp>
57 
58 #include <memory>
59 
60 namespace moveit_rviz_plugin
61 {
62 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_ros_visualization.motion_planning_frame_scenes");
63 
64 void MotionPlanningFrame::saveSceneButtonClicked()
65 {
67  {
68  const std::string& name = planning_display_->getPlanningSceneRO()->getName();
69  if (name.empty() || planning_scene_storage_->hasPlanningScene(name))
70  {
71  std::unique_ptr<QMessageBox> q;
72  if (name.empty())
73  q = std::make_unique<QMessageBox>(
74  QMessageBox::Question, "Change Planning Scene Name",
75  QString("The name for the planning scene should not be empty. Would you like to rename "
76  "the planning scene?'"),
77  QMessageBox::Cancel, this);
78  else
79  q = std::make_unique<QMessageBox>(QMessageBox::Question, "Confirm Planning Scene Overwrite",
80  QString("A planning scene named '")
81  .append(name.c_str())
82  .append("' already exists. Do you wish to "
83  "overwrite that scene?"),
84  QMessageBox::Yes | QMessageBox::No, this);
85  std::unique_ptr<QPushButton> rename(q->addButton("&Rename", QMessageBox::AcceptRole));
86  if (q->exec() != QMessageBox::Yes)
87  {
88  if (q->clickedButton() == rename.get())
89  {
90  bool ok = false;
91  QString new_name = QInputDialog::getText(this, "Rename Planning Scene",
92  "New name for the planning scene:", QLineEdit::Normal,
93  QString::fromStdString(name), &ok);
94  if (ok)
95  {
96  planning_display_->getPlanningSceneRW()->setName(new_name.toStdString());
97  rviz_common::properties::Property* prop =
98  planning_display_->subProp("Scene Geometry")->subProp("Scene Name");
99  if (prop)
100  {
101  bool old = prop->blockSignals(true);
102  prop->setValue(new_name);
103  prop->blockSignals(old);
104  }
105  saveSceneButtonClicked();
106  }
107  return;
108  }
109  return;
110  }
111  }
112 
113  planning_display_->addBackgroundJob([this] { computeSaveSceneButtonClicked(); }, "save scene");
114  }
115 }
116 
117 void MotionPlanningFrame::planningSceneItemClicked()
118 {
119  checkPlanningSceneTreeEnabledButtons();
120 }
121 
122 void MotionPlanningFrame::saveQueryButtonClicked()
123 {
125  {
126  QList<QTreeWidgetItem*> sel = ui_->planning_scene_tree->selectedItems();
127  if (!sel.empty())
128  {
129  QTreeWidgetItem* s = sel.front();
130 
131  // if we have selected a PlanningScene, add the query as a new one, under that planning scene
132  if (s->type() == ITEM_TYPE_SCENE)
133  {
134  std::string scene = s->text(0).toStdString();
135  planning_display_->addBackgroundJob([this, scene] { computeSaveQueryButtonClicked(scene, ""); }, "save query");
136  }
137  else
138  {
139  // if we selected a query name, then we overwrite that query
140  std::string scene = s->parent()->text(0).toStdString();
141  std::string query_name = s->text(0).toStdString();
142 
143  while (query_name.empty() || planning_scene_storage_->hasPlanningQuery(scene, query_name))
144  {
145  std::unique_ptr<QMessageBox> q;
146  if (query_name.empty())
147  q = std::make_unique<QMessageBox>(
148  QMessageBox::Question, "Change Planning Query Name",
149  QString("The name for the planning query should not be empty. Would you like to"
150  "rename the planning query?'"),
151  QMessageBox::Cancel, this);
152  else
153  q = std::make_unique<QMessageBox>(QMessageBox::Question, "Confirm Planning Query Overwrite",
154  QString("A planning query named '")
155  .append(query_name.c_str())
156  .append("' already exists. Do you wish "
157  "to overwrite that query?"),
158  QMessageBox::Yes | QMessageBox::No, this);
159  std::unique_ptr<QPushButton> rename(q->addButton("&Rename", QMessageBox::AcceptRole));
160  if (q->exec() == QMessageBox::Yes)
161  break;
162  else
163  {
164  if (q->clickedButton() == rename.get())
165  {
166  bool ok = false;
167  QString new_name = QInputDialog::getText(this, "Rename Planning Query",
168  "New name for the planning query:", QLineEdit::Normal,
169  QString::fromStdString(query_name), &ok);
170  if (ok)
171  query_name = new_name.toStdString();
172  else
173  return;
174  }
175  else
176  return;
177  }
178  }
180  [this, scene, query_name] { computeSaveQueryButtonClicked(scene, query_name); }, "save query");
181  }
182  }
183  }
184 }
185 
186 void MotionPlanningFrame::deleteSceneButtonClicked()
187 {
188  planning_display_->addBackgroundJob([this] { computeDeleteSceneButtonClicked(); }, "delete scene");
189 }
190 
191 void MotionPlanningFrame::deleteQueryButtonClicked()
192 {
193  planning_display_->addBackgroundJob([this] { computeDeleteQueryButtonClicked(); }, "delete query");
194 }
195 
196 void MotionPlanningFrame::loadSceneButtonClicked()
197 {
198  planning_display_->addBackgroundJob([this] { computeLoadSceneButtonClicked(); }, "load scene");
199 }
200 
201 void MotionPlanningFrame::loadQueryButtonClicked()
202 {
203  planning_display_->addBackgroundJob([this] { computeLoadQueryButtonClicked(); }, "load query");
204 }
205 
206 void MotionPlanningFrame::warehouseItemNameChanged(QTreeWidgetItem* item, int column)
207 {
208  if (item->text(column) == item->toolTip(column) || item->toolTip(column).length() == 0)
209  return;
210  moveit_warehouse::PlanningSceneStoragePtr planning_scene_storage = planning_scene_storage_;
211  if (!planning_scene_storage)
212  return;
213 
214  if (item->type() == ITEM_TYPE_SCENE)
215  {
216  std::string new_name = item->text(column).toStdString();
217 
218  if (planning_scene_storage->hasPlanningScene(new_name))
219  {
220  planning_display_->addMainLoopJob([this] { populatePlanningSceneTreeView(); });
221  QMessageBox::warning(this, "Scene not renamed",
222  QString("The scene name '").append(item->text(column)).append("' already exists"));
223  return;
224  }
225  else
226  {
227  std::string old_name = item->toolTip(column).toStdString();
228  planning_scene_storage->renamePlanningScene(old_name, new_name);
229  item->setToolTip(column, item->text(column));
230  }
231  }
232  else
233  {
234  std::string scene = item->parent()->text(0).toStdString();
235  std::string new_name = item->text(column).toStdString();
236  if (planning_scene_storage->hasPlanningQuery(scene, new_name))
237  {
238  planning_display_->addMainLoopJob([this] { populatePlanningSceneTreeView(); });
239  QMessageBox::warning(this, "Query not renamed",
240  QString("The query name '")
241  .append(item->text(column))
242  .append("' already exists for scene ")
243  .append(item->parent()->text(0)));
244  return;
245  }
246  else
247  {
248  std::string old_name = item->toolTip(column).toStdString();
249  planning_scene_storage->renamePlanningQuery(scene, old_name, new_name);
250  item->setToolTip(column, item->text(column));
251  }
252  }
253 }
254 
255 void MotionPlanningFrame::populatePlanningSceneTreeView()
256 {
257  moveit_warehouse::PlanningSceneStoragePtr planning_scene_storage = planning_scene_storage_;
258  if (!planning_scene_storage)
259  return;
260 
261  ui_->planning_scene_tree->setUpdatesEnabled(false);
262 
263  // remember which items were expanded
264  std::set<std::string> expanded;
265  for (int i = 0; i < ui_->planning_scene_tree->topLevelItemCount(); ++i)
266  {
267  QTreeWidgetItem* it = ui_->planning_scene_tree->topLevelItem(i);
268  if (it->isExpanded())
269  expanded.insert(it->text(0).toStdString());
270  }
271 
272  ui_->planning_scene_tree->clear();
273  std::vector<std::string> names;
274  planning_scene_storage->getPlanningSceneNames(names);
275 
276  for (const std::string& name : names)
277  {
278  std::vector<std::string> query_names;
279  planning_scene_storage->getPlanningQueriesNames(query_names, name);
280  QTreeWidgetItem* item =
281  new QTreeWidgetItem(ui_->planning_scene_tree, QStringList(QString::fromStdString(name)), ITEM_TYPE_SCENE);
282  item->setFlags(item->flags() | Qt::ItemIsEditable);
283  item->setToolTip(0, item->text(0)); // we use the tool tip as a backup of the old name when renaming
284  for (const std::string& query_name : query_names)
285  {
286  QTreeWidgetItem* subitem =
287  new QTreeWidgetItem(item, QStringList(QString::fromStdString(query_name)), ITEM_TYPE_QUERY);
288  subitem->setFlags(subitem->flags() | Qt::ItemIsEditable);
289  subitem->setToolTip(0, subitem->text(0));
290  item->addChild(subitem);
291  }
292 
293  ui_->planning_scene_tree->insertTopLevelItem(ui_->planning_scene_tree->topLevelItemCount(), item);
294  if (expanded.find(name) != expanded.end())
295  ui_->planning_scene_tree->expandItem(item);
296  }
297  ui_->planning_scene_tree->sortItems(0, Qt::AscendingOrder);
298  ui_->planning_scene_tree->setUpdatesEnabled(true);
299  checkPlanningSceneTreeEnabledButtons();
300 }
301 } // namespace moveit_rviz_plugin
moveit_warehouse::PlanningSceneStoragePtr planning_scene_storage_
planning_scene_monitor::LockedPlanningSceneRO getPlanningSceneRO() const
get read-only access to planning scene
planning_scene_monitor::LockedPlanningSceneRW getPlanningSceneRW()
get write access to planning scene
void addMainLoopJob(const std::function< void()> &job)
queue the execution of this function for the next time the main update() loop gets called
void addBackgroundJob(const std::function< void()> &job, const std::string &name)
scene
Definition: pick.py:52
std::string append(const std::string &left, const std::string &right)
name
Definition: setup.py:7
const rclcpp::Logger LOGGER
Definition: async_test.h:31