This can be split into 2 problems.
- Test that the point inside the 3-planes defined by the triangle sides.
- 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'.
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.
# ----------------
# 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)