# Pfeil Klasse



## _fabi (6. Aug 2009)

Hallo!
ich habe mir eine eigene Pfeil-Klasse programmiert, der ich zwei Punkte übergebe und sie zeichnet dann einen Pfeil vom ersten zum zweiten Punkt. Ich habe die Klasse auch überladen, so dass ich Farbe, Strichdicke usw. ändern kann, aber das ist nicht das Problem.
Zuerst bin ich so vorgegangen, dass ich einfach eine Linie von P1 zu P2 zeichne und dann aus den Punkten den Winkel zwischen der Linie und der Horizontalen ausrechne. Dadurch kann ich dann das Koordinatensystem in den Endpunkt schieben und dann dort um diesen Winkel drehen und ein Dreieck (die Pfeilspitze) zeichen.
Das hat auch geklappt, nur hatte ich hier das Problem, dass ich, wenn ich einen Pfeil zeichne diesen nicht von P1 zu P2 zeichne, sondern noch ein bisschen weiter, weil ja die Spitze "obendrauf" gezeichnet wird. Dann habe ich das zu korrigieren versucht und bin auf das nächste Problem gestoßen, den Drehwinkel. irgendwie habe ich das mit der Drehung noch nicht richtig verstanden, denn manche Winkel klappen nicht, da wird dann die Vektorspitze wo anders oder falsch gezeichnet.
Ich werde jetzt auf jeden Fall weiter suchen ob ich da noch selbst draufkomme, aber wenn ihr es euch mal durchsehen könntet wäre super.

Hier der Code:
	
	
	
	





```
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;

public class myVector{
	/**zeichnet einen Vektorpfeil zwischen zwei Punkten (Point d, Point i)
	 * Point d= Startpunkt
	 * Point i= Endpunkt*/
	
	//variablen
	Point start = new Point();
	Point ende = new Point();
	Point origin= new Point(0, 0);
	int apex = 20;
	double winkel= 0;
	Color  color = Color.red;
	BasicStroke stroke1
	      = new BasicStroke(3.0f, BasicStroke.CAP_SQUARE,
	                         BasicStroke.JOIN_MITER);
	
	public myVector(Point d, Point i, Point Ursprung){	//d ist Startpunkt und i Endpunkt des Vektors
		start= d;
		ende= i;
		origin= Ursprung;
		}//public Vector(point, point)
	
	public myVector(Point d, Point i, Color c, BasicStroke stroke, int Apex, Point Ursprung){
		start= d;
		ende= i;
		color= c;
		stroke1= stroke;
		apex= Apex;
		origin= Ursprung;
	}//public Vector(point, point, color, stroke, apex
	
	void draw( Graphics gr){
		Polygon pfeil = new Polygon();
		Point eck1 = new Point();
		Point eck2 = new Point();
		
		if (start.y- ende.y!= 0){
			winkel=  Math.atan((ende.x- start.x)/(start.y- ende.y));	
                        //berechnet den drehwinkel für die Pfeilspitze aus den Punkten 'start' und 'ende'
		}
		else if (start.x> ende.x){
			winkel= Math.PI;
		}
		else if (start.x< ende.x){
			winkel= -Math.PI;
		}
		else {
			winkel= 2* Math.PI;
		}
		
		AffineTransform origTransform = ((Graphics2D) gr).getTransform();		
                //originaltransformation speichern

		AffineTransform transformer2= new AffineTransform();
		transformer2.translate(origin.x, origin.y);
		AffineTransform transformer = new AffineTransform();
	    transformer.translate(ende.x+ origin.x, ende.y+ origin.y- (int)(1.5* apex));
	    
	    //Rotation des Koordinatensystems
	    if (ende.y>= start.y && ende.x>= start.x) {
	        transformer.rotate (winkel );
	    }
	    else {
	    	transformer.rotate(winkel);
	    }
	    ((Graphics2D) gr).setTransform(transformer);
		
	    eck1.x = +apex/ 2;
		eck1.y = 0;
		eck2.x = -apex/ 2;
		eck2.y = 0;
		
		pfeil.addPoint(0, (int)(1.5* apex));
		pfeil.addPoint(eck1.x, eck1.y);
		pfeil.addPoint(eck2.x, eck2.y);
		Stroke stroke2 = ((Graphics2D) gr).getStroke();
		((Graphics2D) gr).setStroke(stroke1);
		gr.setColor(color);
		gr.fillPolygon(pfeil);
		
		((Graphics2D) gr).setTransform(transformer2);
	    gr.drawLine(start.x, start.y, ende.x, ende.y);
	    gr.fillOval(start.x- 3, start.y- 3, 6, 6);
	    ((Graphics2D) gr).setStroke(stroke2);
	    ((Graphics2D) gr).setTransform(origTransform);

	}//void draw
	
}//public class Vector
```

