VTK与OCC集成服务介绍(VIS)

一、介绍

VIS(VTK Integration Services)组件通过VTK库为OCCT拓扑形状的可视化提供适配功能。 本用户指南描述了如何在基于 VTK 库的 3D 可视化应用程序中应用 VIS 类。

有两种方式可以使用VIS:

  1. 使用high-level API。 这是一个使用VTK显示 OCCT 形状的简单场景。 它考虑了与 VIS 组件一起提供的工具的使用,例如特定的 VTK 数据源、选择器类和特定的 VTK 过滤器。 基本上,在这种情况下,您可以使用来自 VIS 的扩展来丰富您的自定义 VTK 管道。
  2. 使用lou-level API。 对于有特定需求的用户来说,这是一个高级场景,VIS 的high-level API没有解决这些需求。 它假定在 VIS 组件的lou-level API 的帮助下实现自定义 VTK 算法(如过滤器)。 本文档描述了将 VIS 集成到应用程序中的两种情况。 要理解本文档,有必要熟悉 VTK 和 OCCT 库。

二、组件结构

2.1、通用结构

VIS组件提供了以下包:

  • IVtk - 提供了VIS基础对象的通用接口。
  • IVtkOCC - 实现了与CAD领域相关的接口。该软件包中的类处理OCCT中的拓扑形状、分面以及交互操作。
  • IVtkVTK - 实现了与VTK相关的可视化包的接口。
  • IIVtkTools - 为集成到VTK可视化管线而设计的高级工具。

通过它们对特定库(OCCT,VTK)的依赖关系,将接口与其实际实现分离的做法除了提供语义分离之外,这种分离还有助于避免对其他 OCCT 工具包和 VTK 的过度依赖。

  • IVtk包不依赖VTK,对OCCT的依赖也仅仅是因为使用了集合(TKernel库);
  • IVtkOCC 包中的实现类仅依赖于 OCCT 库,不需要 VTK;
  • IVtkVTK 包仅依赖于 VTK 库,不需要任何 OCCT 功能,除了集合。

基本上,应用程序中的前三个包(IVtk、IVtkOCC 和 IVtkVTK)就足以在 VTK 查看器中使用 OCCT 形状。 但是,IVtkTools 包也作为组件的一部分提供,以使工作更加舒适。

2.2、IVtk包

IVtk包包含了以下类:

  • IVtk_Interface - 组件所有接口的基类。 为 Handle(OCCT“智能指针”)功能提供继承。
  • IVtk_IShape - 表示任意性质的 3D 形状。 提供其 ID 属性。 此接口的实现应为所有可视化形状维护唯一的 ID。 这些 ID 可以在应用程序级别轻松转换为原始形状对象。
  • IVtk_IShapeData - 表示分面数据。 提供添加坐标和单元格(顶点、线、三角形)的方法。
  • IVtk_IShapeMesher - 分面接口,即从 IVtk_IShape 输入形状构造 IVtk_IShapeData。
  • IVtk_IShapePickerAlgo - 用于在场景中交互式选择形状的算法界面。 提供根据所选选择模式在给定位置查找形状及其部分(子形状)的方法。
  • IVtk_IView - 获取视图变换参数的接口。 它由 IVtk_IShapePickerAlgo 使用。

2.3、IVtkOCC包

IVtkOCC包包含了以下类:

  • IVtkOCC_Shape - IVtk_IShape 接口的实现作为 TopoDS_Shape 的包装器。
  • IVtkOCC_ShapeMesher - IVtk_IShapeMesher 接口的实现,用于从 TopoDS 形状构建构面。
  • IVtkOCC_ShapePickerAlgo - 交互式拣选算法的实现。 它为形状(IVtk_IShape 实例)和给定光标位置的选择工具提供启用/禁用选择模式。
  • IVtkOCC_ViewerSelector - 交互式选择器,它实现了拾取算法 IVtkOCC_ShapePickerAlgo 的 Pick() 方法,并在抽象 IView 接口的帮助下连接到可视化层。

IVtkOCC_ViewerSelector 是 OCCT 原生 SelectMgr_ViewerSelector 的后代,因此它为 IVtkVTK_View 实现了 OCCT 选择机制(类似于为 OCCT 原生 V3d_View 实现 SelectMgr_ViewerSelector 的 StdSelect_ViewerSelector3D)。 IVtkOCC_ViewerSelector 封装了拾取机制的所有投影变换。 这些转换是从通过 VTK Renderer 可用的 vtkCamera 实例中提取的。 IVtkOCC_ViewerSelector 与本机 OCCT SelectMgr_Selection 实体一起操作。 每个实体代表OCCT可选对象的一种选择模式。 ViewerSelector 是一个内部类,因此它不是公共 API 的一部分。

  • IVtkOCC_SelectableObject – OCCT 形状包装器用于拾取算法中,用于计算所选选择模式的形状选择基元。

2.4、IVtkVTK包

IVtkVTK包包含依赖VTK的接口类实现:

  • IVtkVTK_ShapeData – 为VTK的polydata实现IVtk_IShapeData接口。此类还存储了与子形状ID和子形状网格类型IVtk_MeshType(自由顶点、共享顶点、自由边、共享边、边界边、共享边、线框面和阴影面)相关的信息。此信息存储在单元的VTK数据数组中。
  • IVtkVTK_View – 为VTK的视图实现IVtk_IView接口。此实现类将用于连接IVtkOCC_ViewerSelector到VTK的renderer。

2.5、IVtkTools包

IVtkTools 包为您提供了一个现成的算法工具箱,有助于将 OCCT 形状集成到 VTK 的可视化管道中。 这个包包含以下类:

  • IVtkTools_ShapeDataSource – OCCT 形状的 VTK 多边形数据源。 它继承了 vtkPolyDataAlgorithm 类,并为可视化管道提供了 OCCT 形状的多面表示。
  • IVtkTools_ShapeObject – OCCT 形状的辅助包装类,通过 VTK 信息键将它们传递给管道。
  • IVtkTools_ShapePicker – 形状actor的 VTK 选择器。 内部使用 OCCT 选择算法。
  • IVtkTools_DisplayModeFilter – VTK 过滤器,用于根据给定的显示模式 IVtk_DisplayMode(线框或阴影)提取特定网格类型的单元格。
  • IVtkTools_SubPolyDataFilter – VTK 过滤器,用于提取对应于给定子形状 ID 集的单元格。

此外,IVtkTools 包包含 IVtkTools 命名空间中的辅助方法。 例如。 有一个方便的函数填充 vtkLookupTable 实例来设置颜色方案,以便更好地可视化子形状。

三、使用高级API(简单场景)

3.1、在VTK视图中显示OCCT的shape对象

为了在VTK视图中展示OCCT拓扑形状,需要执行下面的步骤:

  1. 创建IVtkOCC_Shape实例(VIS提供的OCCT shape包装器)并且用包含实际几何数据的TopoDS_Shape初始化:

    TopoDS_Shape aShape;
    // Initialize aShape variable: e.g. load it from BREP file
    IVtkOCC_Shape::Handle aShapeImpl = new IVtkOCC_Shape(aShape);
    
  2. 为目标 OCCT 拓扑形状创建 VTK 多边形数据源,并使用创建的 IVtkOCC_Shape 实例对其进行初始化。 在这个阶段,分面被隐式插入.

    vtkSmartPointer<IVtkTools_ShapeDataSource> DS = vtkSmartPointer<IVtkTools_ShapeDataSource>::New();
    DS->SetShape(aShapeImpl);
    
  3. 以通用的 VTK 方式显示加载的形状,从创建的Source开始VTK管道:

    vtkSmartPointer<vtkPolyDataMapper> Mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    Mapper->SetInputConnection(aDS->GetOutputPort());
    vtkSmartPointer<vtkActor> Actor = vtkSmartPointer<vtkActor>::New();
    Actor->SetMapper(Mapper);
    

    可以通过 IVtkTools_ShapeObject 类的专用方法从 VTK的actor中获取OCCT的shape对象:

    IVtkTools_ShapeDataSource* DS = IVtkTools_ShapeObject::GetShapeSource(Actor);
    IVtkOCC_Shape::Handle occShape = IVtkTools_ShapeObject::GetOccShape(Actor);
    

    也可以从shape数据源获取一个形状封装器:

    IVtkOCC_Shape::Handle occShape = DS->GetShape();
    

