简体   繁体   中英

3D coordinate rotation lacking Precision in perspective 2D

So I wrote a Program to draw and display a 3D cube, using these simple conversion formula's as used in isometric graphs:

x2 = x*cos(30) - y*cos(30)
y2 = x*sin(30) + y*sin(30) + z

The coordinate conversion is fine and everything comes out in perspective.

The Issue is rotating, Large degree rotations messes up all the coordinates and gives me an entire shape. And rotating at small degrees many many times, (ie 1000 1degree rotation or more) reduces the size of the cube.

public void rotateX(double dg) //cube is shrinking along y and z  
{
    y = (y*Math.cos(dg)-z*Math.sin(dg));  
    z = (y*Math.sin(dg)+z*Math.cos(dg));  
}
public void rotateY(double dg) //cube is shrinking along x and z  
{  
    x = x*Math.cos(dg)-z*Math.sin(dg);  
    z = x*Math.sin(dg)+z*Math.cos(dg);  
}  
public void rotateZ(double dg) //cube is shrinking along x and y  
{  
    x = x*Math.cos(dg)-y*Math.sin(dg);  
    y = x*Math.sin(dg)+y*Math.cos(dg);  
}

How can i solve this lack of precision of cos and sin after multiple uses??

Here's the entire code written in 3 seperat classes:
Main class:

import java.awt.*;
import javax.swing.*;
import java.util.Random;
public class Frame extends JFrame
{
    private Random rnd = new Random();
    private cubeGUI cube;
    public Frame()
    {
        super();
    }

    public void paint(Graphics g)
    {
        cube = new cubeGUI(75,300.0,300.0);
        cube.convertall();
        double dg = 0.5; // The Smaller the degree, the less the error after long rotations.
        int sl = 5;
        int turns, axe;  
        while (1 == 1)
        {
            turns = rnd.nextInt(200)-100;
            axe = rnd.nextInt(3);
            for(int i = 0; i<turns; i++)
            {
                switch (axe)
                {
                    case 0: cube.rotatx(dg); break;
                    case 1: cube.rotaty(dg); break;
                    case 2: cube.rotatz(dg); break;
                }
                g.clearRect(0,0,600,600);
                g.drawLine(cube.a.x2,cube.a.y2,cube.b.x2,cube.b.y2);
                g.drawLine(cube.a.x2,cube.a.y2,cube.c.x2,cube.c.y2);
                g.drawLine(cube.c.x2,cube.c.y2,cube.d.x2,cube.d.y2);
                g.drawLine(cube.b.x2,cube.b.y2,cube.d.x2,cube.d.y2);
                g.drawLine(cube.e.x2,cube.e.y2,cube.f.x2,cube.f.y2);
                g.drawLine(cube.e.x2,cube.e.y2,cube.g.x2,cube.g.y2);
                g.drawLine(cube.g.x2,cube.g.y2,cube.h.x2,cube.h.y2);
                g.drawLine(cube.f.x2,cube.f.y2,cube.h.x2,cube.h.y2);
                g.drawLine(cube.a.x2,cube.a.y2,cube.e.x2,cube.e.y2);
                g.drawLine(cube.b.x2,cube.b.y2,cube.f.x2,cube.f.y2);
                g.drawLine(cube.c.x2,cube.c.y2,cube.g.x2,cube.g.y2);
                g.drawLine(cube.d.x2,cube.d.y2,cube.h.x2,cube.h.y2);
                try
                {
                    Thread.sleep(sl); //Rotation Speed, In relation with Angle of rotation.
                } catch(InterruptedException ex)
                {
                    Thread.currentThread().interrupt();
                }
            }
        }
}
public static void main(String[] args)
{
    Frame cube = new Frame();
        cube.setSize(600,600);
        cube.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        cube.setVisible(true);
    }
}

cube class:

