1
$\begingroup$

Given in 3D:

  • a triangle

  • a point A inside the triangle

  • a direction vector D in plane of the triangle pointing from A in a direction towards the edges of the triangle

enter image description here

I am looking for an efficient and fast computer algorithm to find the intersection point T with the edge of the triangle.

For each edge of the triangle I can do a ray to line segment intersection test. But I am wondering if there is a more effecient and faster method to do this.

  • 0
    Is the 2D problem you stated rotated in a 3D space or what do you mean by 3D?2017-02-11
  • 0
    @Zonko The vertices of the triangle, point A and the direction vector D are given in 3D space in (x, y, z) coordinates.2017-02-11

2 Answers 2

0

As mentioned by @Zonko, this looks like a $2D$ problem. You can just use the plane of the triangle or project everything to $\Pi_{xy}$ (assuming it does not lie in $\Pi_{xy}$ or $\Pi_{yz}$). Then, testing the ray for intersection with the three triangle edges is in $\mathcal{O}(1)$ and therefore optimal.

0

Have brainstormed this problem for a side-project. Rather than testing a ray-segment intersection for each edge of the triangle I believe the following works and should be cheaper, though I haven't coded it up yet.

Given Triangle t = { p1, p2, p3 }, Point p within t, Vector v.
Construct Ray r from p with direction v. Find Edge e of t intersected by r.

     /\
    /  \
   /    \
  / p*-> \
 /     v   \
/_....---''

Solution:

For each pair (pa, pb):
    Let q be any point in the triangle (e.g. its centroid)
    Compute c = Clockness(pa - q, pb - q)
    Construct va = (p, pa), vb = (p, pb)
    If Clockness(va, v) == c && Clockness(v, vb) == c:
        Return Edge e = (pa, pb), which r intersects.

Define clockness(a : Vector, b : Vector) as sign(cross(a, b)) - intuitively it represents whether the cross between two 2D vectors goes "into" the plane or "out of" the plane on which they sit.

In most computational geometry libraries, triangles are represented in some order (e.g. clockwise) by convention, so computing c should be free. Intuitively the clockness between (p, pa), v should be the same as the clockness from v, (p, pb), which should be the same as the clockness between (p, pa), (p, pb). That is, cross (p, pa), v should point in the same direction as cross v, (p, pb) which should point in the same direction as cross (p, pa), (p, pb).

Edit:

This seems to work, here's my code. I had to add an additional case for when you're sitting on the triangle edge:

  public static int IntersectRayWithContainedOriginForVertexIndexOpposingEdge(DoubleVector2 origin, DoubleVector2 direction, ref Triangle triangle) {
     // See my explanation on http://math.stackexchange.com/questions/2139740/fast-3d-algorithm-to-find-a-ray-triangle-edge-intersection/2197942#2197942
     // Note: Triangle points (A = p1, B = p2, C = p3) are CCW, origin is p, direction is v.
     // Results are undefined if ray origin is not in triangle (though you can probably math out what it means).
     // If a point is on the edge of the triangle, there will be neither-neither for clockness on the correct edge.
     for (int i = 0; i < 3; i++) {
        var va = triangle.Points[i] - origin;
        var vb = triangle.Points[(i + 1) % 3] - origin;
        var cvad = Clockness(va, direction);
        var cdvb = Clockness(direction, vb);

        // In-triangle case
        if (cvad == Geometry.Clockness.CounterClockwise &&
            cdvb == Geometry.Clockness.CounterClockwise) {
           return (i + 2) % 3;
        }

        // On-edge case
        if (cvad == Geometry.Clockness.Neither &&
            cdvb == Geometry.Clockness.Neither) {
           return (i + 2) % 3;
        }
     }
     throw new ArgumentException("Presumably origin wasn't in triangle (is this case reachable even with malformed input?)");
  }
  • 0
    In my code I did end up having to deal with the ArgumentException case for when the query point was located outside the triangle. I hit this case when the query point was right on a triangle edge, but floating point error made us not hit the neither case, so perhaps you could tweak the code to handle that case somehow. In my code, imprecision is OK so I simply pull the point very slightly towards the triangle centroid, then try again. That works fine for my specific use case.2017-03-23
  • 0
    Also, for OP's problem you'd then do a ray-segment intersection afterward, of course.2017-03-23
  • 0
    I tried this a year later and it works. Best to explain with a picture. https://imgur.com/a/o3a582018-04-17