    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 class ArrowHead extends SerializableEnumeration
    10: {
    11:    private ArrowHead() {}
    12:    /**
    13:       Draws the arrowhead.
    14:       @param g2 the graphics context
    15:       @param p a point on the axis of the arrow head
    16:       @param q the end point of the arrow head
    17:    */
    18:    public void draw(Graphics2D g2, Point2D p, Point2D q)
    19:    {
    20:       if (this == NONE) return;
    21:       final double ARROW_ANGLE = Math.PI / 6;
    22:       final double ARROW_LENGTH = 8;
    23:
    24:       double dx = q.getX() - p.getX();
    25:       double dy = q.getY() - p.getY();
    26:       double angle = Math.atan2(dy, dx);
    27:       double x1 = q.getX()
    28:          - ARROW_LENGTH * Math.cos(angle - ARROW_ANGLE);
    29:       double y1 = q.getY()
    30:          - ARROW_LENGTH * Math.sin(angle - ARROW_ANGLE);
    31:       double x2 = q.getX()
    32:          - ARROW_LENGTH * Math.cos(angle + ARROW_ANGLE);
    33:       double y2 = q.getY()
    34:          - ARROW_LENGTH * Math.sin(angle + ARROW_ANGLE);
    35:
    36:       GeneralPath path = new GeneralPath();
    37:       path.moveTo((float) q.getX(), (float) q.getY());
    38:       path.lineTo((float) x1, (float) y1);
    39:       if (this == V)
    40:       {
    41:          path.moveTo((float) x2, (float) y2);
    42:          path.lineTo((float) q.getX(), (float) q.getY());
    43:       }
    44:       else if (this == TRIANGLE)
    45:       {
    46:          path.lineTo((float) x2, (float) y2);
    47:          path.closePath();
    48:       }
    49:       else if (this == DIAMOND || this == BLACK_DIAMOND)
    50:       {
    51:          double x3 = x1 - ARROW_LENGTH * Math.cos(angle + ARROW_ANGLE);
    52:          double y3 = y1 - ARROW_LENGTH * Math.sin(angle + ARROW_ANGLE);
    53:          path.lineTo((float) x3, (float) y3);
    54:          path.lineTo((float) x2, (float) y2);
    55:          path.closePath();
    56:       }
    57:       Color oldColor = g2.getColor();
    58:       if (this == BLACK_DIAMOND)
    59:          g2.setColor(Color.BLACK);
    60:       else
    61:          g2.setColor(Color.WHITE);
    62:       g2.fill(path);
    63:       g2.setColor(oldColor);
    64:       g2.draw(path);
    65:    }
    66:
    67:    public static final ArrowHead NONE = new ArrowHead();
    68:    public static final ArrowHead TRIANGLE = new ArrowHead();
    69:    public static final ArrowHead V = new ArrowHead();
    70:    public static final ArrowHead DIAMOND = new ArrowHead();
    71:    public static final ArrowHead BLACK_DIAMOND = new ArrowHead();
    72: }