13 #include <QApplication>
14 #include <QHeaderView>
15 #include <QInputDialog>
17 #include <QMessageBox>
20 #include <QStandardItemModel>
91 if (mIconMap.isEmpty()) {
95 if (!mIconMap.contains(
id)) {
96 return (locked ? mDefaultIcons.second : mDefaultIcons.first);
99 const int index = mIconMap[id];
100 const IconPair& icons = mIconList[index];
108 return (icons.second.isNull() ? icons.first : icons.second);
114 using IconPairList = QVector<IconPair>;
115 using IconMap = QMap<CV_CLASS_ENUM, int>;
121 QIcon(QStringLiteral(
":/Resources/images/dbLockSymbol.png"))};
123 const int hObjectIndex = mIconList.count();
125 {QIcon(QStringLiteral(
126 ":/Resources/images/dbHObjectSymbol.png")),
127 QIcon(QStringLiteral(
128 ":/Resources/images/dbHObjectSymbolLocked.png"))});
130 const int cloudIndex = mIconList.count();
132 {QIcon(QStringLiteral(
":/Resources/images/dbCloudSymbol.png")),
133 QIcon(QStringLiteral(
134 ":/Resources/images/dbCloudSymbolLocked.png"))});
136 const int geomIndex = mIconList.count();
138 {QIcon(QStringLiteral(
139 ":/Resources/images/dbMiscGeomSymbol.png")),
140 QIcon(QStringLiteral(
141 ":/Resources/images/dbMiscGeomSymbolLocked.png"))});
143 const int meshIndex = mIconList.count();
145 {QIcon(QStringLiteral(
":/Resources/images/dbMeshSymbol.png")),
146 QIcon(QStringLiteral(
147 ":/Resources/images/dbMeshSymbolLocked.png"))});
149 const int subMeshIndex = mIconList.count();
151 {QIcon(QStringLiteral(
152 ":/Resources/images/dbSubMeshSymbol.png")),
153 QIcon(QStringLiteral(
154 ":/Resources/images/dbSubMeshSymbolLocked.png"))});
156 const int polyLineIndex = mIconList.count();
157 mIconList.append({QIcon(QStringLiteral(
158 ":/Resources/images/dbPolylineSymbol.png")),
161 const int circleIndex = mIconList.count();
163 {QIcon(QStringLiteral(
":/Resources/images/dbCircle.png")), {}});
165 const int octreeIndex = mIconList.count();
167 {QIcon(QStringLiteral(
":/Resources/images/dbOctreeSymbol.png")),
168 QIcon(QStringLiteral(
169 ":/Resources/images/dbOctreeSymbolLocked.png"))});
171 const int calibratedImageIndex = mIconList.count();
173 {QIcon(QStringLiteral(
174 ":/Resources/images/dbCalibratedImageSymbol.png")),
177 const int imageIndex = mIconList.count();
179 {QIcon(QStringLiteral(
":/Resources/images/dbImageSymbol.png")),
182 const int sensorIndex = mIconList.count();
183 mIconList.append({QIcon(QStringLiteral(
184 ":/Resources/images/dbGBLSensorSymbol.png")),
187 const int cameraSensorIndex = mIconList.count();
188 mIconList.append({QIcon(QStringLiteral(
189 ":/Resources/images/dbCamSensorSymbol.png")),
192 const int materialSetIndex = mIconList.count();
193 mIconList.append({QIcon(QStringLiteral(
194 ":/Resources/images/dbMaterialSymbol.png")),
197 const int containerIndex = mIconList.count();
199 {QIcon(QStringLiteral(
200 ":/Resources/images/dbContainerSymbol.png")),
201 QIcon(QStringLiteral(
202 ":/Resources/images/dbContainerSymbolLocked.png"))});
204 const int labelIndex = mIconList.count();
206 {QIcon(QStringLiteral(
":/Resources/images/dbLabelSymbol.png")),
209 const int viewportObjIndex = mIconList.count();
210 mIconList.append({QIcon(QStringLiteral(
211 ":/Resources/images/dbViewportSymbol.png")),
214 const int viewportLabelIndex = mIconList.count();
215 mIconList.append({QIcon(QStringLiteral(
216 ":/Resources/images/dbAreaLabelSymbol.png")),
255 IconPair mDefaultIcons;
256 IconPairList mIconList;
263 QTreeView* propertiesTreeWidget,
265 : QAbstractItemModel(parent) {
269 assert(dbTreeWidget);
270 m_dbTreeWidget = dbTreeWidget;
271 m_dbTreeWidget->setModel(
this);
272 m_dbTreeWidget->header()->hide();
275 m_dbTreeWidget->setDragEnabled(
true);
276 m_dbTreeWidget->setAcceptDrops(
true);
277 m_dbTreeWidget->setDropIndicatorShown(
true);
280 m_dbTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
281 m_expandBranch =
new QAction(tr(
"Expand branch"),
this);
282 m_collapseBranch =
new QAction(tr(
"Collapse branch"),
this);
283 m_gatherInformation =
new QAction(tr(
"Information (recursive)"),
this);
284 m_sortChildrenType =
new QAction(tr(
"Sort children by type"),
this);
285 m_sortChildrenAZ =
new QAction(tr(
"Sort children by name (A-Z)"),
this);
286 m_sortChildrenZA =
new QAction(tr(
"Sort children by name (Z-A)"),
this);
287 m_selectByTypeAndName =
288 new QAction(tr(
"Select children by type and/or name"),
this);
289 m_exportImages =
new QAction(tr(
"Export images"),
this);
290 m_deleteSelectedEntities =
new QAction(tr(
"Delete"),
this);
291 m_toggleSelectedEntities =
new QAction(tr(
"Toggle"),
this);
292 m_toggleSelectedEntitiesVisibility =
293 new QAction(tr(
"Toggle visibility"),
this);
294 m_toggleSelectedEntitiesColor =
new QAction(tr(
"Toggle color"),
this);
295 m_toggleSelectedEntitiesNormals =
new QAction(tr(
"Toggle normals"),
this);
296 m_toggleSelectedEntitiesMat =
297 new QAction(tr(
"Toggle materials/textures"),
this);
298 m_toggleSelectedEntitiesSF =
new QAction(tr(
"Toggle SF"),
this);
299 m_toggleSelectedEntities3DName =
new QAction(tr(
"Toggle 3D name"),
this);
300 m_addEmptyGroup =
new QAction(tr(
"Add empty group"),
this);
301 m_alignCameraWithEntity =
new QAction(tr(
"Align camera"),
this);
302 m_alignCameraWithEntityReverse =
303 new QAction(tr(
"Align camera (reverse)"),
this);
304 m_enableBubbleViewMode =
new QAction(tr(
"Bubble-view"),
this);
305 m_editLabelScalarValue =
new QAction(tr(
"Edit scalar value"),
this);
307 m_contextMenuPos = QPoint(-1, -1);
310 connect(m_dbTreeWidget, &QWidget::customContextMenuRequested,
this,
313 connect(m_collapseBranch, &QAction::triggered,
this,
315 connect(m_gatherInformation, &QAction::triggered,
this,
317 connect(m_sortChildrenAZ, &QAction::triggered,
this,
319 connect(m_sortChildrenZA, &QAction::triggered,
this,
321 connect(m_sortChildrenType, &QAction::triggered,
this,
323 connect(m_selectByTypeAndName, &QAction::triggered,
this,
326 connect(m_deleteSelectedEntities, &QAction::triggered,
this,
328 connect(m_toggleSelectedEntities, &QAction::triggered,
this,
330 connect(m_toggleSelectedEntitiesVisibility, &QAction::triggered,
this,
332 connect(m_toggleSelectedEntitiesColor, &QAction::triggered,
this,
334 connect(m_toggleSelectedEntitiesNormals, &QAction::triggered,
this,
336 connect(m_toggleSelectedEntitiesMat, &QAction::triggered,
this,
338 connect(m_toggleSelectedEntitiesSF, &QAction::triggered,
this,
340 connect(m_toggleSelectedEntities3DName, &QAction::triggered,
this,
342 connect(m_addEmptyGroup, &QAction::triggered,
this,
344 connect(m_alignCameraWithEntity, &QAction::triggered,
this,
346 connect(m_alignCameraWithEntityReverse, &QAction::triggered,
this,
348 connect(m_enableBubbleViewMode, &QAction::triggered,
this,
350 connect(m_editLabelScalarValue, &QAction::triggered,
this,
354 connect(m_dbTreeWidget->selectionModel(),
355 &QItemSelectionModel::selectionChanged,
this,
359 assert(propertiesTreeWidget);
360 m_propertiesTreeWidget = propertiesTreeWidget;
361 m_propertiesModel =
new QStandardItemModel(0, 2, parent);
363 m_propertiesTreeWidget);
364 m_propertiesTreeWidget->setItemDelegate(m_ccPropDelegate);
365 m_propertiesTreeWidget->setModel(m_propertiesModel);
366 m_propertiesTreeWidget->header()->setSectionResizeMode(
367 QHeaderView::Interactive);
368 m_propertiesTreeWidget->setEnabled(
false);
371 connect(m_ccPropDelegate,
374 connect(m_ccPropDelegate,
377 connect(m_ccPropDelegate,
453 QModelIndex insertNodeIndex =
index(parentObject);
457 beginInsertRows(insertNodeIndex, childPos, childPos);
487 toExpand.push_back(item);
488 while (!toExpand.empty()) {
489 item = toExpand.back();
492 QModelIndex itemIndex =
index(item);
493 if (itemIndex.isValid()) {
503 toExpand.push_back(item->
getChild(i));
506 }
catch (
const std::bad_alloc&) {
514 if (objects.empty()) {
528 "object '%1' has no parent")
529 .arg(object->getName()));
533 int childPos =
parent->getChildIndex(
object);
534 assert(childPos >= 0);
537 beginRemoveRows(
index(
parent), childPos, childPos);
539 parent->removeChild(childPos);
568 tr(
"[ccDBRoot::removeElement] Internal error: object has no "
573 int childPos =
parent->getChildIndex(
object);
574 assert(childPos >= 0);
577 beginRemoveRows(
index(
parent), childPos, childPos);
579 parent->removeChild(childPos);
595 QModelIndexList selectedIndexes = qism->selectedIndexes();
596 if (selectedIndexes.empty()) {
599 unsigned selCount =
static_cast<unsigned>(selectedIndexes.size());
602 bool verticesWarningIssued =
false;
608 std::vector<ccHObject*> toBeDeleted;
609 for (
unsigned i = 0; i < selCount; ++i) {
611 static_cast<ccHObject*
>(selectedIndexes[i].internalPointer());
614 CVLog::Warning(tr(
"Object '%1' can't be deleted this way (locked)")
621 bool isDescendent =
false;
622 for (
unsigned j = 0; j < selCount; ++j) {
625 selectedIndexes[j].internalPointer());
636 if (!verticesWarningIssued) {
638 tr(
"Vertices can't be deleted without their parent "
640 verticesWarningIssued =
true;
645 toBeDeleted.push_back(obj);
650 std::vector<removeInfo> toBeDeletedInfos;
651 while (!toBeDeleted.empty()) {
654 object->getTypeID_recursive(toBeDeletedInfos,
true);
655 toBeDeleted.pop_back();
664 object->getParent()->setVisible(
true);
669 int childPos =
parent->getChildIndex(
object);
670 assert(childPos >= 0);
672 beginRemoveRows(
index(
object).
parent(), childPos, childPos);
673 parent->removeChild(childPos);
683 if (!toBeDeletedInfos.empty()) {
691 if (!
index.isValid()) {
703 case Qt::DisplayRole: {
704 QString baseName(item->
getName());
705 if (baseName.isEmpty()) baseName = QStringLiteral(
"no name");
708 baseName = QStringLiteral(
"2D label: ") + baseName;
710 baseName = QStringLiteral(
"2D area label: ") + baseName;
719 case Qt::DecorationRole: {
723 if (!icon.isNull()) {
727 const bool locked = item->
isLocked();
732 return gDBRootIcons->icon(item->
getClassID(), locked);
738 return gDBRootIcons->icon(item->
getClassID(), locked);
744 case Qt::CheckStateRole: {
766 return Qt::Unchecked;
778 const QVariant& value,
780 if (
index.isValid()) {
781 if (role == Qt::EditRole) {
782 if (value.toString().isEmpty()) {
803 item->
setName(value.toString());
816 }
else if (role == Qt::CheckStateRole) {
820 if (value == Qt::Checked)
853 bool shouldShowBB =
true;
858 context.viewID, axesGridProps);
860 shouldShowBB =
false;
885 bool shouldShowBB =
true;
890 context.viewID, axesGridProps);
892 shouldShowBB =
false;
923 const QModelIndex& parentIndex)
const {
924 if (!hasIndex(row, column, parentIndex)) {
925 return QModelIndex();
929 (parentIndex.isValid()
930 ?
static_cast<ccHObject*
>(parentIndex.internalPointer())
934 return QModelIndex();
938 return child ? createIndex(row, column, child) : QModelIndex();
945 return QModelIndex();
954 return QModelIndex();
957 int pos =
parent->getChildIndex(
object);
960 return createIndex(pos, 0,
object);
964 if (!
index.isValid()) {
965 return QModelIndex();
971 return QModelIndex();
976 if (!parentItem || parentItem ==
m_treeRoot) {
977 return QModelIndex();
980 return createIndex(parentItem->
getIndex(), 0, parentItem);
1000 const QItemSelection& deselected) {
1002 QModelIndexList deselectedItems = deselected.indexes();
1004 for (
int i = 0; i < deselectedItems.count(); ++i) {
1006 deselectedItems.at(i).internalPointer());
1015 QModelIndexList selectedItems = selected.indexes();
1017 for (
int i = 0; i < selectedItems.count(); ++i) {
1019 selectedItems.at(i).internalPointer());
1037 QModelIndex objIndex =
index(obj);
1038 if (objIndex.isValid()) {
1039 QItemSelectionModel* selectionModel =
1041 assert(selectionModel);
1042 selectionModel->select(objIndex, QItemSelectionModel::Deselect);
1048 QItemSelectionModel* selectionModel =
m_dbTreeWidget->selectionModel();
1049 assert(selectionModel);
1051 selectionModel->clear();
1055 bool forceAdditiveSelection ) {
1056 bool additiveSelection =
1057 forceAdditiveSelection ||
1058 (QApplication::keyboardModifiers() & Qt::ControlModifier);
1060 QItemSelectionModel* selectionModel =
m_dbTreeWidget->selectionModel();
1061 assert(selectionModel);
1065 QModelIndex selectedIndex =
index(obj);
1066 if (selectedIndex.isValid()) {
1068 if (additiveSelection) {
1071 QModelIndexList selectedIndexes =
1072 selectionModel->selectedIndexes();
1073 if (!selectedIndexes.empty()) {
1077 selectedIndexes[0].internalPointer())
1080 tr(
"[Selection] Labels and other entities "
1081 "can't be mixed (release the CTRL key "
1082 "to start a new selection)"));
1087 selectionModel->select(selectedIndex,
1088 QItemSelectionModel::Toggle);
1091 if (selectionModel->isSelected(selectedIndex))
1093 selectionModel->select(selectedIndex,
1094 QItemSelectionModel::ClearAndSelect);
1104 else if (!additiveSelection) {
1105 selectionModel->clear();
1110 bool ctrlPushed = (QApplication::keyboardModifiers() & Qt::ControlModifier);
1116 entities.reserve(entIDs.size());
1117 }
catch (
const std::bad_alloc&) {
1118 CVLog::Warning(tr(
"[ccDBRoot::selectEntities] Not enough memory"));
1122 for (std::unordered_set<int>::const_iterator it = entIDs.begin();
1123 it != entIDs.end(); ++it) {
1125 if (obj) entities.push_back(obj);
1133 bool incremental ) {
1135 QItemSelectionModel* selectionModel =
m_dbTreeWidget->selectionModel();
1136 assert(selectionModel);
1139 size_t labelCount = 0;
1141 for (
size_t i = 0; i < entities.size(); ++i) {
1152 QItemSelection newSelection;
1155 bool keepLabels =
false;
1157 QModelIndexList formerSelectedIndexes =
1158 selectionModel->selectedIndexes();
1159 if (formerSelectedIndexes.isEmpty() || !incremental)
1160 keepLabels = (labelCount ==
1163 else if (incremental)
1166 formerSelectedIndexes[0].internalPointer())
1173 for (
size_t i = 0; i < entities.size(); ++i) {
1179 if (isLabel == keepLabels &&
1181 QModelIndex selectedIndex =
index(ent);
1182 if (selectedIndex.isValid())
1184 QItemSelection(selectedIndex, selectedIndex),
1192 selectionModel->select(newSelection,
1194 : QItemSelectionModel::ClearAndSelect);
1228 QModelIndexList selectedIndexes = qism->selectedIndexes();
1229 if (selectedIndexes.size() == 1) {
1231 static_cast<ccHObject*
>(selectedIndexes[0].internalPointer()));
1240 QModelIndex idx =
index(
object);
1242 if (idx.isValid()) emit dataChanged(idx, idx);
1247 object->redrawDisplay(forceRedraw);
1251 bool forceRedraw ) {
1253 object->redrawDisplay(forceRedraw);
1258 QModelIndexList selectedIndexes = qism->selectedIndexes();
1259 int selCount = selectedIndexes.size();
1264 for (
int i = 0; i < selCount; ++i) {
1266 static_cast<ccHObject*
>(selectedIndexes[i].internalPointer());
1267 if (
object && object->
isKindOf(filter)) ++realCount;
1276 selectedEntities.clear();
1279 QModelIndexList selectedIndexes = qism->selectedIndexes();
1282 int selCount = selectedIndexes.size();
1283 for (
int i = 0; i < selCount; ++i) {
1285 selectedIndexes[i].internalPointer());
1286 if (
object && object->
isKindOf(filter))
1287 selectedEntities.push_back(
object);
1289 }
catch (
const std::bad_alloc&) {
1295 info->
selCount = selectedIndexes.size();
1297 for (
size_t i = 0; i < info->
selCount; ++i) {
1311 genericCloud->
getOctree() !=
nullptr ? 1 : 0;
1335 return selectedEntities.size();
1339 return Qt::MoveAction;
1343 if (!
index.isValid())
return Qt::NoItemFlags;
1345 Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(
index);
1348 defaultFlags |= (Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |
1349 Qt::ItemIsSelectable | Qt::ItemIsEditable);
1371 defaultFlags |= (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
1378 if (polyVertices != poly->
getParent()) {
1379 defaultFlags |= (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled);
1382 defaultFlags |= Qt::ItemIsDragEnabled;
1386 return defaultFlags;
1390 QMap<int, QVariant> map = QAbstractItemModel::itemData(
index);
1392 if (
index.isValid()) {
1395 if (
object) map.insert(Qt::UserRole, QVariant(object->
getUniqueID()));
1402 Qt::DropAction action,
1405 const QModelIndex& destParent) {
1406 Q_UNUSED(destColumn);
1407 if (action != Qt::MoveAction) {
1412 if (!
data->hasFormat(
"application/x-qabstractitemmodeldatalist")) {
1418 destParent.isValid()
1419 ?
static_cast<ccHObject*
>(destParent.internalPointer())
1421 if (newParent && newParent->
isLeaf()) {
1426 QByteArray encoded =
data->data(
"application/x-qabstractitemmodeldatalist");
1427 QDataStream stream(&encoded, QIODevice::ReadOnly);
1428 while (!stream.atEnd()) {
1431 QMap<int, QVariant> roleDataMap;
1432 stream >> srcRow >> srcCol >> roleDataMap;
1433 if (!roleDataMap.contains(Qt::UserRole))
continue;
1436 int uniqueID = roleDataMap.value(Qt::UserRole).toInt();
1438 if (!item)
continue;
1454 if (oldParent != newParent) {
1456 tr(
"Vertices can't leave their parent mesh"));
1464 CVLog::Error(tr(
"Sub-meshes can't leave their mesh group"));
1471 if (oldParent != newParent) {
1473 tr(
"Meshes can't leave their associated cloud "
1480 if (oldParent != newParent) {
1482 tr(
"This kind of entity can't leave their parent"));
1485 }
else if (oldParent != newParent) {
1531 if (oldParent && newParent == oldParent) {
1536 }
else if (oldRow < destRow) {
1537 assert(destRow > 0);
1539 }
else if (oldRow == destRow) {
1547 int fatherDependencyFlags =
1595 if (!clickIndex.isValid())
return;
1604 toExpand.push_back(item);
1605 while (!toExpand.empty()) {
1606 item = toExpand.back();
1607 toExpand.pop_back();
1609 QModelIndex itemIndex =
index(item);
1610 if (itemIndex.isValid()) {
1620 toExpand.push_back(item->
getChild(i));
1623 }
catch (
const std::bad_alloc&) {
1630 QModelIndexList selectedIndexes = qism->selectedIndexes();
1631 int selCount = selectedIndexes.size();
1632 if (selCount == 0)
return;
1635 static_cast<ccHObject*
>(selectedIndexes[0].internalPointer());
1647 if (label->
size() == 3) {
1657 center = (*_A + *_B + *_C) / 3;
1684 if (!reverse) planeNormal *= -1;
1692 CVLog::Print(tr(
"[Align camera] Corresponding view matrix:"));
1694 tr(
"[Orientation] You can copy this matrix values (CTRL+C) and "
1695 "paste them in the 'Apply transformation tool' dialog"));
1701 QModelIndexList selectedIndexes = qism->selectedIndexes();
1702 int selCount = selectedIndexes.size();
1703 if (selCount == 0)
return;
1707 unsigned pointCount;
1708 unsigned triangleCount;
1709 unsigned colorCount;
1710 unsigned normalCount;
1711 unsigned materialCount;
1712 unsigned scalarFieldCount;
1715 unsigned cloudCount;
1717 unsigned octreeCount;
1718 unsigned imageCount;
1719 unsigned sensorCount;
1720 unsigned labelCount;
1723 memset(&info, 0,
sizeof(GlobalInfo));
1728 toProcess.resize(selCount);
1729 }
catch (
const std::bad_alloc&) {
1734 for (
int i = 0; i < selCount; ++i) {
1736 static_cast<ccHObject*
>(selectedIndexes[i].internalPointer());
1740 while (!toProcess.empty()) {
1742 toProcess.pop_back();
1745 if (std::find(alreadyProcessed.begin(), alreadyProcessed.end(), ent) !=
1746 alreadyProcessed.end()) {
1755 unsigned cloudSize = cloud->
size();
1756 info.pointCount += cloudSize;
1757 info.colorCount += (cloud->
hasColors() ? cloudSize : 0);
1758 info.normalCount += (cloud->
hasNormals() ? cloudSize : 0);
1764 unsigned meshSize = mesh->
size();
1765 info.triangleCount += meshSize;
1767 info.materialCount += 0;
1782 toProcess.push_back(ent->
getChild(i));
1784 alreadyProcessed.push_back(ent);
1785 }
catch (
const std::bad_alloc&) {
1793 QStringList infoStr;
1795 const QString separator(
"--------------------------");
1797 infoStr << tr(
"Point(s):\t\t%1").arg(info.pointCount);
1798 infoStr << tr(
"Triangle(s):\t\t%1").arg(info.triangleCount);
1800 infoStr << separator;
1801 if (info.colorCount)
1802 infoStr << tr(
"Color(s):\t\t%1").arg(info.colorCount);
1803 if (info.normalCount)
1804 infoStr << tr(
"Normal(s):\t\t%1").arg(info.normalCount);
1805 if (info.scalarFieldCount)
1806 infoStr << tr(
"Scalar field(s):\t\t%1").arg(info.scalarFieldCount);
1807 if (info.materialCount)
1808 infoStr << tr(
"Material(s):\t\t%1").arg(info.materialCount);
1810 infoStr << separator;
1811 infoStr << tr(
"Cloud(s):\t\t%1").arg(info.cloudCount);
1812 infoStr << tr(
"Mesh(es):\t\t%1").arg(info.meshCount);
1813 if (info.octreeCount)
1814 infoStr << tr(
"Octree(s):\t\t%1").arg(info.octreeCount);
1815 if (info.imageCount)
1816 infoStr << tr(
"Image(s):\t\t%1").arg(info.imageCount);
1817 if (info.labelCount)
1818 infoStr << tr(
"Label(s):\t\t%1").arg(info.labelCount);
1819 if (info.sensorCount)
1820 infoStr << tr(
"Sensor(s):\t\t%1").arg(info.sensorCount);
1824 infoStr.join(
"\n"));
1838 QModelIndexList selectedIndexes = qism->selectedIndexes();
1839 int selCount = selectedIndexes.size();
1840 if (selCount == 0)
return;
1842 for (
int i = 0; i < selCount; ++i) {
1844 static_cast<ccHObject*
>(selectedIndexes[i].internalPointer());
1846 if (childCount > 1) {
1848 beginRemoveRows(selectedIndexes[i], 0, childCount - 1);
1854 for (
unsigned k = 0; k < childCount - 1; ++k) {
1855 unsigned firstChildIndex = k;
1857 QString firstChildName = firstChild->
getName().toUpper();
1859 for (
unsigned j = k + 1; j < childCount; ++j) {
1861 QString currentName =
1865 swap = (firstChildName.compare(currentName) > 0);
1868 swap = (firstChildName.compare(currentName) < 0);
1873 swap = (firstChildName.compare(currentName) >
1882 firstChildIndex = j;
1883 firstChildName = currentName;
1887 if (k != firstChildIndex)
1892 beginInsertRows(selectedIndexes[i], 0, childCount - 1);
1928 if (!scDlg.exec())
return;
1932 bool exclusive =
false;
1972 bool typeIsExclusive ,
1974 bool nameIsRegex ) {
1979 if (!clickIndex.isValid())
return;
1994 if (
name.isEmpty()) {
1995 toSelect = filteredByType;
1997 for (
size_t i = 0; i < filteredByType.size(); ++i) {
2002 QRegularExpression re(
name);
2003 QRegularExpressionMatch match = re.match(child->
getName());
2004 bool hasMatch = match.hasMatch();
2005 if (hasMatch) toSelect.push_back(child);
2011 toSelect.push_back(child);
2014 }
catch (
const std::bad_alloc&) {
2015 CVLog::Warning(tr(
"[selectChildrenByTypeAndName] Not enough memory"));
2019 bool ctrlPushed = (QApplication::keyboardModifiers() & Qt::ControlModifier);
2025 QModelIndexList selectedIndexes = qism->selectedIndexes();
2026 int selCount = selectedIndexes.size();
2027 if (selCount == 0)
return;
2032 for (
int i = 0; i < selCount; ++i) {
2034 static_cast<ccHObject*
>(selectedIndexes[i].internalPointer());
2080 if (
index.isValid()) {
2090 QModelIndexList selectedIndexes = qism->selectedIndexes();
2091 int selCount = selectedIndexes.size();
2092 if (selCount == 0)
return;
2094 for (
int i = 0; i < selCount; ++i) {
2096 static_cast<ccHObject*
>(selectedIndexes[i].internalPointer());
2108 QModelIndexList selectedIndexes = qism->selectedIndexes();
2109 int selCount = selectedIndexes.size();
2110 if (selCount == 0) {
2115 static_cast<ccHObject*
>(selectedIndexes[0].internalPointer());
2117 if (!label || label->
size() != 1) {
2134 CVLog::Warning(tr(
"[editLabelScalarValue] No active scalar field"));
2141 double newValue = QInputDialog::getDouble(
2143 QString(
"%1 (%2) =").arg(sf->
getName()).arg(P.
index), s,
2144 -2147483647, 2147483647, 6, &ok);
2150 ScalarType newS =
static_cast<ScalarType
>(newValue);
2161 QModelIndexList selectedIndexes = qism->selectedIndexes();
2162 int selCount = selectedIndexes.size();
2163 if (selCount == 0) {
2168 std::set<ccImage*> images;
2170 for (
int i = 0; i < selCount; ++i) {
2172 selectedIndexes[i].internalPointer());
2180 for (
ccHObject* obj : filteredChildren) {
2186 }
catch (
const std::bad_alloc&) {
2191 if (images.empty()) {
2197 QString saveDirectoryName;
2200 settings.beginGroup(
"SaveFile");
2201 QString currentPath =
2202 settings.value(
"CurrentPath", QDir::homePath()).toString();
2204 saveDirectoryName = QFileDialog::getExistingDirectory(
2207 QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
2209 if (saveDirectoryName.isEmpty()) {
2215 settings.setValue(
"CurrentPath", saveDirectoryName);
2216 settings.endGroup();
2219 QDir saveDirectory(saveDirectoryName);
2221 if (
false == saveDirectory.exists()) {
2227 pDlg.setRange(0,
static_cast<int>(images.size()));
2228 pDlg.setWindowTitle(tr(
"Export images"));
2231 QCoreApplication::processEvents();
2234 int overwriteImagesAnswer = QMessageBox::StandardButton::Default;
2235 QMap<QString, size_t> duplicateNameCounter;
2236 int imageCounter = 0;
2238 QString baseName =
image->getName();
2241 if (duplicateNameCounter.contains(baseName)) {
2243 QString(
"_%1").arg(duplicateNameCounter[baseName] + 1);
2245 duplicateNameCounter[baseName] += 1;
2248 baseName += QStringLiteral(
".png");
2249 QString
filename = saveDirectory.absoluteFilePath(baseName);
2251 bool skipImage =
false;
2253 if (overwriteImagesAnswer == QMessageBox::StandardButton::Default) {
2255 overwriteImagesAnswer = QMessageBox::question(
2257 tr(
"Overwrite existing files?"),
2258 QMessageBox::StandardButton::YesToAll,
2259 QMessageBox::StandardButton::NoToAll);
2262 if (overwriteImagesAnswer == QMessageBox::StandardButton::NoToAll) {
2264 "overwrite an existing file")
2277 pDlg.setValue(++imageCounter);
2281 CVLog::Print(tr(
"[Export images] %1 image(s) exported").arg(imageCounter));
2291 if (
index.isValid()) {
2295 QModelIndexList selectedIndexes = qism->selectedIndexes();
2296 int selCount = selectedIndexes.size();
2298 bool toggleVisibility =
false;
2299 bool toggleOtherProperties =
false;
2300 bool toggleMaterials =
false;
2301 bool hasMoreThanOneChild =
false;
2302 bool hasExactlyOnePlanarEntity =
false;
2303 bool leafObject =
false;
2304 bool hasExacltyOneGBLSenor =
false;
2305 bool hasExactlyOnePlane =
false;
2306 bool canEditLabelScalarValue =
false;
2307 bool hasImages =
false;
2308 for (
int i = 0; i < selCount; ++i) {
2310 selectedIndexes[i].internalPointer());
2316 hasMoreThanOneChild =
true;
2318 leafObject |= item->
isLeaf();
2320 toggleVisibility =
true;
2322 toggleOtherProperties =
true;
2324 toggleMaterials =
true;
2325 toggleOtherProperties =
true;
2338 if (selCount == 1) {
2340 hasExactlyOnePlanarEntity =
2345 canEditLabelScalarValue =
2346 (label->
size() == 1 &&
2354 ->getCurrentDisplayedScalarField() !=
2361 hasExactlyOnePlanarEntity =
true;
2362 hasExactlyOnePlane =
2365 hasExacltyOneGBLSenor =
true;
2371 if (hasExactlyOnePlanarEntity) {
2374 menu.addSeparator();
2376 if (hasExactlyOnePlane) {
2379 if (hasExacltyOneGBLSenor) {
2384 menu.addSeparator();
2386 if (toggleVisibility) {
2389 if (toggleOtherProperties) {
2394 if (toggleMaterials) {
2398 menu.addSeparator();
2400 if (selCount == 1 && hasMoreThanOneChild) {
2401 menu.addSeparator();
2407 if (selCount == 1 && !leafObject) {
2408 menu.addSeparator();
2410 menu.addSeparator();
2415 menu.addSeparator();
2419 if (canEditLabelScalarValue) {
2420 menu.addSeparator();
2424 menu.addSeparator();
2430 menu.addSeparator();
2438 const QModelIndex& index,
const QEvent*
event )
const {
2439 if (index.isValid()) {
2441 QModelIndexList selectedIndexes = selectionModel()->selectedIndexes();
2442 if (!selectedIndexes.empty() && !selectionModel()->isSelected(index)) {
2444 static_cast<ccHObject*
>(index.internalPointer());
2448 selectedIndexes[0].internalPointer())
2450 return QItemSelectionModel::ClearAndSelect;
2454 return QTreeView::selectionCommand(index,
event);
int64_t CV_CLASS_ENUM
Type of object type flags (64 bits)
std::shared_ptr< core::Tensor > image
static bool Warning(const char *format,...)
Prints out a formatted warning message in console.
static bool Print(const char *format,...)
Prints out a formatted message in console.
static bool Error(const char *format,...)
Display an error dialog with formatted message.
const QIcon & icon(CV_CLASS_ENUM id, bool locked)
static MainWindow * TheInstance()
Returns the unique instance of this object.
void refreshAll(bool only2D=false, bool forceRedraw=true) override
Redraws all GL windows that have the 'refresh' flag on.
static Vector3Tpl fromArray(const int a[3])
Constructor from an int array.
2D label (typically attached to points)
const PickedPoint & getPickedPoint(unsigned index) const
Returns a given point.
unsigned size() const
Returns current size.
Custom QTreeView widget (for advanced selection behavior)
virtual QItemSelectionModel::SelectionFlags selectionCommand(const QModelIndex &index, const QEvent *event=nullptr) const
QAction * m_alignCameraWithEntity
Context menu action: use 3-points labels or planes to orient camera.
void updatePropertiesView()
Updates properties view.
QAction * m_sortChildrenType
Context menu action: sort children by type.
void toggleSelectedEntitiesMat()
void editLabelScalarValue()
void hidePropertiesView()
Hides properties view.
void expandElement(ccHObject *object, bool state)
Expands tree at a given node.
virtual QModelIndex index(int row, int column, const QModelIndex &parentIndex=QModelIndex()) const override
void dbIsNotEmptyAnymore()
int countSelectedEntities(CV_CLASS_ENUM filter=CV_TYPES::OBJECT)
QAction * m_enableBubbleViewMode
Context menu action: enable bubble-view (on a sensor)
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const override
QAction * m_sortChildrenZA
Context menu action: sort children in reverse alphabetical order.
void updateCCObject(ccHObject *object)
QAction * m_gatherInformation
Context menu action: gather (recursive) information on selected entities.
QAction * m_editLabelScalarValue
Context menu action: change current scalar value (via a 2D label)
void gatherRecursiveInformation()
virtual bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QAction * m_toggleSelectedEntities
Context menu action: enabled/disable selected entities.
void unselectEntity(ccHObject *obj)
Unselects a given entity.
virtual ~ccDBRoot() override
Destructor.
void toggleSelectedEntities()
QTreeView * m_dbTreeWidget
Associated widget for DB tree.
virtual QModelIndex parent(const QModelIndex &index) const override
QAction * m_deleteSelectedEntities
Context menu action: delete selected entities.
void toggleSelectedEntities3DName()
QAction * m_toggleSelectedEntitiesNormals
Context menu action: hide/show selected entities normals.
QPoint m_contextMenuPos
Last context menu pos.
void toggleSelectedEntitiesVisibility()
QAction * m_selectByTypeAndName
Context menu action: select object by type and/or by name.
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
void removeElements(ccHObject::Container &objects)
Removes several elements at once from the DB tree.
void alignCameraWithEntityIndirect()
QAction * m_addEmptyGroup
Context menu action: add empty group.
void redrawCCObjectAndChildren(ccHObject *object, bool forceRedraw=true)
void toggleSelectedEntitiesSF()
ccHObject * m_treeRoot
Associated DB root.
virtual QVariant data(const QModelIndex &index, int role) const override
void selectEntity(ccHObject *obj, bool forceAdditiveSelection=false)
Selects a given entity.
virtual Qt::DropActions supportedDropActions() const override
void selectEntities(std::unordered_set< int > entIDs)
Selects multiple entities at once (shortcut to the other version)
QAction * m_toggleSelectedEntitiesMat
Context menu action: hide/show selected entities materials/textures.
ccHObject * getRootEntity()
Returns associated root object.
void redrawCCObject(ccHObject *object, bool forceRedraw=true)
void selectChildrenByTypeAndName(CV_CLASS_ENUM type, bool typeIsExclusive=true, QString name=QString(), bool nameIsRegex=false)
Selects objects by type and/or name.
QAction * m_alignCameraWithEntityReverse
Context menu action: reverse of m_alignCameraWithEntity.
size_t getSelectedEntities(ccHObject::Container &selectedEntities, CV_CLASS_ENUM filter=CV_TYPES::OBJECT, dbTreeSelectionInfo *info=nullptr)
void selectByTypeAndName()
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const override
QAction * m_toggleSelectedEntitiesColor
Context menu action: hide/show selected entities color.
SortRules
Entities sorting schemes.
ccHObject * find(int uniqueID) const
Finds an element in DB.
void alignCameraWithEntity(bool reverse)
Aligns the camera with the currently selected entity.
void showPropertiesView(ccHObject *obj)
Shows properties view for a given element.
virtual QMap< int, QVariant > itemData(const QModelIndex &index) const override
void reflectObjectPropChange(ccHObject *obj)
void expandOrCollapseHoveredBranch(bool expand)
Expands or collapses hovered item.
QAction * m_sortChildrenAZ
Context menu action: sort children in alphabetical order.
void unselectAllEntities()
Unselects all entities.
void toggleSelectedEntitiesColor()
QAction * m_toggleSelectedEntities3DName
Context menu action: hide/show selected entities 3D name.
void unloadAll()
Unloads all entities.
TOGGLE_PROPERTY
Entity property that can be toggled.
void toggleSelectedEntitiesProperty(TOGGLE_PROPERTY prop)
void enableBubbleViewMode()
QStandardItemModel * m_propertiesModel
Selected entity's properties data model.
void changeSelection(const QItemSelection &selected, const QItemSelection &deselected)
void removeElement(ccHObject *object)
Removes an element from the DB tree.
virtual Qt::ItemFlags flags(const QModelIndex &index) const override
void sortSelectedEntitiesChildren(SortRules rule)
Sorts selected entities children.
QAction * m_expandBranch
Context menu action: expand tree branch.
QTreeView * m_propertiesTreeWidget
Associated widget for selected entity's properties tree.
void showContextMenu(const QPoint &)
void toggleSelectedEntitiesNormals()
QAction * m_collapseBranch
Context menu action: collapse tree branch.
QAction * m_exportImages
Context menu action: export images.
ccPropertiesTreeDelegate * m_ccPropDelegate
Selected entity's properties delegate.
void alignCameraWithEntityDirect()
QAction * m_toggleSelectedEntitiesSF
Context menu action: hide/show selected entities SF.
QAction * m_toggleSelectedEntitiesVisibility
Context menu action: hide/show selected entities.
void deleteSelectedEntities()
void addElement(ccHObject *object, bool autoExpand=true)
Adds an element to the DB tree.
virtual void toggleVisibility()
Toggles visibility.
virtual bool isVisible() const
Returns whether entity is visible or not.
virtual void toggleNormals()
Toggles normals display state.
virtual bool hasColors() const
Returns whether colors are enabled or not.
virtual bool hasNormals() const
Returns whether normals are enabled or not.
virtual void toggleSF()
Toggles SF display state.
virtual void toggleColors()
Toggles colors display state.
virtual bool isSelected() const
Returns whether entity is selected or not.
virtual void toggleShowName()
Toggles name in 3D display state.
virtual bool nameShownIn3D() const
Returns whether name is displayed in 3D or not.
virtual bool hasScalarFields() const
Returns whether one or more scalar fields are instantiated.
virtual void setSelected(bool state)
Selects/Unselects entity.
CCVector3 getNormal() const override
Returns the entity normal.
Ground-based Laser sensor.
void setTranslation(const Vector3Tpl< float > &Tr)
Sets translation (float version)
Vector3Tpl< T > getColumnAsVec3D(unsigned index) const
Returns a copy of a given column as a CCVector3.
Double version of ccGLMatrixTpl.
virtual ccGenericPointCloud * getAssociatedCloud() const =0
Returns the vertices cloud.
A 3D cloud interface with associated features (color, normals, octree, etc.)
virtual ccOctree::Shared getOctree() const
Returns the associated octree (if any)
Generic primitive interface.
virtual void hideShowDrawings(CC_DRAW_CONTEXT &context)
virtual ccGLMatrix & getTransformation()
Returns the transformation that is currently applied to the vertices.
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
static cc2DViewportLabel * To2DViewportLabel(ccHObject *obj)
Converts current object to cc2DViewportLabel (if possible)
static ccGenericPrimitive * ToPrimitive(ccHObject *obj)
Converts current object to ccGenericPrimitive (if possible)
static ccPolyline * ToPolyline(ccHObject *obj)
Converts current object to ccPolyline (if possible)
static cc2DLabel * To2DLabel(ccHObject *obj)
Converts current object to cc2DLabel (if possible)
static ccGenericPointCloud * ToGenericPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccGenericPointCloud.
static ccSensor * ToSensor(ccHObject *obj)
Converts current object to ccSensor (if possible)
static ccImage * ToImage(ccHObject *obj)
static ccGenericMesh * ToGenericMesh(ccHObject *obj)
Converts current object to ccGenericMesh (if possible)
Hierarchical CLOUDVIEWER Object.
void hideBB(CC_DRAW_CONTEXT context)
ccHObject * find(unsigned uniqueID)
Finds an entity in this object hierarchy.
int getChildIndex(const ccHObject *aChild) const
Returns child index.
int getIndex() const
Returns index relatively to its parent or -1 if no parent.
int getDependencyFlagsWith(const ccHObject *otherObject)
Returns the dependency flags with a given object.
void addDependency(ccHObject *otherObject, int flags, bool additive=true)
Adds a new dependence (additive or not)
bool isAncestorOf(const ccHObject *anObject) const
Returns true if the current object is an ancestor of the specified one.
QString getViewId() const
unsigned getChildrenNumber() const
Returns the number of children.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
unsigned int getChildCountRecursive() const
Returns the total number of children under this object recursively.
void setRedrawFlagRecursive(bool redraw=false)
virtual ccBBox getBB_recursive(bool withGLFeatures=false, bool onlyEnabledChildren=true)
Returns the bounding-box of this entity and it's children.
ccHObject * getParent() const
Returns parent object.
virtual void redrawDisplay(bool forceRedraw=true, bool only2D=false)
Redraws associated display.
void removeDependencyFlag(ccHObject *otherObject, DEPENDENCY_FLAGS flag)
Removes a given dependency flag.
void removeChild(ccHObject *child)
virtual QIcon getIcon() const
Returns the icon associated to this entity.
unsigned filterChildren(Container &filteredChildren, bool recursive=false, CV_CLASS_ENUM filter=CV_TYPES::OBJECT, bool strict=false) const
Collects the children corresponding to a certain pattern.
void swapChildren(unsigned firstChildIndex, unsigned secondChildIndex)
Swaps two children.
std::vector< ccHObject * > Container
Standard instances container (for children, etc.)
void setForceRedrawRecursive(bool redraw=false)
void showBB(CC_DRAW_CONTEXT context)
ccHObject * getChild(unsigned childPos) const
Returns the ith child.
CV_CLASS_ENUM getClassID() const override
Returns class ID.
ccBBox getOwnBB(bool withGLFeatures=false) override
Returns the entity's own bounding-box.
virtual unsigned size() const override
Returns the number of triangles.
bool hasTriNormals() const override
Returns whether the mesh has per-triangle normals.
virtual bool isLocked() const
Returns whether the object is locked or not.
virtual QString getName() const
Returns object name.
virtual unsigned getUniqueID() const
Returns object unique ID.
bool isA(CV_CLASS_ENUM type) const
virtual void setName(const QString &name)
Sets object name.
virtual void setEnabled(bool state)
Sets the "enabled" property.
virtual bool isEnabled() const
Returns whether the object is enabled or not.
bool isKindOf(CV_CLASS_ENUM type) const
CCVector3 getNormal() const override
Returns the entity normal.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool hasNormals() const override
Returns whether normals are enabled or not.
bool hasColors() const override
Returns whether colors are enabled or not.
ccScalarField * getCurrentDisplayedScalarField() const
Returns the currently displayed scalar (or 0 if none)
size_t gridCount() const
Returns the number of associated grids.
GUI properties list dialog element.
void ccObjectAppearanceChanged(ccHObject *hObject, bool forceRedraw=true) const
void fillModel(ccHObject *hObject)
Fill property view with QItems corresponding to object's type.
ccHObject * getCurrentObject()
Returns currently bound object.
void ccObjectPropertiesChanged(ccHObject *hObject) const
void ccObjectAndChildrenAppearanceChanged(ccHObject *hObject, bool forceRedraw=true) const
A scalar field associated to display-related parameters.
void computeMinAndMax() override
Determines the min and max values.
Minimal dialog to pick one element in a list (combo box)
bool getNameMatchIsUsed() const
if performing name-match (regex or not)
bool getNameIsRegex() const
if the name must be considered as regex
bool getStrictMatchState() const
Returns the state of the strict type checkbox.
bool getTypeIsUsed() const
CV_CLASS_ENUM getSelectedType()
Returns the selected type.
void addType(QString typeName, CV_CLASS_ENUM type)
Add an element to the 'type' combo box.
QString getSelectedName()
Returns the selected name (if any)
Generic sensor interface.
virtual void hideShowDrawings(CC_DRAW_CONTEXT &context)
Vector3Tpl< T > getCenter() const
Returns center.
virtual const CCVector3 * getPoint(unsigned index) const =0
Returns the ith point.
unsigned getNumberOfScalarFields() const
Returns the number of associated (and active) scalar fields.
unsigned size() const override
virtual GenericIndexedCloudPersist * getAssociatedCloud()
Returns the associated (source) cloud.
ScalarType & getValue(std::size_t index)
void setValue(std::size_t index, ScalarType value)
const char * getName() const
Returns scalar field name.
Graphical progress indicator (thread-safe)
virtual void stop() override
Notifies the fact that the process has ended.
virtual void start() override
virtual bool isCancelRequested() override
Checks if the process should be canceled.
__host__ __device__ float3 cross(float3 a, float3 b)
static bool CanDetachCloud(const ccHObject *obj)
static const int c_propViewLeftColumnWidth
void swap(optional< T > &x, optional< T > &y) noexcept(noexcept(x.swap(y)))
Data Axes Grid properties structure Encapsulates all properties for vtkCubeAxesActor configuration.
unsigned index
Point/triangle index.
ccGenericPointCloud * cloud
Cloud.
Precise statistics about current selection.