# Punkt um ein Rotationszentrum rotieren lassen



## Guest (17. Mrz 2008)

Moin Moin!

Ich zeichne mit der Methode drowLine(x1, x1, x2, x2) des Graphics-Objekt eine Linie. Jetzt möchte ich diese Linie um ein Rotationszentrum mit den Koordinaten x_rz und y_rz um grad Grad rotieren lassen.

So wie ich mir das gerade vorstelle, benötige ich eine Funktion, die die beiden Punkte x1,y1 und x2,y2 jeweils um grad Grad um das Rotationszentrum x_rz,y_rz rotieren lässt. Mit den neuen Koordinaten für die beiden Punkte lasse ich dann mit drawLine() eine neue Linie zeichnen.

Gibt es irgendwo eine solche Funktion? ... oder muss ich sowas selbst schreiben. Für letzteren Fall: Wie wäre mathematisch der einfachste Weg?

Freue mich auf eure Antworten!


----------



## Guest (17. Mrz 2008)

1) Zum Koordinatenursprung transformieren
2) Rotieren
3) Rücktransformieren
4) Ausgeben

Alles klar?  :wink:


----------



## Guest (17. Mrz 2008)

Nein, überhaupt nicht. Bin Anfänger und benötige eine etwas verständlichere und ausführlichere Erläuterung. ;-)


----------



## 0x7F800000 (17. Mrz 2008)

ich nehme mal an dass du nicht mit diesen Graphics2D arbeitest, und keine affine transformationen einsetzst? dann würde wohl einfach sowas reichen: das  eine ende des striches lässt du im zentrum, das andere ende berechnet sich mit der trivialen trigonometrie...
 :roll: 
x=zentrum.x+radius*cos(winkel)
y=zentrum.y+radius*sin(winkel)

den winkel soll dabei irgendwie von der zeit linear abhängen, also etwa 

winkel=omega*t+phi, omega phi konstanten


----------



## Guest (17. Mrz 2008)

Ich habe mal eine kleine Skizze gemacht. Die Linie soll ihre Länge natürlich nicht verändern. Ich möchte quasi die Koordinaten des Start- und Endpunktes einer Linie um ein Rotationszentrum rotieren lassen. Dabei liegt nie einer der Punkte im Rotationszentrum.




Und richtig, ich benutze nicht Graphics2D.


----------



## Marco13 (17. Mrz 2008)

Schau mal hier
http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/AffineTransform.html#setToRotation(double,%20double,%20double)

Damit kannst du dann einzelne Punkte (oder ganze Arrays) transformieren
http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/AffineTransform.html#setToRotation(double,%20double,%20double)


----------



## 0x7F800000 (17. Mrz 2008)

http://de.wikipedia.org/wiki/Rotationsmatrix#Drehmatrix_der_Ebene_R.C2.B2
bei affinen transformationen fasst man zusätzlich 2D vektoren (x,y) zu 3-Tupeln (x,y,1) zusammen und transformiert die mit einer 3x3-Matrix, bei der in der dritten spalte zusätzlich die translation mit reingepackt ist... nur so, ein bisschen was zum hintergrund... schreib dir am besten schnell mal selbst eine klasse für die dreh und translationsmatrizen, das fördert das verständnis unheimlich...


----------



## Guest (17. Mrz 2008)

Vielen Dank für eure Antworten!

Ich werde mich da mal reinarbeiten ... auch wenn es nicht "schnell mal selbst eine Klasse schreiben" wird. Eine gute Übung ist das sicherlich allemal.


----------



## Guest (17. Mrz 2008)

Ui, das ist starker Tobak - bin kein Mathe- oder Informatiker. Habe doch erstmal die Klasse AffineTransform verwendet.

Das Rotieren um ein Rotationszentrum klappt schonmal wunderbar. Jetzt möchte ich aber noch eine rotierte Linie parallel verschieben. Und zwar entweder zum Rotationszentrum hin oder weg.

Doch dies klappt bisher genausowenig wie das auslesen der Koordianten des Start- und Endpunktes der rotierten Linie.

Würde mich über eure Hilfe sehr freuen!

Hier der aktuelle Code:


