【FastCAE源码阅读3】几何模型显示:从OCC对象到VTK对象

从几何到显示还是比较麻烦的,需要将几何对象转换成渲染对象,涉及几何建模、离散化、图形显示,阅读本文需了解一些基本的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拼起来的。这个函数代码如下:

cpp 复制代码
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); // 将面添加到场景中
		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()中,这里只分析面数据的提取。

cpp 复制代码
/* 提取几何表面的多边形数据集 */
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,包含面上的点、边、三角形
  3. vtkPolyDataNormals: 看类名猜测是生成法线的,但是不用这类显示也没啥问题
  4. vtkAppendPolyData:可以将各个面的数据追加在一起

最后来张图吧:

相关推荐
passer__jw76715 分钟前
【LeetCode】【算法】283. 移动零
数据结构·算法·leetcode
Ocean☾21 分钟前
前端基础-html-注册界面
前端·算法·html
顶呱呱程序29 分钟前
2-143 基于matlab-GUI的脉冲响应不变法实现音频滤波功能
算法·matlab·音视频·matlab-gui·音频滤波·脉冲响应不变法
爱吃生蚝的于勒1 小时前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~1 小时前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
王哈哈^_^1 小时前
【数据集】【YOLO】【VOC】目标检测数据集,查找数据集,yolo目标检测算法详细实战训练步骤!
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·pyqt
星沁城1 小时前
240. 搜索二维矩阵 II
java·线性代数·算法·leetcode·矩阵
脉牛杂德2 小时前
多项式加法——C语言
数据结构·c++·算法
legend_jz2 小时前
STL--哈希
c++·算法·哈希算法
CSUC2 小时前
【C++】父类参数有默认值时子类构造函数列表中可以省略该参数
c++