Android: Matrix -> что отличает preconcat и postconcat?

Я использую Matrix для масштабирования и вращения растровых изображений. Теперь мне интересно, какая разница между preconcat и postconcat, или, точнее, разница между:

  • postRotate
  • preRotate
  • setRotate

Из того, что я мог выяснить, setRotate всегда переписывает всю матрицу, а с preRotate и postRotate я могу применить несколько изменений к матрице (например, масштабирование + вращение). Однако либо использование postRotate, либо preRotate не приводило к каким-либо другим результатам в тех случаях, когда я их использовал.

Solutions Collecting From Web of "Android: Matrix -> что отличает preconcat и postconcat?"

Ответ на ваш вопрос не совсем специфичен для Android; Это графический и математический вопрос. В этом ответе есть много теории – вас предупреждают! Для поверхностного ответа на ваш вопрос пропустите снизу. Кроме того, поскольку это такая длинная тирада, у меня может быть опечатка или две вещи, которые неясно. Приносим извинения заранее, если это так.

В компьютерной графике мы можем представлять пиксели (или в 3D, вершины) в качестве векторов. Если ваш экран 640×480, вот 2D-вектор для точки в середине экрана (простите мою дрянную разметку):

[320] [240] [ 1] 

Я объясню, почему это важно позже. Трансформации часто представлены с использованием матриц, потому что тогда очень просто (и очень эффективно) объединять их вместе, как вы упомянули. Чтобы масштабировать точку выше в 1,5 раза, вы можете умножить ее на следующую матрицу:

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

Вы получите новый пункт:

 [480] [360] [ 1] 

Которая представляет исходную точку, масштабированную на 1,5 относительно угла экрана (0, 0). Это важно: масштабирование всегда выполняется относительно происхождения. Если вы хотите масштабировать какую-то другую точку в качестве своего центра (например, в середине спрайта), вам нужно «обернуть» масштаб в переводах в начало и из начала. Вот матрица, чтобы перевести наш исходный пункт в начало:

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

Который дает:

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

Вы узнаете выше, как идентификационную матрицу с координатами смещения, пробитыми в верхнем правом углу. Вот почему 1 («однородная координата») необходимо: освободить место для этих координат, что позволяет переводить с использованием умножения. В противном случае это должно было бы быть представлено добавлением матрицы, которое более интуитивно понятное для людей, но сделало бы графические карты еще более сложными, чем они есть.

Теперь матричное умножение, как правило , не является коммутативным , поэтому, когда «добавление» преобразования (путем умножения вашей матрицы), вам нужно указать, будете ли вы умножать или умножать налево. Разница, которую он делает, – это то, к чему preRotate() ваши преобразования. Путем правильного умножения вашей матрицы (используя preRotate() ) вы указываете, что шаг вращения должен произойти до всех других преобразований, которые вы только что просили. Это может быть то, что вы хотите, но обычно это не так.

Часто это не имеет значения. Если у вас есть только одно преобразование, это никогда не имеет значения. Иногда ваши преобразования могут происходить в любом порядке с таким же эффектом, как масштабирование и вращение. Моя линейная алгебра ржавая, но я считаю, что в этом случае Матричное умножение фактически является коммутативным, потому что матрица шкалы симметрична , т. Е. Зеркально отражается по диагонали. Но на самом деле, просто подумайте об этом: если я поворачиваю изображение на 10 градусов по часовой стрелке, а затем масштабирую его до 200%, он выглядит так же, как если бы я сначала масштабировал его, а затем поворачивал.

Если вы делаете какие-то более сложные сложные преобразования, вы начнете замечать несоответствие. Мой совет – придерживаться postRotate() .

Я ответил на вопрос вчера, но сегодня я чувствую, что неправильно, поэтому я исправляю ответ здесь:

 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, когда мы делаем преобразование, как показано ниже:

 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, когда мы делаем преобразование, как показано ниже:

 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, когда мы делаем преобразование, как показано ниже:

 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, когда мы делаем преобразование, как показано ниже:

  matrix.preSkew(0.4f,0.4f); 

Равен преобразованию последовательности в матрицу 2, как показано ниже:

  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); 
 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}; 

Скажем, наши значения матрицы – это значения выше.

  1. Когда мы делаем трансформацию, как показано ниже:

     matrix.preTranslate(-50, -50); 

    Равен преобразованию последовательности в матрицу 2, как показано ниже:

     matrix2.postTranslate(-50, -50); matrix2.postScale(1.2f, 1.2f); matrix2.postTranslate(30, 30); 
  2. Когда мы делаем трансформацию, как показано ниже:

     matrix.preRotate(50); 

    Равен преобразованию последовательности в матрицу 2, как показано ниже:

     matrix2.postRotate(50); matrix2.postScale(1.2f, 1.2f); matrix2.postTranslate(30, 30); 
  3. Когда мы делаем трансформацию, как показано ниже:

     matrix.preScale(1.3f,1.3f); 

    Равен преобразованию последовательности в матрицу 2, как показано ниже:

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

Однако, если ваша матрица повернута раньше (например, {1.2f,-1f,30,-1f,1.2f,30,0,0,1}; ), то это не так просто, как указано выше, потому что когда вы вращаетесь, вы Также масштабировала матрицу в одно и то же время.