目录
1.QT 64位报错 0xc000007b,这个报错不是 缺DLL 就是 64 与 32位混掉了的缘故。
2.CDB process terminated unexpectedly (exit code : -2)
一、缘起:
还是公司的项目需求,不过原本CC的UI层相关中内容太多,而且和项目需求差异也比较大,所以准备魔改CC (couldCompare )的界面层相关qcc,核心cclib是不准备做任何改动的。
因为有之前的准备相关cmake 构建和准备,同时 qt 也选择了cmake构建工程,就是为了能方便集成进入自己项目中魔改的,所以这次相对顺利很多。
前置环境 以及 cmake 构建 CC 级联 编译pcl 参考笔者上篇内容:
二、qt 的cmake编译
因为git 上涉及跨平台的项目都是需要cmake构建,所以在搭建QT项目的时候就选择了cmake构建。所以基本上在有了cmake 基本语法和基础知识和了解后,了解下与QT cmake的区别和qt 专有的相关内容即可。
原本想着这两个是同一个东西,而且都是cmake编译,而且已经确定是qt构建的所以直接都没改,用qt cmake编译直接各种报错:
so,一看还是要做工程改动,主要几个问题:目录重构,资源的重新载入。反正都是路径的问题
1.最终目录如下:
自己的项目是确定了qt 环境的所有直接通过qt 生成的,剩下的就是直接将CC需要的功能搬入集成并剔除不要的界面层qcc目录,画圈的是直接从原本qcc中提取的,可以自己根据需求使用,然后修改CMakeLists.txt即可。
2.相关cmakelist修改
主要是icones.qrc资源文件集成,和需要用的一些功能代码的集成(有的直接从qcc中拷贝来的)
打马赛克的地方为一些本项目使用的公司需求相关内容不展示了。
主要和CC相关的魔改cmake部分如上。
3.qpcl的启用
plugins/core/standard/qPCL/CMakeLists.txt
option( PLUGIN_STANDARD_QPCL "Check to install qPCL plugin" OFF ) --->OFF改成ON开启
include( ../../../CMakePluginTpl.cmake ) ==========》 plugins/CMakePluginTpl.cmake
也可以在qt cmake 项目构建配置中找对应选项直接勾选:
然后一路编译居然一次即过,真是惊呆了,意外的顺利:
不过一次即过才应该是常态,毕竟都是cmake的。
说明上面基本上的目录和cmakelist的修改应该是正确的。
在概要信息中是直接可以查看编译信息的,不需要像cmake一样手动去开启调试信息。
而且此处原本cmake构建时候侦测成32位的,在这个qt 的cmake是直接可以侦测出来是64位的,不知道是不是和之前改过有关系,也懒的再去看了。
一切编译成功后,
工程项目的结构的一栏中cmakemodel中也会正确的出现相关cmake的相关配置文件
三、实际代码的魔改
1.cc的插件及ui的改造
如果只使用 CC的相关文件格式 bin txt ply 等格式实际上是很简单的不需要插件模块的,
但是笔者还需要使用pcd 等一些第三方的格式,需要加入插件相关内容,
CC的插件分为三种类型:CC_STD_PLUGIN,CC_GL_FILTER_PLUGIN,CC_IO_FILTER_PLUGIN
标准型,第三方型(分两个子类好像是IO 和 Core),还有一种没仔细注意,
所以相关不用的可全部注释掉。
-------以下---2023---10----07----补充----
CC_STD_PLUGIN 标准型
CC_GL_FILTER_PLUGIN:
--》Core型
--》thirdParty型
CC_IO_FILTER_PLUGIN: io型比如文件格式解析/保存,不具备滤波等功能操作
-------以上---2023---10----07----补充----
//插件管理类,QT 原生
class ccPluginUIManager : public QObject
{
//其他都是主界面控件相关的一些关联管理,可全部注释掉
........
//关键变量
QList<ccPluginInterface *> m_plugins;
......
}
同时一些宏条件编译直接剔除了,不过命令行运行还是保留了,不知道会不会和UI有共享使用的东西,main.cpp代码精简后如下:
int main(int argc, char *argv[])
{
bool commandLine = (argc > 1) && (argv[1][0] == '-');
if ( !commandLine )
{
ccApplication::initOpenGL();
}
ccApplication app(argc, argv, commandLine);
//store the log message until a valid logging instance is registered
ccLog::EnableMessageBackup(true);
//restore some global parameters
{
QSettings settings;
settings.beginGroup(ccPS::GlobalShift());
double maxAbsCoord = settings.value(ccPS::MaxAbsCoord(), ccGlobalShiftManager::MaxCoordinateAbsValue()).toDouble();
double maxAbsDiag = settings.value(ccPS::MaxAbsDiag(), ccGlobalShiftManager::MaxBoundgBoxDiagonal()).toDouble();
settings.endGroup();
ccLog::Print(QString("[Global Shift] Max abs. coord = %1 / max abs. diag = %2").arg(maxAbsCoord, 0, 'e', 0).arg(maxAbsDiag, 0, 'e', 0));
ccGlobalShiftManager::SetMaxCoordinateAbsValue(maxAbsCoord);
ccGlobalShiftManager::SetMaxBoundgBoxDiagonal(maxAbsDiag);
}
//global structures initialization
FileIOFilter::InitInternalFilters(); //load all known I/O filters (plugins will come later!)
ccNormalVectors::GetUniqueInstance(); //force pre-computed normals array initialization
ccColorScalesManager::GetUniqueInstance(); //force pre-computed color tables initialization
ccPluginManager::get().loadPlugins();
int result = 0;
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "xxxxTester_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
app.installTranslator(&translator);
break;
}
}
MainWindow w;
w.setWindowFlags(Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint|Qt::MSWindowsFixedSizeDialogHint);
w.showMaximized();
//w.setFixedSize(w.width(), w.height());
QApplication::processEvents();
QDir workingDir = QCoreApplication::applicationDirPath();
QDir::setCurrent(workingDir.absolutePath());
result = app.exec();
//release global structures
FileIOFilter::UnregisterAll();
return result;
}
2.MainWindow.cpp
主要窗体结构的更改,如果不用插件系统,则不需要继承 ccMainAppInterface
ccMainAppInterface这是个接口类,在使用插件中提供给各第三方插件使用的各种方法接口来对本界面上相关的内容操作的,所以如果不需要使用插件可以直接不继承此接口。
同时除了ccMainAppInterface接口的override函数外,还有一些和 DB树视图和属性页视图相关的回显,如果不使用相关的CC定义的控件显示,
或者准备和笔者一样完全魔改的,完全可以注释重改流程。
这样的话整个MainWindow.cpp 会更加精简,可读性更高。
class MainWindow : public QMainWindow,public ccMainAppInterface
{
dbTreeView//自定义显示的控件变量,不用可注释掉,视图模型关联到 ccDBRoot
//-----构造初始化的时候:
//非常重要信号函数,由m_ccRoot->changeSelection内部发射回来 不用显示就注释掉
connect(m_ccRoot, &ccDBRoot::selectionChanged, this,&MainWindow::updateUIWithSelection);
//不用显示就注释掉,同上
connect(m_ccRoot, &ccDBRoot::dbIsEmpty, [&]() { updateUIWithSelection(); updateMenus(); }); //we don't call updateUI because there's no need to update the properties dialog
//不用显示就注释掉,同上
connect(m_ccRoot, &ccDBRoot::dbIsNotEmptyAnymore, [&]() { updateUIWithSelection(); updateMenus(); });
//we don't call updateUI because there's no need to update the properties dialog
}
3.点云文件的显示
MainWindow主窗体中显示点云模型是通过MDI的多文档窗体中子窗口显示的,但在本项目中实际不需要MDI,原本想SDI也可以,后来看QT 的界面控件关联 比MFC的简单太多,没什么panel 之类的这种区分,widget 中嵌widget 直接可以,所以就直接使用一个widget 显示就可以了。
qcc原本的核心显示原理是
1.doActionLoadFile()函数执行打开文件选择对话框(会更具CC插件的内容确认一些额外的格式信息选择),
2.addToDB()解析对应的格式存储在 CC核心的数据格式:ccHObject 中,里面包含了点云数据和属性解析等。
3.new3DView()中对视图窗口的场景设置为 ccHObject* 对象指针。这样只要指针实列一变串口模型就可以更着变化了。
相关显示模型的核心代码的分析整理如下:
class Q_CORE_EXPORT QAbstractItemModel : public QObject;
//QT 的原生结构,提DB视图 及对应读取文件的属性视图的管理和相关操作
class ccDBRoot : public QAbstractItemModel
{
ccHObject* m_treeRoot;//树视图模型--- CC的主要结构
QTreeView* m_dbTreeWidget;//QT窗体显示部件视图,可不用注释
//如果涉及其他qCC中相关的界面控件元素使用需要回去刷新,这是一个接口继承的函数重写
MainWindow::RefreshAllGLWindow(false);
//显示模型使用,非常重要,由加载文件后变更此内容,引起3D视窗中模型变化
ccHObject* ccDBRoot::getRootEntity()
{
return m_treeRoot;
}
//CCDBRoot.cpp line 357
void ccDBRoot::addElement(ccHObject* object, bool autoExpand/*=true*/)
{
}
//本类中非槽函数,在提供给主页面树形部件 信号链接的槽函数,调用本函数
//CCDBRoot.cpp line 964
void ccDBRoot::selectEntities(std::unordered_set<int> entIDs);
}
//一些文件选择对话框相关的设置操作,主要是 是文件过滤相关内容
doActionLoadFile()
------>addToDB(....);
{
//主要的核心调用--CC的从文件加载内容的解析及结构化
ccHObject* newGroup = FileIoFilter::LoadFormFile(...);
if (destWin)
{
newGroup->setDisplay_recursive(destWin);
}
addToDB(newGroup, true, true, false)--》 {
//add object to DB root
if (m_ccRoot)
{
//force a 'global zoom' if the DB was emtpy!
if (!m_ccRoot->getRootEntity() || m_ccRoot->getRootEntity()->getChildrenNumber() == 0)
{
updateZoom = true;
}
m_ccRoot->addElement(obj, autoExpandDBTree);//obj = newGroup
}
}
}
//初始化 生成视窗窗口,重要
new3DView(true);
//槽链接函数,提供给 新曾视图窗口按钮使用
connect(m_UI->actionNew3DView, &QAction::triggered, this, &MainWindow::new3DView);
//主窗体结构接口 继承 的 函数
void MainWindow::activateRegisterPointPairTool(){...new3DView()...}
//主窗体结构接口 继承 的 函数
void MainWindow::activateSectionExtractionMode(){...new3DView()...};
//主窗体结构接口 继承 的 函数,非常重要
new3DView(){
void ccDBRoot::selectEntities(std::unordered_set<int> entIDs);
view3D->setSceneDB(m_ccRoot->getRootEntity());
}
//#include "ccPropertiesTreeDelegate.h"
//#include "ccSelectChildrenDlg.h"
/*
不是必须的头文件,一旦引入会引入一堆 和点云值和模型属性显示相关的界面
相关内容可都注释掉
ccDBRoot <------- sfEditDlg <---- ccHistogramWindow.h
ccDBRoot <------- ccColorScaleEditorDlg.h
ccSelectChildrenDlg.h
*/
//视口上 线宽和点大小尺寸的 + -号 不显示问题
ccGLWindow.cpp
void ccGLWindow::renderText(......);
void ccGLWindow::drawClickableItems(.....){
//+ -号的相关资源图片调用
//line 1398:
static const QImage c_minusPix = QImage(":/CC/images/ccMinus.png").mirrored();
static const QImage c_plusPix = QImage(":/CC/images/ccPlus.png").mirrored();
line 1414 call ccGLUtils::DisplayTexture2DPosition
}
ccGLUtils.cpp
void ccGLUtils::DisplayTexture2DPosition(...) //line 24
4.最终集成进自己的项目
内容魔改效果图如下:(以下是魔改过程中遇到的一些小问题的图片记录及以上的解决过程)
同时主界面采用的是QT 的dockWidget处理,所有可以进行浮动拖拽,
四、总结:
本次的魔改主要对QT的界面开发及QT cmake构建开发项目收获比较巨大,
但是QT 的IDE 调试器真的是太不友好了,总之没VS 的好用。
过程中稍微遇到一些异常就奔溃了或者不能继续调试,只能重启了在重新调试这种问题比比皆是。
1.QT 64位报错 0xc000007b,这个报错不是 缺DLL 就是 64 与 32位混掉了的缘故。
具体可参考:QT出现应用程序无法正常启动0xc000007b的错误_qt应用程序无法正常启动0xc000007b_水军总督的博客-CSDN博客
ACLUI.DLL
ACTIVEDS.DLL
ADSLDPC.DLL
ADVAPI32.DLL
ADVPACK.DLL
AEPIC.DLL
2.CDB process terminated unexpectedly (exit code : -2)
这个比较坑,
QT运行出现The CDB process terminated解决办法(亲测有效)_bloomerOAO的博客-CSDN博客
但是我的错误代码是 -2的,不过看这两个的问题处理都是和IDE相关的,所以大概猜测了一下,
因为公司电脑由加密所以,把IDE中相关的一些文件全部加密了,导致运行可以,但是只要一调试调用CDB就报这个错。
后来解密下,就可以了。