collision_linear_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 
37 #include "collision_linear_model.h"
38 #include "collision_matrix_model.h"
39 
40 #include <QItemSelection>
41 #include <QPainter>
42 #include <QtCore/QRegularExpression>
43 #include <cmath>
44 
45 CollisionLinearModel::CollisionLinearModel(CollisionMatrixModel* src, QObject* parent) : QAbstractProxyModel(parent)
46 {
47  setSourceModel(src);
48 }
50 {
51  delete sourceModel();
52 }
53 
54 QModelIndex CollisionLinearModel::mapFromSource(const QModelIndex& sourceIndex) const
55 {
56  // map (row,column) index to linear index k
57  // http://stackoverflow.com/questions/27086195/linear-index-upper-triangular-matrix
58  int r = sourceIndex.row(), c = sourceIndex.column();
59  int n = this->sourceModel()->columnCount();
60  if (r == c)
61  return QModelIndex(); // main diagonal elements are invalid
62  if (r > c) // only consider upper triagonal matrix
63  std::swap(r, c); // swap r,c if below diagonal
64 
65  int k = (n * (n - 1) / 2) - (n - r) * ((n - r) - 1) / 2 + c - r - 1;
66  return index(k, 2);
67 }
68 
69 QModelIndex CollisionLinearModel::mapToSource(const QModelIndex& proxyIndex) const
70 {
71  // map linear index k to (row, column)
72  // http://stackoverflow.com/questions/27086195/linear-index-upper-triangular-matrix
73  int n = sourceModel()->columnCount();
74  int k = proxyIndex.row(); // linear (row) index
75  int r = n - 2 - (int)(sqrt(-8 * k + 4 * n * (n - 1) - 7) / 2.0 - 0.5);
76  int c = k + r + 1 - n * (n - 1) / 2 + (n - r) * ((n - r) - 1) / 2;
77  return sourceModel()->index(r, c);
78 }
79 
80 int CollisionLinearModel::rowCount(const QModelIndex& /*parent*/) const
81 {
82  int n = this->sourceModel()->rowCount();
83  return (n * (n - 1) / 2);
84 }
85 
86 int CollisionLinearModel::columnCount(const QModelIndex& /*parent*/) const
87 {
88  return 4;
89 }
90 
91 QModelIndex CollisionLinearModel::index(int row, int column, const QModelIndex& /*parent*/) const
92 {
93  return createIndex(row, column);
94 }
95 
96 QModelIndex CollisionLinearModel::parent(const QModelIndex& /*child*/) const
97 {
98  return QModelIndex();
99 }
100 
101 QVariant CollisionLinearModel::data(const QModelIndex& index, int role) const
102 {
103  QModelIndex src_index = this->mapToSource(index);
104  switch (index.column())
105  {
106  case 0: // link name 1
107  if (role != Qt::DisplayRole)
108  return QVariant();
109  else
110  return this->sourceModel()->headerData(src_index.row(), Qt::Horizontal, Qt::DisplayRole);
111  case 1: // link name 2
112  if (role != Qt::DisplayRole)
113  return QVariant();
114  return this->sourceModel()->headerData(src_index.column(), Qt::Vertical, Qt::DisplayRole);
115  case 2: // checkbox
116  if (role != Qt::CheckStateRole)
117  return QVariant();
118  else
119  return this->sourceModel()->data(src_index, Qt::CheckStateRole);
120  case 3: // reason
121  if (role != Qt::DisplayRole)
122  return QVariant();
123  else
124  return this->sourceModel()->data(src_index, Qt::ToolTipRole);
125  }
126  return QVariant();
127 }
128 
129 bool CollisionLinearModel::setData(const QModelIndex& index, const QVariant& value, int role)
130 {
131  if (role == Qt::CheckStateRole)
132  {
133  QModelIndex src_index = this->mapToSource(index);
134  if (sourceModel()->setData(src_index, value, role))
135  {
136  int r = index.row();
137  Q_EMIT dataChanged(this->index(r, 2), this->index(r, 3)); // reason changed too
138  return true;
139  }
140  }
141  return false; // reject all other changes
142 }
143 
144 void CollisionLinearModel::setEnabled(const QItemSelection& selection, bool value)
145 {
146  for (const auto idx : selection.indexes())
147  {
148  if (idx.column() != 2) // only consider checkbox indexes
149  continue;
150  setData(idx, value ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);
151  }
152 }
153 
154 Qt::ItemFlags CollisionLinearModel::flags(const QModelIndex& index) const
155 {
156  if (index.column() == 2)
157  return Qt::ItemIsUserCheckable | QAbstractItemModel::flags(index);
158  else
159  return QAbstractItemModel::flags(index);
160 }
161 
162 QVariant CollisionLinearModel::headerData(int section, Qt::Orientation orientation, int role) const
163 {
164  if (role != Qt::DisplayRole)
165  return QVariant();
166 
167  if (orientation == Qt::Horizontal)
168  {
169  switch (section)
170  {
171  case 0:
172  return "Link A";
173  case 1:
174  return "Link B";
175  case 2:
176  return "Disabled";
177  case 3:
178  return "Reason to Disable";
179  }
180  }
181  else if (orientation == Qt::Vertical)
182  {
183  return section + 1;
184  }
185  return QVariant();
186 }
187 
188 SortFilterProxyModel::SortFilterProxyModel(QObject* parent) : QSortFilterProxyModel(parent), show_all_(false)
189 {
190 #if (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0))
191  connect(this, SIGNAL(sourceModelChanged()), this, SLOT(initSorting()));
192 #endif
193 
194  // by default: sort by link A (col 0), then link B (col 1)
195  sort_columns_ << 0 << 1;
196  sort_orders_ << Qt::AscendingOrder << Qt::AscendingOrder;
197 }
198 
199 QVariant SortFilterProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
200 {
201  if (role == Qt::DisplayRole && orientation == Qt::Vertical)
202  return section + 1; // simply enumerate rows
203  else
204  return QSortFilterProxyModel::headerData(section, orientation, role);
205 }
206 
207 void SortFilterProxyModel::setEnabled(const QItemSelection& selection, bool value)
208 {
209  static_cast<CollisionLinearModel*>(sourceModel())->setEnabled(mapSelectionToSource(selection), value);
210 }
211 
213 {
214  int cols = sourceModel()->columnCount();
215  int prev_size = sort_columns_.size();
216  sort_columns_.resize(cols);
217  sort_orders_.resize(cols);
218 
219  // initialize new entries to -1
220  for (int i = prev_size, end = sort_columns_.size(); i < end; ++i)
221  sort_columns_[i] = -1;
222 }
223 
225 {
226  if (show_all_ == show_all)
227  return;
228 
229  show_all_ = show_all;
230  invalidateFilter();
231 }
232 
233 bool SortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
234 {
235  CollisionLinearModel* m = qobject_cast<CollisionLinearModel*>(sourceModel());
236  if (!(show_all_ || m->data(m->index(source_row, 2), Qt::CheckStateRole) == Qt::Checked))
237  return false; // not accepted due to check state
238 #if (QT_VERSION < QT_VERSION_CHECK(5, 12, 0))
239  const QRegExp regexp = this->filterRegExp();
240  if (regexp.isEmpty())
241  return true;
242 #else
243  const QRegularExpression regexp = this->filterRegularExpression();
244  if (!regexp.isValid())
245  return true;
246 #endif
247 
248  return m->data(m->index(source_row, 0, source_parent), Qt::DisplayRole).toString().contains(regexp) ||
249  m->data(m->index(source_row, 1, source_parent), Qt::DisplayRole).toString().contains(regexp);
250 }
251 
252 // define a fallback comparison operator for QVariants
253 #if (QT_VERSION < QT_VERSION_CHECK(5, 0, 0))
254 namespace
255 {
256 bool operator<(const QVariant& left, const QVariant& right)
257 {
258  if (left.userType() == QVariant::Type::Int)
259  return left.toInt() < right.toInt();
260  else
261  return left.toString() < right.toString();
262 }
263 } // namespace
264 #endif
265 
266 bool SortFilterProxyModel::lessThan(const QModelIndex& src_left, const QModelIndex& src_right) const
267 {
268  int row_left = src_left.row();
269  int row_right = src_right.row();
270  QAbstractItemModel* m = sourceModel();
271 
272  for (int i = 0, end = sort_columns_.size(); i < end && sort_columns_[i] >= 0; ++i)
273  {
274  int sc = sort_columns_[i];
275  int role = sc == 2 ? Qt::CheckStateRole : Qt::DisplayRole;
276  QVariant value_left = m->data(m->index(row_left, sc), role);
277  QVariant value_right = m->data(m->index(row_right, sc), role);
278 
279  if (value_left == value_right)
280  continue;
281 
282  bool smaller{};
283 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
284  switch (value_left.type())
285 #else
286  switch (value_left.typeId())
287 #endif
288  {
289  case QVariant::Int:
290  smaller = value_left.toInt() < value_right.toInt();
291  break;
292  default:
293  smaller = value_left.toString() < value_right.toString();
294  break;
295  }
296  if (sort_orders_[i] == Qt::DescendingOrder)
297  smaller = !smaller;
298  return smaller;
299  }
300  return false;
301 }
302 
303 void SortFilterProxyModel::sort(int column, Qt::SortOrder order)
304 {
305  beginResetModel();
306  if (column < 0)
307  initSorting();
308  else
309  {
310  // remember sorting history
311  int prev_idx = sort_columns_.indexOf(column);
312  if (prev_idx < 0)
313  prev_idx = sort_columns_.size() - 1;
314  // remove old entries
315  sort_columns_.remove(prev_idx);
316  sort_orders_.remove(prev_idx);
317  // add new entries at front
318  sort_columns_.insert(0, column);
319  sort_orders_.insert(0, order);
320  }
321  QSortFilterProxyModel::sort(column, Qt::AscendingOrder);
322  endResetModel();
323 }
CollisionLinearModel::~CollisionLinearModel
~CollisionLinearModel() override
Definition: collision_linear_model.cpp:49
CollisionMatrixModel
Definition: collision_matrix_model.h:48
SortFilterProxyModel::setEnabled
void setEnabled(const QItemSelection &selection, bool value)
Definition: collision_linear_model.cpp:207
CollisionLinearModel::rowCount
int rowCount(const QModelIndex &parent) const override
Definition: collision_linear_model.cpp:80
r
r
CollisionLinearModel::setData
bool setData(const QModelIndex &index, const QVariant &value, int role) override
Definition: collision_linear_model.cpp:129
CollisionLinearModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Definition: collision_linear_model.cpp:91
CollisionLinearModel
Definition: collision_linear_model.h:45
SortFilterProxyModel::initSorting
void initSorting()
Definition: collision_linear_model.cpp:212
CollisionLinearModel::setEnabled
void setEnabled(const QItemSelection &selection, bool value)
Definition: collision_linear_model.cpp:144
SortFilterProxyModel::lessThan
bool lessThan(const QModelIndex &src_left, const QModelIndex &src_right) const override
Definition: collision_linear_model.cpp:266
collision_matrix_model.h
c
c
SortFilterProxyModel::SortFilterProxyModel
SortFilterProxyModel(QObject *parent=nullptr)
Definition: collision_linear_model.cpp:188
CollisionLinearModel::mapFromSource
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override
Definition: collision_linear_model.cpp:54
SortFilterProxyModel::show_all_
bool show_all_
Definition: collision_linear_model.h:93
value
float value
CollisionLinearModel::CollisionLinearModel
CollisionLinearModel(CollisionMatrixModel *src, QObject *parent=nullptr)
Definition: collision_linear_model.cpp:45
SortFilterProxyModel::sort_orders_
QVector< int > sort_orders_
Definition: collision_linear_model.h:95
m
m
CollisionLinearModel::flags
Qt::ItemFlags flags(const QModelIndex &index) const override
Definition: collision_linear_model.cpp:154
CollisionLinearModel::parent
QModelIndex parent(const QModelIndex &child) const override
Definition: collision_linear_model.cpp:96
collision_linear_model.h
cols
int cols
SortFilterProxyModel::sort_columns_
QVector< int > sort_columns_
Definition: collision_linear_model.h:94
CollisionLinearModel::mapToSource
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override
Definition: collision_linear_model.cpp:69
CollisionLinearModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
Definition: collision_linear_model.cpp:162
SortFilterProxyModel::filterAcceptsRow
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
Definition: collision_linear_model.cpp:233
SortFilterProxyModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
Definition: collision_linear_model.cpp:199
CollisionLinearModel::data
QVariant data(const QModelIndex &index, int role) const override
Definition: collision_linear_model.cpp:101
SortFilterProxyModel::sort
void sort(int column, Qt::SortOrder order) override
Definition: collision_linear_model.cpp:303
SortFilterProxyModel::setShowAll
void setShowAll(bool show_all)
Definition: collision_linear_model.cpp:224
CollisionLinearModel::columnCount
int columnCount(const QModelIndex &parent) const override
Definition: collision_linear_model.cpp:86


moveit_setup_assistant
Author(s): Dave Coleman
autogenerated on Sat May 3 2025 02:28:04