39 #include <QApplication>
40 #include <QButtonGroup>
44 #include <QHBoxLayout>
49 #include <QMessageBox>
50 #include <QProgressBar>
51 #include <QPushButton>
52 #include <QRadioButton>
57 #include <QVBoxLayout>
61 #include "../tools/collision_matrix_model.h"
62 #include "../tools/collision_linear_model.h"
63 #include "../tools/rotated_header_view.h"
74 srdf.disabled_collision_pairs_.clear();
80 for (
const auto& item : pairs)
83 if (item.second.disable_check)
85 dc.
link1_ = item.first.first;
86 dc.
link2_ = item.first.second;
88 srdf.disabled_collision_pairs_.push_back(dc);
100 :
SetupScreenWidget(parent), model_(nullptr), selection_model_(nullptr), worker_(nullptr), config_data_(config_data)
103 layout_ =
new QVBoxLayout(
this);
107 "Optimize Self-Collision Checking",
108 "This searches for pairs of robot links that can safely be disabled from collision checking, decreasing motion "
109 "planning time. These pairs are disabled when they are always in collision, never in collision, in collision in "
110 "the robot's default position, or when the links are adjacent to each other on the kinematic chain. Sampling "
111 "density specifies how many random robot positions to check for self collision.",
118 QVBoxLayout* controls_box_layout =
new QVBoxLayout(
controls_box_);
120 QHBoxLayout* slider_layout =
new QHBoxLayout();
121 slider_layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
122 controls_box_layout->addLayout(slider_layout);
125 QLabel* density_left_label =
new QLabel(
this);
126 density_left_label->setText(
"Sampling Density: Low");
127 slider_layout->addWidget(density_left_label);
143 QLabel* density_right_label =
new QLabel(
this);
144 density_right_label->setText(
"High ");
145 slider_layout->addWidget(density_right_label);
158 QHBoxLayout* buttons_layout =
new QHBoxLayout();
159 buttons_layout->setAlignment(Qt::AlignRight);
160 controls_box_layout->addLayout(buttons_layout);
164 fraction_label_->setText(
"Min. collisions for \"always\"-colliding pairs:");
176 btn_generate_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
198 btn_interrupt_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
209 action =
new QAction(tr(
"Show"),
this);
211 connect(action, SIGNAL(triggered()),
this, SLOT(
showSections()));
212 action =
new QAction(tr(
"Hide"),
this);
214 connect(action, SIGNAL(triggered()),
this, SLOT(
hideSections()));
215 action =
new QAction(tr(
"Hide others"),
this);
218 action =
new QAction(tr(
"Disable by default"),
this);
220 connect(action, &QAction::triggered,
this, [
this] {
setDefaults(
true); });
221 action =
new QAction(tr(
"Enable by default"),
this);
223 connect(action, &QAction::triggered,
this, [
this] {
setDefaults(
false); });
227 QHBoxLayout* bottom_layout =
new QHBoxLayout();
228 bottom_layout->setAlignment(Qt::AlignRight);
229 layout_->addLayout(bottom_layout);
244 QRadioButton* radio_btn;
245 radio_btn =
new QRadioButton(
"linear view");
246 bottom_layout->addWidget(radio_btn);
249 radio_btn =
new QRadioButton(
"matrix view");
250 bottom_layout->addWidget(radio_btn);
252 radio_btn->setChecked(
true);
258 btn_revert_->setToolTip(
"Revert current changes to collision matrix");
259 btn_revert_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
265 setWindowTitle(
"Default Collision Matrix");
295 if (QMessageBox::No == QMessageBox::question(
this,
"Collision Matrix Generation",
296 "Collision Matrix Generation is still active. Cancel computation?",
297 QMessageBox::Yes | QMessageBox::No, QMessageBox::No))
332 num_trials = num_trials < 1000 ? 1000 : num_trials;
336 const bool include_never_colliding =
true;
339 config_data_->getPlanningScene()->getAllowedCollisionMatrixNonConst().clear();
343 config_data_->getPlanningScene(), collision_progress, include_never_colliding, num_trials, min_frac,
verbose);
350 *collision_progress = 100;
361 wip_srdf_,
config_data_->getPlanningScene()->getRobotModel()->getLinkModelNamesWithCollisionGeometry());
362 QAbstractItemModel* model;
366 model = matrix_model;
373 model = sorted_model;
374 sorted_model->setSourceModel(linear_model);
376 linear_model->setParent(sorted_model);
377 matrix_model->setParent(linear_model);
379 connect(
link_name_filter_, SIGNAL(textChanged(QString)), model, SLOT(setFilterRegExp(QString)));
380 QMetaObject::invokeMethod(model,
"setFilterRegExp", Q_ARG(QString,
link_name_filter_->text()));
391 QHeaderView *horizontal_header, *vertical_header;
396 connect(
selection_model_, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
this,
407 horizontal_header->setVisible(
true);
408 vertical_header->setVisible(
true);
410 horizontal_header->setContextMenuPolicy(Qt::CustomContextMenu);
411 connect(horizontal_header, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(
showHeaderContextMenu(QPoint)));
412 vertical_header->setContextMenuPolicy(Qt::CustomContextMenu);
413 connect(vertical_header, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(
showHeaderContextMenu(QPoint)));
417 connect(
selection_model_, SIGNAL(currentChanged(QModelIndex, QModelIndex)),
this,
423 collision_table_->setHorizontalHeader(horizontal_header =
new QHeaderView(Qt::Horizontal,
this));
424 collision_table_->setVerticalHeader(vertical_header =
new QHeaderView(Qt::Vertical,
this));
429 horizontal_header->setVisible(
true);
430 vertical_header->setVisible(
true);
431 horizontal_header->setSectionResizeMode(QHeaderView::Stretch);
433 vertical_header->setContextMenuPolicy(Qt::CustomContextMenu);
434 connect(vertical_header, SIGNAL(customContextMenuRequested(QPoint)),
this, SLOT(
showHeaderContextMenu(QPoint)));
436 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
437 horizontal_header->setSectionsClickable(
true);
438 vertical_header->setSectionsClickable(
true);
440 horizontal_header->setClickable(
true);
441 vertical_header->setClickable(
true);
446 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
447 connect(
model_, SIGNAL(dataChanged(QModelIndex, QModelIndex, QVector<int>)),
this,
458 if (!
index.isValid())
463 if ((linear_mode && !selection.contains(
index)) ||
464 (!linear_mode && !(selection.contains(
index) ||
467 QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::Select | QItemSelectionModel::Current;
469 flags |= QItemSelectionModel::Rows;
515 list <<
index.column();
536 for (
auto index : list)
546 if (!selected.contains(
index))
570 if (logicalIndexes.size() < 2)
586 for (
auto index : list)
588 bool changed =
false;
591 const auto&
name =
m->headerData(
index, Qt::Horizontal, Qt::DisplayRole).toString().toStdString();
593 auto& links =
wip_srdf_->no_default_collision_links_;
594 if (
std::find(links.begin(), links.end(),
name) == links.end())
596 links.push_back(
name);
600 auto& pairs =
wip_srdf_->disabled_collision_pairs_;
601 auto last = std::remove_if(pairs.begin(), pairs.end(),
602 [&
name](
const auto& p) { return p.link1_ == name || p.link2_ == name; });
603 changed |= last != pairs.end();
604 pairs.erase(last, pairs.end());
608 const auto&
name =
m->headerData(
index, Qt::Horizontal, Qt::DisplayRole).toString().toStdString();
610 auto& links =
wip_srdf_->no_default_collision_links_;
612 auto last = std::remove(links.begin(), links.end(),
name);
613 changed |= last != links.end();
614 links.erase(last, links.end());
618 auto& pairs =
wip_srdf_->enabled_collision_pairs_;
619 auto last = std::remove_if(pairs.begin(), pairs.end(), [&
name, &links](
const auto& p) {
620 return (p.link1_ == name && std::find(links.begin(), links.end(), p.link2_) == links.end()) ||
621 (p.link2_ == name && std::find(links.begin(), links.end(), p.link1_) == links.end());
623 pairs.erase(last, pairs.end());
642 if (event->type() == QEvent::Enter)
648 else if (event->type() == QEvent::KeyPress)
650 QKeyEvent* key_event =
static_cast<QKeyEvent*
>(event);
651 if (key_event->key() != Qt::Key_Space)
666 for (
int r = 0;
r !=
rows; ++
r)
669 selection.merge(QItemSelection(
model_->index(
r, 0),
model_->index(
r,
cols - 1)), QItemSelectionModel::Deselect);
671 for (
int c = 0;
c !=
cols; ++
c)
674 selection.merge(QItemSelection(
model_->index(0,
c),
model_->index(
rows - 1,
c)), QItemSelectionModel::Deselect);
681 QModelIndex input_index;
682 if (cur_idx.flags() & Qt::ItemIsUserCheckable)
683 input_index = cur_idx;
686 for (
const auto idx : selection.indexes())
688 if (idx.flags() & Qt::ItemIsUserCheckable)
694 if (!input_index.isValid())
698 bool current =
model_->data(input_index, Qt::CheckStateRole) == Qt::Checked;
700 m->setEnabled(selection, !current);
704 bool current =
model_->data(
model_->index(cur_idx.row(), 2), Qt::CheckStateRole) == Qt::Checked;
706 m->setEnabled(selection, !current);
718 int rounded_value = round(
value / 1000.0) * 1000;
750 QApplication::processEvents();
770 if (!
index.isValid())
782 const QString& first_link =
model_->headerData(
r, Qt::Vertical, Qt::DisplayRole).toString();
783 const QString& second_link =
model_->headerData(
c, Qt::Horizontal, Qt::DisplayRole).toString();
784 uint check_state =
model_->data(
index, Qt::CheckStateRole).toUInt();
786 QColor color = (check_state == Qt::Checked) ? QColor(0, 255, 0) : QColor(255, 0, 0);
796 if (!
index.isValid())
800 const QString& first_link =
model_->data(
model_->index(
index.row(), 0), Qt::DisplayRole).toString();
801 const QString& second_link =
model_->data(
model_->index(
index.row(), 1), Qt::DisplayRole).toString();
802 uint check_state =
model_->data(
model_->index(
index.row(), 2), Qt::CheckStateRole).toUInt();
804 QColor color = (check_state == Qt::Checked) ? QColor(0, 255, 0) : QColor(255, 0, 0);
829 if (QMessageBox::No == QMessageBox::question(
this,
"Collision Matrix Generation",
830 "Collision Matrix Generation is still active. Cancel computation?",
831 QMessageBox::Yes | QMessageBox::No, QMessageBox::No))
845 QProgressBar* progress_bar)
846 : progress_(0), canceled_(false)
852 connect(
this, SIGNAL(
progress(
int)), progress_bar, SLOT(setValue(
int)));
858 while (!canceled_ && progress_ < 100)
860 Q_EMIT progress(progress_);
861 QThread::msleep(100);
870 Q_EMIT progress(progress_);