```
class MyPanel extends JPanel {
    
    public void MyPanel() {
        setBorder(BorderFactory.createLineBorder(Color.black));
    }
    
    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 400);
    }
    
    @Override
    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        
        // Setzen und Zeichnen der Ursprungslinie
        Line2D line = new Line2D.Double(100,100,100,150);
        g2d.draw(line);
        
        
        // Rotieren der Ursprungslinie um das Rotationszentrum (125,125)
        AffineTransform t = new AffineTransform();
        t.setToRotation(Math.toRadians(29), 125, 125);
        g2d.setTransform(t);
        g2d.setColor( Color.red );
        g2d.draw(line);
        
        // Ausgabe der Koordinaten der Linie
        System.out.println("=============================================================");
        System.out.println("Line: ("+line.getX1()+","+line.getY1()+" -> ("+line.getX2()+","+line.getY2()+")");
        System.out.println("=============================================================");
        
        // Parallelverschiebung der zweiten (roten) Linie ... klappt nicht
        t.setToTranslation(10, 10);
        g2d.setTransform(t);  
        g2d.setColor( Color.blue );
        g2d.draw(line);
    }
    
}
```


----------



## Marco13 (17. Mrz 2008)

Es gibt auch Leute, die in ihrem Garten Gemüse anbauen und keine Gärtner sind. Wenn man so etwas machen will, ist AffineTransform schon ein ziemlich praktisches Werkzeug, da braucht man sowas wie Homogene Koordinaten und Pojektionen auf die 3dimensionale Hyperebene gernicht verstanden zu haben - aber um ein paar Basics wird man nicht drumrumkommen.

Im Moment bewegst du die Linie nicht. Sie wird nur "gedreht gezeichnet". Wenn du die Linie wirklich drehen willst, darfst du die AffineTransform nicht im Graphics2D setzen, sondern musst sie wirklich auf die Endpunkte der Linie anwenden (wie ich auch schon angedeutet hatte - der zweite Link sollte nämlich hierhin
http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/AffineTransform.html#transform(java.awt.geom.Point2D,%20java.awt.geom.Point2D)
verweisen... :roll: )


```
AffineTransform t = new AffineTransform();
t.setToRotation(Math.toRadians(29), 125, 125); 
t.transform(line.getPoint1(), line.getPoint1());
t.transform(line.getPoint2(), line.getPoint2());
System.out.println("Line: ("+line.getX1()+","+line.getY1()+" -> ("+line.getX2()+","+line.getY2()+")"); // Müßte dann die gedrehten Koordinaten ausgeben
```

In bezug auf das zusätzliche Verschieben: Man kann mehrere AffineTransforms miteinander multiplizieren, und das Produkt dieser AffineTransforms ist dann wieder eine AffineTransform, die die _Hintereinanderausführung_ der einzelnen Bewegungen/Drehungen beschriebt.

```
AffineTransform t1 = new AffineTransform();
t1.setToRotation(Math.toRadians(29), 125, 125); 

AffineTransform t0 = new AffineTransform();
t0.setToTranslation(10,10);

AffineTransform tFinal = new AffineTransform(t0);
tFinal.concatenate(t1); // "Concatenate" heißt "verknüpfen", bzw. "miteinander multiplizieren"
tFinal.transform(line.getPoint2(), line.getPoint2()); // Bewirkt, dass der Punkt erst gedreht und dann verschoben wird
```
Beides ungetestet. Aber so in etwa.


----------



## Guest (18. Mrz 2008)

Vielen Dankl für die Antwort!

Das mit dem Drehen klappt jetzt sehr gut. Allerdings ist das verschieben nicht ganz das, was ich möchte.

Wie in der nachfolgenden Skizze verdeutlicht, möchte ich eine Linie parallel zur gedrehten Linie verschieben. Aber so, dass der Mittelpunkt (orange Markierung) der ursprünglichen Linie und der verschobenen Linie auf einem Radius vom Rotationszentrum zum Liegen kommt. D.h., dass sich die verschobenene Linie nur innerhalb der hellgrün markierten Grenzen bewegen darf.

Das Verschieben sollte so funktionieren, dass die Radiuslänge (also der Abstand des Mittelpunktes der Linie vom Rotationszentrum) gesetzt werden kann und alles andere berechnet wird.

Sowas sollte doch möglich sein, oder? Irgendwelche Ideen oder Vorschläge? 

Ich habe mich auch mal mit Geodreieck und Zirkel hingesetzt und ausprobiert. Das Rotieren des Start- und Endpunktes ist recht einfach mit den trigonomischen Funktiionen (sin, cos) zu bewerkstelligen. Hingegen habe ich für das Verschieben keine Lösung finden können.








```
@Override
    public void paintComponent(Graphics g) {
        Graphics2D g2d = (Graphics2D)g;
        
        // Zeichnen des Rotationszentrums
        Ellipse2D arc = new Ellipse2D.Double(200, 125, 2, 2);
        g2d.draw(arc);
        
        // Setzen und Zeichnen der Ursprungslinie
        Line2D line = new Line2D.Double(100,100,100,150);
        g2d.draw(line);
        System.out.println("=============================================================");
        System.out.println("Line 1: ("+line.getX1()+","+line.getY1()+" -> ("+line.getX2()+","+line.getY2()+")");
        
        // Rotieren der Ursprungslinie um das Rotationszentrum (125,125)
        AffineTransform t0 = new AffineTransform();
        Point2D p1 = new Point2D.Double();
        Point2D p2 = new Point2D.Double();
        t0.setToRotation(Math.toRadians(45), 200, 125);
        t0.transform(line.getP1(), p1);
        t0.transform(line.getP2(), p2);
        line.setLine(p1, p2);
        
        System.out.println("Line 2: ("+line.getX1()+","+line.getY1()+" -> ("+line.getX2()+","+line.getY2()+")");
        g2d.setColor( Color.red );
        g2d.draw(line);
        
        // Parallelverschiebung der zweiten (roten) Linie ... klappt nicht
        AffineTransform t1 = new AffineTransform();
        t1.setToRotation(Math.toRadians(29), 125, 125);
        
        AffineTransform t2 = new AffineTransform();
        t2.setToTranslation(30,3T0); 
        
        AffineTransform tf = new AffineTransform(t1); 
        tf.concatenate(t2);
        
        tf.transform(line.getP1(), p1);
        tf.transform(line.getP2(), p2);
        line.setLine(p1, p2);
        
        System.out.println("Line 3: ("+line.getX1()+","+line.getY1()+" -> ("+line.getX2()+","+line.getY2()+")");
        System.out.println("=============================================================");
        g2d.setColor( Color.blue );
        g2d.draw(line);
    }
```


----------



## Marco13 (18. Mrz 2008)

Schwarz, rot, magenta, blau - welche der Linien ist die original-Linie, welche die gedrehte, welche die verschobene? Auf welcher Linie soll die Verschiebung stattfinden?


----------



## Guest (18. Mrz 2008)

Die schwarze Linie ist die Ursprungslinie. Diese wurde um das Rotationszentrum (der kleine unscheinbare Punkt am linken unteren Ende der grünen Straße) gedreht und kommt als orange Linie zum Erliegen. Diese orange Linie ist okay (Rotation um 45 Grad).

Den Mittelpunkt der Linien habe ich mit einen orangen Punkt markiert.

Wenn man jetzt einen Radius, ausgehend vom Rotationszentrum, durch den Mittelpunkt der orangen Linie zeichnet, dann sollte es möglich sein, diese orange Linie auf dem Radius parallel zu verschieben. Entweder zum Rotationszentrum hin oder davon weg. Die rosa Linie wäre ein mögliches richtiges Resultat. In diesem Beispiel sollten es also nur Parallelverschiebungen der orangen Linie innerhalb der grünen Straße möglich sein.

Die blaue Linie hingegen ist das aktuelle Resulat. Die ist zwar innerhalb der grünen Straße, aber nicht parallel zur orangen Linie.

Das ferne Ziel ist es, dass ich per Klick mit der linken Maustaste die Linie setzen (das Rotationszentrum wird automatisch mit generiert), die Linie mit dem Mausrad um das Rotationszentrum drehen und mit zwei Keyboard-Tasten die Linie auf das Rotationszentrum zu und fort bewegen kann.
Naja, eigentlich werden es zwei Linien sein, die sich auf entgegengesetzten Seiten des Roationszentrums befinden werden.


----------



## Guest (18. Mrz 2008)

Ich glaube, ich habe die Lösung. Muss das mal ausprobieren.


----------



## Guest (20. Mrz 2008)

Es funktioniert!

Ich habe das jetzt so gemacht, dass ich, wenn der Radius verändert wurde, die Linie komplett neu rotieren lasse. Somit brauche ich nicht die rotierte Linie zum Rotationszentrum hin oder davon fort bewegen.

Allerdings habe ich zwei neue Probleme. ;-)

1)
Wenn ich die Linien mit

```
AffineTransform t = new AffineTransform();
t.setToRotation(Math.toRadians(angle), center.getX(), center.getY());
g2d.setTransform(t);
```
um das Rotationszentrum "Point2D center" rotieren lasse, dann werden offensichtlich die Dimensionen von JFrame und nicht JPanel zugrunde gelegt. In JPanel wird aber gezeichnet und JFrame hat damit nichts zu tun. Wie mache ich AffineTransform klar, dass er sich nur auf JPanel beziehen soll? Denn augenblicklich verzieht sich beim Rotieren alles nach oben (JFrame ist deutlich höher als JPanel).

2)
Ich habe eine Klasse "MyPanel" von JPanel abgeleitet und dort die Methode "paintComponent" überschrieben.

```
@Override
    public void paintComponent(Graphics g) {
        myLeftLine.paintLine(g, 0);        
        myRightLine.paintLine(g, 1);        
    }
```
Jetzt ist es so, dass diese Methode scheinbar "andauernd" aufgerufen wird. Auch ohne, dass ich Eigenschaften der Instanz der Klasse MyPanel veränder oder die Methode repaint() aufrufe.

Auf jeden Fall wird zeilenweise "check -> 1" und "check -> 2" in der Konsole gedruckt.

Woran liegt das?

```
class MyLine {
[...]

public void paintLine(Graphics g, int color) {
        if(x != 0 && y != 0) {
            
            Graphics2D g2d = (Graphics2D)g;
            AffineTransform t = new AffineTransform();
            
//            Point2D p0 = new Point2D.Double(x, y);
            Point2D p1 = new Point2D.Double(x, y + (LENGTH / 2));
            Point2D p2 = new Point2D.Double(x, y - (LENGTH / 2));
                    
            switch(color) {
                case 0: g2d.setColor(Color.ORANGE); break;
                case 1: g2d.setColor(Color.RED); break;
            }
            
            Line2D line = new Line2D.Double(p1, p2);
            System.out.println("check -> 1");
            
            if(angle != 0) {
                t.setToRotation(Math.toRadians(angle), center.getX(), center.getY());
                g2d.setTransform(t);
                System.out.println("check -> 2");
            }
            
            // Zeichnen der Linie
            g2d.draw(line);
            
            // Zeichnen des Rotationszentrums
            Ellipse2D dot = new Ellipse2D.Double(center.getX(), center.getY(), 2, 2);
            g2d.draw(dot);
        }
    }
}
```


----------



## Marco13 (20. Mrz 2008)

Hm. Zum 1: Wenn du dir das Rotationszentrum anzeigen läßt, sollte man eigentlich erkennen, worum genau rotiert wird. (D.h. mir ist nicht klar, wie es sich äußert, dass "die Dimensionen des JFrame zugrunde gelegt" werden).

Es kann (anfangs) SEHR verwirrend aussehen, wenn man Verschiebungen und Drehungen kombiniert. Es ist ja z.B. ein gewaltiger Unterschied, ob men ERST dreht und DANN verschiebt, oder umgekehrt....

2. Und wenn paintComponent immer wieder aufgerufen wird... Schau' mal, ob du irgendwo im Bereich der paintComponent-Methode ein "repaint()" aufrufst. Oder hast du irgendwo einen Thread, der irgendwelche Swing-Komponenten verändert oder so?


----------

