2013-05-08 6 views
0

j'ai donc écrit un programme pour dessiner et afficher un cube en 3D, en utilisant ces formules simples de conversion est aussi utilisé dans les graphiques isométriques:rotation de coordonnées 3D manque de précision en perspective 2D

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

La coordonnée conversion va bien et tout sort en perspective.

Le problème est en rotation, les rotations de grand degré bousillent toutes les coordonnées et me donnent une forme entière. Et la rotation à de nombreux degrés plusieurs fois (c.-à-d. 1000 1degree rotation ou plus) réduit la taille du 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); 
} 

Comment puis-je résoudre ce manque de précision de cos et sin après de multiples utilisations ??

est ici tout le code écrit en 3 classes de seperat:
classe principale:

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); 
    } 
} 

classe cube:

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); 
    } 
} 

classe Point (ce calcule toutes les coordonnées):

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); 
    } 
} 
+0

Avez-vous essayé d'utiliser 'BigDecimal'? – durron597

+0

Eh bien, je ne voulais pas aller avec BigDecimal parce que cela ne ferait que gaspiller de la mémoire, et seulement réduire le problème, pas le supprimer. Tout ce que je devrais faire est de continuer à tourner jusqu'à ce que les nombres BigDecimal ne soient pas suffisants pour se débarrasser de l'erreur rencontrée par cos/sin car ils donnent beaucoup de nombres irrationnels avec des chiffres infinis. – ThaBomb

Répondre

2

L'approche habituelle est de représenter le c ube comme une configuration de point et une transformation en cours. Lors de la rotation, mettez à jour la transformation mais ne mettez pas à jour les points eux-mêmes. Ce n'est que lorsque les coordonnées des points sont nécessaires (pour le rendu, l'affichage des valeurs de coordonnées, etc.) que la transformation doit être appliquée aux points. Les points eux-mêmes ne devraient jamais être modifiés.

Ceci éliminera les erreurs qui s'accumulent lorsque de nombreuses rotations sont appliquées en séquence. Cependant, il est important que la matrice de transformation soit maintenue en rotation (déterminant 1). Sinon, la transformation introduira toujours des artefacts aléatoires (mise à l'échelle, inclinaison ou autres distorsions). Ainsi, après l'application de chaque rotation, la matrice de transformation doit être renormalisée pour qu'elle reste pure transformation. La normalisation peut être aussi simple que de diviser chaque entrée par le déterminant.

+0

Merci pour le conseil :) Bien que je puisse avoir 1 problème, en tournant avec des degrés plus grands, l'exemple le plus bas que je peux vous donner, tourne de 90. si j'utilise 1 degré et tourne 90 fois, le cube est bien. Mais si j'utilise 90 degrés une fois, le cube se transforme en un rectangle 2D et bousille les coordonnées de tous les points. Comment puis-je résoudre ceci? – ThaBomb

+0

Merci, cela a résolu le problème de précision, mais a créé un autre problème maintenant: P.La rotation d'un axe seul est très bien, si j'en fais tourner d'autres, les formes commencent à gâcher et j'ai l'impression d'im- primer un hypercube 4D. – ThaBomb

+0

@ThaBomb - Cela ressemble à une erreur mathématique. Je vérifierais le code qui met à jour la transformation. –

0

Vous utilisez x, qui est déjà modifié: x = x * Math.cos (dg) -y * Math.sin (dg);
y = x * Math.sin (dg) + y * Math.cos (dg);

c'est la bonne variante. double xx = x; x = x * Math.cos (dg) -y * Math.sin (dg); y = xx * Math.sin (dg) + y * Math.cos (dg);

+0

Mon problème avec cette méthode était le manque de précision pour sin et cos, cela signifiait qu'après plusieurs rotations (environ 1000) les coordonnées seraient complètement différentes des initiales, et l'objet aurait été redimensionné et parfois traduit. Tout va bien maintenant, le programme fonctionne bien. – ThaBomb

Questions connexes