public class cubeGUI
{
    public Point center,a,b,c,d,e,f,g,h;
    private double x, y;
    public cubeGUI(int m, double x, double y)
    {
        this.x = x;
        this.y = y;
        a = new Point(-m,-m,-m);
        b = new Point(m,-m,-m);
        c = new Point(-m,m,-m);
        d = new Point(m,m,-m);
        e = new Point(-m,-m,m);
        f = new Point(m,-m,m);
        g = new Point(-m,m,m);
        h = new Point(m,m,m);
    }
    public void rotatx(double dg)
    {
        a.rotateX(Math.toRadians(dg));
        b.rotateX(Math.toRadians(dg));
        c.rotateX(Math.toRadians(dg));
        d.rotateX(Math.toRadians(dg));
        e.rotateX(Math.toRadians(dg));
        f.rotateX(Math.toRadians(dg));
        g.rotateX(Math.toRadians(dg));
        h.rotateX(Math.toRadians(dg));
        convertall();
    }
    public void rotaty(double dg)
    {
        a.rotateY(Math.toRadians(dg));
        b.rotateY(Math.toRadians(dg));
        c.rotateY(Math.toRadians(dg));
        d.rotateY(Math.toRadians(dg));
        e.rotateY(Math.toRadians(dg));
        f.rotateY(Math.toRadians(dg));
        g.rotateY(Math.toRadians(dg));
        h.rotateY(Math.toRadians(dg));
        convertall();
    }
    public void rotatz(double dg)
    {
        a.rotateZ(Math.toRadians(dg));
        b.rotateZ(Math.toRadians(dg));
        c.rotateZ(Math.toRadians(dg));
        d.rotateZ(Math.toRadians(dg));
        e.rotateZ(Math.toRadians(dg));
        f.rotateZ(Math.toRadians(dg));
        g.rotateZ(Math.toRadians(dg));
        h.rotateZ(Math.toRadians(dg));
        convertall();
    }
    public void convertall()
    {
        a.convert(x,y);
        b.convert(x,y);
        c.convert(x,y);
        d.convert(x,y);
        e.convert(x,y);
        f.convert(x,y);
        g.convert(x,y);
        h.convert(x,y);
    }
}

Point class (this calculates all coordinates):

public class Point
{
    private double x, y, z, F;
    public int x2, y2;
    public Point(double a, double b, double c)
    {
        x = a;
        y = b;
        z = c;
    }
    public int getX()
    {
        return (int)x;
    }
    public int getY()
    {
        return (int)y;
    }
    public int getZ()
    {
        return (int)z;
    }
    public void rotateX(double dg) //cube is shrinking along y and z
    {
        y = (y*Math.cos(dg)-z*Math.sin(dg));
        z = (y*Math.sin(dg)+z*Math.cos(dg));
    }
    public void rotateY(double dg) //cube is shrinking along x and z
    {
        x = x*Math.cos(dg)-z*Math.sin(dg);
        z = x*Math.sin(dg)+z*Math.cos(dg);
    }
    public void rotateZ(double dg) //cube is shrinking along x and y
    {
        x = x*Math.cos(dg)-y*Math.sin(dg);
        y = x*Math.sin(dg)+y*Math.cos(dg);
    }
    public void convert(double xx, double yy)
    {
        x2 = (int)(-(Math.cos(Math.toRadians(30))*x - Math.cos(Math.toRadians(30))*y) + xx);
        y2 = (int)(-(Math.sin(Math.toRadians(30))*x + Math.sin(Math.toRadians(30))*y + z) + yy);
    }
    public String toString()
    {
        return ("Y = " + y + ", Z = " + z);
    }
}

The usual approach is to represent the cube as a point configuration and a current transformation. When rotating, update the transformation but do not update the points themselves. Only when point coordinates are needed (for rendering, displaying coordinate values, etc.) should the transformation be applied to the points. The points themselves should never be modified.

This will eliminate the errors that accumulate when many rotations are applied in sequence. However, it is important that the transformation matrix be maintained as a rotation (determinant 1). Otherwise the transformation will still introduce random artifacts (scaling, skewing, or other distortions). Thus, after each rotation is applied, the transformation matrix should be renormalized so that it remains a pure transformation. The normalization can be as simple as dividing each entry by the determinant.

You use x, which is already changed: x = x*Math.cos(dg)-y*Math.sin(dg);
y = x*Math.sin(dg)+y*Math.cos(dg);

it is right variant. double xx =x; x = x*Math.cos(dg)-y*Math.sin(dg); y = xx*Math.sin(dg)+y*Math.cos(dg);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM