Search code examples
c#mathmultidimensional-array3dtrigonometry

3D-Coordinate Transformation in C#


What is the Goal?: I want to know the new Coordinates of a point after rotating the 3D-Object (Cuboid), around the anchorpoint (x,y & z) on the opposite side.

What i did: I tried to calculate the position with the following function. I had to convert doubles to floats , because of the Autodesk Inventor API. Note: Vector is the difference from the origin /anchorpoint to the designated point.

Vector3 coordinateTransformation(Vector3 vector, float r_x, float r_y, float r_z, Vector3 origin)
        {
            vector.X = vector.X;  //Just for demonstration
            vector.Y = vector.Y * Convert.ToSingle(Math.Cos(DegreesToRadians(r_x))) - vector.Z * Convert.ToSingle(Math.Sin(DegreesToRadians(r_x)));
            vector.Z = vector.Y * Convert.ToSingle(Math.Sin(DegreesToRadians(r_x))) + vector.Z * Convert.ToSingle(Math.Cos(DegreesToRadians(r_x)));
            
            vector.X = vector.X * Convert.ToSingle(Math.Cos(DegreesToRadians(r_y))) + vector.Z * Convert.ToSingle(Math.Sin(DegreesToRadians(r_y)));
            vector.Y = vector.Y;  //Just for demonstration
            vector.Z = vector.Z * Convert.ToSingle(Math.Cos(DegreesToRadians(r_y))) - vector.X * Convert.ToSingle(Math.Sin(DegreesToRadians(r_y)));
            
            vector.X = vector.X * Convert.ToSingle(Math.Cos(DegreesToRadians(r_z))) - vector.Y * Convert.ToSingle(Math.Sin(DegreesToRadians(r_z)));
            vector.Y = vector.X * Convert.ToSingle(Math.Sin(DegreesToRadians(r_z))) + vector.Y * Convert.ToSingle(Math.Cos(DegreesToRadians(r_z)));
            vector.Z = vector.Z;  //Just for demonstration

            vector.X = Math.Abs(vector.X) + origin.X;
            vector.Y = Math.Abs(vector.Y) + origin.Y;
            vector.Z = Math.Abs(vector.Z) + origin.Z;
            
            return vector;
        }

Somehow the object does not get placed on the correct place.

Next step: On the internet i found a website which does the correct transformation.Casio Website If i manually set vector to the calculated point on the website, everything else works fine. So i somehow have to get the exact same calculation into my code.

If you need further information, feel free to comment!

Edit: 1 : I want to place 2 Objects (e.g. Cuboids) within 1 Assembly Group in Inventor. Every Object as an anchorpoint (origin) and on the opposite side a connection point, which is described as the delta between the anchorpoint and the connection point itself. At first one Object is placed on the origin coordinates, followed by a rotation around the anchorpoint (degrees). After that the connection point coordinates of Object 1 have changed. In the next step i want to place Object 2 with its origin on the connection point of Object 1, while Object 2 has the same rotation as Object 1. 2 : Inventor uses a right-handed coordinate system


Solution

  • When you apply rotation to a vector manually, you'd need to update all the components (X, Y and Z) at once as follows.

    Vector3 coordinateTransformation(Vector3 vector, float r_x, float r_y, float r_z, Vector3 origin)
    {
    
        // In the rotation around X axis below, `Y relies on Z` and `Z relies on Y`. So both must be updated simultaneously. 
        vector = new Vector3(
            vector.X,
            vector.Y * Convert.ToSingle(Math.Cos(DegreesToRadians(r_x))) - vector.Z * Convert.ToSingle(Math.Sin(DegreesToRadians(r_x))),
            vector.Y * Convert.ToSingle(Math.Sin(DegreesToRadians(r_x))) + vector.Z * Convert.ToSingle(Math.Cos(DegreesToRadians(r_x)))
        );
    
        vector = new Vector3(
            vector.X * Convert.ToSingle(Math.Cos(DegreesToRadians(r_y))) + vector.Z * Convert.ToSingle(Math.Sin(DegreesToRadians(r_y))),
            vector.Y,
            vector.Z * Convert.ToSingle(Math.Cos(DegreesToRadians(r_y))) - vector.X * Convert.ToSingle(Math.Sin(DegreesToRadians(r_y)))
        );
    
        vector = new Vector3(
            vector.X * Convert.ToSingle(Math.Cos(DegreesToRadians(r_z))) - vector.Y * Convert.ToSingle(Math.Sin(DegreesToRadians(r_z))),
            vector.X * Convert.ToSingle(Math.Sin(DegreesToRadians(r_z))) + vector.Y * Convert.ToSingle(Math.Cos(DegreesToRadians(r_z))),
            vector.Z
        );
    
        vector.X = Math.Abs(vector.X) + origin.X;
        vector.Y = Math.Abs(vector.Y) + origin.Y;
        vector.Z = Math.Abs(vector.Z) + origin.Z;
    
        return vector;
    }
    

    Appendix: Use of Matrix4x4

    As @JonasH suggests, it's a good idea to use reliable libraries, if there are.

    Since, row-vectors are used in the .NET world (while your implementation is based on column-vectors), X->Y->Z rotations can be written by straightforward matrices multiplications as follows.

    Vector3 coordinateTransformation(Vector3 vector, float r_x, float r_y, float r_z, Vector3 origin)
    {
    
        var mat = Matrix4x4.CreateRotationX(DegreesToRadians(r_x))
            * Matrix4x4.CreateRotationY(DegreesToRadians(r_y))
            * Matrix4x4.CreateRotationZ(DegreesToRadians(r_z));
    
        vector = Vector3.Transform(vector, mat);
        
        vector.X = Math.Abs(vector.X) + origin.X;
        vector.Y = Math.Abs(vector.Y) + origin.Y;
        vector.Z = Math.Abs(vector.Z) + origin.Z;
    
        return vector;
    }