【FastCAE源码阅读3】几何模型显示:从OCC对象到VTK对象_vtk occ-程序员宅基地

技术标签: FastCAE源码阅读  算法  c++  图形渲染  

从几何到显示还是比较麻烦的,需要将几何对象转换成渲染对象,涉及几何建模、面的三角化、图形渲染等学科,阅读本文需了解一些基本的OCC、VTK编程

一、几何体显示基本流程

FastCAE几何内核使用的是OCC,显示渲染用的VTK,那么就存在将OCC建模后的几何对象变成VTK支持类型的数据这个过程。

FastCAE在用OCC创建完模型之后,会生成一个Geometry::GeometrySet对象,这个对象包含了最原始的OCC中TopoDS_Shape实例对象。创建完成后都会发出信号emit showSet(set);,这个信号会触发将TopoDS_Shape变成VTK显示对象。这个段代码是在void GeometryViewProvider::showGeoSet(Geometry::GeometrySet *set, bool render)函数中实现。

二、几何对象变成显示对象过程

几何体是由点、线、面构成的,进行显示的时候是分别提取这些数据,进行单独显示的。也就是说我们看到的一个立方体等几何对象是由三个VTK显示对象Actor拼起来的。注意一个体是没有直接的数据对象与其对应的,体只是逻辑上的概念,所以很多软件中隐藏一个体的面会发现内部是空的。这个函数代码如下:

void GeometryViewProvider::showGeoSet(Geometry::GeometrySet *set, bool render)
{
    
	QList<vtkPolyData *> viewPolys = _viewData->transferToPoly(set); // 对几何体进行点、线、面的拆分
	vtkPolyData *facePoly = viewPolys.at(0); // 面的多边形数据
	vtkPolyData *edgePoly = viewPolys.at(1); // 边的数据集
	vtkPolyData *pointPoly = viewPolys.at(2); // 点数据集
	GeoViewObj viewObj;
	if (facePoly != nullptr) // 创建显示面的Actor
	{
    
		vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
		vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
		mapper->SetInputData(facePoly);
		actor->SetMapper(mapper);
		bool vis = set->isVisible();
		bool show = Setting::BusAPI::instance()->getGraphOption()->isShowGeoSurface();
		actor->SetVisibility(show && vis); // 设置是否显示面
		actor->SetPickable(false);   // 不可鼠标拾取?哪里打开呢?
		actor->GetProperty()->SetRepresentationToSurface(); // 这个函数不调用也没看到啥影响
		_preWindow->AppendActor(actor, ModuleBase::D3, false); // 将面actor添加到场景中
		viewObj._faceObj = QPair<vtkActor *, vtkPolyData *>(actor, facePoly);
	}

	// 创建显示边的Actor
	if (edgePoly != nullptr) 
	{
    
		vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
		vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
		mapper->SetInputData(edgePoly);
		actor->SetMapper(mapper);
		bool vis = set->isVisible();
		bool show = Setting::BusAPI::instance()->getGraphOption()->isShowGeoEdge();
		actor->SetVisibility(show && vis);
		actor->SetPickable(false);
		actor->GetProperty()->SetRepresentationToWireframe();
		//			actor->GetProperty()->EdgeVisibilityOn();
		float width = Setting::BusAPI::instance()->getGraphOption()->getGeoCurveWidth();
		actor->GetProperty()->SetLineWidth(width);
		_preWindow->AppendActor(actor, ModuleBase::D3, false);
		viewObj._edgeObj = QPair<vtkActor *, vtkPolyData *>(actor, edgePoly);
	}

	// 创建显示点的Actor
	if (pointPoly != nullptr)
	{
    
		vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
		vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
		float size = Setting::BusAPI::instance()->getGraphOption()->getGeoPointSize();
		mapper->SetInputData(pointPoly);
		actor->SetMapper(mapper);
		bool vis = set->isVisible();
		bool show = Setting::BusAPI::instance()->getGraphOption()->isShowGeoPoint();
		actor->SetVisibility(show && vis);
		actor->SetPickable(false);
		actor->GetProperty()->SetRepresentationToPoints();
		actor->GetProperty()->SetPointSize(size);
		_preWindow->AppendActor(actor, ModuleBase::D3, false);
		viewObj._pointObj = QPair<vtkActor *, vtkPolyData *>(actor, pointPoly);
	}
	_geoViewHash.insert(set, viewObj);
	if (render)
		_preWindow->resetCamera();
}

