代码之家  ›  专栏  ›  技术社区  ›  David James

从CATransform3D获取缩放、平移和旋转

  •  0
  • David James  · 技术社区  · 7 年前

    给予 CATransform3D 变换,我想提取的比例,平移和旋转作为单独的变换。通过一些挖掘,我能做到这一点 CGAffineTransform 在斯威夫特,像这样:

    extension CGAffineTransform {
        var scaleDelta:CGAffineTransform {
            let xScale = sqrt(a * a + c * c)
            let yScale = sqrt(b * b + d * d)
            return CGAffineTransform(scaleX: xScale, y: yScale)
        }
        var rotationDelta:CGAffineTransform {
            let rotation = CGFloat(atan2f(Float(b), Float(a)))
            return CGAffineTransform(rotationAngle: rotation)
        }
        var translationDelta:CGAffineTransform {
            return CGAffineTransform(translationX: tx, y: ty)
        }
    }
    

    一个人怎么做类似的事情 CATransform3D变压器 用数学?(我正在寻找不使用密钥路径的解决方案。)

    (实现或数学答案由您自行决定)

    2 回复  |  直到 7 年前
        1
  •  4
  •   warrenm    7 年前

    如果您从一个合适的仿射矩阵开始,该仿射矩阵可以被正确分解(如果不是明确的话)成一系列的缩放、旋转、平移,这个方法将执行分解成一个表示平移、旋转(欧拉角)和缩放组件的向量元组:

    extension CATransform3D {
        func decomposeTRS() -> (float3, float3, float3) {
            let m0 = float3(Float(self.m11), Float(self.m12), Float(self.m13))
            let m1 = float3(Float(self.m21), Float(self.m22), Float(self.m23))
            let m2 = float3(Float(self.m31), Float(self.m32), Float(self.m33))
            let m3 = float3(Float(self.m41), Float(self.m42), Float(self.m43))
    
            let t = m3
    
            let sx = length(m0)
            let sy = length(m1)
            let sz = length(m2)
            let s = float3(sx, sy, sz)
    
            let rx = m0 / sx
            let ry = m1 / sy
            let rz = m2 / sz
    
            let pitch = atan2(ry.z, rz.z)
            let yaw = atan2(-rx.z, hypot(ry.z, rz.z))
            let roll = atan2(rx.y, rx.x)
            let r = float3(pitch, yaw, roll)
    
            return (t, r, s)
        }
    }
    

    要显示此例程正确提取了各种组件,请构造转换并确保它按预期分解:

    let rotationX = CATransform3DMakeRotation(.pi / 2, 1, 0, 0)
    let rotationY = CATransform3DMakeRotation(.pi / 3, 0, 1, 0)
    let rotationZ = CATransform3DMakeRotation(.pi / 4, 0, 0, 1)
    let translation = CATransform3DMakeTranslation(1, 2, 3)
    let scale = CATransform3DMakeScale(0.1, 0.2, 0.3)
    let transform = CATransform3DConcat(CATransform3DConcat(CATransform3DConcat(CATransform3DConcat(scale, rotationX), rotationY), rotationZ), translation)
    let (T, R, S) = transform.decomposeTRS()
    print("\(T), \(R), \(S))")
    

    这会产生:

    float3(1.0, 2.0, 3.0), float3(1.5708, 1.0472, 0.785398), float3(0.1, 0.2, 0.3))
    

    注意,这个分解假定了一个XYZ的Euler乘法阶,它只是 several possible orderings .

    警告 :对于某些值,这种方法在数值上是不稳定的。我还没有进行足够广泛的测试来知道这些陷阱在哪里,所以 警告清空器 .

        2
  •  0
  •   David James    7 年前

    对称于 CGAffineTransform 在我的问题中,这里是 CATransform3D 根据Warren的 decomposeTRS ,我已将其标记为已接受的答案。

    extension CATransform3D {
        var scaleDelta:CATransform3D {
            let s = decomposeTRS().2
            return CATransform3DMakeScale(CGFloat(s.x), CGFloat(s.y), CGFloat(s.z))
        }
        var rotationDelta:CATransform3D {
            let r = decomposeTRS().1
            let rx = CATransform3DMakeRotation(CGFloat(r.x), 1, 0, 0)
            let ry = CATransform3DMakeRotation(CGFloat(r.y), 0, 1, 0)
            let rz = CATransform3DMakeRotation(CGFloat(r.z), 0, 0, 1)
            return  CATransform3DConcat(CATransform3DConcat(rx, ry), rz)
        }
        var translationDelta:CATransform3D {
            let t = decomposeTRS().0
            return CATransform3DMakeTranslation(CGFloat(t.x), CGFloat(t.y), CGFloat(t.z))
        }
    }
    
    推荐文章