Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ao2/62383c6d46f2e33eab65 to your computer and use it in GitHub Desktop.
Save ao2/62383c6d46f2e33eab65 to your computer and use it in GitHub Desktop.
CloudCompare: add a way to select entities by type and name
From cd135ab70d0b40d9f7c575d088d04271a2989154 Mon Sep 17 00:00:00 2001
From: Antonio Ospite <ao2@ao2.it>
Date: Fri, 17 Apr 2015 17:39:09 +0200
Subject: [PATCH] Add a mechanism to select entities by type and then by name
in the DBRoot
X-Face: z*RaLf`X<@C75u6Ig9}{oW$H;1_\2t5)({*|jhM<pyWR#k60!#=#>/Vb;]yA5<GWI5`6u&+
;6b'@y|8w"wB;4/e!7wYYrcqdJFY,~%Gk_4]cq$Ei/7<j&N3ah(m`ku?pX.&+~:_/wC~dwn^)MizBG
!pE^+iDQQ1yC6^,)YDKkxDd!T>\I~93>J<_`<4)A{':UrE
This is particularly useful when doing batch processing on entities of
the same type, it avoids selecting the entities manually one by one
before performing the wanted operation.
Sponsored by Stage Srl: https://twitter.com/StageSrl
---
qCC/db_tree/ccDBRoot.cpp | 101 +++++++++++++++++++++++++++++++++++++++++++++++
qCC/db_tree/ccDBRoot.h | 7 ++++
2 files changed, 108 insertions(+)
diff --git a/qCC/db_tree/ccDBRoot.cpp b/qCC/db_tree/ccDBRoot.cpp
index 39e8376..33e72bd 100644
--- a/qCC/db_tree/ccDBRoot.cpp
+++ b/qCC/db_tree/ccDBRoot.cpp
@@ -26,6 +26,7 @@
#include <QHeaderView>
#include <QMimeData>
#include <QMessageBox>
+#include <QInputDialog>
//qCC_db
#include <ccLog.h>
@@ -47,6 +48,7 @@
//local
#include "ccPropertiesTreeDelegate.h"
#include "../mainwindow.h"
+#include "../ccPickOneElementDlg.h"
//system
#include <assert.h>
@@ -90,6 +92,8 @@ ccDBRoot::ccDBRoot(ccCustomQTreeView* dbTreeWidget, QTreeView* propertiesTreeWid
m_sortSiblingsType = new QAction("Sort siblings by type",this);
m_sortSiblingsAZ = new QAction("Sort siblings by name (A-Z)",this);
m_sortSiblingsZA = new QAction("Sort siblings by name (Z-A)",this);
+ m_selectByType = new QAction("Select by type",this);
+ m_selectByTypeAndName = new QAction("Select by type and name",this);
m_deleteSelectedEntities = new QAction("Delete",this);
m_toggleSelectedEntities = new QAction("Toggle",this);
m_toggleSelectedEntitiesVisibility = new QAction("Toggle visibility",this);
@@ -113,6 +117,8 @@ ccDBRoot::ccDBRoot(ccCustomQTreeView* dbTreeWidget, QTreeView* propertiesTreeWid
connect(m_sortSiblingsAZ, SIGNAL(triggered()), this, SLOT(sortSiblingsAZ()));
connect(m_sortSiblingsZA, SIGNAL(triggered()), this, SLOT(sortSiblingsZA()));
connect(m_sortSiblingsType, SIGNAL(triggered()), this, SLOT(sortSiblingsType()));
+ connect(m_selectByType, SIGNAL(triggered()), this, SLOT(selectByType()));
+ connect(m_selectByTypeAndName, SIGNAL(triggered()), this, SLOT(selectByTypeAndName()));
connect(m_deleteSelectedEntities, SIGNAL(triggered()), this, SLOT(deleteSelectedEntities()));
connect(m_toggleSelectedEntities, SIGNAL(triggered()), this, SLOT(toggleSelectedEntities()));
connect(m_toggleSelectedEntitiesVisibility, SIGNAL(triggered()), this, SLOT(toggleSelectedEntitiesVisibility()));
@@ -1585,6 +1591,96 @@ void ccDBRoot::sortSelectedEntitiesSiblings(SortRules sortRule)
}
}
+static CC_CLASS_ENUM objectTypeDlg()
+{
+ std::vector<std::pair<QString,CC_CLASS_ENUM> > objectTypes;
+ objectTypes.push_back(std::make_pair("Mesh", CC_TYPES::MESH));
+ objectTypes.push_back(std::make_pair("Point Cloud", CC_TYPES::POINT_CLOUD));
+
+ ccPickOneElementDlg pDlg("Select by type", "Choose object type", MainWindow::TheInstance());
+
+ for(unsigned int i = 0; i < objectTypes.size(); i++) {
+ pDlg.addElement(objectTypes[i].first);
+ }
+ pDlg.setDefaultIndex(0);
+ if (!pDlg.exec())
+ return -1;
+
+ int typeIndex = pDlg.getSelectedIndex();
+
+ return objectTypes[typeIndex].second;
+}
+
+void ccDBRoot::selectByType()
+{
+ CC_CLASS_ENUM objectType = objectTypeDlg();
+ if (objectType < 0)
+ return;
+
+ selectChildrenByTypeAndName(objectType);
+}
+
+void ccDBRoot::selectByTypeAndName()
+{
+ CC_CLASS_ENUM objectType = objectTypeDlg();
+ if (objectType < 0)
+ return;
+
+ bool ok;
+ QString objectName = QInputDialog::getText(MainWindow::TheInstance(),
+ "Object name", "Object name",
+ QLineEdit::Normal, "", &ok);
+ if (!ok)
+ return;
+
+ selectChildrenByTypeAndName(objectType, objectName);
+}
+
+/* name is optional, if passed it is used to restrict the selection by type */
+void ccDBRoot::selectChildrenByTypeAndName(CC_CLASS_ENUM type, QString name)
+{
+ //not initialized?
+ if (m_contextMenuPos.x() < 0 || m_contextMenuPos.y() < 0)
+ return;
+
+ QModelIndex clickIndex = m_dbTreeWidget->indexAt(m_contextMenuPos);
+ if (!clickIndex.isValid())
+ return;
+ ccHObject* item = static_cast<ccHObject*>(clickIndex.internalPointer());
+ assert(item);
+
+ if (!item || item->getChildrenNumber() == 0)
+ return;
+
+ ccHObject::Container filteredByType;
+ item->filterChildren(filteredByType, true, type, true);
+
+ // The case of an empty filteredByType is handled implicitly, to make
+ // the ctrlPushed behavior below more consistent (i.e. when no object
+ // is found and Control was NOT pressed the selction gets still
+ // cleared).
+
+ ccHObject::Container toSelect;
+ if (name == NULL)
+ {
+ toSelect = filteredByType;
+ }
+ else
+ {
+ while (!filteredByType.empty())
+ {
+ item = filteredByType.back();
+ filteredByType.pop_back();
+
+ if (item->getName().compare(name) == 0)
+ toSelect.push_back(item);
+ }
+ }
+
+ bool ctrlPushed = (QApplication::keyboardModifiers () & Qt::ControlModifier);
+ selectEntities(toSelect, ctrlPushed);
+}
+
void ccDBRoot::toggleSelectedEntities()
{
toggleSelectedEntitiesProperty(0);
@@ -1817,6 +1913,11 @@ void ccDBRoot::showContextMenu(const QPoint& menuPos)
menu.addAction(m_sortSiblingsZA);
menu.addAction(m_sortSiblingsType);
}
+
+ menu.addSeparator();
+ menu.addAction(m_selectByType);
+ menu.addAction(m_selectByTypeAndName);
+
if (selCount==1 && !leafObject)
{
menu.addSeparator();
diff --git a/qCC/db_tree/ccDBRoot.h b/qCC/db_tree/ccDBRoot.h
index e514a16..2096fad 100644
--- a/qCC/db_tree/ccDBRoot.h
+++ b/qCC/db_tree/ccDBRoot.h
@@ -190,6 +190,9 @@ protected slots:
void sortSiblingsAZ();
void sortSiblingsZA();
void sortSiblingsType();
+ void selectByType();
+ void selectByTypeAndName();
+ void selectChildrenByTypeAndName(CC_CLASS_ENUM type, QString name = NULL);
void toggleSelectedEntities();
void toggleSelectedEntitiesVisibility();
void toggleSelectedEntitiesColor();
@@ -262,6 +265,10 @@ protected:
QAction* m_sortSiblingsZA;
//! Context menu action: sort siblings by type
QAction* m_sortSiblingsType;
+ //! Context menu action: select object by type
+ QAction* m_selectByType;
+ //! Context menu action: select Point Clouds named "vertices"
+ QAction* m_selectByTypeAndName;
//! Context menu action: delete selected entities
QAction* m_deleteSelectedEntities;
//! Context menu action: enabled/disable selected entities
--
2.1.4
diff --git a/qCC/db_tree/ccDBRoot.cpp b/qCC/db_tree/ccDBRoot.cpp
index 39e8376..62092f7 100644
--- a/qCC/db_tree/ccDBRoot.cpp
+++ b/qCC/db_tree/ccDBRoot.cpp
@@ -90,6 +90,8 @@ ccDBRoot::ccDBRoot(ccCustomQTreeView* dbTreeWidget, QTreeView* propertiesTreeWid
m_sortSiblingsType = new QAction("Sort siblings by type",this);
m_sortSiblingsAZ = new QAction("Sort siblings by name (A-Z)",this);
m_sortSiblingsZA = new QAction("Sort siblings by name (Z-A)",this);
+ m_selectCloudsNamedVertices = new QAction("Select clouds named \"vertices\"",this);
+ m_selectMeshes = new QAction("Select meshes",this);
m_deleteSelectedEntities = new QAction("Delete",this);
m_toggleSelectedEntities = new QAction("Toggle",this);
m_toggleSelectedEntitiesVisibility = new QAction("Toggle visibility",this);
@@ -113,6 +115,8 @@ ccDBRoot::ccDBRoot(ccCustomQTreeView* dbTreeWidget, QTreeView* propertiesTreeWid
connect(m_sortSiblingsAZ, SIGNAL(triggered()), this, SLOT(sortSiblingsAZ()));
connect(m_sortSiblingsZA, SIGNAL(triggered()), this, SLOT(sortSiblingsZA()));
connect(m_sortSiblingsType, SIGNAL(triggered()), this, SLOT(sortSiblingsType()));
+ connect(m_selectCloudsNamedVertices, SIGNAL(triggered()), this, SLOT(selectCloudsNamedVertices()));
+ connect(m_selectMeshes, SIGNAL(triggered()), this, SLOT(selectMeshes()));
connect(m_deleteSelectedEntities, SIGNAL(triggered()), this, SLOT(deleteSelectedEntities()));
connect(m_toggleSelectedEntities, SIGNAL(triggered()), this, SLOT(toggleSelectedEntities()));
connect(m_toggleSelectedEntitiesVisibility, SIGNAL(triggered()), this, SLOT(toggleSelectedEntitiesVisibility()));
@@ -1585,6 +1589,74 @@ void ccDBRoot::sortSelectedEntitiesSiblings(SortRules sortRule)
}
}
+void ccDBRoot::selectCloudsNamedVertices()
+{
+ selectChildrenByTypeAndName(CC_TYPES::POINT_CLOUD, "vertices");
+}
+
+void ccDBRoot::selectMeshes()
+{
+ selectChildrenByTypeAndName(CC_TYPES::MESH);
+}
+
+/* name is optional, and can be used to restrict the selection
+ * XXX: allow both exact match and prefix match? */
+void ccDBRoot::selectChildrenByTypeAndName(CC_CLASS_ENUM type, const char* name)
+{
+ //not initialized?
+ if (m_contextMenuPos.x() < 0 || m_contextMenuPos.y() < 0)
+ return;
+
+ QModelIndex clickIndex = m_dbTreeWidget->indexAt(m_contextMenuPos);
+ if (!clickIndex.isValid())
+ return;
+ ccHObject* item = static_cast<ccHObject*>(clickIndex.internalPointer());
+ assert(item);
+
+ if (!item || item->getChildrenNumber() == 0)
+ return;
+
+ ccHObject::Container toSelect;
+
+ //we recursively visit sub-branches.
+ //
+ // XXX: maybe item->filterChildren() could be used, but we would loose
+ // the restriction by name.
+ //
+ // Add an extension of filterChildren()? Something like
+ // filterChildrenByTypeAndName(), maybe renaming filterChildren() to
+ // filterChildrenByType()?
+ ccHObject::Container toVisit;
+ toVisit.push_back(item);
+ while (!toVisit.empty())
+ {
+ item = toVisit.back();
+ toVisit.pop_back();
+
+ QModelIndex itemIndex = index(item);
+ if (itemIndex.isValid())
+ {
+ if (item->isA(type) &&
+ (name == NULL || item->getName().toStdString().compare(name) == 0)) {
+ toSelect.push_back(item);
+ }
+ }
+
+ assert(item->getChildrenNumber() > 0);
+ for (unsigned i=0; i<item->getChildrenNumber(); ++i)
+ toVisit.push_back(item->getChild(i));
+ }
+
+ unselectAllEntities();
+ while (!toSelect.empty())
+ {
+ item = toSelect.back();
+ toSelect.pop_back();
+
+ selectEntity(item, true);
+ }
+}
+
void ccDBRoot::toggleSelectedEntities()
{
toggleSelectedEntitiesProperty(0);
@@ -1817,6 +1889,11 @@ void ccDBRoot::showContextMenu(const QPoint& menuPos)
menu.addAction(m_sortSiblingsZA);
menu.addAction(m_sortSiblingsType);
}
+
+ menu.addSeparator();
+ menu.addAction(m_selectCloudsNamedVertices);
+ menu.addAction(m_selectMeshes);
+
if (selCount==1 && !leafObject)
{
menu.addSeparator();
diff --git a/qCC/db_tree/ccDBRoot.h b/qCC/db_tree/ccDBRoot.h
index e514a16..9386df5 100644
--- a/qCC/db_tree/ccDBRoot.h
+++ b/qCC/db_tree/ccDBRoot.h
@@ -190,6 +190,9 @@ protected slots:
void sortSiblingsAZ();
void sortSiblingsZA();
void sortSiblingsType();
+ void selectCloudsNamedVertices();
+ void selectMeshes();
+ void selectChildrenByTypeAndName(CC_CLASS_ENUM type, const char* name = NULL);
void toggleSelectedEntities();
void toggleSelectedEntitiesVisibility();
void toggleSelectedEntitiesColor();
@@ -262,6 +265,10 @@ protected:
QAction* m_sortSiblingsZA;
//! Context menu action: sort siblings by type
QAction* m_sortSiblingsType;
+ //! Context menu action: select Point Clouds named "vertices"
+ QAction* m_selectCloudsNamedVertices;
+ //! Context menu action: select Meshes
+ QAction* m_selectMeshes;
//! Context menu action: delete selected entities
QAction* m_deleteSelectedEntities;
//! Context menu action: enabled/disable selected entities
diff --git a/qCC/db_tree/ccDBRoot.cpp b/qCC/db_tree/ccDBRoot.cpp
index 39e8376..33e72bd 100644
--- a/qCC/db_tree/ccDBRoot.cpp
+++ b/qCC/db_tree/ccDBRoot.cpp
@@ -26,6 +26,7 @@
#include <QHeaderView>
#include <QMimeData>
#include <QMessageBox>
+#include <QInputDialog>
//qCC_db
#include <ccLog.h>
@@ -47,6 +48,7 @@
//local
#include "ccPropertiesTreeDelegate.h"
#include "../mainwindow.h"
+#include "../ccPickOneElementDlg.h"
//system
#include <assert.h>
@@ -90,6 +92,8 @@ ccDBRoot::ccDBRoot(ccCustomQTreeView* dbTreeWidget, QTreeView* propertiesTreeWid
m_sortSiblingsType = new QAction("Sort siblings by type",this);
m_sortSiblingsAZ = new QAction("Sort siblings by name (A-Z)",this);
m_sortSiblingsZA = new QAction("Sort siblings by name (Z-A)",this);
+ m_selectByType = new QAction("Select by type",this);
+ m_selectByTypeAndName = new QAction("Select by type and name",this);
m_deleteSelectedEntities = new QAction("Delete",this);
m_toggleSelectedEntities = new QAction("Toggle",this);
m_toggleSelectedEntitiesVisibility = new QAction("Toggle visibility",this);
@@ -113,6 +117,8 @@ ccDBRoot::ccDBRoot(ccCustomQTreeView* dbTreeWidget, QTreeView* propertiesTreeWid
connect(m_sortSiblingsAZ, SIGNAL(triggered()), this, SLOT(sortSiblingsAZ()));
connect(m_sortSiblingsZA, SIGNAL(triggered()), this, SLOT(sortSiblingsZA()));
connect(m_sortSiblingsType, SIGNAL(triggered()), this, SLOT(sortSiblingsType()));
+ connect(m_selectByType, SIGNAL(triggered()), this, SLOT(selectByType()));
+ connect(m_selectByTypeAndName, SIGNAL(triggered()), this, SLOT(selectByTypeAndName()));
connect(m_deleteSelectedEntities, SIGNAL(triggered()), this, SLOT(deleteSelectedEntities()));
connect(m_toggleSelectedEntities, SIGNAL(triggered()), this, SLOT(toggleSelectedEntities()));
connect(m_toggleSelectedEntitiesVisibility, SIGNAL(triggered()), this, SLOT(toggleSelectedEntitiesVisibility()));
@@ -1585,6 +1591,96 @@ void ccDBRoot::sortSelectedEntitiesSiblings(SortRules sortRule)
}
}
+static CC_CLASS_ENUM objectTypeDlg()
+{
+ std::vector<std::pair<QString,CC_CLASS_ENUM> > objectTypes;
+ objectTypes.push_back(std::make_pair("Mesh", CC_TYPES::MESH));
+ objectTypes.push_back(std::make_pair("Point Cloud", CC_TYPES::POINT_CLOUD));
+
+ ccPickOneElementDlg pDlg("Select by type", "Choose object type", MainWindow::TheInstance());
+
+ for(unsigned int i = 0; i < objectTypes.size(); i++) {
+ pDlg.addElement(objectTypes[i].first);
+ }
+ pDlg.setDefaultIndex(0);
+ if (!pDlg.exec())
+ return -1;
+
+ int typeIndex = pDlg.getSelectedIndex();
+
+ return objectTypes[typeIndex].second;
+}
+
+void ccDBRoot::selectByType()
+{
+ CC_CLASS_ENUM objectType = objectTypeDlg();
+ if (objectType < 0)
+ return;
+
+ selectChildrenByTypeAndName(objectType);
+}
+
+void ccDBRoot::selectByTypeAndName()
+{
+ CC_CLASS_ENUM objectType = objectTypeDlg();
+ if (objectType < 0)
+ return;
+
+ bool ok;
+ QString objectName = QInputDialog::getText(MainWindow::TheInstance(),
+ "Object name", "Object name",
+ QLineEdit::Normal, "", &ok);
+ if (!ok)
+ return;
+
+ selectChildrenByTypeAndName(objectType, objectName);
+}
+
+/* name is optional, if passed it is used to restrict the selection by type */
+void ccDBRoot::selectChildrenByTypeAndName(CC_CLASS_ENUM type, QString name)
+{
+ //not initialized?
+ if (m_contextMenuPos.x() < 0 || m_contextMenuPos.y() < 0)
+ return;
+
+ QModelIndex clickIndex = m_dbTreeWidget->indexAt(m_contextMenuPos);
+ if (!clickIndex.isValid())
+ return;
+ ccHObject* item = static_cast<ccHObject*>(clickIndex.internalPointer());
+ assert(item);
+
+ if (!item || item->getChildrenNumber() == 0)
+ return;
+
+ ccHObject::Container filteredByType;
+ item->filterChildren(filteredByType, true, type, true);
+
+ // The case of an empty filteredByType is handled implicitly, to make
+ // the ctrlPushed behavior below more consistent (i.e. when no object
+ // is found and Control was NOT pressed the selction gets still
+ // cleared).
+
+ ccHObject::Container toSelect;
+ if (name == NULL)
+ {
+ toSelect = filteredByType;
+ }
+ else
+ {
+ while (!filteredByType.empty())
+ {
+ item = filteredByType.back();
+ filteredByType.pop_back();
+
+ if (item->getName().compare(name) == 0)
+ toSelect.push_back(item);
+ }
+ }
+
+ bool ctrlPushed = (QApplication::keyboardModifiers () & Qt::ControlModifier);
+ selectEntities(toSelect, ctrlPushed);
+}
+
void ccDBRoot::toggleSelectedEntities()
{
toggleSelectedEntitiesProperty(0);
@@ -1817,6 +1913,11 @@ void ccDBRoot::showContextMenu(const QPoint& menuPos)
menu.addAction(m_sortSiblingsZA);
menu.addAction(m_sortSiblingsType);
}
+
+ menu.addSeparator();
+ menu.addAction(m_selectByType);
+ menu.addAction(m_selectByTypeAndName);
+
if (selCount==1 && !leafObject)
{
menu.addSeparator();
diff --git a/qCC/db_tree/ccDBRoot.h b/qCC/db_tree/ccDBRoot.h
index e514a16..2096fad 100644
--- a/qCC/db_tree/ccDBRoot.h
+++ b/qCC/db_tree/ccDBRoot.h
@@ -190,6 +190,9 @@ protected slots:
void sortSiblingsAZ();
void sortSiblingsZA();
void sortSiblingsType();
+ void selectByType();
+ void selectByTypeAndName();
+ void selectChildrenByTypeAndName(CC_CLASS_ENUM type, QString name = NULL);
void toggleSelectedEntities();
void toggleSelectedEntitiesVisibility();
void toggleSelectedEntitiesColor();
@@ -262,6 +265,10 @@ protected:
QAction* m_sortSiblingsZA;
//! Context menu action: sort siblings by type
QAction* m_sortSiblingsType;
+ //! Context menu action: select object by type
+ QAction* m_selectByType;
+ //! Context menu action: select Point Clouds named "vertices"
+ QAction* m_selectByTypeAndName;
//! Context menu action: delete selected entities
QAction* m_deleteSelectedEntities;
//! Context menu action: enabled/disable selected entities
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment