2010-10-04 7 views
43

Estoy usando Matrix para escalar y rotar Bitmaps. Ahora me pregunto cuál es la diferencia entre preconcat & postconcat es, o más precisamente la diferencia entre:Android: Matrix -> ¿cuál es la diferencia entre preconcat y postconcat?

Por lo que pude averiguar hasta el momento setRotate siempre sobrescribe toda la matriz, mientras que con preRotate y postRotate puedo aplicar múltiples cambios a una matriz (por ejemplo, escala + rotación). Sin embargo, usar postRotate o preRotate no causó ningún resultado diferente para los casos que los utilicé.

Respuesta

120

La respuesta a su pregunta no es realmente específica de Android; es una pregunta de gráficos y matemáticas. Hay mucha teoría en esta respuesta: ¡has sido advertido! Para una respuesta superficial a su pregunta, salte al final. Además, debido a que esta es una diatriba tan larga, podría tener un error tipográfico o dos que hacen que las cosas no estén claras. Me disculpo de antemano si ese es el caso.

En gráficos por computadora, podemos representar píxeles (o en 3D, vértices) como vectores. Si la pantalla es de 640x480, aquí es un vector 2D para el punto en el centro de la pantalla (perdona mi margen de beneficio de mala calidad):

[320] 
[240] 
[ 1] 

voy a explicar por qué el 1 es importante más adelante. Las transformaciones a menudo se representan usando matrices porque entonces es muy simple (y muy eficiente) encadenarlas, como usted mencionó. Para escalar el punto anterior por un factor de 1,5, puede left-multiply por la siguiente matriz:

[1.5 0 0] 
[ 0 1.5 0] 
[ 0 0 1] 

Usted obtendrá este nuevo punto:

[480] 
[360] 
[ 1] 

que representa el punto original, escalado por 1.5 relativo a la esquina de su pantalla (0, 0). Esto es importante: el escalado siempre se hace con respecto al origen. Si desea escalar con algún otro punto como su centro (como el centro de un sprite), debe "ajustar" la escala en las traducciones hacia y desde el origen. Aquí está la matriz de traducir nuestro punto original al origen:

[1 0 -320] 
[0 1 -240] 
[0 0  1] 

que produce:

[320*1 + 1*-320] [0] 
[240*1 + 1*-240] = [0] 
[  1*1  ] [1] 

usted reconocerá lo anterior como la matriz identity con el desplazamiento coordenadas dio una palmada en la esquina superior derecha . Es por eso que el 1 (la "coordenada homogénea") es necesario: para hacer espacio para estas coordenadas, lo que hace posible traducir utilizando la multiplicación. De lo contrario, tendría que estar representado por la adición de la matriz, que es más intuitiva para los humanos, pero haría las tarjetas gráficas aún más complicadas de lo que ya son.

Ahora, la multiplicación de matrices generalmente isn't commutative, por lo que cuando "añadir" una transformación (por multiplicando su matriz) que necesita para especificar si uno se queda multiplicación o haga multiplicador. La diferencia que hace es en qué orden están encadenadas tus transformaciones.Al multiplicar correctamente su matriz (usando preRotate()) está indicando que el paso de rotación debería ocurrir antes de todas las demás transformaciones que acaba de solicitar. Esto podría ser lo que quieras, pero por lo general no lo es.

A menudo, no importa. Si solo tiene una transformación, por ejemplo, nunca importa :) A veces, las transformaciones pueden ocurrir en cualquier orden con el mismo efecto, como escalado y rotación: mi álgebra lineal está oxidada, pero creo que en este caso el la multiplicación de la matriz en realidad es conmutativa porque la matriz de la escala es symmetric, es decir, se refleja en la diagonal. Pero en realidad, solo piénselo: si giro una imagen 10 grados en el sentido de las agujas del reloj y luego la escala al 200%, se ve igual que si primero la escalara, luego la roté.

Si estaba haciendo transformaciones de compuestos más extraños, comenzaría a notar una discrepancia. Mi consejo es seguir con postRotate().

+1

