moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
collision_matrix_model.cpp
Go to the documentation of this file.
1/*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2016, 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 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: Robert Haschke */
36
38#include <boost/assign.hpp>
39#include <QVector>
40#include <QBrush>
41#include <QColor>
42#include <QPalette>
43#include <QApplication>
44#include <QItemSelection>
45#include <unordered_map>
46
47namespace moveit_setup
48{
49namespace srdf_setup
50{
52static const std::unordered_map<DisabledReason, const char*> LONG_REASONS_TO_STRING =
53 boost::assign::map_list_of // clang-format off
54 ( NEVER, "Never in Collision" )
55 ( DEFAULT, "Collision by Default" )
56 ( ADJACENT, "Adjacent Links" )
57 ( ALWAYS, "Always in Collision" )
58 ( USER, "User Disabled" )
59 ( NOT_DISABLED, ""); // clang-format on
60
62static const std::unordered_map<DisabledReason, QVariant> LONG_REASONS_TO_BRUSH =
63 boost::assign::map_list_of // clang-format off
64 ( NEVER, QBrush(QColor("lightgreen")) )
65 ( DEFAULT, QBrush(QColor("lightpink")) )
66 ( ADJACENT, QBrush(QColor("powderblue")) )
67 ( ALWAYS, QBrush(QColor("tomato")) )
68 ( USER, QBrush(QColor("yellow")) )
69 ( NOT_DISABLED, QBrush()); // clang-format on
70
71CollisionMatrixModel::CollisionMatrixModel(LinkPairMap& pairs, const std::vector<std::string>& names, QObject* parent)
72 : QAbstractTableModel(parent), pairs_(pairs), std_names_(names)
73{
74 int idx = 0;
75 for (std::vector<std::string>::const_iterator it = names.begin(), end = names.end(); it != end; ++it, ++idx)
76 {
77 visual_to_index_ << idx;
78 q_names_ << QString::fromStdString(*it);
79 }
80}
81
82// return item in pairs map given a normalized index, use item(normalized(index))
83LinkPairMap::iterator CollisionMatrixModel::item(const QModelIndex& index)
84{
85 int r = visual_to_index_[index.row()], c = visual_to_index_[index.column()];
86 if (r == c)
87 return pairs_.end();
88
89 // setLinkPair() actually inserts the pair (A,B) where A < B
90 if (std_names_[r] >= std_names_[c])
91 std::swap(r, c);
92
93 return pairs_.find(std::make_pair(std_names_[r], std_names_[c]));
94}
95
96int CollisionMatrixModel::rowCount(const QModelIndex& /*parent*/) const
97{
98 return visual_to_index_.size();
99}
100
101int CollisionMatrixModel::columnCount(const QModelIndex& /*parent*/) const
102{
103 return visual_to_index_.size();
104}
105
106QVariant CollisionMatrixModel::data(const QModelIndex& index, int role) const
107{
108 if (index.isValid() && index.row() == index.column() && role == Qt::BackgroundRole)
109 return QApplication::palette().window();
110
111 LinkPairMap::const_iterator item = this->item(index);
112 if (item == pairs_.end())
113 return QVariant();
114
115 switch (role)
116 {
117 case Qt::CheckStateRole:
118 return item->second.disable_check ? Qt::Checked : Qt::Unchecked;
119 case Qt::ToolTipRole:
120 return LONG_REASONS_TO_STRING.at(item->second.reason);
121 case Qt::BackgroundRole:
122 return LONG_REASONS_TO_BRUSH.at(item->second.reason);
123 }
124 return QVariant();
125}
126
127DisabledReason CollisionMatrixModel::reason(const QModelIndex& index) const
128{
129 LinkPairMap::const_iterator item = this->item(index);
130 if (item == pairs_.end())
131 return NOT_DISABLED;
132 return item->second.reason;
133}
134
135bool CollisionMatrixModel::setData(const QModelIndex& index, const QVariant& value, int role)
136{
137 if (role == Qt::CheckStateRole)
138 {
139 LinkPairMap::iterator item = this->item(index);
140 if (item == pairs_.end())
141 return false;
142
143 bool new_value = (value.toInt() == Qt::Checked);
144 if (item->second.disable_check == new_value)
145 return true;
146
147 item->second.disable_check = new_value;
148
149 // Handle USER Reasons: 1) pair is disabled by user
150 if (item->second.disable_check && item->second.reason == NOT_DISABLED)
151 {
152 item->second.reason = USER;
153
154 // Handle USER Reasons: 2) pair was disabled by user and now is enabled (not checked)
155 }
156 else if (!item->second.disable_check && item->second.reason == USER)
157 {
158 item->second.reason = NOT_DISABLED;
159 }
160
161 QModelIndex mirror = this->index(index.column(), index.row());
162 Q_EMIT dataChanged(index, index);
163 Q_EMIT dataChanged(mirror, mirror);
164 return true;
165 }
166 return false; // reject all other changes
167}
168
169void CollisionMatrixModel::setEnabled(const QItemSelection& selection, bool value)
170{
171 // perform changes without signalling
172 QItemSelection changes;
173 blockSignals(true);
174 for (const auto& range : selection)
175 {
176 setEnabled(range.indexes(), value);
177
178 const QModelIndex& top_left = range.topLeft();
179 const QModelIndex& bottom_right = range.bottomRight();
180 changes.select(top_left, bottom_right);
181 changes.select(createIndex(top_left.column(), top_left.row()),
182 createIndex(bottom_right.column(), bottom_right.row()));
183 }
184 blockSignals(false);
185
186 // emit changes
187 for (const auto& range : changes)
188 Q_EMIT dataChanged(range.topLeft(), range.bottomRight());
189}
190
191void CollisionMatrixModel::setEnabled(const QModelIndexList& indexes, bool value)
192{
193 for (const auto idx : indexes)
194 setData(idx, value ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
195}
196
197void CollisionMatrixModel::setFilterRegExp(const QString& filter)
198{
199 beginResetModel();
200 QRegExp regexp(filter);
201 visual_to_index_.clear();
202 for (int idx = 0, end = q_names_.size(); idx != end; ++idx)
203 {
204 if (q_names_[idx].contains(regexp))
205 visual_to_index_ << idx;
206 }
207 endResetModel();
208}
209
210QVariant CollisionMatrixModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const
211{
212 if (role == Qt::DisplayRole)
213 return q_names_[visual_to_index_[section]];
214 return QVariant();
215}
216
217Qt::ItemFlags CollisionMatrixModel::flags(const QModelIndex& index) const
218{
219 if (!index.isValid())
220 return Qt::NoItemFlags;
221
222 Qt::ItemFlags f = QAbstractTableModel::flags(index);
223 if (index.row() != index.column())
224 f |= Qt::ItemIsUserCheckable;
225 return f;
226}
227} // namespace srdf_setup
228} // namespace moveit_setup
int columnCount(const QModelIndex &parent=QModelIndex()) const override
bool setData(const QModelIndex &, const QVariant &value, int role) override
CollisionMatrixModel(LinkPairMap &pairs, const std::vector< std::string > &names, QObject *parent=nullptr)
void setEnabled(const QItemSelection &selection, bool value)
DisabledReason reason(const QModelIndex &index) const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Qt::ItemFlags flags(const QModelIndex &index) const override
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
DisabledReason
Reasons for disabling link pairs. Append "in collision" for understanding. NOT_DISABLED means the lin...
std::map< std::pair< std::string, std::string >, LinkPairData > LinkPairMap
LinkPairMap is an adjacency list structure containing links in string-based form. Used for disabled l...