01: import java.awt.Color;
02: import java.awt.Graphics2D;
03: import java.awt.geom.GeneralPath;
04: import java.awt.geom.Point2D;
05: 
06: /**
07:    This class defines arrowheads of various shapes.
08: */
09: public enum ArrowHead
10: {
11:    NONE, TRIANGLE, BLACK_TRIANGLE, V, DIAMOND, BLACK_DIAMOND;
12: 
13:    /**
14:       Draws the arrowhead.
15:       @param g2 the graphics context
16:       @param p a point on the axis of the arrow head
17:       @param q the end point of the arrow head
18:    */
19:    public void draw(Graphics2D g2, Point2D p, Point2D q)
20:    {
21:       GeneralPath path = getPath(p, q);
22:       Color oldColor = g2.getColor();
23:       if (this == BLACK_DIAMOND || this == BLACK_TRIANGLE)
24:          g2.setColor(Color.BLACK);
25:       else
26:          g2.setColor(Color.WHITE);
27:       g2.fill(path);
28:       g2.setColor(oldColor);
29:       g2.draw(path);
30:    }
31: 
32:    /**
33:       Gets the path of the arrowhead
34:       @param p a point on the axis of the arrow head
35:       @param q the end point of the arrow head
36:       @return the path
37:    */
38:    public GeneralPath getPath(Point2D p, Point2D q)
39:    {
40:       GeneralPath path = new GeneralPath();
41:       if (this == NONE) return path;
42:       final double ARROW_ANGLE = Math.PI / 6;
43:       final double ARROW_LENGTH = 8;
44: 
45:       double dx = q.getX() - p.getX();
46:       double dy = q.getY() - p.getY();
47:       double angle = Math.atan2(dy, dx);
48:       double x1 = q.getX() 
49:          - ARROW_LENGTH * Math.cos(angle + ARROW_ANGLE);
50:       double y1 = q.getY() 
51:          - ARROW_LENGTH * Math.sin(angle + ARROW_ANGLE);
52:       double x2 = q.getX() 
53:          - ARROW_LENGTH * Math.cos(angle - ARROW_ANGLE);
54:       double y2 = q.getY() 
55:          - ARROW_LENGTH * Math.sin(angle - ARROW_ANGLE);
56: 
57:       path.moveTo((float)q.getX(), (float)q.getY());
58:       path.lineTo((float)x1, (float)y1);
59:       if (this == V)
60:       {
61:          path.moveTo((float)x2, (float)y2);
62:          path.lineTo((float)q.getX(), (float)q.getY());
63:       }
64:       else if (this == TRIANGLE || this == BLACK_TRIANGLE)
65:       {
66:          path.lineTo((float)x2, (float)y2);
67:          path.closePath();                  
68:       }
69:       else if (this == DIAMOND || this == BLACK_DIAMOND)
70:       {
71:          double x3 = x2 - ARROW_LENGTH * Math.cos(angle + ARROW_ANGLE);
72:          double y3 = y2 - ARROW_LENGTH * Math.sin(angle + ARROW_ANGLE);
73:          path.lineTo((float)x3, (float)y3);
74:          path.lineTo((float)x2, (float)y2);
75:          path.closePath();         
76:       }      
77:       return path;
78:    }
79:    
80: }