Intersection Ligne-Plan 3D

Si une ligne (représenté par un vecteur ou deux points sur la ligne) comment puis-je trouver le point où la ligne croise un avion? J'ai trouvé beaucoup de ressources à ce sujet, mais je ne peux pas comprendre les équations (elles ne semblent pas être algébriques standard). Je voudrais une équation (peu importe combien de temps) qui peut être interprétée par un langage de programmation standard (J'utilise Java).

21
demandé sur ideasman42 2011-04-14 20:11:44

6 réponses

Vous devrez considérer trois cas:

  • le plan est parallèle à la ligne, et la ligne ne se trouve pas dans le plan (pas d'intersection)
  • Le Plan n'est pas parallèle à la ligne (un point d'intersection)
  • le plan contient la ligne (la ligne se croise en chaque point)

Vous pouvez exprimer la ligne sous forme paramétrée, comme ici:

Http://answers.yahoo.com/question/index?qid=20080830195656AA3aEBr

Les premières pages de cette conférences faites de même pour l'avion:

Http://math.mit.edu/classes/18.02/notes/lecture5compl-09.pdf

Si la normale au plan est perpendiculaire à la direction le long de la ligne, alors vous avez un cas de bord et avez besoin de voir si elle se croise du tout, ou se trouve dans le plan.

Sinon, vous avez un point d'intersection, et peut résoudre pour cela.

Je sais que ce n'est pas du code mais pour obtenir une solution robuste, vous voudrez probablement mettre ceci dans le contexte de votre candidature.

EDIT: Voici un exemple pour lequel il y a exactement un point d'intersection. Disons que vous commencez avec les équations paramétrées dans le premier lien:

x = 5 - 13t
y = 5 - 11t
z = 5 - 8t

Le paramètre t peut être n'importe quoi. L'ensemble (infini) de tous les {[3] } qui satisfont ces équations comprend la ligne. Ensuite, si vous avez l'équation pour un avion, dites:

x + 2y + 2z = 5

(tiré de ici) Vous pouvez remplacer les équations par x, y, et z ci-dessus dans l'équation pour le plan, qui est maintenant dans seulement le paramètre t. Résoudre pour t. C'est la valeur particulière de t pour cette ligne qui se trouve dans le plan. Ensuite, vous pouvez résoudre pour x, y, et {[6] } en remontant aux équations de ligne et en remplaçant t dans.

18
répondu John 2011-04-14 18:24:14

Voici un exemple Python qui trouve l'intersection d'une ligne et d'un plan.

Où le plan peut être soit un point et une normale, soit un vecteur 4d (forme normale), Dans les exemples ci-dessous (le code pour les deux est fourni).

Notez également que cette fonction calcule une valeur représentant où le point est sur la ligne, (appelée fac dans le code ci-dessous). Vous voudrez peut-être renvoyer cela aussi, car les valeurs de 0 à 1 croisent le segment de ligne - ce qui peut être utile pour le appelant.

Autres détails notés dans le code-commentaires.


Note: Cet exemple utilise des fonctions pures, sans aucune dépendance - pour faciliter le passage à d'autres langues. Avec un type de données Vector et une surcharge d'opérateur, il peut être plus concis (inclus dans l'exemple ci-dessous).

# intersection function
def isect_line_plane_v3(p0, p1, p_co, p_no, epsilon=1e-6):
    """
    p0, p1: define the line
    p_co, p_no: define the plane:
        p_co is a point on the plane (plane coordinate).
        p_no is a normal vector defining the plane direction;
             (does not need to be normalized).

    return a Vector or None (when the intersection can't be found).
    """

    u = sub_v3v3(p1, p0)
    dot = dot_v3v3(p_no, u)

    if abs(dot) > epsilon:
        # the factor of the point between p0 -> p1 (0 - 1)
        # if 'fac' is between (0 - 1) the point intersects with the segment.
        # otherwise:
        #  < 0.0: behind p0.
        #  > 1.0: infront of p1.
        w = sub_v3v3(p0, p_co)
        fac = -dot_v3v3(p_no, w) / dot
        u = mul_v3_fl(u, fac)
        return add_v3v3(p0, u)
    else:
        # The segment is parallel to plane
        return None

# ----------------------
# generic math functions

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


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 len_squared_v3(v0):
    return dot_v3v3(v0, v0)


def mul_v3_fl(v0, f):
    return (
        v0[0] * f,
        v0[1] * f,
        v0[2] * f,
        )

Si le plan est défini comme un vecteur 4d (Forme Normale) , nous devons trouver un point sur le plan, puis calculer l'intersection comme précédemment (voir p_co affectation).

def isect_line_plane_v3_4d(p0, p1, plane, epsilon=1e-6):    
    u = sub_v3v3(p1, p0)
    dot = dot_v3v3(plane, u)

    if abs(dot) > epsilon:
        # calculate a point on the plane
        # (divide can be omitted for unit hessian-normal form).
        p_co = mul_v3_fl(plane, -plane[3] / len_squared_v3(plane))

        w = sub_v3v3(p0, p_co)
        fac = -dot_v3v3(plane, w) / dot
        u = mul_v3_fl(u, fac)
        return add_v3v3(p0, u)
    else:
        return None

Pour plus de référence, cela a été pris de Blender et adapté à Python. isect_line_plane_v3() dans math_geom.c


Pour plus de clarté, voici des versions utilisant l'APImathutils (qui peut être modifiée pour d'autres bibliothèques mathématiques avec une surcharge d'opérateur) .

# point-normal plane
def isect_line_plane_v3(p0, p1, p_co, p_no, epsilon=1e-6):
    u = p1 - p0
    dot = p_no * u
    if abs(dot) > epsilon:
        w = p0 - p_co
        fac = -(plane * w) / dot
        return p0 + (u * fac)
    else:
        return None


# normal-form plane
def isect_line_plane_v3_4d(p0, p1, plane, epsilon=1e-6):    
    u = p1 - p0
    dot = plane.xyz * u
    if abs(dot) > epsilon:
        p_co = plane.xyz * (-plane[3] / plane.xyz.length_squared)

        w = p0 - p_co
        fac = -(plane * w) / dot
        return p0 + (u * fac)
    else:
        return None
25
répondu ideasman42 2016-11-17 21:40:52

En utilisant numpy et python:

#Based on http://geomalgorithms.com/a05-_intersect-1.html
from __future__ import print_function
import numpy as np

epsilon=1e-6

#Define plane
planeNormal = np.array([0, 0, 1])
planePoint = np.array([0, 0, 5]) #Any point on the plane

#Define ray
rayDirection = np.array([0, -1, -1])
rayPoint = np.array([0, 0, 10]) #Any point along the ray

ndotu = planeNormal.dot(rayDirection) 

if abs(ndotu) < epsilon:
    print ("no intersection or line is within plane")

w = rayPoint - planePoint
si = -planeNormal.dot(w) / ndotu
Psi = w + si * rayDirection + planePoint

print ("intersection at", Psi)
7
répondu TimSC 2017-02-02 17:22:32

Basé sur CE code Matlab (moins les contrôles d'intersection), en Python

# n: normal vector of the Plane 
# V0: any point that belongs to the Plane 
# P0: end point 1 of the segment P0P1
# P1:  end point 2 of the segment P0P1
n = np.array([1., 1., 1.])
V0 = np.array([1., 1., -5.])
P0 = np.array([-5., 1., -1.])
P1 = np.array([1., 2., 3.])

w = P0 - V0;
u = P1-P0;
N = -np.dot(n,w);
D = np.dot(n,u)
sI = N / D
I = P0+ sI*u
print I

Résultat

[-3.90909091  1.18181818 -0.27272727]

Je l'ai vérifié graphiquement ça semble marcher,

entrez la description de l'image ici

Je crois que c'est une implémentation plus robuste du lien partagé avant

3
répondu user423805 2017-04-18 11:12:07

Cette question Est ancienne mais comme il existe une solution beaucoup plus pratique, j'ai pensé que cela pourrait aider quelqu'un.

Les intersections de plan et de ligne sont assez élégantes lorsqu'elles sont exprimées en coordonnées homogènes, mais supposons que vous voulez juste la solution:

Il existe un vecteur 4x1 p qui décrit le plan tel que p^T * x = 0 pour tout point homogène sur le plan. Ensuite, calculez les coordonnées de plucker pour la ligne L = ab^t-ba^t où a = {point_1; 1}, b = {point_2; 1}, les deux 4x1 sur la ligne

Calculer: x=L*p = {x0,x1,x2,x3}

X_intersect=({x0, x1, x2}/x3) où si x3 est zéro, il n'y a pas d'intersection au sens euclidien.

2
répondu midjji 2017-07-26 15:07:06

Si vous avez deux points p et q qui définissent une ligne, et un plan sous la forme cartésienne générale ax + by + cz + d = 0, Vous pouvez utiliser la méthode paramétrique.

Si vous en avez besoin à des fins de codage, voici un extrait javascript:

/**
* findLinePlaneIntersectionCoords (to avoid requiring unnecessary instantiation)
* Given points p with px py pz and q that define a line, and the plane
* of formula ax+by+cz+d = 0, returns the intersection point or null if none.
*/
function findLinePlaneIntersectionCoords(px, py, pz, qx, qy, qz, a, b, c, d) {
    var tDenom = a*(qx-px) + b*(qy-py) + c*(qz-pz);
    if (tDenom == 0) return null;

    var t = - ( a*px + b*py + c*pz + d ) / tDenom;

    return {
        x: (px+t*(qx-px)),
        y: (py+t*(qy-py)),
        z: (pz+t*(qz-pz))
    };
}

// Example (plane at y = 10  and perpendicular line from the origin)
console.log(JSON.stringify(findLinePlaneIntersectionCoords(0,0,0,0,1,0,0,1,0,-10)));

// Example (no intersection, plane and line are parallel)
console.log(JSON.stringify(findLinePlaneIntersectionCoords(0,0,0,0,0,1,0,1,0,-10)));
2
répondu DNax 2017-07-27 22:32:43