Python代码检查给定网格内是否包含一个点。

huangapple go评论64阅读模式
英文:

Python code to check whether a point is inside a given mesh

问题

I am using the trimesh library, to check this. It has mesh.contains for performing these checks. I am trying to truncate an array of lines using the mesh.contains, such that the new lines only contain the points from inside the mesh.

Although this works fine for in some cases, it fails in multiple other cases. I am attaching a few pictures, the blue is the truncated line and the red is the original line. The gray shaded region is the mesh. In one case, it is able to detect points outside and truncate properly. However, there are issues in case of outside regions that are sandwiched between the domains. The points are outside, but this function is unable to eliminate them.

The code chunk is given below:

# create an empty array to store truncated lines
truncated_arr = []

# loop over each line in the array
for line in arr:
    new_line = []
    # loop over each point in the line and check if it's inside the mesh
    for point in line:
        if ((mesh1.contains([point])) or (mesh2.contains([point])) or (mesh3.contains([point]))):
            new_line.append(point)
    # append the truncated line to the new array
    if len(new_line) > 1:
        truncated_arr.append(new_line)

I am looking for ideas to overcome this? Is there a way to make this algorithm detect points that are outside the domain but is sandwiched between two wings of the domain, as seen in the picture? Ideally I would want this library to work but unfortunately if it doesn't suggestions for others might also be helpful.

Thanks.

Python代码检查给定网格内是否包含一个点。
Python代码检查给定网格内是否包含一个点。
Python代码检查给定网格内是否包含一个点。

英文:

I am using the trimesh library, to check this. It has mesh.contains for performing these checks. I am trying to truncate an array of lines using the mesh.contains, such that the new lines only contain the points from inside the mesh.

Although this works fine for in some cases, it fails in multiple other cases. I am attaching a few pictures, the blue is the truncated line and the red is the original line. The gray shaded region is the mesh. In one case, it is able to detect points outside and truncate properly. However, there are issues in case of outside regions that are sandwiched between the domains. The points are outside, but this function is unable to eliminate them.

The code chunk is given below:

# create an empty array to store truncated lines
truncated_arr = []

# loop over each line in the array
for line in arr:
    new_line = []
    # loop over each point in the line and check if it's inside the mesh
    for point in line:
        if ((mesh1.contains([point])) or (mesh2.contains([point])) or (mesh3.contains([point]))):
            new_line.append(point)
    # append the truncated line to the new array
    if len(new_line) > 1:
        truncated_arr.append(new_line)

I am looking for ideas to overcome this? Is there a way to make this algorithm detect points that are outside the domain but is sandwinched between two wings of the domain, as seen in the picture? Ideally I would want this library to work but unfortunately if it doesn't suggestions for others might also be helpful.

Thanks.

Python代码检查给定网格内是否包含一个点。
Python代码检查给定网格内是否包含一个点。
Python代码检查给定网格内是否包含一个点。

答案1

得分: 1

欢迎来到网格合并的乐趣!

您是否有一个体积网格,以表面网格作为边界?我之所以问是因为要确定表面网格是否已提取。如果您有体积网格,检测网格外点可能更容易。此外,连续点的测试成本很低。

您是否有相邻表?

您是否可以选择要交叉的射线?如果可以的话,与表面网格相交点[i]、point[i+1]的线段会更便宜、更准确、更具信息价值,而不是从point[i]发送随机射线。您知道初始点point[0]在外部(尽管这是一个特殊情况,您可以处理)。然后,您只需要知道以下段p[i] + tp[i+1]是否与网格相交,其中0 < t <= 1。如果线段相交,您还可以精确知道在哪里,这避免了截断线和网格之间的间隙,这些间隙在排除段结束时可能会出现。

如果线段与网格相交,您可以将其记入内存,并将其放入triangle_guesses中。如果有相邻,您可以将其用作快速相交搜索的起点。您的段都紧密相邻,很可能许多段与相同的三角形相交,或者与彼此非常接近的三角形相交。

就我所知,RayMeshIntersector类可能需要修改以使用除默认值之外的check_direction参数来调用contains_points。您甚至可以自己编写三角形-线段相交的代码。有相邻的话,您甚至可能比那个算法更快,因为您可以使用先前的猜测来重新启动搜索。

如果算法无法执行射线相交,也许是因为您有平面元素(顶点与相反的边)或者网格不是封闭的。

英文:

Welcome to the joys of meshing !

Do you happen to have a volume mesh with that surface mesh as the boundary? I'm asking in case that surface mesh had been extracted. If you had a volume mesh, it could be easier to detect points outside the mesh. Moreover, it would be very cheap to test successive points.

Do you have the neighbours table?

Is it possible for you to choose the rays to intersect? In that case, it would be cheaper, more accurate and more informative to intersect the segment [point[i],point[i+1]] with the surface mesh rather than sending random rays from point[i]. You know the initial point point[0] is outside (presumably, though that's an edge case you can manage). Then, you only need to know if the following segments p[i] + tp[i+1] intersect the mesh for 0 < t <= 1. If the segment intersects, you also know exactly where, which avoids having gaps between the truncated lines and the mesh, as you would have by excluding segment ends.

If the segment intersects the mesh, you can keep in memory the triangle it intersected, put it in triangle_guesses. If you have neighbours, you can then use that as a starting point for a fast intersection search. Your segments are all packed together, it's very likely many are intersecting the same triangle, or triangles all close to each other.

From what I can tell, the RayMeshIntersector class may be modified to call contains_points with a check_direction argument other than the default. You could just code triangle-segment intersection yourself, too. Having neighbours, you'd even be faster than that algorithm because you could use previous guesses to restart the search.

If the algorithm is failing ray intersection, perhaps you have flat elements (vertex against opposite edge) or the mesh is not watertight.

答案2

得分: 0

使用mesh.ray.intersects_location()方法对每个点执行射线投射,并计算交点数量来确定点是否在网格内部或外部可能是一个解决方案。

以下是修改后的代码示例:

import numpy as np
import trimesh

def is_inside(point, meshes, direction=np.array([1.0, 0.0, 0.0]), tol=1e-5):
    count = 0

    for mesh in meshes:
        intersections, _ = mesh.ray.intersects_location(
            ray_origins=[point - direction * tol],
            ray_directions=[direction],
        )

        count += len(intersections) % 2

    return count % 2 == 1

# 创建一个空数组以存储截断后的线
truncated_arr = []

# 网格列表
meshes = [mesh1, mesh2, mesh3]

# 遍历数组中的每条线
for line in arr:
    new_line = []
    # 遍历线中的每个点并检查它是否在网格内
    for point in line:
        if is_inside(point, meshes):
            new_line.append(point)
    # 如果截断后的线长度大于1,则将其添加到新数组中
    if len(new_line) > 1:
        truncated_arr.append(new_line)

is_inside()函数对给定的点进行射线投射,沿着正X方向进行投射,然后计算射线与网格相交的次数。如果交点数量为奇数,则认为点在网格内部。您可以通过更改direction参数来更改射线的方向。tol参数是一个小的容差值,用于避免将射线交点放置在网格表面上。

请注意,与使用mesh.contains()方法相比,这种方法可能较慢,因为它需要进行额外的射线交点计算。但是,它应该更好地处理位于域外但夹在域的两侧的点。

英文:

A possible solution would be to use the mesh.ray.intersects_location() method to perform a ray casting for each point, and count the number of intersections to determine whether the point is inside or outside the mesh.

Here's a modified version of your code that implements this approach:

import numpy as np
import trimesh

def is_inside(point, meshes, direction=np.array([1.0, 0.0, 0.0]), tol=1e-5):
    count = 0

    for mesh in meshes:
        intersections, _ = mesh.ray.intersects_location(
            ray_origins=[point - direction * tol],
            ray_directions=[direction],
        )

        count += len(intersections) % 2

    return count % 2 == 1

# create an empty array to store truncated lines
truncated_arr = []

# the list of meshes
meshes = [mesh1, mesh2, mesh3]

# loop over each line in the array
for line in arr:
    new_line = []
    # loop over each point in the line and check if it&#39;s inside the meshes
    for point in line:
        if is_inside(point, meshes):
            new_line.append(point)
    # append the truncated line to the new array
    if len(new_line) &gt; 1:
        truncated_arr.append(new_line)

Given a point, the is_inside() function ray-casts the point along an axis in the positive X direction, then it counts the number of times the ray intersects the mesh. If the number of intersections is odd, the point is assumed to be inside the mesh. You can change the direction of the ray by changing the direction parameter. The tol parameter is a small tolerance value to avoid starting the ray intersection exactly on the surface of the mesh.

Note that this approach might be slower than using the mesh.contains() method due to the additional ray intersection calculations. However, it should better handle points outside the domain but sandwiched between two wings of the domain.

答案3

得分: 0

以下是翻译好的内容:

射线跟踪提案中的代码似乎过于资源密集,您已经有一个(可能经过良好调整的).contains 函数。我认为您需要改变操作的顺序。我无法运行这段代码,但在我看来,如果您不是链接这三个mesh.contain(.) or...,而是分别执行这三个操作,然后在这三个结果上使用numpy的集合交集,您可能会更幸运。

只是一个快速尝试,希望它比尝试重新实现射线跟踪要好。不是说它不会起作用,我不知道,但我打赌它会起作用,但这需要大量的工作,而且坦率地说,这个工作已经为您完成了。这是一种逻辑错误,而不是您工具的不足。

英文:

The ray tracing proposed in the other answer seems overly resource intensive you already have an (presumably well-tuned) .contains function. I think instead you need to change your order of operations. I can't run this code, but it seems to me like if instead of chaining those three mesh.contain(.) or... you did all three separate then used numpy's set intersection on the three resulting lines you might have better luck.

Just a quick try, hope it works out better than trying to reimplement ray tracing. Not that it wouldnt work, idk but i bet it would, but it would be a ton of work to do and to be honest it's already been done for you. This is a logic error, not a deficiency in your tools.

huangapple
  • 本文由 发表于 2023年4月11日 03:52:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/75980249.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定