实例代码:

#include <BRepPrimAPI_MakeBox.hxx>
#include <vtkRenderWindow.h>
#include <vtkNew.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkPolyDataMapper.h>
#include <IVtkTools_ShapeDataSource.hxx>

int main()
{
	BRepPrimAPI_MakeBox box(5, 2, 3);
	const TopoDS_Shape& shape = box.Shape();

	vtkNew<vtkRenderWindow>  renderWindow;
	vtkNew<vtkRenderer> renderer;
	renderWindow->AddRenderer(renderer);

	vtkNew<vtkInteractorStyleTrackballCamera> interactorStyle;
	vtkNew<vtkRenderWindowInteractor> windowInteractor;

	windowInteractor->SetRenderWindow(renderWindow);
	windowInteractor->SetInteractorStyle(interactorStyle);

	vtkNew<IVtkTools_ShapeDataSource> boxSource;
	boxSource->SetShape(new IVtkOCC_Shape(shape));

	vtkNew<vtkPolyDataMapper> mapper;
	mapper->SetInputConnection(boxSource->GetOutputPort());

	vtkNew<vtkActor> actor;
	actor->SetMapper(mapper.Get());
	renderer->AddActor(actor.Get());

	renderWindow->Render();
	windowInteractor->Start();

	return 0;
}

3.2、配色方案

3.2.1、OCCT默认的配色方案

要根据默认的 OCCT 配色方案为形状的不同部分着色,可以使用 IVtkTools 命名空间的专用辅助功能配置相应的 VTK 映射器:

IVtkTools::InitShapeMapper(Mapper);

可以通过以下方法获取具有默认 OCCT 颜色方案的 vtkLookupTable 类的实例:

vtkSmartPointer<vtkLookupTable> Table = IVtkTools::InitLookupTable();

3.2.2、自定义配色方案

要为形状表示设置应用程序特定的颜色,请以自定义颜色表为参数调用 InitShapeMapper 函数:

SetLookupTableColor(aLookupTable, MT_FreeEdge, R, G, B);
SetLookupTableColor(aLookupTable, MT_FreeEdge, R, G, B, A);
GetLookupTableColor(aLookupTable, MT_FreeEdge, R, G, B);
GetLookupTableColor(aLookupTable, MT_FreeEdge, R, G, B, A);

R、G、B 是 [0, 1] 范围内红色、绿色和蓝色double型分量值。 可选参数 A 代表相同范围 [0, 1] 中的双精度值(不透明度)。 默认情况下 alpha 值为 1,即颜色不透明。

3.2.3、使用mapper的配色方案

由于 VTK 颜色映射方法基于将标量数据数组与 VTK 单元相关联,因此可以通过以下方式打开/关闭形状组件的着色:

Mapper->ScalarVisibilityOn();  // use colors from lookup table
Mapper->ScalarVisibilityOff(); // use a color of actor’s property

例如,可以禁用基于标量的着色然后将单一颜色绑定到actor来显示整个VTK的actor。

3.3、显示模式

形状数据源的输出可以线框或阴影显示方式呈现。 IVtkTools_DisplayModeFilter 类中的定义的过滤器可以用来选择显示模式。 过滤器允许与给定模式对应的单元。 可用模式集由 IVtk_DisplayMode 枚举定义。

例如,可以通过以下方式获得阴影表示:

vtkSmartPointer<IVtkTools_ShapeDataSource> DS = vtkSmartPointer<IVtkTools_ShapeDataSource>::New();
vtkSmartPointer<IVtkTools_DisplayModeFilter> DMFilter = vtkSmartPointer<IVtkTools_DisplayModeFilter>::New();
DMFilter->AddInputConnection(DS->GetOutputPort());
DMFilter->SetDisplayMode(DM_Shading);
vtkSmartPointer<vtkDataSetMapper> M = vtkSmartPointer<vtkDataSetMapper>::New();
M->SetInputConnection(DMFilter->GetOutputPort());

默认情况下,显示模式过滤器以线框模式工作。

