2016-03-19 4 views
0

Ich schreibe ein Programm, das ein rechteckiges Prisma um einen Punkt drehen wird. Es behandelt die Rotationen über 3 Rotationsverfahren, die jeweils eine Rotation um eine einzelne Achse (X, Y und Z) verwalten. Hier ist der CodeJava: Rotationen und 3D-Verzerrungen

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 ist eine nutzlose Klasse, die drei Doppel speichert (die Umdrehungen). Diese Methoden konvertieren im Grunde die Rotationen in 2D-Vektoren (wie ich die Punkte speichern) und rotiere sie als solche. Die erste if-Anweisung stellt sicher, dass die 2D-Vektoren nicht die Größe 0 haben. Sie dürfen, aber in diesem Fall müssen die Rotationsberechnungen nicht durchgeführt werden. Der andere Teil behandelt nur die Triggerung. Die untere Methode bindet alles zusammen und erlaubt mir, die Reihenfolge der Rotationen schnell zu ändern (weil die Reihenfolge die endgültige Rotation beeinflussen sollte).

Das Problem ist nicht mit den einzelnen Rotationen, sondern wenn sie alle zusammenkommen. Ich kann leicht eine einzige Drehung um eine Achse ausführen, ohne das rechteckige Prisma zu verzerren. Wenn ich sie alle zusammensetze, wie wenn du addSpin() aufrufen würdest.

Wenn spinY zuerst aufgerufen wird, ist das Prisma verzerrt, wenn die Drehungen eine Y-Drehung enthalten (wenn die y-Komponente der Drehung Null ist und keine Drehung um die y-Achse auftreten sollte, tritt keine Verzerrung auf). In der Tat, wenn spinY() jederzeit aufgerufen wird, aber zuletzt eine Verzerrung des Würfels auftreten wird.

Das gleiche gilt für spinZ(). Wenn spinZ() zuletzt aufgerufen wird, wird der Würfel nicht verzogen. Allerdings kann spinX() überall hingehen und keine Verzerrung verursachen.

Also die Frage ist: Gibt es ein Problem mit, wie ich über die Rotationen gehe? Die andere Frage ist, während alle Rotationen nicht von Rotationen entlang nur der X- und Y-Achse oder irgendeinem anderen Paar von verschiedenen Achsen (wie X und Z oder Y und Z) umfasst sein können, können diese drei Sätze kollektiv alle Rotationen durchführen? Zur Verdeutlichung: Können die Rotationen, die nicht durch eine Reihe von Rotationen um die X- und Y-Achse erreicht werden können, durch eine Reihe von Rotationen um die X- und Z-Achsen oder die Y- und Z-Achsen erreicht werden?

Ich vertraue dem Medium, das ich verwende, um die Prismen anzuzeigen. Es ist ein Ray-Tracer, den ich gemacht habe, der gut mit rechteckigen Prismen funktioniert. Dies ist eine mathematischere Frage, aber es hat eine ziemlich umfassende Programmierungskomponente.

Dies sind einige parallele Berechnungen, die immer noch Verzerrungen ergeben.

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

Antwort

1

Ihre Kontrollen für Dinge wie

x == 0 

sind unnötig und gefährlich wie ein Doppel fast den genauen Wert nie 0. Der Atan, wenn Sie eine Abteilung zu einem katastrophalen Verlust an Präzision haben müssen führen kann Gut.

Warum sind sie unnötig? Da die folgenden Ihre Drehung in einer sauberere führt (numerisch stabil) Art und Weise:

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; 

Natürlich, mein Beispiel vorausgesetzt, dass Sie die y-Rotation mit einer rechtshändigen Orientierung behandeln, aber von Ihrem Beispielcode Sie scheinen es zu behandeln als Linkshänder. Wie auch immer, der Wikipedia-Artikel auf der Rotation matrix erklärt die Mathematik.

+0

Der Grund, den ich für 0 überprüfe, ist nicht so sehr, dass, wenn x und z gleich sind, ich die Berechnungen nicht benötige. Wenn Sie in Java 0 durch 0 teilen, erhalten Sie NaN, was die Dinge verschraubt. Und wären es die linksdrehenden rechtsdrehenden Drehungen, die die Verzerrungen verursachen?Ich würde das nicht glauben, aber ich könnte mich irren ... –

+0

Nein, ich würde mir vorstellen, dass die Verzerrungen auftreten, weil Ihre Berechnung des Radialwinkels nicht zwischen (+, +) und (-, -) oder zwischen ihnen unterscheidet (+, -) und (-, +) Koordinatenpaare. Ich weiß, warum Sie auf Null überprüfen, aber wie ich schon sagte, wenn Sie eine Rotationsmatrix-Berechnung anstelle einer Koordinatenänderung verwenden, werden Sie stabilere Berechnungen haben, ohne Verzweigungsbedingungen. –

+0

Okay, ich ersetzte Ihre Berechnungsmethoden anstelle von meinen (indem ich sie an die der Rotationsmatrizen anpasste) und testete sie. Das Prisma wurde immer noch verzerrt. Ich werde die angepassten Methoden einfügen, um sicherzustellen, dass die Triggerung auscheckt. –