001package horstmann.ch08_umleditor;
002import java.awt.Color;
003import java.awt.Graphics2D;
004import java.awt.geom.GeneralPath;
005import java.awt.geom.Point2D;
006
007/**
008   This class defines arrowheads of various shapes.
009 */
010public enum ArrowHead
011{
012        NONE, TRIANGLE, BLACK_TRIANGLE, V, DIAMOND, BLACK_DIAMOND;
013
014        /**
015      Draws the arrowhead.
016      @param g2 the graphics context
017      @param p a point on the axis of the arrow head
018      @param q the end point of the arrow head
019         */
020        public void draw(Graphics2D g2, Point2D p, Point2D q)
021        {
022                GeneralPath path = getPath(p, q);
023                Color oldColor = g2.getColor();
024                if (this == BLACK_DIAMOND || this == BLACK_TRIANGLE)
025                        g2.setColor(Color.BLACK);
026                else
027                        g2.setColor(Color.WHITE);
028                g2.fill(path);
029                g2.setColor(oldColor);
030                g2.draw(path);
031        }
032
033        /**
034      Gets the path of the arrowhead
035      @param p a point on the axis of the arrow head
036      @param q the end point of the arrow head
037      @return the path
038         */
039        public GeneralPath getPath(Point2D p, Point2D q)
040        {
041                GeneralPath path = new GeneralPath();
042                if (this == NONE) return path;
043                final double ARROW_ANGLE = Math.PI / 6;
044                final double ARROW_LENGTH = 8;
045
046                double dx = q.getX() - p.getX();
047                double dy = q.getY() - p.getY();
048                double angle = Math.atan2(dy, dx);
049                double x1 = q.getX()
050                                - ARROW_LENGTH * Math.cos(angle + ARROW_ANGLE);
051                double y1 = q.getY()
052                                - ARROW_LENGTH * Math.sin(angle + ARROW_ANGLE);
053                double x2 = q.getX()
054                                - ARROW_LENGTH * Math.cos(angle - ARROW_ANGLE);
055                double y2 = q.getY()
056                                - ARROW_LENGTH * Math.sin(angle - ARROW_ANGLE);
057
058                path.moveTo((float)q.getX(), (float)q.getY());
059                path.lineTo((float)x1, (float)y1);
060                if (this == V)
061                {
062                        path.moveTo((float)x2, (float)y2);
063                        path.lineTo((float)q.getX(), (float)q.getY());
064                }
065                else if (this == TRIANGLE || this == BLACK_TRIANGLE)
066                {
067                        path.lineTo((float)x2, (float)y2);
068                        path.closePath();
069                }
070                else if (this == DIAMOND || this == BLACK_DIAMOND)
071                {
072                        double x3 = x2 - ARROW_LENGTH * Math.cos(angle + ARROW_ANGLE);
073                        double y3 = y2 - ARROW_LENGTH * Math.sin(angle + ARROW_ANGLE);
074                        path.lineTo((float)x3, (float)y3);
075                        path.lineTo((float)x2, (float)y2);
076                        path.closePath();
077                }
078                return path;
079        }
080
081}