Описание тега affinetransform
Аффинное преобразование - это специальная матрица 3x3, используемая для применения сдвига, поворота, сдвига или наклона и масштабирования к системам координат в двухмерных графических контекстах. Параллельные линии останутся параллельными, поэтому перспективу применить нельзя. Угол между непараллельными линиями можно изменить с помощью операций перекоса.
a c x
b d y
0 0 1
Нижняя строка матрицы аффинного преобразования всегда 0 0 1
, поэтому аффинное преобразование описывается всего шестью значениями. Преобразование точки - это основа всех операций с аффинными преобразованиями.
new.x = old.x * at.a + old.y * at.c + at.x
new.y = old.x * at.b + old.y * at.d + at.y
Преобразование идентичности преобразует точку в себя.
1 0 0
0 1 0
0 0 1
Значения x и y (часто называемые tx и ty) переводят точку. Значения abcd применяют к точке вращение, сдвиг и масштабирование. Следующее аффинное преобразование повернет точку наr
радианы вокруг начала координатного пространства.
cos(r) sin(r) 0
-sin(r) cos(r) 0
0 0 1
Чтобы применить сдвиг или перекос на rx
а также ry
радианы используют следующую матрицу. С положительнымrx
вертикальные линии значения будут наклонены влево и с положительным ry
горизонтальные линии значения будут скользить вниз вправо.
1 tan(rx) 0
tan(ry) 1 0
0 0 1
Масштабирование применяется более напрямую. Масштабировать наsx
а также sy
используйте следующую матрицу. Использование отрицательного масштаба перевернет или отразит систему координат вокруг оси. Например, используя -1 дляsy
в этой матрице перевернет систему координат вверх ногами.
sx 0 0
0 sy 0
0 0 1
Чтобы применить несколько эффектов одновременно, несколько матриц аффинного преобразования могут быть объединены вместе. Порядок соединения имеет значение. Порядок наименьшего удивления - это перевести, повернуть, наклонить, затем масштабировать. Таким же образом будет восприниматься преобразование, независимо от исходного порядка операций.
Для поворота вокруг точки, отличной от исходной, операция поворота заключена в скобки операциями перемещения. Второй сдвиг будет в направлении поворота, поскольку сдвиг будет сцеплен после поворота.
translate(-x,-y) rotate(r) translate(x,y)
В контекстах, где преобразование связано с определенным визуальным элементом, например css или CALayer, может быть источник преобразования, который неявно переводит аффинное преобразование. Помните об этом, если вам нужно переводить между координатными пространствами.
Чтобы объединить два аффинных преобразования u
а также v
в new
преобразовать сделайте следующее.
new.a = u.a * v.a + u.c * v.b
new.b = u.b * v.a + u.d * v.b
new.c = u.a * v.c + u.c * v.d
new.d = u.b * v.c + u.d * v.d
new.x = u.a * v.x + u.c * v.y + u.x
new.y = u.b * v.x + u.d * v.y + u.y
Обратная матрица может быть вычислена, если определитель не равен нулю. Преобразование точки с помощью аффинного преобразования и обратного преобразования аффинного преобразования восстановит исходную точку.
determinant = a*d - b*c
inverse.a = d/determinant
inverse.b = -b/determinant
inverse.c = -c/determinant
inverse.d = a/determinant
inverse.x = (c*y - d*x)/determinant
inverse.y = (b*x - a*y)/determinant
Перевод аффинного преобразования всегда доступен как x
а также y
ценности. Другие входы также могут быть извлечены. Для аффинного преобразования, которое, как известно, не имеет перекоса, поворот и масштаб можно рассчитать следующим образом.
r = atan2( c , d )
sx = sqrt( a*a + b*b )
sy = sqrt( d*d + c*c )
Вращение, наклон и масштаб могут быть вычислены для произвольного аффинного преобразования. Это будут воспринимаемые значения в порядке наименьшего удивления, а не входные значения. Когда аффинное преобразование вращается и наклоняется или наклоняется по обеим осям, будет два значения поворота. Наименьшим из них будет вращение восприятия, а разница - перекос.
if ( a*d < 0 ) {
if ( a < 0 ) { flip = 1; a = -a; b = -b; }
else { flip = 2; d = -d; c = -c; }
} else {
flip = 0
}
rx = atan2( -b , a )
ry = atan2( c , d )
if ( abs( rx ) < abs( ry ) ) {
r = rx
skew_rx = 0
skew_ry = ry - rx
scale_x = sqrt( a*a + b*b )
scale_y = d / (cos(r) - sin(r)*tan(skew_ry))
} else {
r = ry
skew_ry = 0
skew_rx = ry - rx
scale_y = sqrt( d*d + c*c )
scale_x = a / (cos(r) + sin(r)*tan(skew_rx))
}
if ( 1 == flip ) scale_x = -scale_x;
if ( 2 == flip ) scale_y = -scale_y;
Исходная матрица будет равна объединению следующих эффектов.
translate(x,y) rotate(r) skew(skew_rx,skew_ry) scale(scale_x,scale_y)
Это можно использовать для проверки того, что преобразование будет восприниматься как задуманное. Когда все операции поворота, наклона и масштабирования объединены, масштабирование может быть искажено, если наклон и поворот не дополняют друг друга.
Документация по аффинному преобразованию для некоторых популярных платформ: