我发现了一个关于仅获取旋转的类似问题,但是据我了解,缩放和旋转在变换矩阵中的工作方式不同。
矩阵不是我的强项,所以如果有人提示我如何仅从 CGAffineTransform 中进行缩放,我将不胜感激。
顺便提一句。我尝试在 CGSize 上应用 CGAffineTransform,然后获取高度 x 宽度以查看它的缩放程度,但高度 x 宽度具有奇怪的值(取决于在 CGAffineTransform 中找到的旋转,所以......嗯,这不起作用)
我发现了一个关于仅获取旋转的类似问题,但是据我了解,缩放和旋转在变换矩阵中的工作方式不同。
矩阵不是我的强项,所以如果有人提示我如何仅从 CGAffineTransform 中进行缩放,我将不胜感激。
顺便提一句。我尝试在 CGSize 上应用 CGAffineTransform,然后获取高度 x 宽度以查看它的缩放程度,但高度 x 宽度具有奇怪的值(取决于在 CGAffineTransform 中找到的旋转,所以......嗯,这不起作用)
假设变换是一个缩放,然后是一个旋转(可能在那里有一个平移,但没有倾斜),水平比例因子是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 |
- (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);
}
这是一个老问题,但如果有人需要,我仍然会添加更多信息。
对我来说,获取比例、变换旋转和复制它的好答案和示例代码来自文章:
我不熟悉 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)
由于仿射变换是通过线性变换的简单技巧实现的,并且由于线性变换不是可交换的,因此在实际研究如何提取单个变换之前,您需要了解变换的排序方式。
这是一个古老的(Swift 之前的)问题,因此对于基于以下搜索的 Swift 人来说,CGAffineTransform
这里是基于其他答案的 Swift 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
}
[编辑:根据评论更新轮换以使用双打。谢谢!]
Swift 4 扩展(感谢 Robin Macharg 的回答)
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,因此转换需要为 Double。
让我提出不同的解决方案。我首先沿相反方向旋转仿射变换,然后从 ta 和 td 读取比例:
- (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);
}