三、几何面数据的提取

几何体的面、边、点转换为vtkPolyData对象的方式类似,都在函数GeometryViewData::transferToPoly()中,这里只分析面数据的提取。

/* 提取几何表面的多边形数据集 */
vtkPolyData *GeometryViewData::transferFace(Geometry::GeometrySet *gset)
{
    
	TopoDS_Shape *shape = gset->getShape(); // 获取OCC的Shape
	TopExp_Explorer faceExp(*shape, TopAbs_FACE); // 这个类可访问Shape的拓扑关系
	QList<Handle(TopoDS_TShape)> tshapelist; // 放置已访问的Face对象,防止重复访问
	vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::New();
	vtkPolyData *polyData = vtkPolyData::New();
	int beg = 0;
	for (int index = 0; faceExp.More(); faceExp.Next(), ++index) // 开始遍历面
	{
    
		const TopoDS_Shape &s = faceExp.Current();
		Handle(TopoDS_TShape) ts = s.TShape();
		if (tshapelist.contains(ts)) // 防止重复访问,会存在这种情况吗?
			continue;
		tshapelist.append(ts);
		IVtkOCC_Shape::Handle aShapeImpl = new IVtkOCC_Shape(s); // OCC提供IVtkOCC_Shape类
		vtkSmartPointer<IVtkTools_ShapeDataSource> DS = vtkSmartPointer<IVtkTools_ShapeDataSource>::New(); // OCC提供的VTK数据源
		DS->SetShape(aShapeImpl); 
		vtkSmartPointer<vtkCleanPolyData> cleanFilter = vtkSmartPointer<vtkCleanPolyData>::New();
		cleanFilter->SetInputConnection(DS->GetOutputPort());
		cleanFilter->Update();
		vtkSmartPointer<vtkPolyData> tpolys = vtkSmartPointer<vtkPolyData>::New();
		vtkPolyData *tpolydata = cleanFilter->GetOutput();
		const int np = tpolydata->GetNumberOfPoints(); // 点的数量
		const int nc = tpolydata->GetNumberOfCells();  // cell的数量
		vtkPoints *points = vtkPoints::New();
		for (int i = 0; i < np; i++) //  提取几何点数据
		{
    
			double *coor = tpolydata->GetPoint(i);
			points->InsertNextPoint(coor);
		}
		tpolys->SetPoints(points); // 设置几何点数据
		vtkCellArray *cells = vtkCellArray::New();
		for (int i = 0; i < nc; ++i)
		{
    
			vtkCell *cell = tpolydata->GetCell(i);
			vtkIdList *ceid = cell->GetPointIds();
			if (ceid->GetNumberOfIds() == 3) // 只提取三角形,这里获取的cell包含点、线、三角形,一个立方体最后应该有12个三角形
			{
    
				vtkTriangle *triangle = vtkTriangle::New();
				triangle->DeepCopy(cell); // 有DeepCopy接口
				cells->InsertNextCell(triangle);
			}
		}
		tpolys->SetPolys(cells); // 设置拓扑多边形数据集的cell

		// 法线数据?打开与否貌似不影响显示效果
		vtkSmartPointer<vtkPolyDataNormals> normals = vtkSmartPointer<vtkPolyDataNormals>::New();
		normals->SetInputData(tpolys);
		normals->FlipNormalsOn();
		normals->Update();
		vtkPolyData *facePoly = normals->GetOutput();
		const int ncell = facePoly->GetNumberOfCells();
		if (ncell < 1)
			continue;
		GeometryViewObject *obj = new GeometryViewObject(GeometryViewObject::Face, beg, beg + ncell - 1, ts);
		beg += ncell;
		appendFilter->AddInputData(facePoly);  // 追加到appendFilter中
		auto setViewObj = this->getGeosetObj(gset);
		setViewObj->appendFaceViewObj(index, ts, obj);
	}
	appendFilter->Update();
	polyData->DeepCopy(appendFilter->GetOutput());
	auto setViewObj = this->getGeosetObj(gset);
	setViewObj->setFacePoly(polyData); // 保存面多边形数据
	const int npc = polyData->GetNumberOfCells();
	if (npc < 1)
		return nullptr;
	return polyData;
}

