# rotate Text wird verschoben angezeigt?



## malufi89 (2. Nov 2011)

Hallo zusammen.

ich habe eine Funktion die mir eine Linie zeichnet, danach den Neigungswinkel dieser Linie berechnet und dann eine Schrift in diesem Winkel zeichnet.
Die Funktion sieht in etwa so aus:


```
zeichnePfeil(int x1, int y1, int x2, int y2, String name){
pfeil.drawLine(x1, y1, x2, y2);
double angle=Math.atan2(y2 - y1, x2 - x1) * 180 /Math.PI;
pfeil.rotate(angle);
pfeil.drawString(name, (x1+((x2-x1)/2), (y1+((y2-y1)/2));
}
```

Die schrift hat den richtigen winkel, wird aber vollkommen versetzt angezeigt. auch wenn ich pfeil.drawString(name, x1, y1) angebe, steht der Text dann abseits von gut und böse!
Warum ist das so? Wie kann ich den Punkt richtig berechnen? (Der Text soll also relativ mittig auf der Linie stehen).

Danke und Liebe Grüße


----------



## malufi89 (2. Nov 2011)

entschuldigt bitte - ich habe die Lösung (translate) soeben selbst entdeckt... die api doku muss man lesen, gelle?

sorry...


----------



## malufi89 (2. Nov 2011)

ich habe das ganze gerade mal probiert.
leider treten minimale, aber sehr unschöne abweichungen auf.
ich könnte mir vorstellen dass das an rundungsfehlern liegt, weiß aber nicht wo der rundungsfehler auftritt? Oder vielleicht ist es kein Rundungsfehler?

anbei der code.

```
private void zeichneSymbolPfeil(int i, int j, int k, int l, String firstname) {
		string.setColor(Color.black);
		form = new Line2D.Double(i, j, k, l);
		string.setFont(font);
		string.setColor(Color.black);
		string.setStroke(dicke(symbolfarbenranddicke));
		string.setColor(symbolrandfarbe);
		string.setStroke(dicke(symbolranddicke));
		string.draw(form);
		//Länge der Ankathete per Satz des Phytagoras rausbekommen
                double length= Math.sqrt(((k-i)*(k-i))+((l-j)+(l-j)));
		System.out.println("length:" + length);
		//cos(alph) kriegen
                double angle1= (k-i)/length;
		System.out.println("angle1:" + angle1);
                //winkel kriegen
		double angle = Math.cos(angle1);
		System.out.println(angle);
                //neuen Nullpunkt setzen
		string.translate((i+((k-i)/2)),(j+((l-j)/2)));
		string.rotate(angle);
		string.drawString(firstname, 0, 0);
	}
```

achso. die ausgaben sind:
length:160.31219541881399
angle1:0.9980525784828885
angle:0.5419399789996303

und k-i war in dem betreffenden fall 160

das sieht dann so aus:


----------



## malufi89 (2. Nov 2011)

und ich habe leider gleich noch eine frage:
wie kann ich denn die rotation wieder aufheben? 
irgendwie zeichnet es mir jetzt alles rotiert, wenn ich einmal rotiert habe :/


----------



## Gassst (2. Nov 2011)

Deine Mathematik ist einfach falsch, zum einen hast du im Pythagoras ein + wo ein * stehen muss und zum anderen musst du cos^-1 berechnen von angle1, nicht cos, angle1 ist doch der cosinus.
dein "length" ist übrigens die hypothenuse nicht die ankathete wie im Kommentar geschrieben.


----------



## Gassst (2. Nov 2011)

malufi89 hat gesagt.:


> und ich habe leider gleich noch eine frage:
> wie kann ich denn die rotation wieder aufheben?
> irgendwie zeichnet es mir jetzt alles rotiert, wenn ich einmal rotiert habe :/


Wieder zurückrotieren?


----------



## Marco13 (2. Nov 2011)

'string' ist wohl unpassendSTerweise ein Graphics2D? Da kann man sich am Anfang einmal die AffineTransform holen (mit getTransform) und die am Ende wieder setzen (setTransform - dort ist in der Doku auch Beispielcode). Alternativ KANN es manchmal Sinn machen, sich mit g.create() ein "neues" Graphics2D zu erstellen, das man am Ende mit 'dispose()' wieder freigibt.


----------



## malufi89 (3. Nov 2011)

vielen dank schonmal. das mit dem affine transform ist ja ganzschön nett.

allerdings stimmt die berechnung vom winkel nun wohl garnicht mehr - die schrift steht jetzt im rechten winkel auf der Linie - ja noch nicht mal das!

bitte hilfe :/ ich glaube jetzt funktionieret das translate nicht mehr wie ich möchte...


```
double length= Math.sqrt(((k-i)*(k-i))+((l-j)*(l-j)));
		System.out.println("length:" + length);
		double angle1= (k-i)/length;
		System.out.println("angle1:" + angle1);
		double angle = Math.acos(angle1) * 180/Math.PI;;
		System.out.println(angle);
		
		AffineTransform trans = new AffineTransform(); 
		trans.rotate(angle); 
		trans.translate((i+((k-i)/2)),(j+((l-j)/2)));
		
		string.setTransform(trans); 
		string.drawString(firstname, 0, 0);
		string.setTransform(origTransform);
```


----------



## Gasssst (3. Nov 2011)

Wo kommt das *180/PI plötzlich her? Außerdem hast du rotate und translate in der falschen Reihenfolge...


----------



## malufi89 (3. Nov 2011)

tut mir leid ich dachte so kriege ich das mit dem cos^-1 hin??

PS: Habs weggenommen und es klappt. super!!! vielen dank!


----------



## Marco13 (3. Nov 2011)

Lies' dir die Doku zu 'setTransform' durch! Man sollte das NICHT so verwenden, wie du es jetzt machst!!!


----------



## malufi89 (3. Nov 2011)

```
AffineTransform saveAT = string.getTransform();

		AffineTransform trans = new AffineTransform(); 
		trans.translate((i+((k-i)/2)),(j+((l-j)/2)));
		trans.rotate(angle); 
				
		string.setTransform(trans); 
		string.drawString(firstname, 0, 0);
		System.out.println("I printed " + firstname);
		string.setTransform(saveAT);
```

ist das so besser, oder soll ich dann das trans rausnehmen und string selbst verändern?


----------



## Marco13 (3. Nov 2011)

Nein, wie in setTransform beschrieben:

```
AffineTransform saveAT = string.getTransform();
 
        string.translate((i+((k-i)/2)),(j+((l-j)/2)));
        string.rotate(angle); 
        string.drawString(firstname, 0, 0);
        System.out.println("I printed " + firstname);

        string.setTransform(saveAT);
```

ansonsten wäre ein KSKB natürlich praktisch


----------



## malufi89 (5. Nov 2011)

sagt mal die berechnung müsste doch für alle winkel funktionieren, oder?

manchmal klappts nämlich und manchmal nicht. ich vermute ja fast dass das was mit den winkeln zu tun hat? ich habe keine ahnung woran es liegt, dass es manchmal nicht geht... hiernochmal der aktuelle code:

```
private void zeichneSymbolPfeil(int i, int j, int k, int l, String firstname) {
		string.setColor(Color.black);
		form = new Line2D.Double(i, j, k, l);
		string.setFont(font);
		string.setColor(Color.black);
		string.setStroke(dicke(symbolfarbenranddicke));
		string.setColor(symbolrandfarbe);
		string.setStroke(dicke(symbolranddicke));
		string.draw(form);

		//WInkel für die Schrift berechnen
		double length= Math.sqrt(((k-i)*(k-i))+((l-j)*(l-j)));
		double angle1= (k-i)/length;
		double angle = Math.acos(angle1);
		//Affine transform erstellen
		AffineTransform saveAT = string.getTransform();
		//String drehen
		string.translate((i+((k-i)/2)),(j+((l-j)/2)));
		string.rotate(angle); 
		string.drawString(firstname, 0, 0);

		string.setTransform(saveAT);
	}
```

achso und falls das wichtig ist: es gibt noch ein anderes graphics ding mit dem ich zeichne, das heißt "zeichnung". Da arbeite ich aber nicht mit transform...


----------



## André Uhres (5. Nov 2011)

Marco13 hat gesagt.:


> ansonsten wäre ein KSKB natürlich praktisch




```
import java.awt.*;
import java.awt.geom.*;
import java.awt.geom.Line2D.Double;
import javax.swing.*;
import javax.swing.event.*;

public class Testing {

    private final JSpinner s1, s2, s3, s4;

    public Testing() {
        JFrame frame = new JFrame("KSKB");
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setLocationRelativeTo(null);
        final Drawings drawings = new Drawings(50, 100, 300, 100, "aha");
        frame.add(drawings);
        JToolBar tools = new JToolBar("Tools");
        frame.add(tools, BorderLayout.PAGE_START);
        ChangeListener changeHandler = new ChangeListener() {

            @Override
            public void stateChanged(final ChangeEvent e) {
                JSpinner source = (JSpinner) e.getSource();
                if (source == s1) {
                    drawings.setI((Integer) s1.getValue());
                } else if (source == s2) {
                    drawings.setJ((Integer) s2.getValue());
                } else if (source == s3) {
                    drawings.setK((Integer) s3.getValue());
                } else if (source == s4) {
                    drawings.setL((Integer) s4.getValue());
                }
                drawings.repaint();
            }
        };
        s1 = new JSpinner();
        s2 = new JSpinner();
        s3 = new JSpinner();
        s4 = new JSpinner();
        JLabel l1 = new JLabel("    i ");
        JLabel l2 = new JLabel("    j ");
        JLabel l3 = new JLabel("    k ");
        JLabel l4 = new JLabel("    l ");
        tools.add(l1);
        tools.add(s1);
        tools.add(l2);
        tools.add(s2);
        tools.add(l3);
        tools.add(s3);
        tools.add(l4);
        tools.add(s4);
        s1.setValue(drawings.getI());
        s2.setValue(drawings.getJ());
        s3.setValue(drawings.getK());
        s4.setValue(drawings.getL());
        s1.addChangeListener(changeHandler);
        s2.addChangeListener(changeHandler);
        s3.addChangeListener(changeHandler);
        s4.addChangeListener(changeHandler);
        frame.setVisible(true);
    }

    public static void main(final String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                Testing test = new Testing();
            }
        });
    }

    private class Drawings extends JPanel {

        private Graphics2D string;
        private Double form;
        private Font font;
        private int symbolfarbenranddicke = 1;
        private int symbolranddicke = 1;
        private Color symbolrandfarbe = Color.BLACK;
        private int i, j, k, l;
        private final String firstname;

        Drawings(final int i, final int j, final int k, final int l, final String firstname) {
            this.i = i;
            this.j = j;
            this.k = k;
            this.l = l;
            this.firstname = firstname;
        }

        @Override
        protected void paintComponent(final Graphics g) {
            super.paintComponent(g);
            string = (Graphics2D) g;
            zeichneSymbolPfeil(i, j, k, l, firstname);
        }

        private void zeichneSymbolPfeil(final int i, final int j,
                final int k, final int l, final String firstname) {
            string.setColor(Color.black);
            form = new Line2D.Double(i, j, k, l);
            string.setFont(font);
            string.setColor(Color.black);
            string.setStroke(dicke(symbolfarbenranddicke));
            string.setColor(symbolrandfarbe);
            string.setStroke(dicke(symbolranddicke));
            string.draw(form);
            //WInkel für die Schrift berechnen
            double length = Math.sqrt(((k - i) * (k - i)) + ((l - j) * (l - j)));
            double angle1 = (k - i) / length;
            double angle = Math.acos(angle1);
            //Affine transform erstellen
            AffineTransform saveAT = string.getTransform();
            //String drehen
            string.translate((i + ((k - i) / 2)), (j + ((l - j) / 2)));
            string.rotate(angle);
            string.drawString(firstname, 0, 0);
            string.setTransform(saveAT);
        }

        private Stroke dicke(final int symbolfarbenranddicke) {
            return new BasicStroke(symbolfarbenranddicke);
        }

        private void setI(final int integer) {
            i = integer;
        }

        private void setJ(final int integer) {
            j = integer;
        }

        private void setK(final int integer) {
            k = integer;
        }

        private void setL(final int integer) {
            l = integer;
        }

        public int getI() {
            return i;
        }

        public int getJ() {
            return j;
        }

        public int getK() {
            return k;
        }

        public int getL() {
            return l;
        }
    }
}
```


----------



## André Uhres (5. Nov 2011)

malufi89 hat gesagt.:


> manchmal klappts nämlich und manchmal nicht. ich vermute ja fast dass das was mit den winkeln zu tun hat?



Da hast du wohl recht. Das Problem scheint mit dem Vorzeichen des Winkels zusammen zu hängen. Versuch's mal mit [c]angle = j > l ? -angle : angle;[/c]. 

Im Fall von (i > k) gibt es allerdings auch ein Problem, denn dann steht der Text auf dem Kopf. So was könnte in dem Fall helfen (wenn dieser Fall überhaupt eintreten kann):

```
if(i > k){
    angle = Math.toRadians(180) - angle;
    angle = j > l ? angle : -angle;
}else{
    angle = j > l ? -angle : angle;
}
```
Vielleicht gibt's auch noch eine elegantere Lösung. Ich bin in Mathe nicht so fit .

Gruß,
André


----------



## malufi89 (5. Nov 2011)

klasse, jetzt geht es wieder! Und ja, den fall gab es!

nur um sicherzustellen dass ich verstehe was das macht:
wenn i>k wird angle zuerst gleich Math.toRadiants/(180)-angle gesetzt. (d.h. der Text bzw der winkel wird schonmal um 180 Grad gedreht?)
die zeile darunter verstehe ich nicht genau.... ich kenne weder ? als operator noch weiß ich genau genug was das ":" macht... du musst es mir nicht erklären, aber kannst du mir ein stichwort geben, wo ich das nachlesen kann?

jedenfalls: wenn i nicht größer ist als k, wird der winkel nicht um 180° verändert.

und für das nächste mal: KSKB ist ein ausführbares Programm? Ich bin mit solchen Kürzeln weniger vertraut, deshalb habe ich darauf nicht reagiert... war nicht aus faulheit.


----------



## Marco13 (5. Nov 2011)

malufi89 hat gesagt.:


> und für das nächste mal: KSKB ist ein ausführbares Programm? Ich bin mit solchen Kürzeln weniger vertraut, deshalb habe ich darauf nicht reagiert... war nicht aus faulheit.



Das steht auch da, wenn man mit der Maus über KSKB drüberfährt: Kleines, Selbstständig Kompilierbares Beispiel. Hilft solche Fehler nachzuvollziehen. Wenn man jeden Tag "viele" Fragen beantworten will (oder könnte), man aber für jedes erstmal eine Testklasse drumrumstricken müßte, kostet das viel Zeit, und es ist wohl nicht zu viel verlangt, wenn der Fragesteller dem helfen wollenden da etwas entgegenkommt...


----------



## André Uhres (5. Nov 2011)

malufi89 hat gesagt.:


> d.h. der Text bzw der winkel wird schonmal um 180 Grad gedreht?
> ich kenne weder ? als operator noch weiß ich genau genug was das ":" macht



Da der Text bei (i > k) auf dem Kopf steht (das kannst du ja mit dem KSKB testen), muss um 180 Grad gedreht werden. Das geschieht mit [c]angle = Math.toRadians(180) - angle;[/c]. [c]A ? B : C[/c] ist der Bedingungsoperator. Da bei (j > l) der Text in die entgegengesetzte Richtung dreht (das kannst du ebenfalls mit dem KSKB testen), muss das Vorzeichen in dem Fall einfach umgedreht werden. Man kann den Code allerdings noch kürzen, etwa so:

```
if (i > k) {
    angle -= Math.toRadians(180);
}
angle = j > l ? -angle : angle;
```

Gruß,
André


----------



## malufi89 (6. Nov 2011)

Ich schreibe hier gleich nochmal rein: Ich will dieses Bild, das in einem neuen Frame erzeugt wird speichern als PNG.
Das funktioniert tadellos - also das Bilöd wird so erzeugt, wie ich möchte. 

```
speicherLeeren();
    	    	savePicture(paintComponent(zeichenpanel), "screen.png");
```


```
private static void savePicture(BufferedImage img, String file) {
		 try {
		      ImageIO.write(img, "png", new File(file));
		    }
		    catch (IOException e) {
		      e.printStackTrace();
		    }
		  }
private static BufferedImage paintComponent(JPanel zeichenpanel2) {
		BufferedImage img = new BufferedImage(zeichenpanel2.getWidth(), zeichenpanel2.getHeight(), BufferedImage.TYPE_INT_RGB);
	    Graphics2D g = img.createGraphics();
	    zeichenpanel2.paintAll(g);
	    g.dispose();
	    return img;
	}
```

ich befürchte, dass jedoch durch die paint component methode, wie sie ist, wird nicht komplett neu gezeichnet, sondern "weiter gezeichnet". Die X und Y werte werden automatisch berechnen und stehen in Array Lists. die habe ich vor dem Zeichnen mit speicherLeeren() geleert. Dennoch wird meine Zählvariable i (nicht Static) weiter hochgezählt. (d.h. wenn bei der ersten Zeichnung i bei 3 war, dann zählt es jetzt hoch bis 7) das bedingt dass die Grafik total verschoben ist.

ich kann es mir nicht so recht erklären, denn i wird zurück auf 0 gesetzt, bevor die schleife startet: (unten seht ihr auch, warum dann alles verschoben ist. da kann ich posX und posY zurücksetzen wie ich will... ich habe keine ahnung warum i echt so weit hochzählt... )

```
@Override 
	protected void paintComponent(Graphics grafik) 
	{ 
		super.paintComponent(grafik);
		int i= 0;
		int z=12;
		zeichnung = (Graphics2D) grafik;
		zeichnung.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		origTransform = zeichnung.getTransform();
		
		
		while (i<Knoten.getKnoten().size()){
			string = (Graphics2D) grafik;
		string.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
			if(i==0){
				border=2;
			}
			else{
				border=1;
			}
			if (Knoten.formen.get(i).equals("rectangular")==true){
				symbol=1;
			}
			else{
				symbol=2;
			}
			
			name=Knoten.namen.get(i);
			// Zeichne Symbole
			positionSymboleX = 10;
			positionSymbolMitteY = 10;
			switch (border) {
			case 1:
				zeichneSymbol(positionSymboleX+posX, positionSymbolMitteY+posY, symbolbreite, symbolhoehe, symbol, name, i);
				break;
			case 2:
				
				zeichneSymbol(250+posX, positionSymbolMitteY+posY, symbolbreite, symbolhoehe, symbol, name, i);
				zeichneSymbol(250+posX-5, positionSymbolMitteY+posY-5,symbolbreite+10, symbolhoehe+10, symbol, "", i);
				posX_to_up.add(0, 250+posX+80);
				posY_to_up.add(0,positionSymbolMitteY);
				posX_to_left.add(0,250+ posX);
				posY_to_left.add(0,positionSymbolMitteY+45);
				posX_to_down.add(0,250+ posX+80);
				posY_to_down.add(0,positionSymbolMitteY+85);
				break;
			}
			if(i%2==0){
					if(i==0){
						posX=posX+120;
						posY=posY+150;
					}
					else{
						posX=(i*30)+120+(2*z);
						posY=posY+130;
					}
			}
			else if(i%2==1){
				posX=posX+350;
			}
			
			...
			
			}
			i++;
			
		}
		starteBerechnung();
	}
```


----------



## malufi89 (6. Nov 2011)

Ich habe den Fehler mal wieder selber gefunden und behoben:

I wurde weiter hochgezählt weil ich ne whileschleife mit nem array drinne hatte, das ich irgendwo auf größe 200 festgelegt hatte 
der andere fehler war genauso dämlich: beim Schreiben der getter und setter für PosX und PosY habe ich

public void getPosX(int neueZahl){
   neueZahl=posX;
}

geschrieben... statt anders rum... au man... :noe:


----------



## André Uhres (7. Nov 2011)

Anstatt "paintAll" versuch's mal mit 
	
	
	
	





```
print
```
: 
	
	
	
	





```
zeichenpanel2.print(g);
```
Du kannst eventuell auch noch die 
	
	
	
	





```
print
```
 Methode in deiner ZeichenPanel-Klasse überschreiben, um Initialisierungen vorzunehmen bevor du 
	
	
	
	





```
super.print(g)
```
 aufrufst. Beispiel:

```
@Override
public void print(Graphics g) {
    speicherLeeren();
    super.print(g);
}
```
Oder um beispielsweise den Hintergrund zu ändern:

```
@Override
public void print(Graphics g) {
    Color orig = getBackground();
    setBackground(Color.WHITE);

    // wrap in try/finally so that we always restore the state
    try {
        super.print(g);
    } finally {
        setBackground(orig);
    }
}
```
Gruß,
André


----------



## malufi89 (7. Nov 2011)

warum verwendet man denn da print statt paint?

gibt es da einen vorteil in der situation?


----------



## André Uhres (7. Nov 2011)

Die Methode [c]public void print (Graphics g)[/c] ist leistungsfähiger, weil die Doppelpufferung während des Vorgangs ausgeschaltet wird (in dieser Situation wäre sie nur hinderlich). Sie bietet zudem eine einfache Möglichkeit der Druckanpassung durch Überschreiben von print (wie bereits oben gezeigt wurde) und/oder printComponent.

Gruß,
André


----------

