Get just the scaling transformation out of CGAffineTransform

时光总嘲笑我的痴心妄想 提交于 2020-01-22 06:57:26

问题


I found a similar question about getting just the rotation, but as I understand scaling and rotating work different in the transform matrix.

Matrixes are not my strength, so if anybody would hint me how to get only the scaling out of a CGAffineTransform I'd greatly appreciate.

btw. I tried applying the CGAffineTransform on a CGSize and then get the height x width to see how much it scaled, but height x width have strange values (depending on the rotation found in the CGAffineTransform, so ... hm that does not work)


回答1:


Assuming that the transformation is a scaling followed by a rotation (possibly with a translation in there, but no skewing) the horizontal scale factor is sqrt(a^2+c^2), the vertical scale factor is sqrt(b^2+d^2), and the ratio of the horizontal scale factor to the vertical scale factor should be a/d = -c/b, where a, b, c, and d are four of the six members of the CGAffineTransform, per the documentation (tx and ty only represent translation, which does not affect the scale factors).

|  a  b 0 |
|  c  d 0 |
| tx ty 1 |



回答2:


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



回答3:


That is an old question, but I still add more information in case someone needs.

For me, the good answer and sample code for getting scale, rotation of transformation and for reproducing it are from article:

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




回答4:


I'm not familiar with CGAffineTransform or Objective-C (you caught me with the math tag). In general, you need to back out the transforms individually. For instance if the affine transform A performs scaling, rotation and translation only (the order of scaling & rotation isn't important in the method below, but translation should be definitely be last):

Translation: Applying A to the vector (0,0) will return the result (tx, ty) where tx and ty are the translations in the X and Y directions respectively.

Scaling in X: Apply A to the vector (1, 0) and get (sx0 + tx, sx1 + ty). The scaling in X will be sqrt(sx0^2 + sx1^2)

Scaling in Y: Apply A to the vector (0, 1) and get (sy0 + tx, sy1 + ty). The scaling in Y will be sqrt(sy0^2 + sy1^2)

Since affine transformations are implemented by a simple trick with linear transformations and since linear transformations are not commutative, you need to understand how the transformations are ordered before actually working through how to pull the individual transformation out.




回答5:


It's an old (pre-Swift) question so for Swift folk arriving here based on a search for CGAffineTransform here's a Swift 3 convenience extension based on the other answers:

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 
}

[Edit: Updated rotation to use Doubles in light of the comment. Thx!]




回答6:


Let me propose different solution. I first rotate the affine transform in the opposite direction and just read scale from t.a and 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);
}



回答7:


Swift 4 Extension (thanks to Robin Macharg's answer)

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

Note that CGFloat equals a Double on most platforms, thus conversions need to be to Double.



来源:https://stackoverflow.com/questions/2690337/get-just-the-scaling-transformation-out-of-cgaffinetransform

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!