Vielen Dank,

Fabi


----------



## Landei (6. Aug 2009)

Ich weiß nicht, ob das jetzt dein Problem löst, aber die ganzen komplizierten Fälle bei atan kannst du knicken, wenn du Math.atan2 verwendest, das ganz genau für solche Winkelberechnungen da ist :-D


----------



## _fabi (13. Nov 2009)

Hallo!

ich bins wieder mal. Der Grund, warum ich hier so sporadisch am selben Problem schreibe ist, dass ich diese Klasse überall benutze, und bislang hat sie immer funktioniert. Jetzt habe ich aber ein Problem, da etwas nicht so klappt wie ich es mir vorgestellt habe. Ich wollte einen Pfeil zeichnen, der im Winkel variabel ist und habe deshalb Punkte übergeben mit sinus und cosinus, aber anstatt dass sich der Pfeil dreht wie der Winkel den ich einstelle (10°-80°) dreht er  sich nur im Bereich von 45°- 80°.

Ich habe jetzt hier mal die fertige Klasse reingestellt, ich versuche die Schritte zu erklären, wäre super, wenn ihr noch mal drüber schauen könntet.
Vielen Dank schon mal!


```
public class MyVector5{
	/**zeichnet einen Vektorpfeil zwischen zwei Punkten (Point d, Point i)
	 * Point d= Startpunkt
	 * Point i= Endpunkt*/
	
	//Variablen
	Point start = new Point();
	Point ende = new Point();
	Point origin= new Point();
	int apex = 10;
	int punkt = 0; //Punkt am Angriffspunkt zeichnen oder nicht
	double winkel= 0;
	double length;
	Point eck1 = new Point();
	Point eck2 = new Point();
	Point eck3 = new Point();
	Point rel = new Point();
	Polygon pfeil = new Polygon();
	Color  color = Color.red;
	BasicStroke stroke= new BasicStroke(3.0f, BasicStroke.CAP_SQUARE,
                       BasicStroke.JOIN_MITER);
    AffineTransform transformer = new AffineTransform();

public MyVector5(Point d, Point i, Color c, BasicStroke Stroke, int Apex, Point Ursprung, int x){
		start= d;               //Startpunkt des Pfeils
		ende= i;                //Endpunkt
		color= c;               //Farbe
		stroke= Stroke;      //Originalstrich
		apex= Apex;          //Pfeilspitzenlänge
		origin= Ursprung;    //aktueller Ursprung der Mainklasse
		punkt= x;              //Angriffspunkt zeichnen oder nicht
	}//public Vector(point, point, color, stroke, apex, x)
	
	void draw( Graphics gr){
		
		//originaleinstellungen speichern
		Stroke origstroke = ((Graphics2D) gr).getStroke();		
		AffineTransform origtransform= ((Graphics2D) gr).getTransform();
	    Color origcolor= ((Graphics2D) gr).getColor();	

	    //Drehwinkel berechnen
		rel.x = ende.x- start.x;
		rel.y = ende.y- start.y;
		winkel= Math.atan2(rel.y, rel.x);
	        length= Math.sqrt(rel.x* rel.x + rel.y* rel.y);
	    
	    //Pfeilspitze initialisieren
	    eck1.x= (int)(length- apex);
	    eck1.y= 7;
	    eck2.x= (int)(length- apex+ 3);
	    eck2.y= 0;
	    eck3.x= (int)(length- apex);
	    eck3.y= -7;
	 
	    
	    //Verschiebung des Koordinatensystems
		transformer.translate(origin.x+ start.x, origin.y+ start.y);
	    transformer.rotate(winkel);
		((Graphics2D) gr).setStroke(stroke);
	    ((Graphics2D) gr).setTransform(transformer);
	    ((Graphics2D) gr).setColor(color);
	   
	    pfeil.addPoint(eck1.x, eck1.y);
	    pfeil.addPoint(eck2.x, eck2.y);
	    pfeil.addPoint(eck3.x, eck3.y);
	    pfeil.addPoint((int) (length), 0);
	    
	    gr.drawLine(0, 0, (int) (length)- apex+ 3, 0);
	    gr.fillPolygon(pfeil);
	    if(punkt== 1){
		    gr.drawOval(-2, -2, 3, 3);
		}
	    
	    ((Graphics2D) gr).setTransform(origtransform);
	    ((Graphics2D) gr).setStroke(origstroke);
	    ((Graphics2D) gr).setColor(origcolor);
	    

	}//void draw
	
}//public class Vector
```


Mein Hauptproblem ist denke ich, dass ich nicht genau weiss, was die Funktion Math.atan2 bewirkt, bzw. welchen Winkel sie berechnet. Ich habe deshalb einmal aufgezeichnet (siehe Anhang) welcher Winkel hier meiner Meinung nach berechnet wurde.

Vielen Dank noch mal für eure Zeit,
lg

Fabi


----------



## _fabi (15. Nov 2009)

Hi!

gibt's denn niemanden, der mir das kurz mal durchschauen könnte bitte?


----------



## Marco13 (15. Nov 2009)

Gibt's denn keinen der ein KSKB bauen kann?

```
// From http://www.java-forum.org/java-basics-anfaenger-themen/86645-pfeil-klasse.html

import java.awt.*;
import java.awt.geom.*;
import javax.swing.*;


class ArrowTest extends JPanel
{
    public static void main(String args[])
    {
        JFrame f = new JFrame();
        final ArrowTest arrowTest = new ArrowTest();
        f.getContentPane().setLayout(new GridLayout(1,1));
        f.getContentPane().add(arrowTest);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(600,600);
        f.setVisible(true);


        Thread t = new Thread(new Runnable()
        {
            public void run()
            {
                int a = 0;
                while (true)
                {
                    a = (a+1) % 360;
                    arrowTest.v0.setAngle(a);
                    arrowTest.repaint();
                    try{Thread.sleep(10);}catch(Exception e){}
                }
            }
        });
        t.start();

    }

    MyVector5 v0 = new MyVector5(new Point(100,100), new Point(200,100), 20, new Point(0,0), 1);


    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        v0.draw(g);
    }




}




class MyVector5{
    /**zeichnet einen Vektorpfeil zwischen zwei Punkten (Point d, Point i)
     * Point d= Startpunkt
     * Point i= Endpunkt*/

    //Variablen
    Point start = new Point();
    Point ende = new Point();
    Point origin= new Point();
    int apex = 10;
    int punkt = 0; //Punkt am Angriffspunkt zeichnen oder nicht
    double winkel= 0;
    double length;
    Point eck1 = new Point();
    Point eck2 = new Point();
    Point eck3 = new Point();
    Point rel = new Point();
    Polygon pfeil = new Polygon();
    Color  color = Color.red;
    BasicStroke stroke= new BasicStroke(3.0f, BasicStroke.CAP_SQUARE,
                       BasicStroke.JOIN_MITER);
    AffineTransform transformer = new AffineTransform();


    public void setAngle(double angleDeg)
    {
        double a = Math.toRadians(angleDeg);
        double x1 = 100 + 100 * Math.cos(a);
        double y1 = 100 + 100 * Math.sin(a);
        ende = new Point((int)x1, (int)y1);
    }



public MyVector5(Point d, Point i, int Apex, Point Ursprung, int x){
        start= d;               //Startpunkt des Pfeils
        ende= i;                //Endpunkt
        apex= Apex;          //Pfeilspitzenlänge
        origin= Ursprung;    //aktueller Ursprung der Mainklasse
        punkt= x;              //Angriffspunkt zeichnen oder nicht
    }//public Vector(point, point, color, stroke, apex, x)

    void draw( Graphics gr){
        Graphics2D g = (Graphics2D) gr;

        gr.setColor(Color.BLACK);

        //originaleinstellungen speichern
        //Stroke origstroke = g.getStroke();
        AffineTransform origtransform= g.getTransform();
        //Color origcolor= g.getColor();

        //Drehwinkel berechnen
        rel.x = ende.x- start.x;
        rel.y = ende.y- start.y;
        winkel= Math.atan2(rel.y, rel.x);
            length= Math.sqrt(rel.x* rel.x + rel.y* rel.y);

        //Pfeilspitze initialisieren
        eck1.x= (int)(length- apex);
        eck1.y= 7;
        eck2.x= (int)(length- apex+ 3);
        eck2.y= 0;
        eck3.x= (int)(length- apex);
        eck3.y= -7;

        //Verschiebung des Koordinatensystems
        transformer.setToIdentity();
        transformer.translate(origin.x+ start.x, origin.y+ start.y);
        transformer.rotate(winkel);
        //g.setStroke(stroke);
        g.transform(transformer);
        //g.setColor(color);

        pfeil.addPoint(eck1.x, eck1.y);
        pfeil.addPoint(eck2.x, eck2.y);
        pfeil.addPoint(eck3.x, eck3.y);
        pfeil.addPoint((int) (length), 0);

        gr.drawLine(0, 0, (int) (length)- apex+ 3, 0);
        gr.fillPolygon(pfeil);
        if(punkt== 1){
            gr.drawOval(-2, -2, 3, 3);
        }

        g.setTransform(origtransform);

        //g.setStroke(origstroke);
        //g.setColor(origcolor);


    }//void draw

}//public class Vector
```

