c++ - resueltos - que es la proyeccion ortogonal de un punto sobre un plano
¿Cómo proyectar un punto en un plano en 3D? (7)
Tengo un punto 3D (point_x, point_y, point_z) y quiero proyectarlo en un plano 2D en el espacio 3D que (el plano) está definido por un punto coordenadas (orig_x, orig_y, orig_z) y un vector perpendicular unario (normal_dx) , normal_dy, normal_dz).
¿Cómo debería manejar esto?
Creo que deberías cambiar ligeramente la forma en que describes el avión. De hecho, la mejor manera de describir el plano es a través de un vector n y un escalar c
( x , n ) = c
La (constante de (valor absoluto) de la c) es la distancia del plano desde el origen, y es igual a ( P , n ), donde P es cualquier punto en el plano.
Entonces, sea P el punto de origen y A ''la proyección de un nuevo punto A en el plano. Lo que hay que hacer es encontrar un tal que A ''= A - a * n satisfaga la ecuación del plano, es decir
( A - a * n , n ) = ( P , n )
Resolviendo para un, encuentras que
a = ( A , n ) - ( P , n ) = ( A , n ) - c
lo que da
A ''= A - [( A , n ) - c] n
Usando tus nombres, esto lee
c = orig_x*normal_dx + orig_y*normal_dy+orig_z*normal_dz;
a = point_x*normal_dx + point_y*normal_dy + point_z*normal_dz - c;
planar_x = point_x - a*normal_dx;
planar_y = point_y - a*normal_dy;
planar_z = point_z - a*normal_dz;
Nota: su código ahorraría un producto escalar si en lugar del punto original P almacena c = ( P , n ), lo que significa básicamente un 25% menos de flops para cada proyección (en caso de que esta rutina se use muchas veces en su código).
Esta respuesta es una adición a dos respuestas existentes. Mi objetivo es mostrar cómo las explicaciones de @tmpearce y @bobobobo se reducen a lo mismo, al mismo tiempo que proporciono respuestas rápidas a aquellos que simplemente están interesados en copiar la ecuación que mejor se adapte a su situación.
Método para planos definidos por n normal y punto o
Este método fue explicado en la respuesta por @tmpearce.
Dada una definición normal de punto de un plano con n normal y punto o en el plano, un punto p '', que es el punto en el plano más cercano al punto p dado, se puede encontrar por:
1) p ''= p - ( n ⋅ ( p - o )) * n
Método para planos definidos por n normal y escalar d
Este método fue explicado en la respuesta por @bobobobo.
Dado un plano definido por n normal y escalar d , un punto p '', que es el punto en el plano más cercano al punto p dado, se puede encontrar por:
2) p ''= p - ( n ⋅ p + d ) * n
Si, en cambio, tienes una definición de punto normal de un plano (el plano está definido por n normal y punto o en el plano) @bobobobo sugiere encontrar d :
3) d = - n ⋅ o
e inserte esto en la ecuación 2. Esto da como resultado:
4) p ''= p - ( n ⋅ p - n ⋅ o ) * n
Una nota sobre la diferencia.
Observa más de cerca las ecuaciones 1 y 4. Al compararlas, verás que la ecuación 1 usa n ⋅ ( p - o ) donde la ecuación 2 usa n ⋅ p - n ⋅ o . En realidad son dos formas de escribir lo mismo:
5) n ⋅ ( p - o ) = n ⋅ p - n ⋅ o = n ⋅ p + d
Por lo tanto, uno puede elegir interpretar el escalar d como si fuera un "cálculo previo". Explicaré: si se conocen los n y o de un plano, pero o solo se usa para calcular n ⋅ ( p - o ), también podemos definir el plano con n y d y calcular n ⋅ p + d en su lugar, porque Acabamos de ver que eso es lo mismo.
Adicionalmente para la programación usando d tiene dos ventajas:
- Encontrar p ''ahora es un cálculo más simple, especialmente para computadoras. Comparar:
- usando n y o : 3 restas + 3 multiplicaciones + 2 sumas
- usando n y d : 0 restas + 3 multiplicaciones + 3 sumas.
- El uso de d limita la definición de un plano a solo 4 números reales (3 para n + 1 para d ), en lugar de 6 (3 para n + 3 para o ). Esto ahorra ⅓ memoria.
Esto es realmente fácil, todo lo que tiene que hacer es encontrar la distancia perpendicular (abbr here |_
) desde el punto P
al plano, luego trasladar P
hacia atrás por la distancia perpendicular en la dirección del plano normal . El resultado es que la P
traducida se encuentra en el plano.
Tomando un ejemplo fácil (que podemos verificar por inspección):
Establecer n = (0,1,0) y P = (10,20, -5).
El punto proyectado debe ser (10,10, -5). Se puede ver por inspección que Pproj está a 10 unidades perpendiculares del plano, y si estuviera en el plano, tendría y = 10.
Entonces, ¿cómo encontramos esto analíticamente?
La ecuación de plano es Ax + By + Cz + d = 0. Lo que significa esta ecuación es "para que un punto (x, y, z) esté en el plano, debe satisfacer Ax + Por + Cz + d = 0" .
¿Cuál es la ecuación de Ax + By + Cz + d = 0 para el plano dibujado arriba?
El plano tiene n normal = (0,1,0). La d se encuentra simplemente usando un punto de prueba ya en el plano :
(0)x + (1)y + (0)z + d = 0
El punto (0,10,0) está en el plano. Al enchufar arriba, encontramos, d = -10. La ecuación del plano es entonces 0x + 1y + 0z - 10 = 0 (si simplificas, obtienes y = 10).
Una buena interpretación de d
es que habla de la distancia perpendicular que necesitaría para traducir el plano a lo largo de su normalidad para que el plano pase a través del origen .
De todos modos, una vez que tengamos d
, podemos encontrar la distancia | _ de cualquier punto al plano mediante la siguiente ecuación:
Hay 3 clases posibles de resultados para | _ distancia al plano:
- 0: EN UN AVIÓN EXACTAMENTE (casi nunca sucede con problemas de inexactitud de punto flotante)
- +1:> 0: FRENTE al plano (en el lado normal)
- -1: <0: plano DETRÁS (en el lado opuesto de lo normal)
De todas formas,
Lo que puede verificar como correcto por inspección en el diagrama de arriba
No es suficiente proporcionar solo el origen del plano y el vector normal. Esto sí define el plano 3d, sin embargo, esto no define el sistema de coordenadas en el plano.
Piensa que puedes rotar tu plano alrededor del vector normal con respecto a su origen (es decir, poner el vector normal en el origen y "rotar").
Sin embargo, puede encontrar la distancia desde el punto proyectado hasta el origen (que obviamente es invariante a la rotación).
Resta el origen del punto 3d. Luego hacer un producto cruzado con la dirección normal. Si su vector normal está normalizado, la longitud del vector resultante es igual al valor necesario.
EDITAR
Una respuesta completa necesitaría un parámetro extra. Digamos que también suministras el vector que denota el eje x en tu plano. Así que tenemos los vectores n y x . Supongamos que están normalizados.
El origen se denota por O , su punto 3D es p .
Entonces tu punto es proyectado por lo siguiente:
x = ( p - O ) punto x
y = ( p - O ) punto ( n cruz x )
Sea r el punto para proyectar y p el resultado de la proyección. Sea c cualquier punto en el plano y n sea normal al plano (no necesariamente normalizado). Escriba p = r + m d para algún escalar m que se verá como indeterminado si no hay solución. Desde ( p - c ). n = 0 porque todos los puntos en el plano satisfacen esta restricción que uno tiene ( r - c ). n + m ( d . n ) = 0 y entonces m = [( c - r ). n ] / [ d . n ] donde se usa el producto de puntos (.) Pero si d . n = 0 no hay solución. Por ejemplo, si d y n son perpendiculares entre sí, no hay solución disponible.
Sea V = (orig_x, orig_y, orig_z) - (point_x, point_y, point_z)
N = (normal_dx, normal_dy, normal_dz)
Sea d = V.dotproduct (N);
Punto proyectado P = V + dN
1) Haz un vector desde tu punto de origen hasta el punto de interés:
v = point-orig (in each dimension);
2) Tome el producto punto de ese vector con la unidad normal vector n
:
dist = vx*nx + vy*ny + vz*nz;
dist = distancia escalar de punto a plano a lo largo de lo normal
3) Multiplica el vector normal de la unidad por la distancia y resta ese vector de tu punto.
projected_point = point - dist*normal;
Editar con foto: He modificado un poco tu foto. Rojo es v
; v
punto normal
= longitud de azul y verde ( dist
arriba). El azul es normal*dist
. Green = blue * -1
: para encontrar planar_xyz, comience desde el point
y agregue el vector verde.