[c++] Rotation eines Körpers

exitium

Grünschnabel
Hallo,

ich programmiere mit Borland.

Ich führe bzw. ich möchte eine eine einfache Rotation einer Matrix durchführen. Dabei sollen die ersten drei Punkte in die xz-Ebene gelegt werden, also Punkt1 (0,0,0), Punkt2 (0,0,z) und Punkt3 (x,0,z).

Ganz am Anfang den Code, den ich benutze:

PHP:
vector< vector<double> > Molekuel3D = make_2DimVector<double>( AtomAnzahl, 3 );
//es wird eine einfache Matrix erzeugt, diese wird anschließend gefüllt
//mit dieser Matrix wird nun gearbeitet

if(Molekuel3D.size() > 0)
		{
			print_2DimVector(Molekuel3D); //die Matrix wird in der Konsole ausgegeben
			translation(Atom1); //Atom1 bildet nach der Translation den Koordiantenursprung also (0,0,0)
			print_2DimVector(Molekuel3D);
			rotation_um_x_Achse(Atom2); //die Matrix wird um die x-Achse rotiert
			print_2DimVector(Molekuel3D);
			rotation_um_y_Achse(Atom2); //die Matrix wird um die y-Achse rotiert
			print_2DimVector(Molekuel3D);
			rotation_um_z_Achse(Atom3); //die Matrix wird um die z-Achse rotiert
//es wird diesmal der dritte Punkt genommen, da Punkt1 und 2 schon in der xz-Ebene sind
			print_2DimVector(Molekuel3D);
		}

	void rotation_um_x_Achse(int AtomNummer)		
	{						
		double ver_x = Molekuel3D[AtomNummer-1][0]; //x-Koordinate des Punktes
		double ver_y = Molekuel3D[AtomNummer-1][1]; //y-Koordinate des Punktes
		double ver_z = Molekuel3D[AtomNummer-1][2]; //z-Koordinate des Punktes
	
		double alpha = acos(ver_z/(sqrt(pow(ver_y,2)+pow(ver_z,2)))); //es wird der Winkel berechnet um den die Matrix rotiert werden muss, damit Atom2 in die die xz-Ebene gelegt werden kann
		
		for(int i = Molekuel3D.size()-1; i>=0; i--)		
		{
			Molekuel3D[i][1] = (Molekuel3D[i][1]*cos(alpha)) - (Molekuel3D[i][2]*sin(alpha));
			Molekuel3D[i][2] = (Molekuel3D[i][1]*sin(alpha)) + (Molekuel3D[i][2]*cos(alpha));
		}	
	}

        void rotation_um_y_Achse(int AtomNummer)		
	{							
		double ver_x = Molekuel3D[AtomNummer-1][0]; 
		double ver_y = Molekuel3D[AtomNummer-1][1];
		double ver_z = Molekuel3D[AtomNummer-1][2];
	
		double beta = asin(-1*ver_x);
		
		for(int i = Molekuel3D.size()-1; i>=0; i--)		
		{
			Molekuel3D[i][0] = (Molekuel3D[i][0]*cos(beta)) + (Molekuel3D[i][2]*sin(beta));
			//Molekuel3D[i][1] = (Molekuel3D[i][1]*cos(alpha)) + (-1*Molekuel3D[i][2]*sin(alpha));
			Molekuel3D[i][2] = (-1*Molekuel3D[i][0]*sin(beta)) + (Molekuel3D[i][2]*cos(beta));
		}	
	}
	

	void rotation_um_z_Achse(int AtomNummer)		
	{							
		double ver_x = Molekuel3D[AtomNummer-1][0]; 
		double ver_y = Molekuel3D[AtomNummer-1][1];
		double ver_z = Molekuel3D[AtomNummer-1][2];
	
		double zeta = acos(ver_x/(sqrt(pow(ver_x,2)+pow(ver_y,2))));
		
		for(int i = Molekuel3D.size()-1; i>=0; i--)		
		{
		
			Molekuel3D[i][0] = (Molekuel3D[i][0]*cos(zeta)) - (Molekuel3D[i][1]*sin(zeta));
			Molekuel3D[i][1] = (Molekuel3D[i][0]*sin(zeta)) + (Molekuel3D[i][1]*cos(zeta));
		}	
	}


Mein erstes Problem ist die Ungenauigkeit die bei mir entsteht. bei der Rotation um die x-Achse kommt er z.B. nicht auf genau null aber fast

Code:
x y z
0.010561 1.89761 1.59433
--> Roation um x-Achse

Code:
x y z
0.010561 -1.38995e-16 1.02559

Also ich sehe schon das dies nahezu null ist, aber trotzdem.

Bei der Rotation um die y-Achse wird die Ungenauigkeit noch deutlicher:

Code:
x y z
0.010561 -1.38995e-16 1.02559
--> Rotation um y-Achse

Code:
x y z
-0.000270832 -1.38995e-16 1.02559

Ich denke mal das -0.000270832 nicht wirklich ausreichend klein ist um als null durch zugehen.

Kann mir hier jemand helfen wie ich die Genauigkeit erhöhen kann?

Das nächste Problem ist die Rotation um die z-Achse. Der Winkel um den rotiert werden sollte müsste wie folgt berechnet werden:
Code:
double zeta = acos(ver_x/(sqrt(pow(ver_x,2)+pow(ver_y,2))));

Das ist also die Projektion des Vektors OP (Ortsvektor*die Koordinaten des dritten Atoms) auf die xy-Ebene. OP = (x,y,z) dann ist die Projektion pOP = (x,y,0).
Laut Tafelwerk, kann der Winkel im Kreis, dann mit cos a = u/v berechnet werden. u entspricht hier dem x-Wert, v ist die Gerade vom Ursprung zum projizierten Punkt also die Quadratwurzel aus x²+y²

Wende ich das in meinem Programm an, kommt aber nur misst dabei raus! Kann mir jemand sagen ob mein Gedanke falsch war oder ob ich programmier-technisch einfach einen Fehler gemacht habe?

Gruß und besten Danke für Vorschläge, exitium

PS: ich habe gerade mitbekommen, dass ich diesen Beitrag falsch geposted habe. Leider kann ich Ihn nicht in das Unterverzeichnis für Borland verschieben, wäre nett wenn das ein Mod machen könnte. Danke.

PPS: leider kann ich auch nicht mehr den Titel bearbeiten, also nicht Körber sondern Körper. Ist mir leider zu spät aufgefallen!
 
Zuletzt bearbeitet:
Hallo,

Ich weiß nicht ganz wie das alles bei dir Funktioniert, aber normalerweise gibt man die Drehung in Matrizen doch als Rad und nicht als Deg an oder ?

Gruß
Anfänger
 
Hallo exitium,

ich kann dir zwar nicht sagen was bei deinem Algorithmus schief läuft, aber ich kann dir zumindest erklären, wie ich das Problem lösen würde. Das Stichwort lautet Basiswechsel. In Pseudocode:
Code:
// Orthonormalsystem aufbauen
Vec3 z = (Atom2.Position - Atom1.Position).normalize(); // normalize(): Vektor auf Länge 1 bringen
Vec3 x = (Atom3.Position - Atom1.Position).normalize();
Vec3 y = x.cross(z); // cross(): Kreuzprodukt
x = z.cross(y);
// Transformationsmatrix
Matrix3x3 trans(x, y, z); // x, y, z sind die Spalten der Matrix
trans = trans.inverse(); // Inverse der Matrix bilden
// Alle Punkte transformieren
for each Atom in Molekül3D
    Atom.Position = trans * Atom.Position; // Matrix-Vektor-Produkt
Es werden also zunächst die drei Basisvektoren für die neue Basis anhand der Positionen der Atome bestimmt. Anschließend erzeugt man damit die entsprechende Basistransformationsmatrix und invertiert diese (wir wollen die Koordinaten ja zurücktransformieren). Mit dieser Matrix transformiert man dann einfach die Positionen aller Atome.

Grüße, Matthias
 
Zurück