Was ist die Frage?


----------



## _fabi (15. Nov 2009)

Die Frage ist, ob der Pfeil so, wie ich die Math.atan2-Funktion so richtig benutzt habe. Ich weiss nicht, ob ich den Pfeil richtig gedreht habe.
Vielen Dank,

Fabi


----------



## rocknralle (15. Nov 2009)

dir ist aber klar dass z.B. "math.atan" als bogenmaß berrechnet wird.
wenn du den winkel in grad umrechnen willst, musst du das folgendermaßen machen:

gradwinkel =winkel*180/Math.PI

oder 

gradwinkel =Math.toDegrees(winkel)


----------



## _fabi (15. Nov 2009)

ja, aber da man bei AffineTransform.rotate den Winkel auch im Bogenmaß benötigt und das das einzige ist wo ich ihn einsetze ist das egal denke ich. Mein Problem ist nur, welcher Winkel in einem Dreieck von Math.atan2 denn berechnet wird.
Aber danke trotzdem.


----------



## rocknralle (16. Nov 2009)

Referenz: java.lang.Math

http://i.msdn.microsoft.com/ms973830.designsurface_03(de-de,MSDN.10).gif

ich könnte mir vorstellen dass die zwei links evtl. helfen könnten


----------



## rocknralle (16. Nov 2009)

http://almaer.com/blog/uploads/atan2.png

hier ist auch noch ein schönes bild


----------



## 0x7F800000 (16. Nov 2009)

vielleicht nützt's dir ja was...

