Извлекать вращение, масштабировать значения из двумерной матрицы преобразования
Как извлечь значения поворота, масштаба и перемещения из матрицы преобразования 2D? я имею в виду 2d преобразование
matrix = [1, 0, 0, 1, 0, 0]
matrix.rotate(45 / 180 * PI)
matrix.scale(3, 4)
matrix.translate(50, 100)
matrix.rotate(30 / 180 * PI)
matrix.scale(-2, 4)
теперь моя матрица имеет значения [a, b, c, d, tx, ty]
давайте забудем о вышеописанных процессах и представим, что у нас есть только значения a, b, c, d, tx, ty
Как я могу найти значения поворота и масштаба через a, b, c, d, tx, ty
Извините за мой английский
Спасибо ваше продвижение
РЕДАКТИРОВАТЬ
Я думаю, что это должен быть ответ где-то...
я только что попробовал во Flash Builder (AS3) вот так
var m:Matrix = new Matrix;
m.rotate(.25 * Math.PI);
m.scale(4, 5);
m.translate(100, 50);
m.rotate(.33 * Math.PI);
m.scale(-3, 2.5);
var shape:Shape = new Shape;
shape.transform.matrix = m;
trace(shape.x, shape.y, shape.scaleX, shape.scaleY, shape.rotation);
и вывод:
x = -23.6
y = 278.8
scaleX = 11.627334873920528
scaleY = -13.54222263865791
rotation = 65.56274134518259 (in degrees)
4 ответа
Не все значения a, b, c, d, tx, ty приведут к правильной последовательности вращения. Я предполагаю, что приведенные выше значения являются частью матрицы однородного вращения 3x3 в 2D
| a b tx |
A = | c d ty |
| 0 0 1 |
который преобразует координаты [x, y, 1]
в:
[x', y', 1] = A * |x|
|y|
|z|
- Таким образом установите перевод в
[dx, dy]=[tx, ty]
- Масштаб
sx = sqrt(a² + c²)
а такжеsy = sqrt(b² + d²)
- Угол поворота
t = atan(c/d)
или жеt = atan(-b/a)
а также они должны быть одинаковыми.
В противном случае у вас нет действительной матрицы вращения.
Вышеуказанное преобразование расширено до:
x' = tx + sx (x Cos θ - y Sin θ)
y' = ty + sy (x Sin θ + y Cos θ)
когда заказ - вращение, сопровождаемый масштабом и затем переводом.
Термин для этого - матричное разложение. Вот решение, которое включает перекос, как описано Фредериком Вангом.
function decompose_2d_matrix(mat) {
var a = mat[0];
var b = mat[1];
var c = mat[2];
var d = mat[3];
var e = mat[4];
var f = mat[5];
var delta = a * d - b * c;
let result = {
translation: [e, f],
rotation: 0,
scale: [0, 0],
skew: [0, 0],
};
// Apply the QR-like decomposition.
if (a != 0 || b != 0) {
var r = Math.sqrt(a * a + b * b);
result.rotation = b > 0 ? Math.acos(a / r) : -Math.acos(a / r);
result.scale = [r, delta / r];
result.skew = [Math.atan((a * c + b * d) / (r * r)), 0];
} else if (c != 0 || d != 0) {
var s = Math.sqrt(c * c + d * d);
result.rotation =
Math.PI / 2 - (d > 0 ? Math.acos(-c / s) : -Math.acos(c / s));
result.scale = [delta / s, s];
result.skew = [0, Math.atan((a * c + b * d) / (s * s))];
} else {
// a = b = c = d = 0
}
return result;
}
Я столкнулся с этой проблемой сегодня и нашел самое простое решение для преобразования точки с помощью матрицы. Таким образом, вы можете сначала извлечь перевод, затем вращение и масштабирование.
Это работает, только если x и y всегда масштабируются одинаково (равномерное масштабирование).
Учитывая вашу матрицу м, которая претерпела ряд преобразований,
var translate:Point;
var rotate:Number;
var scale:Number;
// extract translation
var p:Point = new Point();
translate = m.transformPoint(p);
m.translate( -translate.x, -translate.y);
// extract (uniform) scale
p.x = 1.0;
p.y = 0.0;
p = m.transformPoint(p);
scale = p.length;
// and rotation
rotate = Math.atan2(p.y, p.x);
Там вы идете!
Если при масштабировании вы бы масштабировали на одну и ту же величину по x и y, то определитель матрицы, то есть ad-bc, который говорит вам, что множитель площади также сообщит вам о линейном изменении масштаба - это будет квадрат корень определителя. atan( b/a) или лучше atan2( b,a) скажут вам полный угол, на который вы повернули.
Однако, поскольку ваше масштабирование не является равномерным, обычно не будет способа уплотнить вашу серию вращений и масштабирование до одного поворота, за которым следует одно неравномерное масштабирование по x и y.