moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
default_collisions_widget.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: Dave Coleman */
36
37#include <QApplication>
38#include <QHBoxLayout>
39#include <QKeyEvent>
40#include <QMenu>
41#include <QMessageBox>
42#include <QRadioButton>
43#include <QString>
44
50
51namespace moveit_setup
52{
53namespace srdf_setup
54{
55// ******************************************************************************************
56// User interface for editing the default collision matrix list in an SRDF
57// ******************************************************************************************
59{
60 model_ = nullptr;
61 selection_model_ = nullptr;
62 worker_ = nullptr;
63
64 // Basic widget container
65 layout_ = new QVBoxLayout(this);
66
67 // Top Label Area ------------------------------------------------
68 auto header = new HeaderWidget(
69 "Optimize Self-Collision Checking",
70 "This searches for pairs of robot links that can safely be disabled from collision checking, decreasing motion "
71 "planning time. These pairs are disabled when they are always in collision, never in collision, in collision in "
72 "the robot's default position, or when the links are adjacent to each other on the kinematic chain. Sampling "
73 "density specifies how many random robot positions to check for self collision.",
74 this);
75 layout_->addWidget(header);
76
77 // Top Button Area -----------------------------------------------
78 controls_box_ = new QGroupBox(this);
79 layout_->addWidget(controls_box_);
80 QVBoxLayout* controls_box_layout = new QVBoxLayout(controls_box_);
81
82 QHBoxLayout* slider_layout = new QHBoxLayout();
83 slider_layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
84 controls_box_layout->addLayout(slider_layout);
85
86 // Slider Label
87 QLabel* density_left_label = new QLabel(this);
88 density_left_label->setText("Sampling Density: Low");
89 slider_layout->addWidget(density_left_label);
90
91 // Slider
92 density_slider_ = new QSlider(this);
93 density_slider_->setTickPosition(QSlider::TicksBelow);
94 density_slider_->setMinimum(0);
95 density_slider_->setMaximum(99);
96 density_slider_->setSingleStep(10);
97 density_slider_->setPageStep(50);
98 density_slider_->setSliderPosition(9); // 10,000 is default
99 density_slider_->setTickInterval(10);
100 density_slider_->setOrientation(Qt::Horizontal);
101 slider_layout->addWidget(density_slider_);
102 connect(density_slider_, SIGNAL(valueChanged(int)), this, SLOT(changeDensityLabel(int)));
103
104 // Slider Right Label
105 QLabel* density_right_label = new QLabel(this);
106 density_right_label->setText("High ");
107 slider_layout->addWidget(density_right_label);
108
109 // Slider Value Label
110 density_value_label_ = new QLabel(this);
111 density_value_label_->setMinimumWidth(50);
112 slider_layout->addWidget(density_value_label_);
113 changeDensityLabel(density_slider_->value()); // initialize label with value
114
115 QHBoxLayout* buttons_layout = new QHBoxLayout();
116 buttons_layout->setAlignment(Qt::AlignRight);
117 controls_box_layout->addLayout(buttons_layout);
118
119 // Fraction spin box
120 fraction_label_ = new QLabel(this);
121 fraction_label_->setText("Min. collisions for \"always\"-colliding pairs:");
122 buttons_layout->addWidget(fraction_label_);
123
124 fraction_spinbox_ = new QSpinBox(this);
125 fraction_spinbox_->setRange(1, 100);
126 fraction_spinbox_->setValue(95);
127 fraction_spinbox_->setSuffix("%");
128 buttons_layout->addWidget(fraction_spinbox_);
129
130 // Generate Button
131 btn_generate_ = new QPushButton(this);
132 btn_generate_->setText("&Generate Collision Matrix");
133 btn_generate_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
134 connect(btn_generate_, SIGNAL(clicked()), this, SLOT(startGeneratingCollisionTable()));
135 buttons_layout->addWidget(btn_generate_);
136
137 // Progress Bar Area ---------------------------------------------
138
139 // Progress Label
140 progress_label_ = new QLabel(this);
141 progress_label_->setText("Generating Default Collision Matrix");
142 progress_label_->hide();
143 layout_->addWidget(progress_label_);
144
145 // Progress Bar
146 progress_bar_ = new QProgressBar(this);
147 progress_bar_->setMaximum(100);
148 progress_bar_->setMinimum(0);
149 progress_bar_->hide(); // only show when computation begins
150 layout_->addWidget(progress_bar_);
151
152 // Table Area --------------------------------------------
153
154 // Table
155 collision_table_ = new QTableView(this);
156 layout_->addWidget(collision_table_);
157
158 QAction* action;
159 action = new QAction(tr("Show"), this);
160 header_actions_ << action;
161 connect(action, SIGNAL(triggered()), this, SLOT(showSections()));
162 action = new QAction(tr("Hide"), this);
163 header_actions_ << action;
164 connect(action, SIGNAL(triggered()), this, SLOT(hideSections()));
165 action = new QAction(tr("Hide others"), this);
166 header_actions_ << action;
167 connect(action, SIGNAL(triggered()), this, SLOT(hideOtherSections()));
168
169 // Bottom Area ----------------------------------------
170
171 QHBoxLayout* bottom_layout = new QHBoxLayout();
172 bottom_layout->setAlignment(Qt::AlignRight);
173 layout_->addLayout(bottom_layout);
174
175 // Link Filter QLineEdit
176 link_name_filter_ = new QLineEdit(this);
177 link_name_filter_->setPlaceholderText("link name filter");
178 bottom_layout->addWidget(link_name_filter_);
179
180 // Collision Filter Checkbox
181 collision_checkbox_ = new QCheckBox(this);
182 collision_checkbox_->setText("show enabled pairs");
183 connect(collision_checkbox_, SIGNAL(toggled(bool)), this, SLOT(checkedFilterChanged()));
184 bottom_layout->addWidget(collision_checkbox_);
185
186 // View Mode Buttons
187 view_mode_buttons_ = new QButtonGroup(this);
188 QRadioButton* radio_btn;
189 radio_btn = new QRadioButton("linear view");
190 bottom_layout->addWidget(radio_btn);
191 view_mode_buttons_->addButton(radio_btn, LINEAR_MODE);
192 radio_btn->setChecked(true);
193
194 radio_btn = new QRadioButton("matrix view");
195 bottom_layout->addWidget(radio_btn);
196 view_mode_buttons_->addButton(radio_btn, MATRIX_MODE);
197 connect(view_mode_buttons_, SIGNAL(buttonClicked(int)), this, SLOT(loadCollisionTable()));
198
199 // Revert Button
200 btn_revert_ = new QPushButton(this);
201 btn_revert_->setText("&Revert");
202 btn_revert_->setToolTip("Revert current changes to collision matrix");
203 btn_revert_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
204 btn_revert_->setDisabled(true);
205 connect(btn_revert_, SIGNAL(clicked()), this, SLOT(revertChanges()));
206 bottom_layout->addWidget(btn_revert_);
207
208 setLayout(layout_);
209 setWindowTitle("Default Collision Matrix");
210
211 collision_table_->installEventFilter(this);
212}
213
218
219// ******************************************************************************************
220// start thread generating the collision table
221// ******************************************************************************************
222void DefaultCollisionsWidget::startGeneratingCollisionTable()
223{
224 // Disable controls on form
225 disableControls(true);
226 btn_revert_->setEnabled(true); // allow to interrupt and revert
227
228 // Start actual worker thread
229 setup_step_.startGenerationThread(density_slider_->value() * 1000 + 1000, fraction_spinbox_->value() / 100.0);
230
231 // create a MonitorThread running generateCollisionTable() in a worker thread and monitoring the progress
232 worker_ = new MonitorThread(setup_step_, progress_bar_);
233 connect(worker_, SIGNAL(finished()), this, SLOT(finishGeneratingCollisionTable()));
234 worker_->start(); // start after having finished() signal connected
235}
236
237// ******************************************************************************************
238// cleanup after worker_ thread has finished
239// ******************************************************************************************
240void DefaultCollisionsWidget::finishGeneratingCollisionTable()
241{
242 if (worker_->canceled())
243 return;
244
245 // Load the results into the GUI
246 loadCollisionTable();
247
248 // Hide the progress bar
249 disableControls(false); // enable everything else
250
251 worker_->deleteLater();
252 worker_ = nullptr;
253}
254
255// ******************************************************************************************
256// Displays data in the link_pairs_ data structure into a QtTableWidget
257// ******************************************************************************************
258void DefaultCollisionsWidget::loadCollisionTable()
259{
260 CollisionMatrixModel* matrix_model =
261 new CollisionMatrixModel(setup_step_.getLinkPairs(), setup_step_.getCollidingLinks());
262 QAbstractItemModel* model;
263
264 if (view_mode_buttons_->checkedId() == MATRIX_MODE)
265 {
266 model = matrix_model;
267 }
268 else
269 {
270 CollisionLinearModel* linear_model = new CollisionLinearModel(matrix_model);
271 SortFilterProxyModel* sorted_model = new SortFilterProxyModel();
272 model = sorted_model;
273 sorted_model->setSourceModel(linear_model);
274 // ensure deletion of underlying models with model
275 linear_model->setParent(sorted_model);
276 matrix_model->setParent(linear_model);
277 }
278 connect(link_name_filter_, SIGNAL(textChanged(QString)), model, SLOT(setFilterRegularExpression(QString)));
279 QMetaObject::invokeMethod(model, "setFilterRegularExpression", Q_ARG(QString, link_name_filter_->text()));
280
281 collision_table_->setModel(model);
282 // delete old and remember new model
283 delete model_;
284 model_ = model;
285
286 // delete old and fetch new selection model
287 delete selection_model_;
288 selection_model_ = collision_table_->selectionModel();
289
290 QHeaderView *horizontal_header, *vertical_header;
291
292 // activate some model-specific settings
293 if (view_mode_buttons_->checkedId() == MATRIX_MODE)
294 {
295 connect(selection_model_, SIGNAL(currentChanged(QModelIndex, QModelIndex)), this,
296 SLOT(previewSelectedMatrix(QModelIndex)));
297
298 collision_table_->setSelectionBehavior(QAbstractItemView::SelectItems);
299 collision_table_->setSelectionMode(QAbstractItemView::ExtendedSelection);
300
301 collision_table_->setHorizontalHeader(horizontal_header = new RotatedHeaderView(Qt::Horizontal, this));
302 collision_table_->setVerticalHeader(vertical_header = new RotatedHeaderView(Qt::Vertical, this));
303 collision_table_->setSortingEnabled(false);
304
305 collision_checkbox_->hide();
306 horizontal_header->setVisible(true);
307 vertical_header->setVisible(true);
308
309 horizontal_header->setContextMenuPolicy(Qt::CustomContextMenu);
310 connect(horizontal_header, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showHeaderContextMenu(QPoint)));
311 vertical_header->setContextMenuPolicy(Qt::CustomContextMenu);
312 connect(vertical_header, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showHeaderContextMenu(QPoint)));
313 }
314 else
315 {
316 connect(selection_model_, SIGNAL(currentChanged(QModelIndex, QModelIndex)), this,
317 SLOT(previewSelectedLinear(QModelIndex)));
318
319 collision_table_->setSelectionBehavior(QAbstractItemView::SelectRows);
320 collision_table_->setSelectionMode(QAbstractItemView::ExtendedSelection);
321
322 collision_table_->setHorizontalHeader(horizontal_header = new QHeaderView(Qt::Horizontal, this));
323 collision_table_->setVerticalHeader(vertical_header = new QHeaderView(Qt::Vertical, this));
324 collision_table_->sortByColumn(0, Qt::AscendingOrder);
325 collision_table_->setSortingEnabled(true);
326
327 collision_checkbox_->show();
328 horizontal_header->setVisible(true);
329 vertical_header->setVisible(true);
330
331 vertical_header->setContextMenuPolicy(Qt::CustomContextMenu);
332 connect(vertical_header, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showHeaderContextMenu(QPoint)));
333
334#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
335 horizontal_header->setSectionsClickable(true);
336 vertical_header->setSectionsClickable(true);
337#else
338 horizontal_header->setClickable(true);
339 vertical_header->setClickable(true);
340#endif
341 }
342
343// notice changes to the model
344#if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
345 connect(model_, SIGNAL(dataChanged(QModelIndex, QModelIndex, QVector<int>)), this,
346 SLOT(collisionsChanged(QModelIndex)));
347#else
348 connect(model_, SIGNAL(dataChanged(QModelIndex, QModelIndex)), this, SLOT(collisionsChanged(QModelIndex)));
349#endif
350}
351
352void DefaultCollisionsWidget::collisionsChanged(const QModelIndex& index)
353{
354 btn_revert_->setEnabled(true); // enable revert button
355
356 if (!index.isValid())
357 return;
358 // Hm. For some reason, QTableView doesn't change selection if we click a checkbox
359 bool linear_mode = (view_mode_buttons_->checkedId() == LINEAR_MODE);
360 const QItemSelection& selection = selection_model_->selection();
361 if ((linear_mode && !selection.contains(index)) || // in linear mode: index not in selection
362 (!linear_mode && !(selection.contains(index) || // in matrix mode: index or symmetric index not in selection
363 selection.contains(model_->index(index.column(), index.row())))))
364 {
365 QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::Select | QItemSelectionModel::Current;
366 if (linear_mode)
367 flags |= QItemSelectionModel::Rows;
368 selection_model_->setCurrentIndex(index, flags);
369 }
370}
371
372void DefaultCollisionsWidget::showHeaderContextMenu(const QPoint& p)
373{
374 // This method might be triggered from either of the headers
375 QPoint global;
376 if (sender() == collision_table_->verticalHeader())
377 {
378 clicked_section_ = collision_table_->verticalHeader()->logicalIndexAt(p);
379 clicked_headers_ = Qt::Vertical;
380 global = collision_table_->verticalHeader()->mapToGlobal(p);
381 }
382 else if (sender() == collision_table_->horizontalHeader())
383 {
384 clicked_section_ = collision_table_->horizontalHeader()->logicalIndexAt(p);
385 clicked_headers_ = Qt::Horizontal;
386 global = collision_table_->horizontalHeader()->mapToGlobal(p);
387 }
388 else
389 {
390 clicked_section_ = -1;
391 clicked_headers_ = Qt::Horizontal | Qt::Vertical;
392 }
393
394 QMenu menu;
395 if (clicked_section_ < 0)
396 {
397 menu.addAction(header_actions_.at(0)); // only 'show' action
398 }
399 else
400 {
401 menu.addActions(header_actions_);
402 }
403 menu.exec(global);
404
405 clicked_headers_ = {};
406 clicked_section_ = -1;
407}
408
409void DefaultCollisionsWidget::hideSections()
410{
411 QList<int> list;
412 QHeaderView* header = nullptr;
413 if (clicked_headers_ == Qt::Horizontal)
414 {
415 for (const QModelIndex& index : selection_model_->selectedColumns())
416 list << index.column();
417 header = collision_table_->horizontalHeader();
418 }
419 else if (clicked_headers_ == Qt::Vertical)
420 {
421 for (const QModelIndex& index : selection_model_->selectedRows())
422 list << index.row();
423 header = collision_table_->verticalHeader();
424 }
425
426 // if somewhere else than the selection was clicked, hide only this row/column
427 if (!list.contains(clicked_section_))
428 {
429 list.clear();
430 list << clicked_section_;
431 }
432
433 for (auto index : list)
434 header->setSectionHidden(index, true);
435}
436
437void DefaultCollisionsWidget::hideOtherSections()
438{
439 QList<int> list;
440 QHeaderView* header = nullptr;
441 if (clicked_headers_ == Qt::Horizontal)
442 {
443 header = collision_table_->horizontalHeader();
444 for (const QModelIndex& index : selection_model_->selectedColumns())
445 {
446 if (!header->isSectionHidden(index.column()))
447 list << index.column();
448 }
449 }
450 else if (clicked_headers_ == Qt::Vertical)
451 {
452 header = collision_table_->verticalHeader();
453 for (const QModelIndex& index : selection_model_->selectedRows())
454 {
455 if (!header->isSectionHidden(index.row()))
456 list << index.row();
457 }
458 }
459
460 // if somewhere else than the selection was clicked, hide only this row/column
461 if (!list.contains(clicked_section_))
462 {
463 list.clear();
464 list << clicked_section_;
465 }
466
467 // first hide all sections
468 for (std::size_t index = 0, end = header->count(); index != end; ++index)
469 header->setSectionHidden(index, true);
470
471 // and subsequently show selected ones
472 for (auto index : list)
473 header->setSectionHidden(index, false);
474}
475
476void DefaultCollisionsWidget::showSections()
477{
478 QList<int> list;
479 if (clicked_section_ < 0) // show all
480 {
481 if (clicked_headers_.testFlag(Qt::Horizontal))
482 {
483 // show all columns
484 list.clear();
485 list << 0 << model_->columnCount() - 1;
486 showSections(collision_table_->horizontalHeader(), list);
487 }
488
489 if (clicked_headers_.testFlag(Qt::Vertical)) // show all rows
490 {
491 list.clear();
492 list << 0 << model_->rowCount() - 1;
493 showSections(collision_table_->verticalHeader(), list);
494 }
495 return;
496 }
497
498 QHeaderView* header = nullptr;
499 if (clicked_headers_ == Qt::Horizontal)
500 {
501 for (const QModelIndex& index : selection_model_->selectedColumns())
502 list << index.column();
503 header = collision_table_->horizontalHeader();
504 }
505 else if (clicked_headers_ == Qt::Vertical)
506 {
507 for (const QModelIndex& index : selection_model_->selectedRows())
508 list << index.row();
509 header = collision_table_->verticalHeader();
510 }
511
512 // if somewhere else than the selection was clicked, hide only this row/column
513 if (!list.contains(clicked_section_))
514 {
515 list.clear();
516 list << clicked_section_;
517 }
518 showSections(header, list);
519}
520void DefaultCollisionsWidget::showSections(QHeaderView* header, const QList<int>& logicalIndexes)
521{
522 if (logicalIndexes.size() < 2)
523 return;
524 int prev = 0;
525 for (int next = 1, end = logicalIndexes.size(); next != end; prev = next, ++next)
526 {
527 for (int index = logicalIndexes[prev], index_end = logicalIndexes[next]; index <= index_end; ++index)
528 header->setSectionHidden(index, false);
529 }
530}
531
532void DefaultCollisionsWidget::revertChanges()
533{
534 setup_step_.linkPairsFromSRDF();
535 loadCollisionTable();
536 btn_revert_->setEnabled(false); // no changes to revert
537}
538
539bool DefaultCollisionsWidget::eventFilter(QObject* object, QEvent* event)
540{
541 if (object != collision_table_)
542 return false; // leave event unhandled
543
544 if (event->type() == QEvent::Enter)
545 {
546 // grab focus as soon as mouse enters to allow for <space> to work in all cases
547 collision_table_->setFocus();
548 return false;
549 }
550 else if (event->type() == QEvent::KeyPress)
551 {
552 QKeyEvent* key_event = static_cast<QKeyEvent*>(event);
553 if (key_event->key() != Qt::Key_Space)
554 return false;
555
556 toggleSelection(selection_model_->selection());
557 return true; // no need for further processing
558 }
559
560 return false;
561}
562
563void DefaultCollisionsWidget::toggleSelection(QItemSelection selection)
564{
565 // remove hidden rows / columns from selection
566 int rows = model_->rowCount();
567 int cols = model_->columnCount();
568 for (int r = 0; r != rows; ++r)
569 {
570 if (collision_table_->isRowHidden(r))
571 selection.merge(QItemSelection(model_->index(r, 0), model_->index(r, cols - 1)), QItemSelectionModel::Deselect);
572 }
573 for (int c = 0; c != cols; ++c)
574 {
575 if (collision_table_->isColumnHidden(c))
576 selection.merge(QItemSelection(model_->index(0, c), model_->index(rows - 1, c)), QItemSelectionModel::Deselect);
577 }
578
579 // set all selected items to inverse value of current item
580 const QModelIndex& cur_idx = selection_model_->currentIndex();
581 if (view_mode_buttons_->checkedId() == MATRIX_MODE)
582 {
583 QModelIndex input_index;
584 if (cur_idx.flags() & Qt::ItemIsUserCheckable)
585 {
586 input_index = cur_idx; // if current index is checkable, this serves as input
587 }
588 else
589 { // search for first checkable index in selection that can serve as input
590 for (const auto idx : selection.indexes())
591 {
592 if (idx.flags() & Qt::ItemIsUserCheckable)
593 {
594 input_index = idx;
595 break;
596 }
597 }
598 if (!input_index.isValid())
599 return; // no valid selection
600 }
601
602 bool current = model_->data(input_index, Qt::CheckStateRole) == Qt::Checked;
603 CollisionMatrixModel* m = static_cast<CollisionMatrixModel*>(model_);
604 m->setEnabled(selection, !current);
605 }
606 else
607 {
608 bool current = model_->data(model_->index(cur_idx.row(), 2), Qt::CheckStateRole) == Qt::Checked;
609 SortFilterProxyModel* m = static_cast<SortFilterProxyModel*>(model_);
610 m->setEnabled(selection, !current);
611 }
612}
613
614// ******************************************************************************************
615// GUI func for showing sampling density amount
616// ******************************************************************************************
617void DefaultCollisionsWidget::changeDensityLabel(int value)
618{
619 density_value_label_->setText(QString::number(value * 1000 + 1000)); //.append(" samples") );
620}
621
622// ******************************************************************************************
623// Helper function to disable parts of GUI during computation
624// ******************************************************************************************
625void DefaultCollisionsWidget::disableControls(bool disable)
626{
627 controls_box_->setDisabled(disable);
628 collision_table_->setDisabled(disable);
629
630 if (disable)
631 {
632 progress_bar_->show(); // only show when computation begins
633 progress_label_->show();
634 }
635 else
636 {
637 progress_label_->hide();
638 progress_bar_->hide();
639 }
640
641 QApplication::processEvents(); // allow the progress bar to be shown
642}
643
644// ******************************************************************************************
645// Changes the table to show or hide collisions that are not disabled (that have collision checking enabled)
646// ******************************************************************************************
647void DefaultCollisionsWidget::checkedFilterChanged()
648{
649 SortFilterProxyModel* m = qobject_cast<SortFilterProxyModel*>(model_);
650 m->setShowAll(collision_checkbox_->checkState() == Qt::Checked);
651}
652
653// ******************************************************************************************
654// Preview whatever element is selected
655// ******************************************************************************************
656void DefaultCollisionsWidget::previewSelectedMatrix(const QModelIndex& index)
657{
658 // Unhighlight all links
659 rviz_panel_->unhighlightAll();
660
661 if (!index.isValid())
662 return;
663
664 // normalize index
665 int r = index.row();
666 int c = index.column();
667 if (r == c)
668 return;
669 if (r > c)
670 std::swap(r, c);
671
672 // Highlight link pair
673 const QString& first_link = model_->headerData(r, Qt::Vertical, Qt::DisplayRole).toString();
674 const QString& second_link = model_->headerData(c, Qt::Horizontal, Qt::DisplayRole).toString();
675 uint check_state = model_->data(index, Qt::CheckStateRole).toUInt();
676
677 QColor color = (check_state == Qt::Checked) ? QColor(0, 255, 0) : QColor(255, 0, 0);
678 rviz_panel_->highlightLink(first_link.toStdString(), color);
679 rviz_panel_->highlightLink(second_link.toStdString(), color);
680}
681
682void DefaultCollisionsWidget::previewSelectedLinear(const QModelIndex& index)
683{
684 // Unhighlight all links
685 rviz_panel_->unhighlightAll();
686
687 if (!index.isValid())
688 return;
689
690 // Highlight link pair
691 const QString& first_link = model_->data(model_->index(index.row(), 0), Qt::DisplayRole).toString();
692 const QString& second_link = model_->data(model_->index(index.row(), 1), Qt::DisplayRole).toString();
693 uint check_state = model_->data(model_->index(index.row(), 2), Qt::CheckStateRole).toUInt();
694
695 QColor color = (check_state == Qt::Checked) ? QColor(0, 255, 0) : QColor(255, 0, 0);
696 rviz_panel_->highlightLink(first_link.toStdString(), color);
697 rviz_panel_->highlightLink(second_link.toStdString(), color);
698}
699
700// ******************************************************************************************
701// Called when setup assistant navigation switches to this screen
702// ******************************************************************************************
704{
705 // Convert the SRDF data to LinkPairData format
706 setup_step_.linkPairsFromSRDF();
707
708 // Load the data to the table
709 loadCollisionTable();
710
711 // Enable the table
712 disableControls(false);
713 btn_revert_->setEnabled(false); // no changes to revert
714}
715
717{
718 if (worker_)
719 {
720 if (QMessageBox::No == QMessageBox::question(this, "Collision Matrix Generation",
721 "Collision Matrix Generation is still active. Cancel computation?",
722 QMessageBox::Yes | QMessageBox::No, QMessageBox::No))
723 return false;
724 worker_->cancel();
725 worker_->wait();
726 }
727
728 // Copy changes to srdf_writer object
729 setup_step_.linkPairsToSRDF();
730 return true;
731}
732
733MonitorThread::MonitorThread(DefaultCollisions& setup_step, QProgressBar* progress_bar)
734 : setup_step_(setup_step), canceled_(false)
735{
736 // connect progress bar for updates
737 if (progress_bar)
738 connect(this, SIGNAL(progress(int)), progress_bar, SLOT(setValue(int)));
739}
740
742{
743 // loop until worker thread is finished or cancel is requested
744 int thread_progress;
745 while (!canceled_ && (thread_progress = setup_step_.getThreadProgress()) < 100)
746 {
747 Q_EMIT progress(thread_progress);
748 QThread::msleep(100); // sleep 100ms
749 }
750
751 // cancel worker thread
752 if (canceled_)
753 setup_step_.cancelGenerationThread();
754 setup_step_.joinGenerationThread();
755
756 Q_EMIT progress(100);
757}
758
759} // namespace srdf_setup
760} // namespace moveit_setup
761
762#include <pluginlib/class_list_macros.hpp> // NOLINT
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
The GUI code for one SetupStep.
virtual void focusGiven()
function called when widget is activated, allows to update/initialize GUI
virtual bool focusLost()
function called when widget loses focus, although switching away can be rejected
User interface for editing the default collision matrix list in an SRDF.
void startGenerationThread(unsigned int num_trials, double min_frac, bool verbose=true)
QThread to monitor progress of the setup step.
MonitorThread(DefaultCollisions &setup_step, QProgressBar *progress_bar=nullptr)