simd_quatF 转欧拉角

问题描述 投票:0回答:3

我正在尝试将我的季铵化合物转换为欧拉,但在 x/y/z 分量中,只有我的 X 具有准确的值,而 y/z 不正确:- (任何人都可以查看/帮助吗?

func quatToEulerAngles(_ quat: simd_quatf) -> SIMD3<Double>{
    
    
    var angles = SIMD3<Double>();
    let qfloat = quat.vector
    let q = SIMD4<Double>(Double(qfloat.x),Double(qfloat.y),Double(qfloat.z), Double(qfloat.w))
    // roll (x-axis rotation)
    
    let sinr_cosp : Double = 2.0 * (q.w * q.x + q.y * q.z);
    let cosr_cosp : Double = 1.0 - 2.0 * (q.x * q.x + q.y * q.y);
    angles.x = atan2(sinr_cosp, cosr_cosp);
    
    // pitch (y-axis rotation)
    let sinp : Double = 2 * (q.w * q.y - q.z * q.x);
    if (abs(sinp) >= 1){
        angles.y = copysign(Double.pi / 2, sinp); // use 90 degrees if out of range
    }
    else{
        angles.y = asin(sinp);
    }
    // yaw (z-axis rotation)
    let siny_cosp : Double = 2 * (q.w * q.z + q.x * q.y);
    let cosy_cosp : Double = 1 - 2 * (q.y * q.y + q.z * q.z);
    angles.z = atan2(siny_cosp, cosy_cosp);
    
    return angles;
}

Wiki 示例已转换为 swifht。 TIA

swift quaternions euler-angles
3个回答
4
投票

我的解决方案是让(SceneKit)库来完成它:

func quatToEulerAngles(_ quat: simd_quatf) -> SIMD3<Float>{
    let n = SCNNode()
    n.simdOrientation = quat
    return n.simdEulerAngles
}

0
投票

我看了一下并将其转换为 Swift,

https://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/

它对我有用。

func quatToEulerAngles(_ quat: simd_quatf) -> SIMD3<Float>{

var angles = SIMD3<Float>();
let qfloat = quat.vector

// heading = x, attitude = y, bank = z

let test = qfloat.x*qfloat.y + qfloat.z*qfloat.w;

if (test > 0.499) { // singularity at north pole
    
    angles.x = 2 * atan2(qfloat.x,qfloat.w)
    angles.y = (.pi / 2)
    angles.z = 0
    return  angles
}
if (test < -0.499) { // singularity at south pole
    angles.x = -2 * atan2(qfloat.x,qfloat.w)
    angles.y = -(.pi / 2)
    angles.z = 0
    return angles
}


let sqx = qfloat.x*qfloat.x;
let sqy = qfloat.y*qfloat.y;
let sqz = qfloat.z*qfloat.z;
angles.x = atan2(2*qfloat.y*qfloat.w-2*qfloat.x*qfloat.z , 1 - 2*sqy - 2*sqz)
angles.y = asin(2*test)
angles.z = atan2(2*qfloat.x*qfloat.w-2*qfloat.y*qfloat.z , 1 - 2*sqx - 2*sqz)

return angles

}


0
投票

我只是想指出,依赖 SceneKit 进行转换可能会导致问题。我注意到,当从 Xcode 中的默认 SceneKit 项目绕 y(垂直)轴旋转船舶时,接近 90° 和 270° 的角度会导致生成的欧拉角绕 y 轴翻转 180°,从而导致错误的动画。以下代码演示了该问题。

import SceneKit
import QuartzCore

class GameViewController: NSViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // create a new scene
        let scene = SCNScene(named: "art.scnassets/ship.scn")!
        
        // create and add a camera to the scene
        let cameraNode = SCNNode()
        cameraNode.camera = SCNCamera()
        scene.rootNode.addChildNode(cameraNode)
        
        // place the camera
        cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
        
        // retrieve the ship node
        let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
        
        // animate the 3d object
        let tempNode = SCNNode()
        ship.runAction(.customAction(duration: 100, action: { node, t in
            tempNode.simdOrientation = simd_quatf(angle: Float(t), axis: simd_float3(x: 0, y: 1, z: 0))
            let eulerAngles = tempNode.eulerAngles
            print(t, eulerAngles)
            node.eulerAngles = eulerAngles
        }))
        
        // retrieve the SCNView
        let scnView = self.view as! SCNView
        
        // set the scene to the view
        scnView.scene = scene
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.