这里要注意几个类:

  1. TopExp_Explorer: OCC提供的遍历几何体拓扑结构的类;
  2. IVtkOCC_Shape、IVtkTools_ShapeDataSource:这俩类可以将面三角化,并变成VTK的cell,注意cell包含面上的点、边、三角形,所以提取面的时候只提取了三角形,这俩类同样是OCC提供的;
  3. vtkPolyDataNormals: 看类名猜测是生成法线的,但是不用这类显示也没啥问题;
  4. vtkAppendPolyData:可以将各个面的数据追加在一起。

四、面数据的最终数据结构

OCC对象在转换过程中,会生成成一系列对象,用于后续的拾取高亮等功能。FastCAE中有个组件叫GeometryViewProvider,其中的字段_viewData(类型 GeometryViewData)保存这些数据。GeometryViewData类中有哈希表,key是几何对象,value是GeoSetViewObject。GeoSetViewObject又有hash表_faceObjHash、_faceViewObjs。以立方体为例,_faceViewObjs保存6个面对应的GeometryViewObject对象,每个GeometryViewObject对象记录这这个面对应的cell范围及所有面的多边形数据集vtkPloyData。这个数据集在GeoSetViewObject也有引用(_facePoly字段),也是面Actor中的数据集,一个体的所有面组成一个Actor。最终形成如下的一种数据结构:
在这里插入图片描述

边和点的数据与面类似,这里就不再分析了。

最后来张图吧:
在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/loveoobaby/article/details/134203489

智能推荐

Unity优化——LOD技术_lod技术原理-程序员宅基地

文章浏览阅读1.4w次,点赞9次,收藏30次。什么是LODLOD是Level Of Detais 的简称,多细节层次在游戏场景中,根据摄像机与模型的距离,来决定显示哪一个模型,一般距离近的时候显示高精度多细节模型,距离远的时候显示低精度低细节模型游戏中有高模低模的存在。说白的就是离得远看不清,离得近很清楚。根据摄像机与物体距离,unity会自动切换模型。使用LOD先准备几个模型,从高模到低模。没有模型。。。低配版..._lod技术原理

javax.imageio.IIOException: Not a JPEG file: starts with 0x47 0x49-程序员宅基地

文章浏览阅读7.8k次。java处理图片时出现异常javax.imageio.IIOException: Not a JPEG file: starts with 0x47 0x49at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImageHeader(Native Method)at com.sun.imageio.plugins.jpeg.JPEGI_javax.imageio.iioexception: not a jpeg file: starts with 0x52 0x49

代发外链哪家好?-程序员宅基地

文章浏览阅读343次,点赞11次,收藏6次。与其授人以鱼不如授人以渔,在这里说说如何选择好的外链商,可以先找一下你要发的这家外链商的口碑,了解其专业水平,这倒是最基本的了,说到底这些东西说得难听点都是可以伪造的,所以最重要的,是要了解外链的作用。外链可以说是网站外部优化最重要的组成部分,一个网站的外链建设对于网站网站优化是至关重要的,选择到一家好的外链商可以说成功了一半,毕竟不是谁都有外链资源。外链最重要的作用毫无疑问,就是提升网站的关键词排名,不能提升排名的外链可以说没有意义,有人就会说了,但外链的作用不是日积月累的吗?

使用Apache的ab工具进行压力测试_用apache中的ab测试接口压力中的时延是什么-程序员宅基地

文章浏览阅读442次。ab命令原理 Apache的ab命令模拟多线程并发请求,测试服务器负载压力,也可以测试nginx、lighthttp、IIS等其它Web服务器的压力。 Apache附带的ab工具(使用的PHP环境是WAMP集成环境,ab工具位于D:\wamp\bin\apache\Apache2.2.21\bin)非常容易使用。ab命令对发出负载的计算机要求很低,既不会占用很多CPU,也不会占用太多的内存,但_用apache中的ab测试接口压力中的时延是什么

falsk框架中安装flask-mysqldb报错解决方案_flask_mysqldb安装失败windows-程序员宅基地

文章浏览阅读1k次。我的是py37版本,无法直接安装flask-mysqldb。下载完成之后直接在控制台本地安装。下载mysqlclient。_flask_mysqldb安装失败windows

手把手教你启用Win10的Linux子系统(超详细)_win10自带linux子系统怎么用-程序员宅基地

文章浏览阅读10w+次,点赞143次,收藏775次。今天为大家介绍如何才能启用Windows10下的Linux子系统,废话不多说,直接看步骤:启用开发者模式打开设置 点击更新和安全 点击开发者选项 启用开发人员模式 更改系统功能使用win+X快捷键调出系统管理菜单后点击应用和功能,然后拉到底下,选择程序和功能 选中应用或关闭Windows功能 勾选适用于Linux的Windows子系统,然后确认并重启..._win10自带linux子系统怎么用

随便推点

超文本标记语言_head表示超文本文件头信息的结束-程序员宅基地

文章浏览阅读6.2k次。超文本标记语言百科名片超文本标记语言,即HTML(Hypertext Markup Language),是用于描述网页文档的一种标记语言。 查看精彩图册目录基本介绍由来定义语言特点编辑发展历史超文本标记语言可扩展超文本标记语言整体结构文件头部内容文件主体内容字符集_head表示超文本文件头信息的结束

h265硬解码和软解码_h265能通过gpu解码-程序员宅基地

文章浏览阅读2k次。h.265解码库,支持GPU和CPU1.初始化PlayerSDK_Init(CallBack callBackFunc,int nType);callBackFunc 回调函数nType 视频解码方式 CPU解码或者GPU解码2.播放接口PlayerSDK_Play(char* URL, long hWnd, int nType);URL 播放地址hWnd 播放句柄nType 播放类型接口返回播放句柄号3.停止播放接口Play_h265能通过gpu解码

stable diffusion(1): webui的本地部署(windows)_sd webui torch版本-程序员宅基地

文章浏览阅读2.1k次。有一个坑一直没过去,就是如果整体环境没完全装好,但是使用我自己提前创建的python虚拟环境来启动SD启动脚本stable-diffusion-webui/webui-user.bat,期间会因为某些原因(比如没梯子东西下载不下来)启动失败,但是第二次启动时就会报没有pip模块的错误,我就只能重新创建python虚拟环境,再装一遍包,这个过程很漫长很浪费时间,所以一定跟着我的脚步,一步不要落下的走,心急吃不了热豆腐。如果没有梯子,这里很慢或者根本过不去,所以参考。三、修改url地址(梯子强可不改)_sd webui torch版本

CTFSHOW做题记录_ctfshow 龙猫-程序员宅基地

文章浏览阅读491次。CTFSHOW做题记录**CTFSHOW做题记录1**(菜菜的我要写日记啦,欢迎大佬指导)**密码学签到1给出“}wohs.ftc{galf”并且提示倒叙。**解题思路:没看提示的时候乍一看以为是栅栏密码,还想着用在线解密去做,但是定睛一看不对劲,再看题目原来就是倒叙。只需要反着来就好啦。**答案:flag{ctf.show}**今天也是元气满满的一天,好好学习。..._ctfshow 龙猫

抓取动态网页的数据的具体操作方法_动态加载的网页怎么获取链接-程序员宅基地

文章浏览阅读1.9k次。不同的方法适用于不同的情况,例如如果目标网站使用的是JavaScript动态加载数据,那么使用Scrapy-Splash可能会更加适合。如果目标网站的数据比较简单,那么使用浏览器开发者工具可能会更加方便。如果需要模拟用户的操作,那么使用Selenium可能是更好的选择。总之,需要根据具体情况选择合适的方法,才能高效地获取动态网页的数据。综上所述,选择合适的方法取决于具体的需求。如果需要模拟用户的操作,可以使用Selenium。动态网页是指在用户交互过程中,网页内容不断更新和变化的网页。_动态加载的网页怎么获取链接

Ubuntu20.04安装向日葵_ubuntu20.04 安装向日库-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏6次。下载最新版本:https://sunlogin.oray.com/download/缺少部分依赖,手动下载:# 你知道最新的版本号了sudo wget http://download.oray.com/sunlogin/linux/SunloginClient-10.0.2.24779_amd64.debsudo wget http://mirrors.aliyun.com/ubuntu/pool/main/i/icu/libicu60_60.2-3ubuntu3_amd64.debsudo w_ubuntu20.04 安装向日库

推荐文章

热门文章

相关标签