2010-02-23 27 views
18

Encontrar el punto de intersección para dos segmentos de línea 2D es fácil; the formula is straight forward. Pero me da miedo encontrar el punto de intersección para dos segmentos de línea 3D.El algoritmo para encontrar el punto de intersección de dos segmentos de línea 3D

¿Cuál es el algoritmo, en C# preferiblemente que encuentra el punto de intersección de dos segmentos de línea 3D?

Encontré un C++ implementation here. Pero no confío en la solución porque hace la preferencia de un cierto plano (mire la forma en que se implementa perp en la sección de implementación, supone una preferencia por z plane. Cualquier algoritmo genérico no debe asumir ninguna orientación o preferencia de plano).

¿Existe una solución mejor?

+1

Me gustan los cálculos en su respuesta, pero no creo que su afirmación sobre un algoritmo genérico sea cierta. Proyectar las líneas en el plano xy convertirá el problema en un problema 2d. Luego, encuentre la intersección de los puntos/líneas resultantes y pruebe su validez. Elegir z es solo una conveniencia de implementación. Trabajar en una dimensión inferior también podría reducir el recuento de la operación. –

+1

@Derek, no estoy seguro de si proyectar líneas en el plano xy es una buena idea. Considere esto suponiendo que hay dos líneas x-y, cada una ubicada en diferentes planos 'z'. Si los proyecta a los planos xy, parecerán estar cruzando, aunque no lo estén. – Graviton

+0

Pronto Hui, sí, eso es correcto. Después de determinar la intersección en el plano xy, necesitaría probar su validez. Esto es solo cuestión de "volver a enchufar los números". La ventaja es que si los números no se verifican, entonces se puede concluir que las líneas no se cruzan. Nota: necesitaría manejar un par de casos especiales (una línea se dirige a lo largo de z-hat, líneas paralelas).En una nota relacionada, la solución que publica a continuación supone que las líneas son infinitas. También necesitaría hacer una prueba de validación en esa solución. –

Respuesta

3

Encontré una solución: it's here.

La idea es hacer uso del álgebra vectorial, para utilizar el dot y cross simplemente la pregunta hasta esta etapa:

a (V1 X V2) = (P2 - P1) X V2 

y calcular la a.

Tenga en cuenta que esta implementación no necesita tener ningún plano o eje como referencia.

+0

Hola, utilicé la solución que presentó, pero a veces obtengo resultados duplicados ... ¿también tuvo este problema? – user3252833

+0

¿Funcionó esta solución? –

+0

@DanielaMorais, no habría aceptado mi propia respuesta contra mi propia pregunta si no funcionó – Graviton

1

Puede que le resulte útil echarle un vistazo al artículo correspondiente en Wikipedia; no tiene un código, pero el algoritmo se describe bastante bien, en mi humilde opinión (pero debe saber algunas matemáticas de todos modos).

http://en.wikipedia.org/wiki/Bentley%e2%80%93Ottmann_algorithm

Actualización: lo suficientemente curioso es que la versión rusa de la misma entrada de la Wikipedia contiene más detalles (y) y formular una descripción del algoritmo es pseudo-código. Aquí hay un enlace a la traducción de esta entrada a Inglés (a través de Google Translate):

http://translate.google.com/translate?hl=en&sl=ru&tl=en&u=http%3A%2F%2Fru.wikipedia.org%2Fwiki%2F%25D0%259F%25D0%25B5%25D1%2580%25D0%25B5%25D1%2581%25D0%25B5%25D1%2587%25D0%25B5%25D0%25BD%25D0%25B8%25D0%25B5_%25D0%25BE%25D1%2582%25D1%2580%25D0%25B5%25D0%25B7%25D0%25BA%25D0%25BE%25D0%25B2

+1

La entrada del wiki contiene solo una descripción de 2D – Graviton

+0

Hombre, dije que debería saber algo de matemática: es fácil dibujar una versión generalizada (solo necesita agregar un componente más (coordinar)) – AlexS

+0

Me parece como el algoritmo de Ottmann en realidad describe las estrategias de cómo encontrar de manera eficiente los puntos de intersección de las listas si hay una lista de líneas, pero en cuanto a cómo encontrar realmente el punto de intersección, no dice. Ver el pseudo código aquí para mi punto: http://softsurfer.com/Archive/algorithm_0108/algorithm_0108.htm#Bentley-Ottmann%20Algorithm – Graviton

1

Pero encontrar el punto de intersección de dos segmentos de línea 3D no es, me temo.

Creo que es. Puede encontrar el punto de intersección exactamente de la misma manera que en 2d (o cualquier otra dimensión). La única diferencia es que el sistema resultante de ecuaciones lineales tiene más posibilidades de no tener solución (es decir, las líneas no se cruzan).

Puede resolver las ecuaciones generales a mano y solo usar su solución, o resolverla mediante programación, usando p. Ej. Gaussian elemination.

+0

Si ampliamos la forma 2D de hacer las cosas, tendrá tres ecuaciones ('x' , 'y' y' z') para dos incógnitas ('u',' v'). Definitivamente no es trivial resolverlo. – Graviton

+1

Bueno ... tan trivial como el caso 2d. Podrías simplemente usar las dos primeras ecuaciones para determinar uyv, y luego verificar si la última ecuación se cumple con estos valores para uy v. Si lo hace, has encontrado tu intersección. Si no lo hace, las líneas no se cruzan. No veo ninguna dificultad aquí. – Jens

+0

En álgebra lineal, esto se considera trivial. Sin embargo, para un algoritmo se debe tener cuidado. Por ejemplo, si las dos líneas vivieran en el plano x = 0, y = 0 o z = 0, una de esas tres ecuaciones no proporcionará ninguna información. (Suponiendo que las ecuaciones son some_point_on_line_1 = some_point_on_line_2) –

11

La mayoría de las líneas 3D no se cruzan. Un método confiable es encontrar la línea más corta entre dos líneas 3D. Si la línea más corta tiene una longitud de cero, entonces usted sabe que las dos líneas originales se cruzan.

Puede encontrar un método para encontrar the shortest line between two 3D lines en el sitio web de Paul Bourke, que es un excelente recurso de geometría. El sitio ha sido reorganizado, así que desplácese hacia abajo para encontrar el tema.

http://paulbourke.net/geometry/pointlineplane/

+0

+1. La única respuesta para haber reconocido claramente los problemas. –

+0

Si bien esto es cierto, es posible que desee aproximar la intersección en el espacio 3D. Al igual que comparar dos carrozas y decir que una es igual a la otra dependiendo de un factor épsilon que define un intervalo (y no un solo valor) de igualdad. Otra solución (si es posible según el caso) es volcar la 3ª dimensión (configurándola en una constante como 0) e ir solo con dos de las coordenadas usando las proyecciones y no las líneas mismas. Todavía +1 para resolver el problema. – rbaleksandar

4
// This code in C++ works for me in 2d and 3d 

// assume Coord has members x(), y() and z() and supports arithmetic operations 
// that is Coord u + Coord v = u.x() + v.x(), u.y() + v.y(), u.z() + v.z() 

inline Point 
dot(const Coord& u, const Coord& v) 
{ 
return u.x() * v.x() + u.y() * v.y() + u.z() * v.z(); 
} 

inline Point 
norm2(const Coord& v) 
{ 
return v.x() * v.x() + v.y() * v.y() + v.z() * v.z(); 
} 

inline Point 
norm(const Coord& v) 
{ 
return sqrt(norm2(v)); 
} 

inline 
Coord 
cross(const Coord& b, const Coord& c) // cross product 
{ 
return Coord(b.y() * c.z() - c.y() * b.z(), b.z() * c.x() - c.z() * b.x(), b.x() * c.y() - c.x() * b.y()); 
} 

bool 
intersection(const Line& a, const Line& b, Coord& ip) 
// http://mathworld.wolfram.com/Line-LineIntersection.html 
// in 3d; will also work in 2d if z components are 0 
{ 
Coord da = a.second - a.first; 
Coord db = b.second - b.first; 
    Coord dc = b.first - a.first; 

if (dot(dc, cross(da,db)) != 0.0) // lines are not coplanar 
    return false; 

Point s = dot(cross(dc,db),cross(da,db))/norm2(cross(da,db)); 
if (s >= 0.0 && s <= 1.0) 
{ 
    ip = a.first + da * Coord(s,s,s); 
    return true; 
} 

return false; 
} 
+4

hay muchos problemas con esta respuesta. –

1

me trataron @ Bill responder y que en realidad no funciona cada vez y que tiene sentido. Basado en el link in his code. Tengamos por ejemplo estos dos segmentos de línea AB y CD.

A = (2,1,5), B = (1,2,5) y C = (2,1,3) y D = (2,1,2)

cuando intenta obtener la intersección que podría decirle Es el punto A (incorrecto) o no hay intersección (correcto). Dependiendo del orden ponemos aquellos segmentos en.

x = A + (B-A) s
x = C + (D-C) t

Bill resuelve para s pero nunca resuelto t. Y dado que desea que ese punto de intersección esté en ambos segmentos de línea, ambos s y t deben ser del intervalo < 0,1>. Lo que realmente ocurre en mi ejemplo es que solo s si de ese intervalo y t es -2. A se encuentra en línea definida por C y D, pero no en segmento de línea CD.

var s = Vector3.Dot(Vector3.Cross(dc, db), Vector3.Cross(da, db))/Norm2(Vector3.Cross(da, db)); 

var t = Vector3.Dot(Vector3.Cross(dc, da), Vector3.Cross(da, db))/Norm2(Vector3.Cross(da, db)); 

donde da es B-A, db es D-C y DC es nombres C-A, sólo preservadas proporcionadas por Bill.

Entonces como dije usted tiene que comprobar si ambos s y t son de < 0,1> y se puede calcular el resultado. Basado en la fórmula anterior.

if ((s >= 0 && s <= 1) && (k >= 0 && k <= 1)) 
{ 
    Vector3 res = new Vector3(this.A.x + da.x * s, this.A.y + da.y * s, this.A.z + da.z * s); 
} 

Otro problema con las cuentas es cuando dos líneas son colineales y hay más de un punto de intersección. Habría división por cero. Quieres evitar eso.

Cuestiones relacionadas