ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ccAsprsModel.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "../include/ccAsprsModel.h"
9 
10 // QT
11 #include <QSettings>
12 
13 ccAsprsModel::ccAsprsModel(QObject* parent) : QAbstractTableModel(parent) {
14  load();
15 
16  if (m_data.size() == 0) {
17  createDefaultItems();
18  }
19 }
20 
21 int ccAsprsModel::rowCount(const QModelIndex& parent) const {
22  Q_UNUSED(parent)
23 
24  return m_data.size();
25 }
26 
27 int ccAsprsModel::columnCount(const QModelIndex& parent) const {
28  Q_UNUSED(parent)
29 
30  return LAST;
31 }
32 
33 QVariant ccAsprsModel::headerData(int section,
34  Qt::Orientation orientation,
35  int role) const {
36  if (role != Qt::DisplayRole) return {};
37 
38  if (orientation == Qt::Vertical) return section;
39 
40  switch (section) {
41  case VISIBLE:
42  return "Visible";
43  case NAME:
44  return "Name";
45  case CODE:
46  return "Code";
47  case COLOR:
48  return "Color";
49  case COUNT:
50  return "Count";
51  default:
52  assert(false);
53  break;
54  }
55 
56  return {};
57 }
58 
59 QVariant ccAsprsModel::data(const QModelIndex& index, int role) const {
60  if (!index.isValid()) return {};
61 
62  const AsprsItem& item = m_data[index.row()];
63 
64  // specific case for the VISIBLE column
65  if (index.column() == VISIBLE) {
66  // we only provide the value for the 'CheckStateRole' role
67  if (role == Qt::CheckStateRole) {
68  return item.visible ? Qt::Checked : Qt::Unchecked;
69  } else {
70  return {};
71  }
72  }
73 
74  // for the others, we only provide the values for the 'Display' and 'Edit'
75  // roles
76  if (role != Qt::DisplayRole && role != Qt::EditRole) {
77  return {};
78  }
79 
80  switch (index.column()) {
81  case NAME:
82  return item.name;
83  case CODE:
84  return item.code;
85  case COLOR:
86  return item.color;
87  case COUNT:
88  return item.count;
89  default:
90  assert(false);
91  break;
92  }
93 
94  return {};
95 }
96 
97 bool ccAsprsModel::setData(const QModelIndex& index,
98  const QVariant& value,
99  int role) {
100  Q_UNUSED(role)
101 
102  if (!index.isValid()) {
103  return false;
104  }
105 
106  AsprsItem& item = m_data[index.row()];
107 
108  switch (index.column()) {
109  case VISIBLE: {
110  if (role == Qt::CheckStateRole) {
111  item.visible = static_cast<Qt::CheckState>(value.toInt()) ==
112  Qt::Checked;
113  emit colorChanged(item);
114  } else {
115  return false;
116  }
117  } break;
118 
119  case NAME: {
120  QString name = value.toString();
121  if (!isNameExist(name)) {
122  item.name = name;
123  break;
124  } else {
125  return false;
126  }
127  }
128 
129  case CODE: {
130  int code = value.toInt();
131  if (!isCodeExist(code)) {
132  int oldCode = item.code;
133  item.code = code;
134  emit codeChanged(item, oldCode);
135  break;
136  } else {
137  return false;
138  }
139  }
140 
141  case COLOR: {
142  item.color = value.value<QColor>();
143  emit colorChanged(item);
144  } break;
145 
146  case COUNT: {
147  item.count = value.toInt();
148  } break;
149  }
150 
151  emit dataChanged(index, index);
152 
153  return true;
154 }
155 
156 Qt::ItemFlags ccAsprsModel::flags(const QModelIndex& index) const {
157  if (!index.isValid()) {
158  return Qt::ItemIsEnabled;
159  }
160 
161  Qt::ItemFlags f = QAbstractItemModel::flags(index);
162  if (index.column() == NAME || index.column() == CODE) {
163  f |= (Qt::ItemIsEditable);
164  } else if (index.column() == VISIBLE) {
165  f |= (Qt::ItemIsUserCheckable);
166  }
167 
168  return f;
169 }
170 
172  const int rowNumber = m_data.size();
173  beginInsertRows(QModelIndex(), rowNumber, rowNumber);
174  m_data.append(
175  {false, "UNNAMED", getUnusedCode(), Qt::GlobalColor::black, 0});
176  endInsertRows();
177 
178  return createIndex(rowNumber, NAME);
179 }
180 
181 bool ccAsprsModel::isNameExist(const QString& name) const {
182  auto item = std::find_if(
183  m_data.begin(), m_data.end(),
184  [name](const AsprsItem& item) { return item.name == name; });
185  return item != m_data.end();
186 }
187 
188 bool ccAsprsModel::isCodeExist(int code) const {
189  auto item = std::find_if(
190  m_data.begin(), m_data.end(),
191  [code](const AsprsItem& item) { return item.code == code; });
192  return item != m_data.end();
193 }
194 
195 static void AddClass(QSettings& settings,
196  const QString& className,
197  int classValue,
198  QColor classColor,
199  bool visible = true) {
200  QString cleanClassName = className;
201  cleanClassName.replace(QChar('/'), QChar('@'));
202 
203  settings.beginGroup(cleanClassName);
204  {
205  settings.setValue("class", classValue);
206  settings.setValue("color", classColor.rgb());
207  settings.setValue("visible", visible);
208  }
209  settings.endGroup();
210 }
211 
212 static void ReadClass(const QSettings& settings,
213  const QString& className,
214  ccAsprsModel::AsprsItem& item) {
215  QString cleanClassName = className;
216  cleanClassName.replace(QChar('/'), QChar('@'));
217 
218  QString readableClassName = className;
219  readableClassName.replace(QChar('@'), QChar('/'));
220 
221  item.name = readableClassName;
222  item.code = settings.value(cleanClassName + "/class", 0).toInt();
223  item.color = QColor(settings.value(cleanClassName + "/color", 0).toUInt());
224  item.visible = settings.value(cleanClassName + "/visible", true).toBool();
225  item.count = 0;
226 }
227 
228 void ccAsprsModel::createDefaultItems() {
229  QSettings settings;
230  settings.beginGroup("qCloudLayers/ASPRS");
231  {
232  AddClass(settings, "Not classified", 0, Qt::white);
233  AddClass(settings, "Unclassified", 1, Qt::lightGray);
234  AddClass(settings, "Ground", 2, qRgb(166, 116, 4));
235  AddClass(settings, "Low vegetation", 3, qRgb(38, 114, 0));
236  AddClass(settings, "Medium vegetation", 4, qRgb(69, 229, 0));
237  AddClass(settings, "High vegetation", 5, qRgb(204, 240, 123));
238  AddClass(settings, "Building", 6, Qt::yellow);
239  AddClass(settings, "Low Noise", 7, Qt::red);
240  AddClass(settings, "Model Keypoint", 8, Qt::magenta);
241  AddClass(settings, "Water", 9, Qt::blue);
242  AddClass(settings, "Rail", 10, qRgb(85, 85, 0));
243  AddClass(settings, "Road surface", 11, Qt::darkGray);
244  AddClass(settings, "Overlap", 12, qRgb(255, 170, 255));
245  AddClass(settings, "Wire Shield/Neutral/Com", 13, qRgb(191, 231, 205));
246  AddClass(settings, "Wire Conductors/Phases", 14, qRgb(193, 230, 125));
247  AddClass(settings, "Transmission Tower", 15, Qt::darkBlue);
248  AddClass(settings, "Wire Insulators", 16, Qt::darkYellow);
249  AddClass(settings, "Bridge Deck", 17, Qt::darkCyan);
250  AddClass(settings, "High Noise", 18, Qt::darkRed);
251 
252  AddClass(settings, "Conductor Attachment Points", 64, qRgb(25, 0, 51));
253  AddClass(settings, "Shield Attachment Points", 65, qRgb(51, 0, 102));
254  AddClass(settings, "Midspan Points", 66, qRgb(76, 0, 153));
255  AddClass(settings, "Structure Top Points", 67, qRgb(102, 0, 204));
256  AddClass(settings, "Structure Bottom Points", 68, qRgb(127, 0, 255));
257 
258  AddClass(settings, "Guy Wire", 70, qRgb(153, 51, 255));
259  AddClass(settings, "Substation", 75, qRgb(178, 102, 255));
260 
261  AddClass(settings, "Misc Temporary", 81, qRgb(204, 153, 255));
262  AddClass(settings, "Misc Permanent", 82, qRgb(229, 204, 255));
263  AddClass(settings, "Misc Fences", 83, qRgb(204, 204, 255));
264  }
265  settings.endGroup();
266  settings.sync();
267 
268  load();
269 }
270 
272  QSettings settings;
273  settings.beginGroup("qCloudLayers/ASPRS");
274 
275  QStringList classes = settings.childGroups();
276 
277  m_data.clear();
278  m_data.reserve(classes.size());
279  for (int i = 0; i < classes.length(); ++i) {
281  ReadClass(settings, classes[i], item);
282  m_data.append(item);
283  }
284 }
285 
286 void ccAsprsModel::save() const {
287  QSettings settings;
288  settings.remove("qCloudLayers/ASPRS");
289  settings.beginGroup("qCloudLayers/ASPRS");
290  {
291  for (int i = 0; i < m_data.length(); ++i) {
292  const AsprsItem& item = m_data[i];
293  AddClass(settings, item.name, item.code, item.color, item.visible);
294  }
295  }
296  settings.endGroup();
297  settings.sync();
298 }
299 
301  QModelIndex a = createIndex(0, COUNT);
302  QModelIndex b = createIndex(m_data.count() - 1, COUNT);
303  emit dataChanged(a, b);
304 }
305 
307  int rows,
308  const QModelIndex& parent) {
309  Q_UNUSED(parent);
310 
311  beginRemoveRows(QModelIndex(), position, position + rows - 1);
312  for (int i = 0; i < rows; ++i) {
313  m_data.removeAt(position);
314  }
315  endRemoveRows();
316 
317  return true;
318 }
319 
321  auto it = std::find_if(m_data.begin(), m_data.end(),
322  [name](const ccAsprsModel::AsprsItem& item) {
323  return item.name == name;
324  });
325  return it != m_data.end() ? &(*it) : nullptr;
326 }
327 
329  auto it = std::find_if(m_data.begin(), m_data.end(),
330  [code](const ccAsprsModel::AsprsItem& item) {
331  return item.code == code;
332  });
333  return it != m_data.end() ? &(*it) : nullptr;
334 }
335 
336 int ccAsprsModel::indexOf(QString name) const {
337  auto it = std::find_if(m_data.begin(), m_data.end(),
338  [name](const ccAsprsModel::AsprsItem& item) {
339  return item.name == name;
340  });
341  return it != m_data.end() ? it - m_data.begin() : -1;
342 }
343 
344 int ccAsprsModel::getUnusedCode() const {
345  auto it = std::max_element(m_data.cbegin(), m_data.cend(),
346  [](const AsprsItem& a, const AsprsItem& b) {
347  return a.code < b.code;
348  });
349  return it != m_data.end() ? (*it).code + 1 : 0;
350 }
std::string name
math::float3 position
static void ReadClass(const QSettings &settings, const QString &className, ccAsprsModel::AsprsItem &item)
static void AddClass(QSettings &settings, const QString &className, int classValue, QColor classColor, bool visible=true)
bool removeRows(int position, int rows, const QModelIndex &parent)
void colorChanged(AsprsItem &item)
QVariant headerData(int section, Qt::Orientation orientation, int role) const
void refreshData()
int rowCount(const QModelIndex &parent) const
AsprsItem * find(QString name)
int columnCount(const QModelIndex &parent) const
int indexOf(QString name) const
QVariant data(const QModelIndex &index, int role) const
void save() const
QModelIndex createNewItem()
void codeChanged(AsprsItem &item, int oldCode)
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole)
Qt::ItemFlags flags(const QModelIndex &index) const
ccAsprsModel(QObject *parent=nullptr)
constexpr Rgb black(0, 0, 0)
constexpr Rgb magenta(MAX, 0, MAX)
constexpr Rgb darkBlue(0, 0, MAX/2)
constexpr Rgb white(MAX, MAX, MAX)
constexpr Rgb red(MAX, 0, 0)
constexpr Rgb blue(0, 0, MAX)
constexpr Rgb yellow(MAX, MAX, 0)