vtk之【vtkPolyData、vtkCell、vtkPoints】

文章目录

  • 一、vtkPolyData、cell、point
    • 1) 例子
    • 2) vtkPolyData、vtkCell、vtkPoints
  • 二、vtkNew<>与vtkSmartPointer<>的区别:
  • 三、补充
  • 四、判断两者的拓扑结构是否一致的简单方法

一、vtkPolyData、cell、point

1) 例子

  /**
  * vtkNew 是一个类模板
  * vtkNew<> 是一个简单的 RAII(Resource Acquisition Is Initialization)(资源获取即初始化)类模板,用于在堆上创建对象,并负责对象的销毁。使用 vtkNew<> 创建的对象会自动在作用域结束时被销毁,无需手动调用 delete。
  *
  * 你知道什么是类模板,什么是模板类吗?
  * 从字面意思看,类模板是一个模板,即class template;模板类是一个类,即 template class。
  * 简单的来讲:类模板就是一个定义,不能直接拿来用,还需要进行实例化,然后模板类就是类模板的实例化,类中的参数被实际类型所替代;(再简单来讲:没是实例化的叫类模板,实例化后的类模板是模板类)
  * 即:vtkNew是一个类模板,然后vtkNew是模板类
  ◆ vtkColor3d GetColor3d(const vtkStdString & 	name	):按名称获取颜色。
该名称被视为不区分大小写。颜色作为vtkColor3d类返回。如果找不到颜色,则返回黑色。
  */
  vtkNew<vtkNamedColors> colors;

  /***
  * vtkPoints:vtkPoints表示3D点。vtkPoints的数据模型是一个vx-vy-vz三元组数组,可通过(点或单元)id访问。
  ◆ vtkIdType vtkPoints::InsertNextPoint	(	double 	x,
     double 	y,
     double 	z 
    )
    其实还都float的方法,但是cpp在你不指定的情况下,小数都是double类型
    
    源码:
    inline vtkIdType vtkPoints::InsertNextPoint(double x, double y, double z)
     {
       double p[3] = { x, y, z };
       return this->Data->InsertNextTuple(p);
     }
     //vtkDataArray* Data;       // Array which represents data
     //InsertNextTuple的定义:
vtkIdType vtkDataArray::InsertNextTuple	(	vtkIdType 	srcTupleIdx,
vtkAbstractArray * 	source 
)	
	然后这个方法继承自vtkAbstractArray类
	virtual vtkIdType vtkAbstractArray::InsertNextTuple	(	vtkIdType 	srcTupleIdx,
vtkAbstractArray * 	source 
)		
	将srcTupleIdx中的元组插入到源数组的末尾。
注意,根据需要执行存储器分配以保持数据。返回插入数据的元组索引。
  ****/
  vtkNew<vtkPoints> points;//构成图形的四个点
  points->InsertNextPoint(0.0, 0.0, 0.0);
  points->InsertNextPoint(1.0, 0.0, 0.0);
  points->InsertNextPoint(1.0, 1.0, 0.0);
  points->InsertNextPoint(0.0, 1.0, 0.0);

  // Create the polygon
/**
*vtkPolygon:表示n边多边形的像元
vtkPolygon是vtkCell的具体实现,用于表示2D n边多边形。多边形不能有任何内部孔,也不能自相交。定义n个点按逆时针方向排列的多边形;不要重复最后一点。
* GetPointIds函数继承自vtkCell类:vtkIdList* vtkCell::GetPointIds	(		)	
返回定义单元格的点ID列表。
vtkIdList* GetPointIds() { return this->PointIds; }

void vtkIdList::SetNumberOfIds	(	vtkIdType 	number	)	
:指定此对象要保存的id数。


void vtkIdList::SetId	(	vtkIdType 	i,
vtkIdType 	vtkid )
:在位置i设置id。
不做范围检查,所以它比InsertId快一点。确保在使用SetId()之前使用SetNumberOfIds()分配内存。
 typedef long long vtkIdType;
 typedef long vtkIdType;
 typedef int vtkIdType;
void SetId(vtkIdType i, vtkIdType vtkid) VTK_EXPECTS(0 <= i && i < GetNumberOfIds())
{
	this->Ids[i] = vtkid;
}//解释:VTK_EXPECTS(0 <= i && i < GetNumberOfIds()): 这是一个断言宏,用于在运行时检查条件是否满足。在这里,断言确保传入的索引值 i 大于等于 0 并且小于多边形点索引数组的大小。
**/
  vtkNew<vtkPolygon> polygon;
  polygon->GetPointIds()->SetNumberOfIds(4); // make a quad
  polygon->GetPointIds()->SetId(0, 0);
  polygon->GetPointIds()->SetId(1, 1);
  polygon->GetPointIds()->SetId(2, 2);
  polygon->GetPointIds()->SetId(3, 3);//如果你对这里有疑问:可以看一下下面的图1与图2

  /*************
  *vtkCellArray : 对象来表示像元连通性
tkCellArray 用于表示数据集的拓扑结构,它通过一个显式的连接表来存储每个单元所包含的点的标识。

在内部,连接表由两个数组表示:Offsets 和 Connectivity。

Offsets 是一个长度为 [numCells+1] 的数组,表示每个单元的点在 Connectivity 数组中的起始索引位置。最后一个值始终是 Connectivity 数组的长度。

Connectivity 数组存储每个单元的点标识列表。

因此,对于包含 2 个三角形、一个四边形和一条线的数据集,内部数组将如下所示:

我不太理解下面这个拓扑结构和当前状态的vtkCellArray是什么意思??????????????????????????????????

拓扑结构:
单元 0: 三角形 | 点标识:{0, 1, 2}
单元 1: 三角形 | 点标识:{5, 7, 2}
单元 2: 四边形 | 点标识:{3, 4, 6, 7}
单元 3: 线 | 点标识:{5, 8}

vtkCellArray(当前状态):
Offsets: {0, 3, 6, 10, 12}
Connectivity: {0, 1, 2, 5, 7, 2, 3, 4, 6, 7, 5, 8}



vtkIdType vtkCellArray::InsertNextCell	(	vtkCell * 	cell	)	
作用:Insert a cell object.
Return the cell id of the cell.
源码:
inline vtkIdType vtkCellArray::InsertNextCell(vtkCell* cell)
 {
   vtkIdList* pts = cell->GetPointIds();
   return this->Visit(
     vtkCellArray_detail::InsertNextCellImpl{}, pts->GetNumberOfIds(), pts->GetPointer(0));
 }
  ******************/
  vtkNew<vtkCellArray> polygons;
  polygons->InsertNextCell(polygon);//vtkNew polygon;polygon是vtkNew,但是可以作为vtkCell*类型的参数(因为vtkPolygon是vtkCell的子类)
