简体   繁体   English

使用Python计算表面单元区域时产生奇怪的VTK结果

[英]Strange VTK results on the computation of surface cell areas using Python

I have a question regarding the use of DeepCopy and Filters/Algorithms in VTK using the vtk python interface. 我对使用vtk python接口在VTK中使用DeepCopy和过滤器/算法有疑问。 I get incorrect and strange results doing the following: 我执行以下操作会得到不正确且奇怪的结果:

  1. Create a cone object cone from a ConeSource algorithm 通过ConeSource算法创建圆锥对象cone
  2. Deep copy cone into cone2 cone深复制到cone2
  3. Compute the area of the first cell (a polygon) of both cones cone and cone2 . 计算锥cone和锥cone的第一个像元(多边形)的cone2

The code also has some opt -lines ( opt1 , opt2 , opt3 ). 该代码也有一些选择 -lines(OPT1,OPT2,OPT3)。 They alter the output of the script. 它们更改脚本的输出。

  • opt1 is imply an import of vtk_to_numpy but is never used in the script. OPT1是暗示vtk_to_numpy的进口,但从未在脚本中使用。
  • opt2 changes the way cone is created. opt2更改cone的创建方式。 Either via a DeepCopy command applied on a newly created vtkPolyData object (like in the code below) or no deep copy simply referencing the object returned vom GetOutput . 通过应用在新创建的vtkPolyData对象上的DeepCopy命令(如下面的代码中所示),或者不通过引用返回vom GetOutput返回的对象的深层副本。
  • opt3 Changes the number of times the area of the first cell is computed and printed. opt3更改计算和打印第一个单元格的面积的次数。

Here is the minimum working example: 这是最小的工作示例:

import vtk
# from vtk.util.numpy_support import vtk_to_numpy  # opt1

coneSource = vtk.vtkConeSource()
coneSource.Update()

cone = vtk.vtkPolyData()
cone.DeepCopy(coneSource.GetOutput())
# cone = coneSource.GetOutput()  # opt2

cone2 = vtk.vtkPolyData()
cone2.DeepCopy(cone)

N = 80  # opt3
for _ in range(N):
    print cone.GetCell(0).ComputeArea(), cone2.GetCell(0).ComputeArea()

The results of that script are depicted in the table below. 下表描述了该脚本的结果。 The entries in the cells are tuples representing the output of the computed are of cone and cone2 respectivly with ok being the correct result and (ok) meaning that the first line was printed correctly but all subsequent computations are incorrect. 在单元中的条目是表示所计算的输出元组的conecone2 respectivly与确定为正确的结果和(OK)这意味着第一线被正确地打印,但所有后续计算不正确。

+--------------------+-----------+-----------+----------+-----------+------------+-----------+
|                    |             DeepCopy             |              GetOutput             |
+--------------------+-----------+-----------+----------+-----------+------------+-----------+
|                    |     1     |    10     |    80    |     1     |     10     |     80    |
+--------------------+-----------+-----------+----------+-----------+------------+-----------+
| w/ numpy_support   |  nan, ok  |  inf, ok  |  ok, ok  |  ok, ok   |  (ok), ok  |  (ok), ok |
| w/o numpy_support  |  inf, ok  |  inf, ok  |  ok, ok  |  ok, inf  |  ok, ok    |  inf, ok  |
+--------------------+-----------+-----------+----------+-----------+------------+-----------+

The results are reproducable in subsequent calls of the script but differ after a reboot or after some longer period of time. 结果在随后的脚本调用中是可重现的,但在重新引导后或较长的时间后会有所不同。 So you might get different results (altough I would hope that you too experiance some results being nan or inf). 因此,您可能会得到不同的结果(尽管我希望您也能获得nan或inf的一些结果)。

I suspect that I am doing something wrong memory wise with the VTK objects. 我怀疑我在VTK对象上做错了一些明智的记忆。 I am interested in feedback if you can reproduce my problem and what I am doing wrong during the deep copy of a vtk object or the creation of one from a source. 如果您可以重现我的问题以及在深复制vtk对象或从源创建对象时我做错了什么,我会对反馈感兴趣。 Also, is there a better way to compute the cell areas of a vtkPolyData instead of looping over all cells? 此外,是否有更好的方法来计算vtkPolyData而不是遍历所有单元格?

I am using VTK-8.0.1, Python2.7 and running this example on CentOS7. 我正在使用VTK-8.0.1,Python2.7并在CentOS7上运行此示例。 Both VTK and Python are built by myself so they are not the versions from the repostory. VTK和Python都是我自己构建的,因此它们不是源代码中的版本。

I think there is actually a bug/unexpected behaviour of the vtkPolygon::ComputeArea() method. 我认为vtkPolygon :: ComputeArea()方法实际上存在错误/意外行为。 The problem I see is that the implementation of ComputeArea() looks like this: 我看到的问题是ComputeArea()的实现如下所示:

