# Kombination von Drehungen



## Scrimau (20. Apr 2010)

Ich habe folgendes Problem:
Für eine grafische Darstellung muss ich eine Gerade/Cylinder, die im Koordinatenursprung (rechtshändiges Koordinatensytem) mit einer Orientierung entlang der y-Achse liegt, so drehen, dass sie von einem beliebigen Punkt zu einem anderen beliebigen Punkt im Raum zeigt.
Ich habe die Koordinaten für diese Punkte gegeben. Ich arbeite mit Java3D und Netbeans.
Ich dachte mir folgendes:

1. Ich drehe um die x-Achse um den Winkel zur x-Achse festzulegen, dieser ergibt sich aus: atan(d_y/d_z)-Pi/2 (d steht für delta also Differenz^^)

2. Ich drehe um die z-Achse um den Winkel zur y-Achse festzulegen, dieser ergibt sich aus: Pi/2-atan(d_y/d_x)

3. Ich drehe um die y-Achse um den Winkel zur z-Achse festzulegen, dieser ergibt sich aus: Pi/2- atan(d_z/d_x)

Nun gut, für Ausrichtungen entlang der Koordinatenachsen funktioniert das super, für z.Bsp. von (0,0,0) zu (0,0,1) oder zu (1,0,0), aber für z.Bsp. von (0,0,0) zu (1,0,1) klappt es nicht (ist dann parallel zur z-Achse).

Ich vermute es liegt an dem Zusammenfügen der Transformationen, aber ich weiß nicht wie man dass anders regeln könnte.

Hier der Code (ignoriert den Code in den Kommentaren)

```
neueKante = new TransformGroup();
                        Drehung = new Transform3D();
                        DrehungZ = new Transform3D();
                        DrehungY = new Transform3D();
                        DrehungX = new Transform3D();
                        KPosition = new Transform3D();

                        //Äbstände, aufgesplittet in x, y und z Richtung
                        abstandX = Nachbar.getX() - aktuellerK.getX();
                        abstandY = Nachbar.getY() - aktuellerK.getY();
                        abstandZ = Nachbar.getZ() - aktuellerK.getZ();

                        //Rotieren in richtige Richtung
                        //um Z Achse rotieren um Winkel zur x-Achse einzustellen
                        if(abstandX!=0)
                        {
                            DrehungZ.rotZ(Math.atan(abstandY / abstandX)-Math.PI/2);
                        }
                        /*else
                        {
                            DrehungZ.rotY(90); //parallel zur Z Achse
                        }*/

                        //um X Achse drehen um Winkel zur Z-Achse einzustellen
                        if (abstandZ!=0)
                        {
                            DrehungX.rotX(Math.PI/2- Math.atan(abstandY / abstandZ));
                        }
                        /*else
                        {
                            DrehungY.rotX(90); //parallel zur Y Achse
                        }
                        */

                        //um Y-Achse rotieren um Winkel zur Z-Achse einzustellen
                        if (abstandX!=0)
                        {
                            DrehungY.rotY(Math.PI/2-Math.atan(abstandZ / abstandX));
                        }
                        /*else
                        {
                            DrehungX.rotZ(90); //parallel zur X Achse
                        }*/


                        //zusammenfassen
                        Drehung.mul(DrehungZ, DrehungX);
                        Drehung.mul(DrehungY);
                        //Drehung.mul(DrehungX);

                        KPosition.setTranslation(new Vector3f((float) (aktuellerK.getX() + Nachbar.getX()) / 2, (float) (aktuellerK.getY() + Nachbar.getY()) / 2, (float) (aktuellerK.getZ() + Nachbar.getZ()) / 2)); // in die Mitte der zwei Punkte bewegen

                        //Drehung zur Position hinzufügen
                        KPosition.mul(Drehung);
                        //KPosition.mul(DrehungY);

                        // Kante positionieren
                        neueKante.setTransform(KPosition);
```


----------



## Landei (20. Apr 2010)

Die drei gängigen Methoden zur Drehung im Raum sind
- Drehmatrizen
- Euler-Winkel
- Quaternionen
Es sieht für mich so aus, als wolltest du über Drehmatrizen (die stecken hinter den Transformationen) eine Drehung mit Euler-Winkeln ausdrücken. Schau mal, was Wikipedia zu diesem Zusammenhang sagt, ich habe leider gerade keine Zeit, mir das genauer anzugucken.


----------



## Marco13 (20. Apr 2010)

Die Beschreibung und den Code konnte (wollte) ich so (ad hoc) nicht nachvollziehen, aber um einen Zylinder C entlang einer Linie L auszurichten, kann man die Rotationasachse berechnen:
A = C x L (Kreuzprodukt)
und den Zylinder dann um diese Achse drehen - und zwar um den Winkel zwischen Zylinder und Linie. Sonderfälle bei denen das Kreuzprodukt Länge ~0 hat, müssen dann noch abgefangen werden...


----------



## Scrimau (21. Apr 2010)

Marco13 hat gesagt.:


> Die Beschreibung und den Code konnte (wollte) ich so (ad hoc) nicht nachvollziehen, aber um einen Zylinder C entlang einer Linie L auszurichten, kann man die Rotationasachse berechnen:
> A = C x L (Kreuzprodukt)
> und den Zylinder dann um diese Achse drehen - und zwar um den Winkel zwischen Zylinder und Linie. Sonderfälle bei denen das Kreuzprodukt Länge ~0 hat, müssen dann noch abgefangen werden...



Spitzenidee! Danke, hat nach ein paar Anläufen super geklappt, hier der Code


```
//Vektor = Zielpunktkoord - Anfangspunktkoord
                        abstandX = Nachbar.getX() - aktuellerK.getX();
                        abstandY = Nachbar.getY() - aktuellerK.getY();
                        abstandZ = Nachbar.getZ() - aktuellerK.getZ();

                        if (abstandX != 0 || abstandY != 0 || abstandZ != 0) {
                            //Punkte nicht identisch

                            //neu initialisieren
                            neueKante = new TransformGroup();
                            Drehung = new Transform3D();
                            KPosition = new Transform3D();


                            //Kreuzprodukt aus Standardausrichtung Cylinder (0,1,0) und Verbindungsgerade zwischen Knoten
                            //kpx=(Nachbar.getZ()-aktuellerK.getZ())=abstandZ;
                            //kpz=(-Nachbar.getX()+aktuellerK.getX())=-abstandX;
                            //kpy=0;

                            //Betrag des verbindungsvektors
                            abstand=(Math.sqrt(Math.pow(abstandX, 2) + Math.pow(abstandY, 2) + Math.pow(abstandZ, 2)));

                            //Winkel ergibt sich aus dem Betrag des Kreuzproduktes und dem Produkt der Beträge der einzelnen Vektoren, die sich schneiden (, da Ausrichtung des Cylinders Einheitsvektor ist Betrag =1)
                            winkel = Math.asin(Math.sqrt(Math.pow(abstandX, 2) + Math.pow(abstandZ, 2)) / abstand);

                            //Kreuzprodukt=Drehachse
                            if (abstandY>=0)
                            {
                                Drehung.set(new AxisAngle4d(abstandZ, 0, -abstandX, winkel));
                            }
                            else
                            {
                                Drehung.set(new AxisAngle4d(abstandZ, 0, -abstandX, Math.PI-winkel));
                            }

                            KPosition.setTranslation(new Vector3f((float) (aktuellerK.getX() + Nachbar.getX()) / 2, (float) (aktuellerK.getY() + Nachbar.getY()) / 2, (float) (aktuellerK.getZ() + Nachbar.getZ()) / 2)); // in die Mitte der zwei Punkte bewegen

                            //Drehung zur Position hinzufügen
                            KPosition.mul(Drehung);

                            // Kante positionieren
                            neueKante.setTransform(KPosition);

                            if (aktuellerK.getbenutzt() == true && Nachbar.getbenutzt() == true) {
                                neueKante.addChild(new Cylinder(0.01f, abstand.floatValue(), abenutzt));
                            }
                            else if ((aktuellerK.getuntersucht() == true) || (Nachbar.getuntersucht() == true)) {
                                neueKante.addChild(new Cylinder(0.01f, abstand.floatValue(), auntersucht));
                            }
                            else {
                                neueKante.addChild(new Cylinder(0.01f, abstand.floatValue(), aunbeachtet));
                            }

                            //neue Kante zunächst in temporäre BranchGroup schreiben
                            temp.addChild(neueKante);
                        }
```


----------



## Marco13 (21. Apr 2010)

Das Kreuzprodukt gibt's auch von ratiopharm, als Vector3f#cross. Aber das nur nebenbei.


----------