提示:要使着色表示平滑,请使用附加的 vtkPolyDataNormals 过滤器。 此过滤器必须在显示模式过滤器之后应用。

3.4、交互选择

IVtkTools 包提供 IVtkTools_ShapePicker 类,用于在 VTK 查看器中选择 OCCT 形状和子形状并访问拾取结果。 IVtkTools_ShapePicker 工具的典型用法包括以下操作步骤:

  1. 创建一个选择器并将其渲染器设置为您的活动 VTK 渲染器:

    vtkSmartPointer<IVtkTools_ShapePicker> aPicker = vtkSmartPointer<IVtkTools_ShapePicker>::New();
    aPicker->SetRenderer(aRenderer);
    
  2. 通过从 IVtk_SelectionMode 枚举中选择相应的子形状类型来激活所需的选择模式。 例如,以下调用允许在渲染器的所有可选形状actors上选择边缘:

    aPicker->SetSelectionMode(SM_Edge);
    

    如果需要限制特定形状 Actor 的选择,可以使用提到的 SetSelectionMode 方法,将 IVtk_IShape 句柄或 vtkActor 指针作为第一个参数:

    IVtk_IShape::Handle aShape = new IVtkOCC_Shape(occShape);
    aPicker->SetSelectionMode(aShape, SM_Edge); // If shape handle is available
    aPicker->SetSelectionMode(anActor, SM_Edge); // If shape actor is available
    

    一个选择器的不同选择模式可以同时独立地打开/关闭。

    aPicker->SetSelectionMode(SM_Edge);
    aPicker->SetSelectionMode(SM_Face);
    

    要关闭选择模式,请使用带有 false 值的附加可选布尔参数,例如:

    aPicker->SetSelectionMode(aShape, SM_Edge, false);
    
  3. 以鼠标的显示坐标为参数调用Pick函数:

    aPicker->Pick(x, y, 0);
    
  4. 以拾取VTK actors的集合获取顶层的拾取结果:

    vtkActorCollection* anActorCollection = aPicker->GetPickedActors();
    

    或以拾取形状的ID集获取结果:

    IVtk_ShapeIdList ids = aPicker->GetPickedShapesIds();
    

    默认情况下,这些方法返回单个顶层选取的actor或shape。 要获得所有拾取的actor或shape,将可选的布尔参数设置为“true”:

    anActorCollection = aPicker->GetPickedActors(true);
    ids = aPicker->GetPickedShapesIds(true);
    
  5. 获取选取的子形状的ID:

    IVtk_ShapeIdList subShapeIds = aPicker->GetPickedSubShapesIds(shapeId);
    

    此方法还返回顶级拾取子形状的单个 ID,可用相同的可选布尔参数来获取形状的所有拾取子形状:

    subShapeIds = aPicker->GetPickedSubShapesIds(shapeId, true);
    

应该注意的是,创建一个唯一的选取器实例并只向渲染器提供一次会更有效。 问题是每次渲染器或其某些参数发生更改时,拾取算法都会执行内部计算。 因此,尽量减少此类更新的数量是有意义的。

OCCT 拾取算法 IVtkTools_ShapePicker 每次更改视图的某些参数时都会计算一个新的变换矩阵来构建投影。 同样,一旦在 SetSelectionMode 方法中为此形状打开了适当的选择模式,就会为每种选择模式构建形状选择基元。

警告:VIS 选择器本质上是在初始拓扑数据结构上工作,而不是在实际可视化的参与者上工作。 这种特性使 VIS 可以利用标准的 OCCT 选择机制,但对相应的可视化管道施加了严格的限制。 一旦构建,刻面形状表示无论如何都不应变形或平移。 否则,拾取结果将失去与源几何体的关联性。 例如。 你不应该使用 vtkTransform 过滤器,而应该在初始模型上应用 OCCT 等距变换,以便在已经重新定位的方面工作。 对于 CAD 可视化,这些限制通常是可以接受的。 如果没有,请考虑使用自定义 VTK 样式的选择器来处理实际可视化的演员。

3.4.1、子形状的选择

