目录
一、源起
项目更新迭代以及新功能的需求,
本来就是点云的处理,需要对基于点的一些基本功能的处理支持(点的拾取,距离测量等)。
所以就有了这一次的功能增加。
环境等前置,参考前面:
主要还是记录,谨防遗忘,因为本身就是CouldCompare的功能移植进自己的项目而已。
二、CouldCompare的相关源码分析
CC的大概逻辑流程也是相对比较简单,都在猜测之内,所以整个移植和修改也相对简单,
毕竟也是有了前面的魔改基础了,就相对更容易把握。
class ccPickingHub : public QObject{
ccPickingHub::ccPickingHub{
//修改部分,为了去除MDI的激活来选定此变量,直接固定即可
m_activeGLWindow =app->getActiveGLWindow();
connect(m_activeGLWindow, &ccGLWindow::itemPicked, this, &ccPickingHub::processPickedItem, Qt::UniqueConnection);
connect(m_activeGLWindow, &QObject::destroyed, this, &ccPickingHub::onActiveWindowDeleted);
//---以上修改-为增加内容---
}
bool addListener(....){}
public slots:
void onActiveWindowChanged(QMdiSubWindow*)
{
.....
....
if (glWindow)
{
//重要,对于MDI 来说存在切换问题,每一次第一次进来的时候要与对应的信号绑定
//对于我们的实列来说不存在这个问题,直接注释掉也可以,需要提升到构造函数中做一次操作即可
connect(glWindow, &ccGLWindow::itemPicked, this, &ccPickingHub::processPickedItem, Qt::UniqueConnection);
connect(glWindow, &QObject::destroyed, this, &ccPickingHub::onActiveWindowDeleted);
m_activeGLWindow = glWindow;
if (m_autoEnableOnActivatedWindow && !m_listeners.empty())
{
togglePickingMode(true);
}
}
}
void onActiveWindowDeleted(QObject*);
void processPickedItem(ccHObject*, unsigned, int, int, const CCVector3&, const CCVector3d&){
//核心 分配到关联的对应实列上
std::set< ccPickingListener* > listeners = m_listeners;//由本类中对应的方法进行切换操作
for (ccPickingListener* l : listeners)
{
if (l)
{
l->onItemPicked(item);
}
}
}
}
MainWindow : public QMainWindow, public ccMainAppInterface, public ccPickingListener {
//picking hub
{
m_pickingHub = new ccPickingHub(this, this);
//对于本列不是MDI 直接注释即可,别忘了需要修改下 m_pickingHub 内部
//connect(m_mdiArea, &QMdiArea::subWindowActivated, m_pickingHub, &ccPickingHub::onActiveWindowChanged);
}
connect(m_UI->actionPointPicking,&QAction::triggered, this, &MainWindow::activatePointPickingMode);
void onItemPicked(const PickedItem& pi) override;
ccPointPropertiesDlg* m_ppDlg;
//核心变量,相关变换的变量及信号发射到槽的实列变化都在此处完成,整个交换中枢,
ccPickingHub* m_pickingHub;
//common
#include <ccPickingHub.h>
void MainWindow::activatePointPickingMode(){
/*----对应的相关依赖项----
pointPropertiesDlg.ui
ccPointPropertiesDlg.h
ccPointPropertiesDlg.cpp
ccPointPickingGenericInterface.h
ccPointPickingGenericInterface.cpp
*/
if (!m_ppDlg)
{
m_ppDlg = new ccPointPropertiesDlg(m_pickingHub, this);
connect(m_ppDlg, &ccOverlayDialog::processFinished,this, &MainWindow::deactivatePointPickingMode);
connect(m_ppDlg, &ccPointPropertiesDlg::newLabel,this, &MainWindow::handleNewLabel);
registerOverlayDialog(m_ppDlg, Qt::TopRightCorner);
}
}
void MainWindow::cancelPreviousPickingOperation(bool aborted){
}
void MainWindow::onItemPicked(const PickedItem& pi){
}
}
class ccGLWindow{
ccGLWindow::startPicking(....){
.....
//在debug 下 拾取3D点 会走CPU这个方法 CPU-based point picking
startCPUBasedPointPicking(params){
//最终也是进入这个方法
processPickingResult();
};
startOpenGLPicking(params);
}
//关键,内部处理完成后发送信号到具体的实列上处理
ccGLWindow::processPickingResult(......){
emit entitySelectionChanged(pickedEntity);
emit itemPicked();
emit itemPickedFast(.....)//信号发射
}
void ccGLWindow::onItemPickedFast(ccHObject* pickedEntity, int pickedItemIndex, int x, int y){
.......
.....
...
emit fastPickingFinished();//拾取 完成 信号发射
}
}
//最终实列中做的处理,后期这整个对话框也可以优化掉。先功能移植过来。
class ccPointPropertiesDlg : public ccPointPickingGenericInterface,
{
void ccPointPropertiesDlg::processPickedPoint(const PickedItem& picked){
}
}
主要核心下面两个类和一个接口类:
ccPickingListener 主要接口类,
ccPickingHub 拾取处理,
ccGLWindow 所有视图显示相关的都在里面。
整个处理流程逻辑参考上面的源码分析。
三、最终效果
移植修改完毕后就是加入自己的处理流程了。
-----以下----编辑自2023-12-05---新增-----
四、CC的实列流程源码分析
通过上面的源码分析已经确定CC提供了设计上的实列扩展,
主要在:ccPointPropertiesDlg这个界面对话框类中,
因为后准备后期直接优化掉这个对话框所以也先做个简单的分析。
分析代码如下:
//注意 cc2DLabel 是继承自 ccHObject对象的
class QCC_DB_LIB_API cc2DLabel : public ccHObject, public ccInteractor{
}
class ccPointPropertiesDlg : public ccPointPickingGenericInterface, public Ui::PointPropertiesDlg
{
ccPointPropertiesDlg(){
//标签对象,关键临时标签
m_label = new cc2DLabel();
m_label->setSelected(true);
//2D 视图区域标签,关键临时标签
m_rect2DLabel = new cc2DViewportLabel();
m_rect2DLabel->setVisible(false); //=invalid
m_rect2DLabel->setSelected(true); //=closed
connect(saveLabelButton,&QToolButton::clicked, this, &ccPointPropertiesDlg::exportCurrentLabel);
}
void exportCurrentLabel(){
ccHObject* newLabelObject = nullptr;
if (m_pickingMode == RECT_ZONE)
{
newLabelObject = m_rect2DLabel = new cc2DViewportLabel();
m_rect2DLabel->setVisible(false); //=invalid
m_rect2DLabel->setSelected(true); //=closed
}
else
{
m_label->getPickedPoint(0).entity()->addChild(labelObject);
newLabelObject = m_label = new cc2DLabel();
m_label->setSelected(true);
}
//关键信号发射,并将标签对象传递过去
//实列在 MainWindow.cpp 主页中
//connect(view3D, &ccGLWindow::newLabel, this, &MainWindow::handleNewLabel);
emit newLabel(labelObject);
}
void ccPointPropertiesDlg::processPickedPoint(const PickedItem& picked){
.....
//此处2D标签的对象的一些操作,后期魔改可用。
m_label->addPickedPoint(static_cast<ccGenericPointCloud*>(picked.entity), picked.itemIndex, picked.entityCenter);
m_label->setVisible(true);
m_label->displayPointLegend(m_label->size() == 3); //we need to display 'A', 'B' and 'C' for 3-points labels
if (m_label->size() == 1 && m_associatedWin)
{
m_label->setPosition(static_cast<float>(picked.clickPoint.x() + 20) / m_associatedWin->glWidth(), static_cast<float>(picked.clickPoint.y() + 20) / m_associatedWin->glHeight());
}
...
}
}
void MainWindow::handleNewLabel(ccHObject* entity)
{
if (entity)
{
addToDB(entity);
//需要做个分支判断,拾取的是点才做下面的处理
//此处将对应的标签保存到自己的文件格式中
cc2DLabel *label = (cc2DLabel *)entity;
ccLog::Print(QString::fromLocal8Bit("[点域加入]\t- ")+label->getName());
}
else
{
assert(false);
}
}
五、修改的效果测试
上面仅是在控制日志 加入了一个打印 【点域加入】效果测试,如下图:
具体可根据实际需求在ccPointPropertiesDlg 中做一些更有必要的修改,
或者如笔者后期准备的直接魔改优化掉整个ccPointPropertiesDlg 对话框。
有了上面的这些分析,可以轻松搞定这些问题了。