```
package gui;

import java.awt.*;
import java.awt.geom.*;

/**
 * This class contains only static methods that might be useful while drawing with Java2D.
 * 
 * @author 0x7F800000
 *
 */

public class VisualizationUtils {
	
	//should not be instantiated
	private VisualizationUtils(){}
	
	/**
	 * Creates a shape that looks like a very basic arrow.
	 * 
	 * This method creates a shape, that looks like the most basic straight arrow 
	 * consisting of three line segments and pointing from first to the second point.
	 * 
	 * @param from			first point, where the arrow starts
	 * @param to			second point, where the arrow points to
	 * @param headLength	length of the arrow head
	 * @param headWidth		width of the arrow head
	 * @return				Shape of an arrow from point "from" to point "to" with specified head dimensions
	 */
	public static Shape createThinArrow(Point2D from, Point2D to, double headLength, double headWidth){
		
		headWidth/=2;
		GeneralPath result=new GeneralPath();
		
		//shaft
		result.append(new Line2D.Double(from,to),false);
		
		//head
		double 	ax=to.getX()-from.getX(),
				ay=to.getY()-from.getY(),
				aLen=Math.sqrt(ax*ax+ay*ay);
		
		ax/=aLen;
		ay/=aLen;
		
		result.append(new Line2D.Double(to,new Point2D.Double(to.getX()-headLength*ax+headWidth*ay,to.getY()-headLength*ay-headWidth*ax)),false);
		result.append(new Line2D.Double(to,new Point2D.Double(to.getX()-headLength*ax-headWidth*ay,to.getY()-headLength*ay+headWidth*ax)),false);
		return result;
	}
	
	/**
	 * Creates a shape that looks like a basic arrow with a triangular head.
	 * 
	 * This method creates a shape, that looks like a basic straight arrow with fillable triangular head.
	 * The arrow is pointing from first to the second point.
	 * 
	 * @param from			first point, where the arrow starts
	 * @param to			second point, where the arrow points to
	 * @param headLength	length of the arrow head
	 * @param headWidth		width of the arrow head
	 * @return				Shape of an arrow from point "from" to point "to" with specified head dimensions
	 */
	
	public static Shape createTriangleArrow(Point2D from, Point2D to, double headLength, double headWidth){
		
		headWidth/=2;
		
		double 	ax=to.getX()-from.getX(),
				ay=to.getY()-from.getY(),
				aLen=Math.sqrt(ax*ax+ay*ay);
		ax/=aLen;
		ay/=aLen;
		
		
		GeneralPath result=new GeneralPath();
		//head
		result.moveTo(to.getX(),to.getY());
		result.lineTo(to.getX()-headLength*ax+headWidth*ay,	to.getY()-headLength*ay-headWidth*ax);
		result.lineTo(to.getX()-headLength*ax-headWidth*ay,	to.getY()-headLength*ay+headWidth*ax);
		result.closePath();
		
		result.append(new Line2D.Double(from,new Point2D.Double(to.getX()-headLength*ax,to.getY()-headLength*ay)), false);
		
		return result;
	}
	
	/**
	 * Derives a transparent color from the actual color of the passed Graphics2D-object and fills the shape, finally switching the color back. 
	 *
	 * @param g			graphics context to draw with
	 * @param s			shape to be filled with a transparent derivation of actual color
	 * @param alpha		alpha-value of the color to fill the shape with
	 */
	
	public static void drawTransparentFill(Graphics2D g, Shape s, int alpha){
		Color temp=g.getColor();
		g.setColor(new Color(temp.getRed(),temp.getGreen(),temp.getBlue(),alpha));
		g.fill(s);
		g.setColor(temp);
	}
}
```
Die Pfeilchen sehen einigermaßen ordentlich aus, schön dreieckig, nach Wunsch mit halbtransparentem Pfeilkopf


----------



## _fabi (16. Nov 2009)

hmm... verstehe das dann nicht. eigentlich müsste ich dann ja alles richtig gemacht haben...
Warum liefert dann der folgende Befehl:

```
Point startF= new Point( 250, 200);
Point endeF= new Point((int)(300* Math.cos(TETHA)), (int)(300* Math.sin(TETHA)));
MyVector5 vectorF= new MyVector5(startF, endeF);
vectorF.draw(g);
```
keinen Pfeil der sich mit dem Winkel Tetha dreht, obwohl der Winkel (in Radians) sicher richtige Werte annimmt?

danke für die Zeichnungen!


----------



## Marco13 (16. Nov 2009)

Das Ende ist um den Ursprung rotiert.

Point endeF= new Point(*250+*(int)(300* Math.cos(TETHA)), *200+*(int)(300* Math.sin(TETHA)));


----------



## _fabi (17. Nov 2009)

Vielen Vielen Dank!

bin ja so froh, dass meine Pfeil-klasse funktioniert!
danke nochmal an alle,
lg 

Fabi


----------

