moveit2
The MoveIt Motion Planning Framework for ROS 2.
motion_planning_frame_joints_widget.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, CITEC, Bielefeld University
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 CITEC / Bielefeld University nor the names of
18  * its 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: Robert Haschke */
36 
39 
40 #include "ui_motion_planning_rviz_plugin_frame_joints.h"
41 #include <QPainter>
42 #include <QSlider>
43 #include <QEvent>
44 #include <QMouseEvent>
45 
46 namespace moveit_rviz_plugin
47 {
48 
49 JMGItemModel::JMGItemModel(const moveit::core::RobotState& robot_state, const std::string& group_name, QObject* parent)
50  : QAbstractTableModel(parent), robot_state_(robot_state), jmg_(nullptr)
51 {
52  if (robot_state_.getRobotModel()->hasJointModelGroup(group_name))
53  jmg_ = robot_state_.getRobotModel()->getJointModelGroup(group_name);
54 }
55 
56 int JMGItemModel::rowCount(const QModelIndex& /*parent*/) const
57 {
58  if (!jmg_)
59  {
60  return robot_state_.getVariableCount();
61  }
62  else
63  {
64  return jmg_->getVariableCount();
65  }
66 }
67 
68 int JMGItemModel::columnCount(const QModelIndex& /*parent*/) const
69 {
70  return 2;
71 }
72 
73 Qt::ItemFlags JMGItemModel::flags(const QModelIndex& index) const
74 {
75  if (!index.isValid())
76  return Qt::ItemFlags();
77 
78  Qt::ItemFlags f = QAbstractTableModel::flags(index);
79 
80  const moveit::core::JointModel* jm = getJointModel(index);
81  bool is_editable = !jm->isPassive() && !jm->getMimic();
82  f.setFlag(Qt::ItemIsEnabled, is_editable);
83  if (index.column() == 1)
84  f.setFlag(Qt::ItemIsEditable, is_editable);
85  return f;
86 }
87 
88 QVariant JMGItemModel::data(const QModelIndex& index, int role) const
89 {
90  if (!index.isValid())
91  return QVariant();
92 
93  int idx = jmg_ ? jmg_->getVariableIndexList()[index.row()] : index.row();
94  switch (index.column())
95  {
96  case 0: // joint name column
97  switch (role)
98  {
99  case Qt::DisplayRole:
100  return QString::fromStdString(robot_state_.getVariableNames()[idx]);
101  case Qt::TextAlignmentRole:
102  return Qt::AlignLeft;
103  }
104  break;
105  case 1: // joint value column
106  {
107  double value = robot_state_.getVariablePosition(idx);
108  const moveit::core::JointModel* jm = robot_state_.getRobotModel()->getJointOfVariable(idx);
109  switch (role)
110  {
111  case Qt::DisplayRole:
112  return value;
113  case Qt::EditRole:
114  if (jm)
115  return jm->getType() == moveit::core::JointModel::REVOLUTE ? value * 180 / M_PI : value;
116  break;
118  if (jm)
119  return jm->getType();
120  break;
122  if (const moveit::core::VariableBounds* bounds = getVariableBounds(jm, index))
123  return QPointF(bounds->min_position_, bounds->max_position_);
124  break;
125  case Qt::TextAlignmentRole:
126  return Qt::AlignLeft;
127  }
128  }
129  }
130  return QVariant();
131 }
132 
133 QVariant JMGItemModel::headerData(int section, Qt::Orientation orientation, int role) const
134 {
135  if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
136  return section == 0 ? "Joint Name" : "Value";
137  return QAbstractTableModel::headerData(section, orientation, role);
138 }
139 
140 bool JMGItemModel::setData(const QModelIndex& index, const QVariant& value, int role)
141 {
142  if (index.column() != 1 || role != Qt::EditRole)
143  return false;
144 
145  int var_idx = jmg_ ? jmg_->getVariableIndexList()[index.row()] : index.row();
146  const moveit::core::JointModel* jm = robot_state_.getRobotModel()->getJointOfVariable(var_idx);
147  if (!value.canConvert<double>())
148  return false;
149 
150  bool ok;
151  double v = value.toDouble(&ok);
152  if (!ok)
153  return false;
154 
155  // for revolute joints, we convert degrees to radians
156  if (jm && jm->getType() == moveit::core::JointModel::REVOLUTE)
157  v *= M_PI / 180;
158 
159  robot_state_.setVariablePosition(var_idx, v);
161  dataChanged(index, index);
162  return true;
163 }
164 
165 const moveit::core::JointModel* JMGItemModel::getJointModel(const QModelIndex& index) const
166 {
167  if (!index.isValid())
168  return nullptr;
169  int var_idx = jmg_ ? jmg_->getVariableIndexList()[index.row()] : index.row();
170  return robot_state_.getRobotModel()->getJointOfVariable(var_idx);
171 }
172 
173 const moveit::core::VariableBounds* JMGItemModel::getVariableBounds(const moveit::core::JointModel* jm,
174  const QModelIndex& index) const
175 {
176  if (!jm)
177  return nullptr;
178  int var_idx = jmg_ ? jmg_->getVariableIndexList()[index.row()] : index.row();
179  const moveit::core::VariableBounds* bounds = &jm->getVariableBounds()[var_idx - jm->getFirstVariableIndex()];
180  return bounds->position_bounded_ ? bounds : nullptr;
181 }
182 
183 // copy positions from new_state and notify about these changes
185 {
186  if (robot_state_.getRobotModel() != state.getRobotModel())
187  return;
188  robot_state_.setVariablePositions(state.getVariablePositions());
189 
190  dataChanged(index(0, 1), index(rowCount() - 1, 1));
191 }
192 
194  : QWidget(parent), ui_(new Ui::MotionPlanningFrameJointsUI()), planning_display_(display)
195 {
196  ui_->setupUi(this);
197  // intercept mouse events delivered to joints_view_ to open editor on first mouse press
198  ui_->joints_view_->viewport()->installEventFilter(new JointsWidgetEventFilter(ui_->joints_view_));
199  ui_->joints_view_->setItemDelegateForColumn(1, new ProgressBarDelegate(this));
200  svd_.setThreshold(0.001);
201 }
202 
204 {
205  delete ui_;
206 }
207 
209 {
210  ui_->joints_view_->setModel(nullptr);
211  start_state_handler_.reset();
212  goal_state_handler_.reset();
213  start_state_model_.reset();
214  goal_state_model_.reset();
215 }
216 
218  const std::string& group_name, const robot_interaction::InteractionHandlerPtr& start_state_handler,
219  const robot_interaction::InteractionHandlerPtr& goal_state_handler)
220 {
221  // release previous models (if any)
222  clearRobotModel();
223  // create new models
224  start_state_handler_ = start_state_handler;
225  goal_state_handler_ = goal_state_handler;
226  start_state_model_ = std::make_unique<JMGItemModel>(*start_state_handler_->getState(), group_name, this);
227  goal_state_model_ = std::make_unique<JMGItemModel>(*goal_state_handler_->getState(), group_name, this);
228 
229  // forward model updates to the PlanningDisplay
230  connect(start_state_model_.get(), &JMGItemModel::dataChanged, this, [this]() {
231  if (!ignore_state_changes_)
232  planning_display_->setQueryStartState(start_state_model_->getRobotState());
233  });
234  connect(goal_state_model_.get(), &JMGItemModel::dataChanged, this, [this]() {
235  if (!ignore_state_changes_)
236  planning_display_->setQueryGoalState(goal_state_model_->getRobotState());
237  });
238 
239  // show the goal state by default
240  setActiveModel(goal_state_model_.get());
242 }
243 
245 {
246  if (!start_state_model_ || !start_state_handler_)
247  return;
248  ignore_state_changes_ = true;
249  start_state_model_->updateRobotState(*start_state_handler_->getState());
250  ignore_state_changes_ = false;
251  setActiveModel(start_state_model_.get());
253 }
254 
256 {
257  if (!goal_state_model_ || !goal_state_handler_)
258  return;
259  ignore_state_changes_ = true;
260  goal_state_model_->updateRobotState(*goal_state_handler_->getState());
261  ignore_state_changes_ = false;
262  setActiveModel(goal_state_model_.get());
264 }
265 
267 {
268  ui_->joints_view_->setModel(model);
269  ui_->joints_view_label_->setText(
270  QString("Group joints of %1 state").arg(model == start_state_model_.get() ? "start" : "goal"));
271 }
272 
274 {
275  if (model == start_state_model_.get())
276  {
277  planning_display_->setQueryStartState(model->getRobotState());
278  }
279  else
280  {
281  planning_display_->setQueryGoalState(model->getRobotState());
282  }
283 }
284 
285 // Find matching key vector in columns of haystack and return the best-aligned column index.
286 // Only consider available indexes (> 0). If no match is found, return largest available index.
287 // sign becomes -1 if key has changed sign compared to the matching haystack column.
288 static Eigen::Index findMatching(const Eigen::VectorXd& key, const Eigen::MatrixXd& haystack,
289  const Eigen::VectorXi& available, double& sign)
290 {
291  Eigen::Index result = available.array().maxCoeff();
292  double best_match = 0.0;
293  for (unsigned int i = 0; i < available.rows(); ++i)
294  {
295  int index = available[i];
296  if (index < 0) // index already taken
297  continue;
298  if (index >= haystack.cols())
299  return result;
300  double match = haystack.col(available[i]).transpose() * key;
301  double abs_match = std::abs(match);
302  if (abs_match > 0.5 && abs_match > best_match)
303  {
304  best_match = abs_match;
305  result = index;
306  sign = match > 0 ? 1.0 : -1.0;
307  }
308  }
309  return result;
310 }
311 
313 {
314  JMGItemModel* model = dynamic_cast<JMGItemModel*>(ui_->joints_view_->model());
315  std::size_t i = 0;
316  if (model && model->getJointModelGroup() && model->getJointModelGroup()->isChain())
317  {
319  Eigen::MatrixXd jacobian;
320  if (!model->getRobotState().getJacobian(model->getJointModelGroup(),
321  model->getJointModelGroup()->getLinkModels().back(),
322  Eigen::Vector3d::Zero(), jacobian, false))
323  goto cleanup;
324 
325  svd_.compute(jacobian, Eigen::ComputeFullV);
326  Eigen::Index rank = svd_.rank();
327  std::size_t ns_dim = svd_.cols() - rank;
328  Eigen::MatrixXd ns(svd_.cols(), ns_dim);
329  Eigen::VectorXi available(ns_dim);
330  for (std::size_t j = 0; j < ns_dim; ++j)
331  available[j] = j;
332 
333  ns_sliders_.reserve(ns_dim);
334  // create/unhide sliders
335  for (; i < ns_dim; ++i)
336  {
337  if (i >= ns_sliders_.size())
338  ns_sliders_.push_back(createNSSlider(i + 1));
339  ns_sliders_[i]->show();
340 
341  // Find matching null-space basis vector in previous nullspace_
342  double sign = 1.0;
343  const Eigen::VectorXd& current = svd_.matrixV().col(rank + i);
344  Eigen::Index index = findMatching(current, nullspace_, available, sign);
345  ns.col(index).noalias() = sign * current;
346  available[index] = -1; // mark index as taken
347  }
348  nullspace_ = ns;
349  }
350 
351 cleanup:
352  if (i == 0)
353  nullspace_.resize(0, 0);
354 
355  // show/hide dummy slider
356  ui_->dummy_ns_slider_->setVisible(i == 0);
357 
358  // hide remaining sliders
359  for (; i < ns_sliders_.size(); ++i)
360  ns_sliders_[i]->hide();
361 }
362 
364 {
365  JogSlider* slider = new JogSlider(this);
366  slider->setOrientation(Qt::Horizontal);
367  slider->setMaximum(0.1);
368  slider->setToolTip(QString("Nullspace dim #%1").arg(i));
369  ui_->nullspace_layout_->addWidget(slider);
370  connect(slider, SIGNAL(triggered(double)), this, SLOT(jogNullspace(double)));
371  return slider;
372 }
373 
375 {
376  if (value == 0)
377  return;
378 
379  std::size_t index = std::find(ns_sliders_.begin(), ns_sliders_.end(), sender()) - ns_sliders_.begin();
380  if (static_cast<int>(index) >= nullspace_.cols())
381  return;
382 
383  JMGItemModel* model = dynamic_cast<JMGItemModel*>(ui_->joints_view_->model());
384  if (!model)
385  return;
386 
387  Eigen::VectorXd values;
388  model->getRobotState().copyJointGroupPositions(model->getJointModelGroup(), values);
389  values += value * nullspace_.col(index);
390  model->getRobotState().setJointGroupPositions(model->getJointModelGroup(), values);
392  triggerUpdate(model);
393 }
394 
395 void ProgressBarDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
396 {
397  // copied from QStyledItemDelegate::paint
398  QStyle* style = option.widget ? option.widget->style() : QApplication::style();
399  QStyleOptionViewItem style_option = option;
400  initStyleOption(&style_option, index);
401 
402  if (index.column() == 1)
403  {
404  QVariant joint_type = index.data(JointTypeRole);
405  double value = index.data().toDouble();
406  if (joint_type.isValid())
407  {
408  switch (joint_type.toInt())
409  {
411  style_option.text = option.locale.toString(value * 180 / M_PI, 'f', 0).append("°");
412  break;
414  style_option.text = option.locale.toString(value, 'f', 3).append("m");
415  break;
416  default:
417  break;
418  }
419  }
420 
421  QVariant vbounds = index.data(VariableBoundsRole);
422  if (vbounds.isValid())
423  {
424  QPointF bounds = vbounds.toPointF();
425  const double min = bounds.x();
426  const double max = bounds.y();
427 
428  QStyleOptionProgressBar opt;
429  opt.rect = option.rect;
430  opt.minimum = 0;
431  opt.maximum = 1000;
432  opt.progress = 1000. * (value - min) / (max - min);
433  opt.text = style_option.text;
434  opt.textAlignment = style_option.displayAlignment;
435  opt.textVisible = true;
436  style->drawControl(QStyle::CE_ProgressBar, &opt, painter);
437  return;
438  }
439  }
440 
441  style->drawControl(QStyle::CE_ItemViewItem, &style_option, painter, option.widget);
442 }
443 
444 QWidget* ProgressBarDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option,
445  const QModelIndex& index) const
446 
447 {
448  if (index.column() == 1)
449  {
450  QVariant vbounds = index.data(VariableBoundsRole);
451  if (vbounds.isValid())
452  {
453  QPointF bounds = vbounds.toPointF();
454  double min = bounds.x();
455  double max = bounds.y();
456  bool is_revolute = (index.data(JointTypeRole).toInt() == moveit::core::JointModel::REVOLUTE);
457  if (is_revolute)
458  {
459  min *= 180. / M_PI;
460  max *= 180. / M_PI;
461  }
462  auto* editor = new ProgressBarEditor(parent, min, max, is_revolute ? 0 : 3);
463  connect(editor, &ProgressBarEditor::editingFinished, this, &ProgressBarDelegate::commitAndCloseEditor);
464  connect(editor, &ProgressBarEditor::valueChanged, this, [=](double value) {
465  const_cast<QAbstractItemModel*>(index.model())->setData(index, value, Qt::EditRole);
466  });
467  return editor;
468  }
469  }
470  return QStyledItemDelegate::createEditor(parent, option, index);
471 }
472 
473 void ProgressBarDelegate::commitAndCloseEditor()
474 {
475  ProgressBarEditor* editor = qobject_cast<ProgressBarEditor*>(sender());
476  commitData(editor);
477  closeEditor(editor);
478 }
479 
481 {
482 }
483 
484 bool JointsWidgetEventFilter::eventFilter(QObject* /*target*/, QEvent* event)
485 {
486  if (event->type() == QEvent::MouseButtonPress)
487  {
488  QAbstractItemView* view = qobject_cast<QAbstractItemView*>(parent());
489  QModelIndex index = view->indexAt(static_cast<QMouseEvent*>(event)->pos());
490  if (index.flags() & Qt::ItemIsEditable) // mouse event on any editable slider?
491  {
492  view->setCurrentIndex(index);
493  view->edit(index);
494  return true; // event handled
495  }
496  }
497  return false;
498 }
499 
500 ProgressBarEditor::ProgressBarEditor(QWidget* parent, double min, double max, int digits)
501  : QWidget(parent), min_(min), max_(max), digits_(digits)
502 {
503  // if left mouse button is pressed, grab all future mouse events until button(s) released
504  if (QApplication::mouseButtons() & Qt::LeftButton)
505  grabMouse();
506 }
507 
508 void ProgressBarEditor::paintEvent(QPaintEvent* /*event*/)
509 {
510  QPainter painter(this);
511 
512  QStyleOptionProgressBar opt;
513  opt.rect = rect();
514  opt.palette = palette();
515  opt.minimum = 0;
516  opt.maximum = 1000;
517  opt.progress = 1000. * (value_ - min_) / (max_ - min_);
518  opt.text = QLocale().toString(value_, 'f', digits_);
519  opt.textAlignment = Qt::AlignRight;
520  opt.textVisible = true;
521  style()->drawControl(QStyle::CE_ProgressBar, &opt, &painter);
522 }
523 
524 void ProgressBarEditor::mousePressEvent(QMouseEvent* event)
525 {
526  if (event->button() == Qt::LeftButton)
527  mouseMoveEvent(event);
528 }
529 
530 void ProgressBarEditor::mouseMoveEvent(QMouseEvent* event)
531 {
532  double v = std::min(max_, std::max(min_, min_ + event->x() * (max_ - min_) / width()));
533  if (value_ != v)
534  {
535  value_ = v;
536  valueChanged(v);
537  update();
538  }
539  event->accept();
540 }
541 
542 void ProgressBarEditor::mouseReleaseEvent(QMouseEvent* event)
543 {
544  if (event->button() == Qt::LeftButton)
545  {
546  event->accept();
547  editingFinished();
548  }
549 }
550 
551 JogSlider::JogSlider(QWidget* parent) : QSlider(parent)
552 {
553  setTimerInterval(50);
554  setResolution(1000);
555  setMaximum(1.0);
556 }
557 
559 {
560  timer_interval_ = ms;
561 }
562 
563 void JogSlider::setResolution(unsigned int resolution)
564 {
565  QSlider::setRange(-resolution, +resolution);
566 }
567 
568 void JogSlider::setMaximum(double value)
569 {
570  maximum_ = value;
571 }
572 
573 void JogSlider::timerEvent(QTimerEvent* event)
574 {
575  QSlider::timerEvent(event);
576  if (event->timerId() == timer_id_)
577  triggered(value());
578 }
579 
580 void JogSlider::mousePressEvent(QMouseEvent* event)
581 {
582  QSlider::mousePressEvent(event);
583  timer_id_ = startTimer(timer_interval_);
584 }
585 
586 void JogSlider::mouseReleaseEvent(QMouseEvent* event)
587 {
588  killTimer(timer_id_);
589  QSlider::mouseReleaseEvent(event);
590  setValue(0);
591 }
592 
593 } // namespace moveit_rviz_plugin
bool isChain() const
Check if this group is a linear chain.
const std::vector< const LinkModel * > & getLinkModels() const
Get the links that are part of this joint group.
unsigned int getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
const std::vector< int > & getVariableIndexList() const
Get the index locations in the complete robot state for all the variables in this group.
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
Definition: joint_model.h:117
size_t getFirstVariableIndex() const
Get the index of this joint's first variable within the full robot state.
Definition: joint_model.h:216
bool isPassive() const
Check if this joint is passive.
Definition: joint_model.h:440
bool enforcePositionBounds(double *values) const
Force the specified values to be inside bounds and normalized. Quaternions are normalized,...
Definition: joint_model.h:292
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a variable. Throw an exception if the variable was not found.
JointType getType() const
Get the type of joint.
Definition: joint_model.h:151
const JointModel * getMimic() const
Get the joint this one is mimicking.
Definition: joint_model.h:390
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
void setVariablePositions(const double *position)
It is assumed positions is an array containing the new positions for all variables in this state....
bool getJacobian(const JointModelGroup *group, const LinkModel *link, const Eigen::Vector3d &reference_point_position, Eigen::MatrixXd &jacobian, bool use_quaternion_representation=false) const
Compute the Jacobian with reference to a particular point on a given link, for a specified group.
void setVariablePosition(const std::string &variable, double value)
Set the position of a single variable. An exception is thrown if the variable name is not known.
Definition: robot_state.h:188
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
Given positions for the variables that make up a group, in the order found in the group (including va...
Definition: robot_state.h:583
void copyJointGroupPositions(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the position values of the variables that make up the group into another loca...
Definition: robot_state.h:669
const RobotModelConstPtr & getRobotModel() const
Get the robot model this state is constructed for.
Definition: robot_state.h:104
void harmonizePositions()
Call harmonizePosition() for all joints / all joints in group / given joint.
double * getVariablePositions()
Get a raw pointer to the positions of the variables stored in this state. Use carefully....
Definition: robot_state.h:147
void updateLinkTransforms()
Update the reference frame transforms for links. This call is needed before using the transforms of l...
double getVariablePosition(const std::string &variable) const
Get the position of a particular variable. An exception is thrown if the variable is not known.
Definition: robot_state.h:207
std::size_t getVariableCount() const
Get the number of variables that make up this state.
Definition: robot_state.h:110
const std::vector< std::string > & getVariableNames() const
Get the names of the variables that make up this state, in the order they are stored in memory.
Definition: robot_state.h:116
int columnCount(const QModelIndex &parent=QModelIndex()) const override
JMGItemModel(const moveit::core::RobotState &robot_state, const std::string &group_name, QObject *parent=nullptr)
Qt::ItemFlags flags(const QModelIndex &index) const override
QVariant data(const QModelIndex &index, int role) const override
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
const moveit::core::JointModelGroup * getJointModelGroup() const
void updateRobotState(const moveit::core::RobotState &state)
call this on any external change of the RobotState
int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
void triggered(double value)
void mousePressEvent(QMouseEvent *event) override
void mouseReleaseEvent(QMouseEvent *event) override
void timerEvent(QTimerEvent *event) override
bool eventFilter(QObject *target, QEvent *event) override
void setQueryGoalState(const moveit::core::RobotState &goal)
void setQueryStartState(const moveit::core::RobotState &start)
void changePlanningGroup(const std::string &group_name, const robot_interaction::InteractionHandlerPtr &start_state_handler, const robot_interaction::InteractionHandlerPtr &goal_state_handler)
MotionPlanningFrameJointsWidget(const MotionPlanningFrameJointsWidget &)=delete
Delegate to show the joint value as with a progress bar indicator between min and max.
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Number editor via progress bar dragging.
ProgressBarEditor(QWidget *parent=nullptr, double min=-1.0, double max=0.0, int digits=0)
Create a progressbar-like slider for editing values in range mix..max.
void update(moveit::core::RobotState *self, bool force, std::string &category)
Definition: robot_state.cpp:47