double vtkPolygon::ComputeArea()
{
    double normal[3]; //not used, but required for the
                      //following ComputeArea call
    return vtkPolygon::ComputeArea(this->GetPoints(),
                             this->GetNumberOfPoints(),
                             this->GetPointIds()->GetPointer(0),
                             normal);

}

However, I think this is "wrong". 但是,我认为这是“错误的”。 this->GetPoints() returns array with just the points of the given polygon, so a 0-indexed array with just 3 points for a triangle cell. this->GetPoints()返回仅包含给定多边形点的数组,因此,一个三角形单元格的索引为0的数组仅包含3个点。 this->GetPointIds() is an array with indices, but in case the cell is part of a large polyData, those are not indices into the this->GetPoints() array, but rather into the global array with all the points of the polydata, not just the one of the cell. this->GetPointIds()是带有索引的数组,但是如果单元格是大型polyData的一部分,则这些不是到this->GetPoints()数组的索引,而是到包含所有点的全局数组的索引polydata,而不仅仅是单元格之一。 Even for the first cell of the mesh produced by vtkConeSource, this is wrong as I found, because even though the first cell uses the first points in the global array (so accesing either one should be fine), they are actually in different order (don't know why, but they are). 即使对于vtkConeSource生成的网格的第一个单元,这也是我发现的错误,因为即使第一个单元使用了全局数组中的第一个点(因此,选择一个都可以),但实际上它们的顺序不同(不知道为什么,但是确实如此。

To sum up, if the array obtained by GetPointIds() is used, it should be used to index the "global" array. 综上所述,如果使用通过GetPointIds()获得的数组,则应将其用于索引“全局”数组。 If the "local" vtkPoints of the cell are used, it should be indexed iteratively from 0 to N, where N is the number of points in the cell. 如果使用单元的“本地” vtkPoint,则应从0到N迭代索引,其中N是单元中的点数。 vtkPolygon::ComputeArea() mangles these two things together so I would advise not to use it at this point. vtkPolygon :: ComputeArea()将这两件事混合在一起,所以我建议此时不要使用它。

Can you please verify that it is computed correctly if you replace the the line inside the loop to use the vtkPolygon::ComputeArea(vtkPoints * p, vtkIdType numPts, vtkIdType * pts, double normal 3 ) ) with the right parameters? 如果您用正确的参数替换循环内的行以使用vtkPolygon :: ComputeArea(vtkPoints * p,vtkIdType numPts,vtkIdType * pts,double normal 3 ))能否验证计算正确? So something like this (not sure about the python syntax, sorry, normal is a not-used vector for storing the normal): 所以像这样(不确定python语法,抱歉, normal是用于存储法线的未使用向量):

print cone.GetCell(0).ComputeArea(cone.GetPoints(), cone.GetCell(0).GetNumberOfPoints(), cone.GetCell(0).GetPointIds().GetPointer(0), normal), cone2.GetCell(0).ComputeArea(cone2.GetPoints(), cone2.GetCell(0).GetNumberOfPoints(), cone2.GetCell(0).GetPointIds().GetPointer(0), normal)

If this is indeed the case for you, I will post the problem on the vtk bugtracker and hopefully it will get fixed in new versions. 如果确实如此,我将在vtk bugtracker上发布该问题,并希望它将在新版本中得到解决。

EDIT : You can use vtkMeshQuality filter to compute the areas (and other quality metrics as well). 编辑 :您可以使用vtkMeshQuality过滤器来计算面积(以及其他质量指标)。 Here is an example, it's in c++, but it should be straightforward to modify it for python, the key lines are just the filter set-up (my attempt for pseudo-python): 是一个示例,它是用c ++编写的,但是为python修改它应该很简单,关键行只是过滤器设置(我对伪python的尝试):

qualityFilter = vtk.vtkMeshQuality
qualityFilter.SetInputData(mesh) // mesh in your case is cone/cone2
qualityFilter.SetTriangleQualityMeasureToArea()
qualityFilter.SetQuadQualityMeasureToArea()
qualityFilter.Update()

...and retrieval of the computed values - they are stored in a celldata array of the output of the filter: ...以及计算值的检索-它们存储在过滤器输出的celldata数组中:

qualityArray = qualityFilter.GetOutput().GetCellData().GetArray("Quality"))

for i in range(qualityArray->GetNumberOfTuples()):
    print "area of  {0}. element is {1}".format(i, qualityArray->GetValue(i))

It's not really "better" in terms of algorithmic complexity (you can't get sublinear complexity if you want the result to be exact), but perhaps it's more convenient to use. 就算法复杂度而言,它并不是真正的“更好”(如果想要精确的结果,则无法获得亚线性复杂度),但是使用起来可能更方便。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM