# Rotation um Bildmittelpunkt ohne Affine Transform!!!!!



## Eichelhäer (4. Jul 2015)

Hallo zusammen,

seit längerem beschäftige ich mich mit der Strategiespielbewegung. Ich habe vor ein 2D Strategiespiel zu programmieren. Das ganze soll erstmal 2D aus der Vogelperspektive sein.

Im Moment habe ich schon die Bewegung ausgerechnet, d.h. es wird ein Panzer per JButton erzeugt, man kann diesen anklicken und ihn dann beliebig rumschicken. 

Nur ist das etwas langweilig wenn dieser dabei ständig in die gleiche Richtung schaut. Deshalb habe ich mich mich Rotationen beschäftigt.

Fast überall wird auf "AffineTransform" verwiesen. Es ist unter anderem generell eines meiner Probleme, dass ich bei den meisten Funktionen oder anderen vorgefertigten Klassen keine Ahnung habe wie diese arbeiten und deshalb meistens nur durch rumprobieren und Quellcode umstellen oder Werte einsetzen dann zu einem Ergebnis komme.

So auch geschehen bei AffineTransform. Ich hatte schon ein beinahe zufriedenstellendes Ergebnis, aber mir fiel auf, dass was ich da geschrieben habe wirklich "Banane" war, also alles andere als guter Programmierstil.

Deshalb bin ich zur Mathematik gewechselt und siehe da habe auch gleich was gefunden.

Nun zu dem was ich machen will.

Also mein Panzer 20 auf 20 erscheint in einem Fenster. Man klickt ihn an und will ihn bewegen, d.h. man klickt irgendwo ins Fenster und er fährt los. Ich möchte aber, dass sich der Panzer zuerst in Bewegungsrichtung dreht und dann erst losfährt. Ich hoffe soweit klar!?!

Schließlich noch zu dem was ich bisher habe:

1. den Winkel Theta der von dem Panzer und der Maus eingeschlossen wird und
2. die neuen Koordinaten nach einer Drehung um den Winkel Theta. (Drehmatrix)
3. die Additionstheoreme (Formeln)

So blöd wie es klingt, aber ich habe ein Problem mit dem Anfangswinkel, also wenn das Bild das erste Mal gezeichnet wird. Ich weiß zwar, dass der 0 ist, aber dennoch muss ich ja nach meiner Vorstellung den ursprünglichen Bildvektor zu den neuen Koordinaten drehen. Ach ja, im Uhrzeigersinn und gegen den Uhrzeigersinn drehen, erreicht man durch invertieren der Vorzeichen in der Drehmatrix soweit ich noch weiß... .

Wäre schön, wenn mir jemand, der an dem Problem Interesse hat ein paar Tipps geben könnte.

Gruß Eichelhäer


----------



## InfectedBytes (4. Jul 2015)

Mit Math.atan2(y, x) erhälst du den Winkel. Als Eingabe übergibst eben die Differenz von Panzer zu Maus


----------



## Eichelhäer (4. Jul 2015)

Hallo,

danke für dein Interesse.

Ich rechne den Winkel zwischen Maus und Sprite mit dem einfachen atan aus.Es reicht schließlich erstmal der normale Arcustangens(Wie man es eben in der Schule gelernt hat). Ich habe deshalb einen anderen Ansatz:

mit der Formel bzw. Matrixformel:

x' = x * cos(angle) - y * sin(angle)
y' = x * sin(angle) + y * cos(angle)

Rechnet man die neuen Koordinaten nach der Rotation aus. Normalerweise dachte ich jetzt, dass man das x' bzw y' zu dem angle dazuaddieren müsste und dann die Additionstheoreme anwendet.

Also:

angle += x';
angle += y';

Und:

 rx = Math.cos(startangle) * Math.cos(angle) + Math.sin(startangle) * Math.sin(angle);
ry
 = Math.sin(startangle) * Math.cos(angle) + Math.cos(startangle) * Math.sin(angle);

Aber:

Was aber mach ich dann. Leider muss ich zu meiner Schande gestehen, dass ich vorher noch nie mit den Additionstheoremen gearbeitet habe und deshalb nicht genau weiß, was diese bewirken sollen für die Rotation.

Ich hoffe es ist jetzt etwas verständlicher.


----------



## InfectedBytes (4. Jul 2015)

nope, der einfache atan reicht nicht, da dieser nur einen Wert erhält und somit nicht zwischen den verschiedenen Quadranten unterscheiden kann. 
atan2 betrachtet hingegen die vorzeichen der einzelnen Werte und kann somit den quadranten angeben.
Beispiel: für atan2 ist die Eingabe (4, -2) eine andere als (-4, 2)
Für atan ist es die gleiche Eingabe, da 4/-2 = -2 = -4/2


----------



## Eichelhäer (4. Jul 2015)

Ja schon klar, 

ich mach halt noch eine Fallunterscheidung, indem ich Deltax, also nur Deltax, auf negatives Vorzeichen teste. Ist halt mehr Arbeit, ist für mich aber logischer nachvollziehbar. Und die Bewegung in jeden Quadranten einschließlich 0,90 180 270 Grad funktioniert.
Genau so wie ich es mir überlegt habe.


----------



## Eichelhäer (4. Jul 2015)

Noch kleiner Nachtrag ich rechne:

atan(deltay/deltax);

Mfg Eichelhäer


----------



## InfectedBytes (4. Jul 2015)

wo ist dann dein problem?
Wenn du den korrekten winkel hast. brauchst du nur noch die bewegung berechnen:

```
float speed = 10f;
float newX = oldX + cos(angle) * speed;
float newY = oldY + sin(angle) * speed;
```


----------



## Eichelhäer (4. Jul 2015)

Noch ein Nachtrag:

Wie heißt denn die korrekte mathematisch Bezeichnung für atan2?

Ich kenn nämlich neben dem Tangens nur noch den Arcustangens.

Mfg Eichelhäer


----------



## InfectedBytes (4. Jul 2015)

atan2 ist einfach nur arcustangens mit 2 parametern anstatt einem


----------



## Eichelhäer (4. Jul 2015)

Ok,

ich melde mich wieder. Der erste Versuch schlug nämlich fehl. Kann noch etwas dauern... .


----------



## DrZoidberg (5. Jul 2015)

Du musst nicht unbedingt mit Drehmatrizen und dem Additionstheorem arbeiten.
Du kannst auch die Winkel als double Werte speichern und dann einfach diese Werte addieren.
Aber ich versuch mal Drehmatrizen etwas näher zu erklären.
Eine solche Matrix representiert ein rotiertes Koordinatensystem.
Die linke Spalte stellt dabei die x-Achse und die rechte Spalte die y-Achse des Koordinatensystems dar.
Die beiden Spalten kann man also als Vektoren betrachten. Beide Vektoren haben eine Länge von genau 1, d.h. sie sind beide Einheitsvektoren.
Die linke Spalte (die x-Achse) ist gleich (cos(winkel), sin(winkel)) und die rechte (die y-Achse) ist (-sin(winkel), cos(winkel)).

Man kann nun einen Punkt drehen indem man ihn in dieses neue rotierte Koordinatensystem einträgt.
Wenn der Punkt die Koordinaten (px, py) hat, dann ist der rotierte Punkt gleich (px * x-Achse + py * y-Achse).
Mit anderen Worten: wir bewegen uns um px Einheiten in Richtung der x-Achse und um py Einheiten in Richtung der y-Achse.

Willst du eine Drehmatrix m1 mittels einer anderen Matrix m2 rotieren, drehst du einfach beide Vektoren aus denen m1 besteht jeweils mittels m2.


----------



## Eichelhäer (6. Jul 2015)

Hallo nochmal,

zunächst Mal ich habe es nicht hingebracht ohne AffineTransform, d.h. aber nicht, dass ich aufgeben werde. Danke für die Erklärung der Drehmatrix aber bei mir dreht sich nach zwei Tagen intensiver Beschäftigung alles aber nicht das PanzerSprite. 

Nun möchte ich es doch erstmal mit der AffineTransform probieren. Zu meiner Schande muss ich gestehen, dass ich selbst das nicht ordnungsgemäß hinbekomme. Hier mal etwas Code:

public double directionradian(){
        deltax = (MouseInput.mousx-tank.getWidth()/2) - centerX;
        deltay = (MouseInput.mousy-tank.getHeight()/2) - centerY;

        directionradian = Math.atan2(deltay,deltax);

        return directionradian;
    }

    public double directiondegree(){
        return directiondegree = Math.toDegrees(directionradian());
    }

    public double distance(){
        distance = Math.sqrt(((deltax)*(deltax))+((deltay)*(deltay)));
        return distance;
    }

    public void update(long delta){

        tankbounding.x = (int) centerX;
        tankbounding.y = (int) centerY;

        if(distance()>speed){
            centerX += Math.cos(directionradian())*speed;
            centerY += Math.sin(directionradian())*speed;

        }


    }

    public BufferedImage rotate(double angle){
        AffineTransform at = AffineTransform.getRotateInstance(Math.toRadians(angle),tank.getWidth()/2,tank.getHeight()/2);
        BufferedImage rotatedImage = new BufferedImage(tank.getWidth(),tank.getHeight(),tank.getType());
        Graphics2D g2 = (Graphics2D) rotatedImage.getGraphics();
        g2.setTransform(at);
        g2.drawImage(tank,0,0,null);
        return rotatedImage;
    }

    public double dreh(){

        if(Display.clicked){


            if(directiondegree()>0){
                i++;
                if(i>=directiondegree()){
                    i--;
Display.canmove = true;

                }
            }

            else if(directiondegree()<0){
                i--;
                if(i<=directiondegree()){
                    i++;
Display.canmove = true;
                }
else{
Display.canmove = false;
            }
        }
        return i;
    }

    public void renderTank(Graphics g){

        g.drawImage(rotate(dreh()),tankbounding.x,tankbounding.y, null);

    }

Tut mir übrigens Leid der schlechte Programmierstil. Bin etwas überarbeitet.
Zum Problem:

Es würde mich interessieren, warum der erste Aufruf von directiondegree() einen Winkel von - 153.345... angibt und nicht 0 wie ich es eingestellt habe. 

Erste Frage: Wie kann ich diesen Winkel von Anfang an auf 0 setzen?

Weitere Fragen folgen... .

Gruß Eichelhäer

PS: Falls DrZoidberg etwas Zeit hat, könnte er mir ein bisschen Code für die Rotation ohne Affine Transform folgen lassen. Wäre sehr hilfreich.


----------



## Eichelhäer (5. Okt 2015)

Hallo,

ich habe es nun endlich geschafft eine funktionierende Applikation zu bauen, in der eine Rotation eines aus einzelnen Linien bestehen Körpers um einen beliebigen Punkt mithilfe von Additiostheoremen und Drehmatrizen dargestellt wird.

Dazu muss man nur die einzelnen Eckpunkte des gewünschten Körpers berechnen und anschließend aus diesen Positionen die neuen Positionen mit der Drehmatrixformel jeweils für x und y berechnen.

In der paint-Methode dann führt man zuerst eine Tranlation mit g.translate durch dann malt man die gewünschten Linien und schließlich macht man die Tranlation wieder rückgängig. Damit sich auch auf dem Bildschirm was tut kann man z.B. den Drehwinkel um 1 erhöhen und die Rotation animiert darzustellen.

Wenn dieses Thema noch jemanden interessieren sollte poste ich auch noch den Code.

Wie das ganze bei Bildern z.B. PNG´s geht weiss ich noch nicht werde ich aber schon noch herausfinden.

Gruß


Eichelhäer


----------



## Tobse (5. Okt 2015)

Ich muss hier aucnoch was loswerden:

@TE: du hast keine Ahnung, wie die Standard-Java-Klassen arbeiten? Schau doch einfach nach! AffineTransform
Du kannst mir nicht erzählen, dass ein Googlen nach "java AffineTransform" dich nicht auf diese Seite gebracht hätte.


----------

