【发布时间】:2019-09-15 19:21:30
【问题描述】:
我试图了解在 iOS 中使用 CGAffineTransform 链接两个转换的结果。根据 Apple 的文档,平移和缩放的组合按预期工作,但平移和旋转的组合不是。
我认为this post 中的问题是针对相同的观察结果,但我将平移与缩放相结合以显示不一致的行为。或者是否有一些一致的方法来理解使用这些方法进行转换的顺序?
Apple 的 CGAffineTransform documentation 显示了通过在右侧乘以矩阵来转换由行向量 [x y 1] 表示的点。要使用 CGAffineTransform 头文件中使用的符号,这个矩阵是[a b c d tx ty](因为最后一列总是[0 0 1] 的转置)。因为矩阵在行向量的右边,如果我们有两个 CGAffineTransform 矩阵A 和B,应用于点的乘积AB 将首先应用变换A,然后应用操作@987654335 @(这与典型的线性代数书籍相反)。
使用平移变换 t、缩放变换 s 和旋转变换 r,我检查了生成的变换及其对以下视图的影响:
s.translatedBy(x: 100, y: 0) // translates first, then scales
s.concatenating(t) // scales first, then translates
t.rotated(by: 45 * .pi/180) // translates first, then rotates
t.concatenating(r) // rotates first, then translates
我了解concatenating 将按照您在执行translatedBy 等操作时看到的相反顺序执行。但是,根据concatenating: documentation,A.concatenatig(B) 应该给出转换AB,如上所述,它执行转换A,然后是B。这确实发生在s.concatenating(t),但不是t.concatenating(r)。根据Matt's iOS book 中的示例,这里有一些设置代码。
let v1 = UIView(frame:CGRect(20, 111, 132, 194))
v1.backgroundColor = .red
view.addSubview(v1)
let v2 = UIView(frame:v1.bounds)
v2.backgroundColor = .green
v1.addSubview(v2)
let v3 = UIView(frame: v1.bounds)
v3.backgroundColor = .blue
v1.addSubview(v3)
let t = CGAffineTransform(translationX:100, y:0)
let r = CGAffineTransform(rotationAngle: 45 * .pi/180)
let s = CGAffineTransform(scaleX: 0.1, y: 0.1)
然后您可以添加此代码以查看平移和缩放是否按预期工作:
// translates first, then scales
v2.transform = s.translatedBy(x: 100, y: 0)
// scales first, then translates
v3.transform = s.concatenating(t)
但是,平移和旋转的行为是不同的:
// translates first, then rotates
v2.transform = t.rotated(by: 45 * .pi/180)
// rotates first, then translates
v3.transform = t.concatenating(r)
此外,rotated 的标头文档信息显示
Rotate t by angle radians and return the result:
t = [ cos(angle) sin(angle) -sin(angle) cos(angle) 0 0 ] * t
乘法应该意味着旋转首先发生,但措辞使旋转似乎是第二个。根据以上结果,措辞正确(轮换次之)。
translatedBy 的标题文档也有翻译的措辞第二,显示翻译的矩阵乘法是第一。但是根据上面的结果,矩阵乘法是正确的(先平移)。
我在这个分析中犯了错误吗?或者基于连接的转换顺序与这些转换和连接方法的文档中的描述是否存在一些不一致。
【问题讨论】:
-
我的书很清楚,翻译然后旋转与旋转然后翻译的结果不同,它说明了两者;操作不可交换(顺序很重要)。我展示了连接与一次应用一个连接的工作方式有何不同。那么还有什么不清楚的呢?
-
感谢您的评论。我知道顺序会在转换(以及一般的矩阵乘法)方面有所不同。通过查看两对示例,似乎转换顺序存在不一致。
s.concatenating(t)先执行s然后t,但t.concatenating(r)先执行r然后t。根据concatenating的文档,应该是A.concatenating(B)产生A * B。所以顺序应该始终是A,后跟B。t.concatenating(r)违反了这一点。 -
没有不一致。
标签: ios swift cgaffinetransform