Получите только преобразование масштабирования из CGAffineTransform - PullRequest
19 голосов
/ 22 апреля 2010

Я нашел похожий вопрос о получении только поворота, но, как я понимаю, масштабирование и вращение работают по-разному в матрице преобразования.

Матрицы не моя сила, поэтому, если кто-нибудь подскажет мне, как получить только масштабирование из CGAffineTransform Я бы очень признателен.

кстати.Я попытался применить CGAffineTransform к CGSize, а затем получить высоту x width, чтобы увидеть, насколько он масштабируется, но высота x width имеет странные значения (в зависимости от поворота, найденного в CGAffineTransform, так что ... хм, который не работает)

Ответы [ 7 ]

45 голосов
/ 22 апреля 2010

Предполагая, что преобразование представляет собой масштабирование, за которым следует поворот (возможно, с переводом, но без перекоса), горизонтальный масштабный коэффициент равен sqrt(a^2+c^2), вертикальный масштабный коэффициент равен sqrt(b^2+d^2), а отношение горизонтального масштабный коэффициент к вертикальному масштабному коэффициенту должен составлять a/d = -c/b, где a, b, c и d - четыре из шести членов CGAffineTransform, в документации (tx и ty представляют только перевод, который не влияет на масштабные коэффициенты).

|  a  b 0 |
|  c  d 0 |
| tx ty 1 |
29 голосов
/ 02 февраля 2013
- (CGFloat)xscale {
    CGAffineTransform t = self.transform;
    return sqrt(t.a * t.a + t.c * t.c);
}

- (CGFloat)yscale {
    CGAffineTransform t = self.transform;
    return sqrt(t.b * t.b + t.d * t.d);
}
8 голосов
/ 14 января 2013

Это старый вопрос, но я все равно добавляю больше информации на случай, если кому-то понадобится.

Для меня хороший ответ и пример кода для получения масштаба, поворота преобразования и его воспроизведения взяты из статьи:

http://www.informit.com/articles/article.aspx?p=1951182

5 голосов
/ 22 апреля 2010

Я не знаком с CGAffineTransform или Objective-C (вы поймали меня с помощью математического тега). В общем, вы должны отказаться от преобразований индивидуально. Например, если аффинное преобразование A выполняет только масштабирование, вращение и перемещение (порядок масштабирования и вращения не важен в следующем методе, но перевод обязательно должен быть последним):

Перевод: Применение A к вектору (0,0) вернет результат (tx, ty), где tx и ty - переводы в направлениях X и Y соответственно.

Масштабирование по X: Применить A к вектору (1, 0) и получить (sx0 + tx, sx1 + ty). Масштабирование в X будет sqrt (sx0 ^ 2 + sx1 ^ 2)

Масштабирование по Y: Применить A к вектору (0, 1) и получить (sy0 + tx, sy1 + ty). Масштаб в Y будет sqrt (sy0 ^ 2 + sy1 ^ 2)

Поскольку аффинные преобразования реализуются с помощью простого трюка с линейными преобразованиями и поскольку линейные преобразования не являются коммутативными, вам необходимо понять, как упорядочены преобразования, прежде чем на самом деле работать, как вытащить отдельное преобразование.

4 голосов
/ 13 марта 2018

Это старый (до Свифта) вопрос, поэтому для приезжих сюда Свифт на основе поиска CGAffineTransform вот дополнительное удобство Свифта 3, основанное на других ответах:

extension CGAffineTransform {
    var xScale: CGFloat { return sqrt(self.a * self.a + self.c * self.c) }
    var yScale: CGFloat { return sqrt(self.b * self.b + self.d * self.d) }
    var rotation: CGFloat { return CGFloat(atan2(Double(self.b), Double(self.a))) }
    // .tx and .ty are already available in the transform 
}

[Редактировать:Обновлено вращение для использования Doubles в свете комментария.Thx!]

0 голосов
/ 13 марта 2019

Расширение Swift 4 (благодаря ответу Робина Мачарга)

extension CGAffineTransform
{
    var xScale: CGFloat { return sqrt(a * a + c * c) }
    var yScale: CGFloat { return sqrt(b * b + d * d) }
    var rotation: CGFloat { return CGFloat(atan2(Double(b), Double(a))) }
    var xOffset: CGFloat { return tx }
    var yOffset: CGFloat { return ty }
}

Обратите внимание, что CGFloat равняется Double на большинстве платформ, поэтому преобразования должны быть удвоены.

0 голосов
/ 14 января 2019

Позвольте мне предложить другое решение. Сначала я поворачиваю аффинное преобразование в противоположном направлении и просто читаю масштаб из t.a и t.d:

- (CGPoint)scaleFromTransform {
    CGAffineTransform t = self.transform;
    CGFloat angle = atan2(t.b, t.a);
    // calculate rotation transform (by -angle)
    CGAffineTransform r = CGAffineTransformMakeRotation(-angle);
    // calculate main transform without rotation
    CGAffineTransform t0 = CGAffineTransformConcat(t, r);
    CGFloat xScale = t0.a;
    CGFloat yScale = t0.d;
    return CGPointMake(xScale, yScale);
}
...