简体   繁体   English

如何确定点在3D中是否在三角形内?

[英]How can I find out if point is within a triangle in 3D?

I need an algorithm (3D), which would determine if point belongs to a triangle. 我需要一个算法(3D),它将确定点是否属于三角形。 And also if it does I want to know the distance between some point in triangle and a another point. 如果确实如此,我想知道三角形中某个点与另一个点之间的距离。 Triangles can be slightly rotated, but if point is outside triangles vertical reach then it should not be considered as inside the triangle. 三角形可以稍微旋转,但如果点在三角形垂直范围之外,则不应将其视为三角形内部。

Now I realize, my question probably doesn't make a lot of sense so here's the picture, which explains what I want. 现在我意识到,我的问题可能并没有多大意义所以这里是图片,它解释了我想要的东西。

在此输入图像描述

Grey lines display, which way triangle is actually facing. 灰色线条显示,三角形实际面向哪个方向。


It's not actually that I want to check if a point is within a prism, but I after i find out if point lies within triangle (not exactly, might be on top of or below) then I need to find the distance between point and a triangle it belongs to. 实际上,我并不是要检查一个点是否在棱柱内,但是当我确定该点是否位于三角形内(不完全是,可能在其顶部或下方)之后,我需要找到点与a之间的距离。它属于的三角形。 And depending on the distance function will finally return if that point is inside the triangle. 如果该点在三角形内,则取决于距离函数将最终返回。 A little inaccuracy is allowed. 允许有点不准确。 However, maybe I want to check if a point is within a prism, but do not know that. 但是,也许我想检查一个点是否在棱镜内,但不知道。 I am just horrible at math so I am not aware of correct terminology. 我对数学很恐怖,所以我不知道正确的术语。

This seems like the 3D equivalent of Data structure to query points which lie inside a triangle . 这看起来像3D 数据结构等效于位于三角形内部的查询点 You could use the same method in 3D: in 3D, a plane cuts the space in two halves: a point is either at one side of the plane or at the other side. 您可以在3D中使用相同的方法:在3D中,平面将空间切成两半:一个点位于平面的一侧或另一侧。 The wedge-shape is a collection of planes: just combine the which_side_of_the_plane information for a given point with all the planes that build up the wedge . 楔形是平面的集合:只需将给定点的which_side_of_the_plane信息与构成楔形的所有平面结合起来

You can use a cylindrical version of barycentric coordinates . 您可以使用圆柱形重心坐标 I've only checked this for prisms that rise perpendicular from the triangular base -- another way to put this is that we are orthogonally projecting the point into the plane defined by the triangle, and checking if it is inside or not. 我只检查了这个从三角形基座垂直上升的棱镜 - 另一种方法是将这个点正交投影到由三角形定义的平面中,并检查它是否在内部。

If you want more details on the math ask (or better yet, try to figure it out yourself since it's a neat little exercise). 如果您想了解有关数学问题的更多详细信息(或更好的方法,请尝试自己解决,因为这是一个精巧的小练习)。

If our triangle is ABC (non-degenerate), then N = (BA)x(CA) (cross product) is a normal to the (unique) plane defined by the triangle. 如果我们的三角形是ABC (非退化),则N = (BA)x(CA) (叉积)是该三角形定义的(唯一)平面的法线。 Call the point we want to test P . 调用我们要测试的点P

Now calculate the value a' = N . ((PB) x (PC)) 现在计算值a' = N . ((PB) x (PC)) a' = N . ((PB) x (PC)) (where . is dot product). a' = N . ((PB) x (PC)) (其中.是点积)。 a' is the usual barycentric coordinate multiplied by NN (which is positive). a'是通常的重心坐标乘以NN (正数)。

Similarly, we find b' = N . ((PC) x (PA)) 同样,我们找到b' = N . ((PC) x (PA)) b' = N . ((PC) x (PA)) and c' = N . ((PA) x (PB)) b' = N . ((PC) x (PA))c' = N . ((PA) x (PB)) c' = N . ((PA) x (PB)) . c' = N . ((PA) x (PB)) If all three of 'a'', 'b'', and 'c'' are non-negative, then the projection of P is inside the triangle (if you want to exclude the triangle itself, then all three must be strictly positive). 如果'a'','b''和'c''中的所有三个都是非负的,则P的投影在三角形内部(如果你想排除三角形本身,那么这三个必须是严格正的)。

This can be split into 2 problems. 这可以分为两个问题。

  1. Test that the point inside the 3-planes defined by the triangle sides. 测试由三角形边界定义的3平面内的点。
  2. Find the distance to the plane defined by the triangle normal. 找到三角形法线定义的平面的距离。
    (and use own logic to test if this distance is considered close or not) . (并使用自己的逻辑来测试这个距离是否接近)

Withe the example below, you can do a check, for eg: 通过以下示例,您可以进行检查,例如:

if (isect_point_tri_prism_v3(p, v1, v2, v2) and
    (dist_signed_squared_point_tri_plane_v3(p, v1, v2, v2) < (eps * eps)):

    # do stuff

... where eps is the distance to consider points 'on the triangle' . ...其中eps是考虑三角形上的点的距离。

This code example uses functional Python so should be easy to move to other languages, it uses only simple arithmetic, no sqrt or complex functions. 此代码示例使用函数式Python,因此应易于迁移到其他语言,它仅使用简单的算术运算,不使用sqrt或复杂的函数。

# ----------------
# helper functions

def sub_v3v3(v0, v1):
    return (v0[0] - v1[0], v0[1] - v1[1], v0[2] - v1[2])


def dot_v3v3(v0, v1):
    return ((v0[0] * v1[0]) + (v0[1] * v1[1]) + (v0[2] * v1[2]))


def cross_v3v3(v0, v1):
    return ((v0[1] * v1[2]) - (v0[2] * v1[1]),
            (v0[2] * v1[0]) - (v0[0] * v1[2]),
            (v0[0] * v1[1]) - (v0[1] * v1[0]))


def closest_to_line_v3(p, l0, l1):
    """
    Return the closest point to p on the line defined by (l0, l1)
    """
    u = sub_v3v3(l1, l0)
    h = sub_v3v3(p, l0)
    l = dot_v3v3(u, h) / dot_v3v3(u, u)
    return (l0[0] + u[0] * l,
            l0[1] + u[1] * l,
            l0[2] + u[2] * l)


def point_in_slice_v3(p, v, l0, l1):
    cp = closest_to_line_v3(v, l0, l1)
    q = sub_v3v3(cp, v)
    rp = sub_v3v3(p, v)
    # For languages which allow divide-by-zero,
    # this is taken into account and returns false.
    h = dot_v3v3(q, rp) / dot_v3v3(q, q)
    return (h >= 0.0 and h <= 1.0)


# --------------
# main functions

def isect_point_tri_prism_v3(p, v0, v1, v2):
    """
    Return True when the point is inside the triangular prism.

    Zero area triangles always return false.
    """
    return (point_in_slice_v3(p, v0, v1, v2) and
            point_in_slice_v3(p, v1, v2, v0) and
            point_in_slice_v3(p, v2, v0, v1))


def dist_signed_squared_point_tri_plane_v3(p, v0, v1, v2):
    """
    Return the squared distance to the triangle,
    positive values are 'in-front' of the triangle, negative behind.
    (using CCW coordinate system - OpenGL).

    Remove the 'copysign' call for the non-signed version.
    (if you don't need to know which side of the triangle the point is on).
    """
    from math import copysign
    n = cross_v3v3(sub_v3v3(v2, v1), sub_v3v3(v0, v1))
    rp = sub_v3v3(p, v1)
    len_sq = dot_v3v3(n, n)
    side = dot_v3v3(rp, n)
    fac = side / len_sq
    return copysign(len_sq * (fac * fac), side)

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

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