1

I need an algorithm (3D), which would determine if point belongs to a triangle. 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.

enter image description here

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. 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.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
Tom Ray
  • 133
  • 3
  • 11
  • 5
    Is the question actually about triangles (2D objects) or prisms (3D objects). The pictures look like prisms. – Antti Huima Nov 30 '11 at 20:53
  • Are you trying to test if a point is inside a wedge? That's what it looks like... – Darren Engwirda Nov 30 '11 at 20:54
  • The most amazing collision detection tutorial ever is here: http://www.metanetsoftware.com/technique/tutorialA.html – Josh Bleecher Snyder Nov 30 '11 at 20:56
  • Does the prism always have a right triangle at the base? – James Kingsbery Nov 30 '11 at 20:57
  • 2
    I imagine all you have to do is take the X and Y coordinates of the point and test whether it lies inside the triangle of the side of the prism (as if it was just a 2D object). Then you would have to determine whether the Z coordinate of the point is between the lowest Z and the highest Z of the prism. – Marlon Nov 30 '11 at 20:59
  • 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. 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. – Tom Ray Nov 30 '11 at 21:01
  • @Marlon: That's actually a good idea. What's the most efficient way to find out if a point is within a triangle in 2D? – Tom Ray Nov 30 '11 at 21:03
  • @TomRay: http://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-triangle – Darren Engwirda Nov 30 '11 at 21:08
  • @Marlon: That only works if the prism is a right-prism, and the top is oriented to be parallel to the z-axis... – BlueRaja - Danny Pflughoeft Nov 30 '11 at 22:59

3 Answers3

2

This seems like the 3D equivalent of Data structure to query points which lie inside a triangle. 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. 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.

Community
  • 1
  • 1
wildplasser
  • 43,142
  • 8
  • 66
  • 109
  • 1
    This actually only works for simplex shapes (triangles in 2D, tetrahedra in 3D etc). If you have more complex elements (quads in 2D, prisms in 3D etc) these elements *can* be distorted to become non-convex, in which case the sign tests may not work (for a non-convex quad in 2D for instance, an inside point may actually be on the "wrong" side of an edge). One general solution is to decompose these higher order elements into simplex shapes (a quad into 2 trias for instance) and then use the tests you've described. – Darren Engwirda Nov 30 '11 at 21:39
  • It does work for non-convex shapes, but the boolean formula for constructing the inside() function from the separate comparisons will need more terms. (and not only "AND" terms, but "OR" terms as well) – wildplasser Nov 30 '11 at 21:50
  • @Darren is right, this will not work for concave shapes; but triangular prisms are never concave, so +1 from me. This works even if the prism is rotated or sheered. – BlueRaja - Danny Pflughoeft Nov 30 '11 at 22:57
  • @BlueRaja-DannyPflughoeft: actually, triangular prisms *can* be concave. If you considered a highly distorted prism, where one of the "end" triangles was rotated more than 90 degrees about its "base" edge you would have a concave (but non-self-intersecting) prism. I'm pretty sure that all non-simplex shapes can be distorted to be concave. – Darren Engwirda Nov 30 '11 at 23:13
  • I added example 2D code to the other topic. I handled the boolean logic by enumerating them into switch cases. – wildplasser Nov 30 '11 at 23:28
  • @Darren: If you rotate just one of the bases, it is no longer a prism – BlueRaja - Danny Pflughoeft Nov 30 '11 at 23:33
  • Thanks! I thought about it and I am going to use this method, because it's more precise that the one by Marlon. Btw, would this method work if a point was on one of the faces/edges? And what about efficiency? Isn't there faster way to do it? – Tom Ray Dec 01 '11 at 00:29
  • There are some obvious optimisations (parallel planes divide the space into 3 slices; non-parallel into 4) For points on the faces: change some of the < into <= YMMV. IIRC the formula to detect on which side of a plane a point is, is "ax+by+cz > some_constant" – wildplasser Dec 01 '11 at 00:39
1

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 = (B-A)x(C-A) (cross product) is a normal to the (unique) plane defined by the triangle. Call the point we want to test P.

Now calculate the value a' = N . ((P-B) x (P-C)) (where . is dot product). a' is the usual barycentric coordinate multiplied by N.N (which is positive).

Similarly, we find b' = N . ((P-C) x (P-A)) and c' = N . ((P-A) x (P-B)). 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).

Sumudu Fernando
  • 1,763
  • 2
  • 11
  • 17
0

This can be split into 2 problems.

  1. Test that the point inside the 3-planes defined by the triangle sides.
  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'.

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)
ideasman42
  • 42,413
  • 44
  • 197
  • 320