Per la documentación, M. preConcat (otro)> M '= M * otro, M.postConcat (otro)> M' = otro * M, Actualmente estoy probando algo de esto, pero parece que 'pre' establece el nuevo operador después de las que ya has hecho, y 'post' lo hace antes. Estoy escalando y luego traduciendo, necesita escalar y luego traducir porque la traducción está en coordenadas escaladas. Funciona si 'pre' pero no si 'posteo'. Esta notación me resulta confusa, así que avíseme si me equivoco. – Kratz

+0

Tuve que doblar y triplicar los documentos, también. El esquema de nombres es bastante confuso, así que podría haberlo conseguido al revés. Sin embargo, no estoy seguro de entender * su * notación :) 'other * M' es un multiplicador izquierdo, y debe dar como resultado las transformaciones de' M' seguidas de 'otras'. Creo. – Cheezmeister

+0

Obtuve esa notación desde aquí: http://developer.android.com/reference/android/graphics/Matrix.html#preConcat(android.graphics.Matrix) También encuentro confusa la denominación. – Kratz

1
matrix: float[] values ={1.2f,0,30,0,1.2f,30,0,0,1}; 
matrix2: float[] values2 ={1f,0,0,0,1f,0,0,0,1}; 

Digamos que nuestros valores de matriz son los valores anteriores.

  1. cuando hacemos la transformación, como a continuación:

    matrix.preTranslate(-50, -50); 
    

    es igual a hacer la transformación de secuencia para Matriz2 anteriormente como a continuación:

    matrix2.postTranslate(-50, -50); 
    matrix2.postScale(1.2f, 1.2f); 
    matrix2.postTranslate(30, 30); 
    
  2. cuando hacemos la transformación, como a continuación:

    matrix.preRotate(50); 
    

    es igual a hacer la transformación de secuencia para Matriz2, como a continuación:

    matrix2.postRotate(50); 
    matrix2.postScale(1.2f, 1.2f); 
    matrix2.postTranslate(30, 30); 
    
  3. cuando hacemos la transformación, como a continuación:

    matrix.preScale(1.3f,1.3f); 
    

    es igual a hacer la transformación de secuencia para Matriz2, como a continuación:

    matrix2.postScale(1.3f,1.3f); 
    matrix2.postScale(1.2f, 1.2f); 
    matrix2.postTranslate(30, 30); 
    

Sin embargo, si su matriz se ha rotado antes (ej. {1.2f,-1f,30,-1f,1.2f,30,0,0,1};), entonces no es tan simple como el anterior porque cuando giraste, también escalaste la matriz al mismo tiempo.

4

que respondieron a la pregunta de ayer, pero me siento sometiong mal hoy, así que corregir la respuesta aquí:

matrix: float[] values ={1.2f,0.5f,30,0.5f,1.2f,30,0,0,1}; 

//as we all know, the basic value in matrix,means no transformation added 
matrix2: float[] values2 ={1f,0,0,0,1f,0,0,0,1}; 

Let's say our matrix values are the values above. 

1, cuando hacemos la transformación, como a continuación:

matrix.preTranslate(-50, -50); 

is equals to do sequence transformation to matrix2 above like below: 

matrix2.postTranslate(-50, -50); 
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f);// note here 
matrix2.postScale(1.2f, 1.2f); 
matrix2.postTranslate(30, 30); 

2, cuando hacemos la transformación como a continuación:

matrix.preRotate(50); 

is equals to do sequence transformation to matrix2 like below: 

matrix2.postRotate(50); 
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f); 
matrix2.postScale(1.2f, 1.2f); 
matrix2.postTranslate(30, 30); 

3, cuando hacemos la transformación como belo w:

matrix.preScale(1.3f,1.3f); 

is equals to do sequence transformation to matrix2 like below: 

matrix2.postScale(1.3f,1.3f); 
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f); 
matrix2.postScale(1.2f, 1.2f); 
matrix2.postTranslate(30, 30); 

4, cuando hacemos la transformación, como a continuación:

matrix.preSkew(0.4f,0.4f); 

es igual que hacer transformación secuencia para Matriz2, como a continuación:

matrix2.postSkew(0.4f,0.4f); 
matrix2.postSkew(0.5f/1.2f,0.5f/1.2f); 
matrix2.postScale(1.2f, 1.2f); 
matrix2.postTranslate(30, 30); 
Cuestiones relacionadas