//总结一下:这两行代码的作用是存储数据集合的拓扑结构,即单元(cell)的连接关系,polygon就是我们写好的拓扑结构

  // Create a PolyData
  vtkNew<vtkPolyData> polygonPolyData;
  polygonPolyData->SetPoints(points);//将坐标点给到Polydata
  polygonPolyData->SetPolys(polygons);//再将这些坐标的拓扑结构给到Polydata(我理解的是坐标的连接顺序)
 //既然知道了坐标,也知道了坐标怎么连接,那么这个Polydata就算封装完成了

  //然后就是:通过mapper得到可渲染的图元数据,再通过actor得到可渲染的图元,最后将actor加入到渲染器
  // Create a mapper and actor
  vtkNew<vtkPolyDataMapper> mapper;
  mapper->SetInputData(polygonPolyData);

  vtkNew<vtkActor> actor;
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(colors->GetColor3d("Silver").GetData());

  // Visualize
  vtkNew<vtkRenderer> renderer;
  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->SetWindowName("Polygon");
  renderWindow->AddRenderer(renderer);
  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);

  renderer->AddActor(actor);
  renderer->SetBackground(colors->GetColor3d("Salmon").GetData());//设置背景颜色

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

vtk之【vtkPolyData、vtkCell、vtkPoints】_第1张图片

vtk之【vtkPolyData、vtkCell、vtkPoints】_第2张图片

2) vtkPolyData、vtkCell、vtkPoints

https://vtk.org/doc/nightly/html/classvtkPolyData.html

https://vtk.org/doc/nightly/html/classvtkCell.html

https://vtk.org/doc/nightly/html/classvtkPoints.html

二、vtkNew<>与vtkSmartPointer<>的区别:

举个例子:同样是构造窗口交互器

vtkSmartPointer<>的写法:
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();

vtkNew<vtkRenderWindowInteractor>的写法:
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;

简单的来说 , vtkNew没有引用计数,而vtkSmartPointer有引用计数的机制

vtkNew和vtkSmartPointer都用于VTK(可视化工具包)中对象的创建和管理。但是,两者之间确实存在着一些主要的区别 :

  • vtkNew 用于在堆上创建一个新的 VTK 对象并保持其所有权。当 vtkNew 对象超出范围时,它将删除其相关联的 VTK 对象。但请注意,vtkNew 不支持引用计数

  • 相反,vtkSmartPointer 是一个智能指针,用于维护VTK对象的引用计数。当一个 vtkSmartPointer 指向一个 VTK 对象时,该对象的引用计数增加1。当 vtkSmartPointer 在超出范围或被重新分配到另一个对象时,原来的VTK对象的引用计数减少1。如果VTK对象的引用计数变为0,那么这个对象就会被删除。

所以,在需要使用引用计数机制进行内存管理的情况下,我们通常会选择使用 vtkSmartPointer 而不是 vtkNew。

然后 , vtk的作者 更加支持使用vtkSmartPointer<>
对于 V T K 库中的对象管理,推荐使用 v t k S m a r t P o i n t e r < > 来避免内存泄漏和悬挂指针等问题。 对于VTK库中的对象管理,推荐使用vtkSmartPointer<>来避免内存泄漏和悬挂指针等问题。 对于VTK库中的对象管理,推荐使用vtkSmartPointer<>来避免内存泄漏和悬挂指针等问题。

三、补充

这里还有一篇大佬的文章:把上面的那个搞懂了,下面这个大佬写的网格分割的例子就不那么难理解了

https://blog.csdn.net/liushao1031177/article/details/118151714#comments_29088179

四、判断两者的拓扑结构是否一致的简单方法

对于三维对象,例如球体和甜甜圈,我们可以用来区分二者的主要是它们具有的孔数。
如果一个对象比另一个对象具有更多的孔,则二者在拓扑上是不同的。这是因为它们违反了我们先前建立的拉伸橡皮泥的规则。要造出一个孔,我们要么在橡皮泥上撕出一个洞,要么将橡皮泥拉伸成一个甜甜圈形状,然后将两端合并在一起。

你可能感兴趣的:(vtk,开发语言,c++,vtk)