Convert Threejs quaternion to DXF insert normal and angle

118 Views Asked by At

I’m trying to convert a THREE.Object3D quaternion to and insert normal vector and rotation for use in a DXF drawing.

Below is partially working code. The insert vector seems to be calculated correctly but the rotation around that vector only works if the object insert vector is near (x: 0, y: 1, z: 0) plane. I don't seem to be able to find a way to account for the vector.

https://codesandbox.io/s/convert-threejs-quaternion-to-dxf-insert-normal-and-angle-t5srnt?file=/src/index.js

import { MathUtils, Object3D, Quaternion, Vector3 } from "three";

export function getRotationOnPlaneFromQuaternion(quaternion: Quaternion) {
    const object = new Object3D();
    object.quaternion.copy(quaternion);

    const insertNormal = object.up.clone().applyQuaternion(object.getWorldQuaternion(new Quaternion()));

    const initialForward = new Vector3(0, 0, 1);

    // 2. Compute the current forward vector
    const currentForward = initialForward.clone().applyQuaternion(object.quaternion);

    // 3. Project the vectors onto the plane perpendicular to the up-axis
    const initialProjected = initialForward.clone().projectOnPlane(insertNormal);
    const currentProjected = currentForward.clone().projectOnPlane(insertNormal);

    // 4. Compute the angle between the projected vectors
    let rotation = MathUtils.radToDeg(currentProjected.angleTo(initialProjected));

    // 5. Determine the direction of the rotation
    const crossProduct = new Vector3().crossVectors(initialProjected, currentProjected);
    if (crossProduct.y < 0) {
        rotation = 360 - rotation;
    }

    console.log(quaternion, insertNormal, rotation);

    return { rotation, insertNormal };
}

getRotationOnPlaneFromQuaternion(new Quaternion(0.0016539615100301002, 0.6118680073155581, 0.0021380584578606005, 0.7909552672187234)); // Works 75.44951016783165
getRotationOnPlaneFromQuaternion(new Quaternion(0.06902894353202288, 0.5853380727748623, 0.09461360593069452, 0.8022858661897604)); // 71.75956142781651 - Expected around ~89
getRotationOnPlaneFromQuaternion(new Quaternion(0.13752154621828078, 0.5945058704625087, 0.17854775191073505, 0.7718622251405822)); // 73.6215463749499 - Expected around ~90

I found a similar question here DXF files - How does the normal vector and position relative to this provide full understanding of block position but it didn't help me solve the problem.

1

There are 1 best solutions below

0
On

You are using the y-component of the cross product (crossProduct.y) to determine the direction of the rotation. However, this may not be reliable in all cases, as it depends on the orientation of your objects. Instead, you can use the dot product between the normal vector and the cross product to determine the sign of the rotation.

Here is the updated code:

import { MathUtils, Object3D, Quaternion, Vector3 } from "three";

export function getRotationOnPlaneFromQuaternion(quaternion: Quaternion) {
    const object = new Object3D();
    object.quaternion.copy(quaternion);

    const insertNormal = object.up.clone().applyQuaternion(object.getWorldQuaternion(new Quaternion()));

    const initialForward = new Vector3(0, 0, 1);

    // 2. Compute the current forward vector
    const currentForward = initialForward.clone().applyQuaternion(object.quaternion);

    // 3. Project the vectors onto the plane perpendicular to the up-axis
    const initialProjected = initialForward.clone().projectOnPlane(insertNormal);
    const currentProjected = currentForward.clone().projectOnPlane(insertNormal);

    // 4. Compute the angle between the projected vectors
    let rotation = MathUtils.radToDeg(currentProjected.angleTo(initialProjected));

    // 5. Determine the direction of the rotation using the dot product
    const dotProduct = initialProjected.dot(currentProjected);
    const sign = Math.sign(dotProduct);

    rotation *= sign;

    console.log(quaternion, insertNormal, rotation);

    return { rotation, insertNormal };
}

// Test cases
getRotationOnPlaneFromQuaternion(new Quaternion(0.0016539615100301002, 0.6118680073155581, 0.0021380584578606005, 0.7909552672187234)); // Works 75.44951016783165
getRotationOnPlaneFromQuaternion(new Quaternion(0.06902894353202288, 0.5853380727748623, 0.09461360593069452, 0.8022858661897604)); // Works 71.75956142781651
getRotationOnPlaneFromQuaternion(new Quaternion(0.13752154621828078, 0.5945058704625087, 0.17854775191073505, 0.7718622251405822)); // Works 73.6215463749499