Jean Valjean
Jean Valjean

Reputation: 736

Java: Rotations and 3D distortions

I'm writing a program that will rotate a rectangular prism around a point. It handles the rotations via 3 rotation methods that each manage a rotation around a single axis (X, Y, and Z). Here's the code

public void spinZ(Spin spin) {

    if (x == 0 && y == 0) {
        return;
    }
    double mag = Math.sqrt(x * x + y * y);
    double pxr = Math.atan(y / x);
    x = Math.cos(spin.zr + pxr) * mag;
    y = Math.sin(spin.zr + pxr) * mag;
}
public void spinY(Spin spin) {

    if (z == 0 && x == 0) {
        return;
    }
    double mag = Math.sqrt(x * x + z * z);
    double pxr = Math.atan(z / x);
    x = Math.cos(spin.yr + pxr) * mag;
    z = Math.sin(spin.yr + pxr) * mag;
}
public void spinX(Spin spin) {

    if (z == 0 && y == 0) {
        return;
    }
    double mag = Math.sqrt(y * y + z * z);
    double pxr = Math.atan(z / y);
    y = Math.cos(spin.xr + pxr) * mag;
    z = Math.sin(spin.xr + pxr) * mag;
}

public void addSpin(Spin spin) {

    spinY(spin);
    spinX(spin);
    spinZ(spin);

}

Spin is a useless class that stores three doubles (which are rotations). These methods basically convert the rotations into 2D vectors (how I store the points) and rotate them as such. The first if statement makes sure the 2D vectors don't a magnitude of 0. They are allowed to, but in that case it's not necessary to carry out the rotation calculations. The other part just handles the trig. The bottom method just ties everything together and allows me to quickly change the order of the rotations (because order should and does affect the final rotation).

The problem isn't with the individual rotations but when they all come together. I can easily get a single rotation around a single axis to work without distorting the rectangular prism. When I put them all together, like if you were to call addSpin().

When spinY is called first, the prism is distorted when the rotations include a Y rotation (if the y component of the rotation is zero, and no rotation around the y-axis should occur, then no distortion occurs). In fact, if spinY() is called anytime but last a distortion of the cube will occur.

The same is the case with spinZ(). If spinZ() is called last, the cube won't get warped. However spinX() can go anywhere and not cause a distortion.

So the question is: Is there a problem with how I'm going about the rotations? The other question is while all rotations cannot be encompassed by rotations along just the X and Y axes or any other pair of distinct axes (like X and Z, or Y and Z), can those three sets collectively make all rotations? To clarify, can the rotations, which cannot be reached by a set of rotations around the X and Y axes, be reached by a set of rotations around the X and Z axes or the Y and Z axes?

I trust the medium I'm using to display the prisms. It's a ray-tracer I made that works well with rectangular prisms. This is a more math-based question, but it has a fairly comprehensive programming component.

These are some parallel calculations that still yield in distortions.

public void spinZ(Spin spin) {

    double c = Math.cos(spin.yr);
    double s = Math.sin(spin.yr);
    double xp = x*c - y*s;
    double yp = y*s + x*c;
    x = xp;
    y = yp;
}
public void spinY(Spin spin) {

    double c = Math.cos(spin.yr);
    double s = Math.sin(spin.yr);
    double zp = z*c - x*s;
    double xp = z*s + x*c;
    x = xp;
    z = zp;
}
public void spinX(Spin spin) {

    double c = Math.cos(spin.yr);
    double s = Math.sin(spin.yr);
    double yp = y*c - z*s;
    double zp = z*c + y*s;
    y = yp;
    z = zp;
}

Upvotes: 0

Views: 113

Answers (1)

Aaryn Tonita
Aaryn Tonita

Reputation: 490

Your checks for things like

x == 0

are unnecessary and dangerous as a double almost never will have the precise value 0. The atan when you have a division can lead to catastrophic loss of precision as well.

Why are they unnecessary? Because the following performs your rotation in a cleaner (numerically stable) fashion:

double c = Math.cos(spin.yr);
double s = Math.cos(spin.yr);
double zp = z*c - x*s;
double xp = z*s + x*c;
x = xp;
z = zp;

Of course, my example assumes you treat the y rotation with a right handed orientation, but from your sample code you seem to be treating it as left handed. Anyways, the wikipedia article on the Rotation matrix explains the math.

Upvotes: 1

Related Questions