IVtkTools_SubPolyDataFilter 是一个方便的 VTK 过滤器类,它允许提取与初始形状的子形状相对应的多边形单元。 它可用于使用来自 IVTkTools_ShapePicker 工具的选择结果从输入的 vtkPolyData 对象生成 vtkPolyData 对象。

例如,子形状可以通过以下方式在 VTK 查看器中表示:

// Load a shape into data source (see 3.1)
...
vtkSmartPointer<IVtkTools_ShapeDataSource> DS = vtkSmartPointer<IVtkTools_ShapeDataSource>::New();
DS->SetShape(shapeImpl);
...
// Create a new sub-polydata filter for sub-shapes filtering
vtkSmartPointer<IVtkTools_SubPolyDataFilter> subShapesFilter = IVtkTools_SubPolyDataFilter::New();
// Set a shape source as an input of the sub-polydata filter
subShapesFilter->SetInputConnection(DS->GetOutputPort());
// Get all picked sub-shapes ids of the shape from a picker (see 3.4)
IVtk_ShapeIdList subShapeIds = aPicker->GetPickedSubShapesIds(ds->GetId(), true);
// Set ids to the filter to pass only picked sub-shapes
subShapesFilter->SetData(subShapeIds);
subShapesFilter->Modified();
// Output the result into a mapper
vtkSmartPointer<vtkPolyDataMapper> aMapper = vtkPolyDataMapper::New();
aMapper->AddInputConnection(subShapesFilter->GetOutputPort());
...

四、使用底层API(高级场景)

4.1、形状呈现

在 IVtkTools 的实用程序不够用的情况下,使用低级工具是合理的。

VTK pipeline中VIS使用的底层场景如下图所示。 Mesher 组件使用 IShapeData 接口的实现来生成形状刻面(VTK 多边形数据)。 然后可以从这个实现中检索结果作为 vtkPolyData 实例。

OCCT 形状表示的可视化管道可以初始化如下:

  1. 创建一个IShape类的实例,并用OCCT的拓扑shape初始化:

    TopoDS_Shape aShape;
    // Load or create a TopoDS_Shape in the variable a Shape
    ...
    IVtkOCC_Shape::Handle aShapeImpl = new IVtkOCC_Shape(aShape);
    
  2. 为 VTK 创建 IShapeData 实现的空实例:

    IVtk_IShapeData::Handle aDataImpl = new IVtkVTK_ShapeData();
    
  3. 为 OCCT 创建一个 IShapeMesher 实现的实例(在此阶段可以使用任何 faceter)::

    IVtk_IShapeMesher::Handle aMesher = new IVtkOCC_ShapeMesher();
    
  4. 通过 Mesher 对 OCCT 拓扑形状进行三角剖分并访问结果:

aMesher->Build (aShapeImpl, aDataImpl);
vtkPolyData* aPolyData = aDataImpl->GetVtkPolyData();

生成的 vtkPolyData 实例可用于初始化 VTK 管道。 IVtkVTK_ShapeData 对象用于保持和通过管道传递子形状、它们的网格类型和生成的网格单元之间的映射。 它将每个生成的单元格的子形状 ID 和网格类型存储在 VTK 数据数组中。 结果,生成的 VTK 单元填充了以下数据数组:

  • SUBSHAPE_IDS - vtkIdTypeArray 类型的数组。 它包含为相应单元格生成的形状 ID。 该数组的名称在 IVtkVTK_ShapeData 类的 ARRNAME_SUBSHAPE_IDS 常量中定义。
  • MESH_TYPES - vtkShortArray 类型的数组。 它包含为其生成相应单元格的形状部件的类型标签。 该数组的名称在 IVtkVTK_ShapeData 类的 ARRNAME_MESH_TYPES 常量中定义。

实例代码:

#include <BRepPrimAPI_MakeBox.hxx>
#include <vtkRenderWindow.h>
#include <vtkNew.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkPolyDataMapper.h>
#include <IVtkTools_ShapeDataSource.hxx>
#include <IVtk_IShapeMesher.hxx>
#include <IVtkOCC_ShapeMesher.hxx>

