基于opencascade7.4+osg3.6.3+qt5.12.7的多文档初级Cad/cae...
基于opencascade7.4+osg3.6.3+qt5.12.7的多文档初级Cad/cae平台,支持十几种格式文件,包括step,igs,stl,obj,3ds,osg等,支持视角切换,显示模式切换,仿Cad命令注册机制,装配体显示,模型高亮,点选功能,着色功能,测量功能,个性化导出图片功能,集成netgen6.2和gmesh8网格划分支持导出stl,obj,osg等格式C+

前阵子帮实验室改毕设的时候翻了一圈开源CAD工具,要么是功能太单一,要么是依赖堆得吓人,干脆自己攒了个轻量的多文档CAD/CAE小平台,基于Occt7.4+OSG3.6.3+Qt5.12.7,折腾俩月总算把基础功能跑通了,今天来碎碎念一下。
先唠唠技术栈的选择
为啥选这仨组合?Qt负责UI和多文档窗口是最省心的,自带的MDI框架直接就能搞定多文件并行打开;OpenCASCADE(也就是Occt)是开源CAD的顶流底层,几何解析、CAD命令逻辑全靠它撑着;最后把Occt自带的Viewer换成了OSG,主要是后期想加多视角同步、自定义着色、网格叠加这些功能的时候,OSG的渲染管线比Occt原生的灵活太多,踩坑也更少。
先上一段导入STEP文件的代码,也是最核心的导入逻辑
一开始我直接抄Occt官方样例的导入代码,后来改了改适配自己的项目,大概长这样:
// 导入STEP格式文件的核心逻辑
Handle(TDocStd_Document) stepDoc;
// 初始化STEP读取器
Handle(XSControl_Reader) reader = new XSControl_Reader;
IFSelect_ReturnStatus readStatus = reader->ReadFile(filePath.toStdString().c_str());
if (readStatus == IFSelect_RetDone) {
// 读取成功后转移所有根节点
Standard_Integer rootCount = reader->NbRootsForTransfer();
for (Standard_Integer i = 1; i <= rootCount; i++) {
reader->TransferRoot(i);
}
// 把Occt的模型转成OSG能识别的场景节点
osg::ref_ptr<osg::Group> modelRoot = Occt2OsgConverter::transferDocToOsg(stepDoc->Main());
// 把节点加到当前的多文档子窗口里
currentMdiChild->addModelNode(modelRoot);
}
这段代码看着简单,其实坑挺多的:比如Occt默认的三角化精度太低,转出来的复杂曲面会破面,后来加了个参数让用户自己调精度;还有装配体导入的时候,内存会暴涨,我加了个进度条提示用户别着急关掉程序。
仿CAD的命令注册机制,省了我好多重复代码
最开始加新命令的时候都是直接在主窗口写槽函数,后来越攒越多代码乱成一团,干脆写了个单例的命令管理器,注册和调用都靠它:
class CommandManager {
public:
using CmdCallback = std::function<void()>;
static CommandManager& getInstance() {
static CommandManager inst;
return inst;
}
// 注册新命令
void registerCmd(const QString& cmdName, CmdCallback callback) {
m_cmdMap.insert(cmdName, std::move(callback));
}
// 执行命令
void execCmd(const QString& cmdName) {
if (m_cmdMap.contains(cmdName)) {
m_cmdMap[cmdName]();
}
}
private:
QHash<QString, CmdCallback> m_cmdMap;
};
// 举个例子,注册测量距离的命令
CommandManager::getInstance().registerCmd("measure_distance", [this](){
// 先点选第一个点
gp_Pnt pointA = currentView->pickPointFromScene();
// 再点选第二个点
gp_Pnt pointB = currentView->pickPointFromScene();
double dist = pointA.Distance(pointB);
QMessageBox::information(this, "测量结果", QString("两点直线距离:%1 mm").arg(dist, 0, 'f', 2));
});
后来再加剖切、高亮、导出这些命令,直接注册就行,完全不用碰主窗口的代码,爽得不行。
网格划分这块集成了Netgen和Gmsh
Occt自带的网格划分工具实在太拉胯,复杂模型根本跑不动,后来直接调用Netgen6.2和Gmsh8的API,代码简化一下大概是这样:
// 调用Netgen生成网格
NETGEN-PROJECT::Mesh* rawMesh = NETGEN-PROJECT::GenerateMesh(occtTargetShape, 5.0);
// 转成OSG能渲染的面片节点,这里要注意坐标系翻转!
osg::ref_ptr<osg::Geometry> meshGeo = Netgen2OsgConverter::convert(rawMesh);
// 把网格叠加到模型上面
currentView->addOverlayNode(meshGeo);
这里踩的最大的坑就是坐标系不统一:Netgen默认Y轴朝上,Occt是Z轴朝上,转的时候要给OSG的节点乘一个旋转矩阵,不然网格会歪成麻花。而且导出网格的时候也支持STL、OBJ、OSG格式,直接用OSG的writeImageFile就行。
其他杂七杂八的功能
比如视角切换,就是给OSG的相机绑定不同的控制模式,正交/透视一键切换;显示模式切换改一下OSG的PolygonMode就行,线框、着色、隐藏线都能快速切;模型高亮就是给选中的节点加一个红色的自发光材质,装配体的时候还能单独高亮某个零件;点选功能用OSG的PickVisitor,点击的时候遍历场景算射线交点,再传回给Occt获取精确的几何信息。

基于opencascade7.4+osg3.6.3+qt5.12.7的多文档初级Cad/cae平台,支持十几种格式文件,包括step,igs,stl,obj,3ds,osg等,支持视角切换,显示模式切换,仿Cad命令注册机制,装配体显示,模型高亮,点选功能,着色功能,测量功能,个性化导出图片功能,集成netgen6.2和gmesh8网格划分支持导出stl,obj,osg等格式C+

还有个性化导出图片,一开始用Qt的grabWindow,但是会把Qt的标题栏也截进去,后来换成OSG自带的截图接口,想截多大分辨率都没问题:
osg::ref_ptr<osg::Image> exportImg = new osg::Image;
exportImg->allocateImage(3840, 2160, 1, GL_RGBA, GL_UNSIGNED_BYTE);
currentView->getCamera()->attach(osg::Camera::COLOR_BUFFER, exportImg);
osgDB::writeImageFile(*exportImg, savePath);
最后唠唠现状
目前这个小平台已经支持STEP、IGS、STL、OBJ、3DS、OSG等十几种格式了,多文档切换、装配体树状显示、模型高亮、测量、导出图片这些功能都能用,网格划分导出也没问题,后续打算加个参数化建模的模块和剖切功能。代码已经开源到Gitee了,有兴趣的小伙伴可以去扒拉,要是能给个star就更开心了😎






AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)