Get just the scaling transformation out of CGAffineTransform

前端 未结 7 1091
北荒
北荒 2021-02-01 19: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

相关标签:
7条回答
  • 2021-02-01 19:39

    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.

    0 讨论(0)
  • 2021-02-01 19:44

    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 |
    
    0 讨论(0)
  • 2021-02-01 19:50

    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);
    }
    
    0 讨论(0)
  • 2021-02-01 19:52

    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.

    0 讨论(0)
  • 2021-02-01 19:56

    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!]

    0 讨论(0)
  • 2021-02-01 19:59
    - (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);
    }
    
    0 讨论(0)
提交回复
热议问题