int main()
{
	BRepPrimAPI_MakeBox box(5, 2, 3);
	const TopoDS_Shape& shape = box.Shape();

	IVtkOCC_Shape::Handle aShapeImpl = new IVtkOCC_Shape(shape);
	IVtkVTK_ShapeData::Handle aDataImpl = new IVtkVTK_ShapeData();
	IVtk_IShapeMesher::Handle aMesher = new IVtkOCC_ShapeMesher();
	aMesher->Build(aShapeImpl, aDataImpl);
	auto aPolyData = aDataImpl->getVtkPolyData();

	vtkNew<vtkPolyDataMapper> mapper;
	mapper->SetInputData(aPolyData);

	vtkNew<vtkRenderWindow>  renderWindow;
	vtkNew<vtkRenderer> renderer;
	renderWindow->AddRenderer(renderer);

	vtkNew<vtkActor> actor;
	actor->SetMapper(mapper.Get());
	renderer->AddActor(actor.Get());

	vtkNew<vtkInteractorStyleTrackballCamera> interactorStyle;
	vtkNew<vtkRenderWindowInteractor> windowInteractor;

	windowInteractor->SetRenderWindow(renderWindow);
	windowInteractor->SetInteractorStyle(interactorStyle);

	renderWindow->Render();
	windowInteractor->Start();

	return 0;
}

4.2、OCCT拾取算法的用法

可以使用拾取算法 IVtk_IShapePickerAlgo 的实例创建自定义 VTK 拾取器,用于交互式选择 OCCT 3D 形状。

拾取算法使用视图选择器(OCCT 术语)的实例,它管理拾取以及选择模式的激活和停用。 VIS 组件在 IVtkOCC_ShapePickerAlgo 和 IVtkOCC_ViewerSelector 类中实现了 OCCT 选择原理。 IVtkOCC_ViewerSelector 是一个内部类,它实现了应用于 IVtkVTK_View 的 OCCT 选择机制。

IVtkOCC_ShapePickerAlgo 必须用于激活/停用形状 IVtk_IShape 的选择模式。 IVtkOCC_ShapePickerAlgo 是 IVtk_IShapePickerAlgo 接口的实现。

IVtk_IShapePickerAlgo 的典型用法包括以下操作步骤:

  1. 创建一个拾取类的实例:

    IVtkOCC_ShapePickerAlgo::Handle Picker = new IVtkOCC_ShapePickerAlgo();
    
  2. 给拾取器设置一个IVtk_IView类的实例以便定义一些视图参数:

    IVtkVTK_View::Handle View = new IVtkVTK_View(Renderer);
    Picker->SetView(View);
    
  3. 使用 IVtk_SelectionMode枚举中的值激活所需的选择模式。 例如,以下调用允许选择边:

    TopoDS_Shape aShape;
    // Load or create a TopoDS_Shape in the variable a Shape
    ...
    IVtk_IShape::Handle shapeImpl = new IVtkOCC_Shape(aShape);
    ...
    myOccPickerAlgo->SetSelectionMode(occShape, SM_Edge);
    

    一个选择器的不同选择模式可以同时独立地打开/关闭。 要关闭选择模式,附加可选布尔参数与 false 值一起使用,例如:

    myOccPickerAlgo->SetSelectionMode(occShape, SM_Edge, false);
    
  4. 以鼠标坐标为参数调用Pick函数:

    myOccPickerAlgo->Pick(x, y);
    
  5. 以拾取shape的ID集合获取顶层的拾取结果:

    IVtk_ShapeIdList ids = myOccPickerAlgo->ShapesPicked();
    
  6. 获取子shape的ID集:

    IVtk_ShapeIdList subShapeIds = myOccPickerAlgo->SubShapesPicked(shapeId);
    

五、DRAW Test Harness

TKIVtkDraw 工具包包含用于将 VIS 功能嵌入到 DRAW 测试工具中的类,具有简单交互的可能性,包括检测和突出显示。

  • IVtkDraw_HighlightAndSelectionPipeline – 使用 OCCT 形状数据源和正确初始化的 VIS 过滤器创建 VTK 管道。
  • IVtkDraw_Interactor – 控制简单的交互动作,例如检测和选择显示的形状。
posted @ 2022-07-16 12:59  禅元天道  阅读(1934)  评论(0编辑  收藏  举报