title: How to draw 2d arrows with Java Swing?
body: <p>I'm trying to draw some rotatable arrows with Swing 2d, there are some sample code online, so I copied and combined them into one app, but there is something wrong with each of the 3 methods : 1st one doesn't rotate from it's center, the other 2 don't look correctly in the arrow head, can someone show me how to fix them ?</p>
  
  <pre><code>import java.awt.*;
  import java.awt.geom.*;
  import javax.swing.*;
  import javax.swing.event.*;
  
  public class Arrow_Test extends JPanel implements ChangeListener {
      Path2D.Double arrow = createArrow();
      double theta = 0;
  
      public void stateChanged(ChangeEvent e) {
          int value = ((JSlider) e.getSource()).getValue();
          theta = Math.toRadians(value);
          repaint();
      }
  
      protected void paintComponent(Graphics g) {
          super.paintComponent(g);
          Graphics2D g2 = (Graphics2D) g;
          g2.setStroke(new BasicStroke(6));
          g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                  RenderingHints.VALUE_ANTIALIAS_ON);
          int cx = getWidth() / 2;
          int cy = getHeight() / 2;
          AffineTransform at = AffineTransform.getTranslateInstance(cx, cy);
          at.rotate(theta);
          at.scale(2.0, 2.0);
          Shape shape = at.createTransformedShape(arrow);
          g2.setPaint(Color.blue);
          g2.draw(shape);
  
          GeneralPath a = drawArrow(20, 20, 30, 20, 50, 13);
          AffineTransform at1 = AffineTransform.getTranslateInstance(cx, cy);
          at1.rotate(theta);
          at1.scale(2.0, 2.0);
          Shape shape1 = at1.createTransformedShape(a);
          g2.setPaint(Color.blue);
          g2.draw(shape1);
  
          drawArrow(100, 100, 50, 0, g2);
      }
  
      private Path2D.Double createArrow() {
          int length = 80;
          int barb = 15;
          double angle = Math.toRadians(20);
          Path2D.Double path = new Path2D.Double();
          path.moveTo(-length / 2, 0);
          path.lineTo(length / 2, 0);
          double x = length / 2 - barb * Math.cos(angle);
          double y = barb * Math.sin(angle);
          path.lineTo(x, y);
          x = length / 2 - barb * Math.cos(-angle);
          y = barb * Math.sin(-angle);
          path.moveTo(length / 2, 0);
          path.lineTo(x, y);
          return path;
      }
  
      GeneralPath drawArrow(int x1, int y1, int x2, int y2, double length,
              double width) {
          double x, y;
          length = 50;
          width = 5;
  
          Point2D start = new Point2D.Double(x1, y1);
          Point2D end = new Point2D.Double(x2, y2);
          Point2D base = new Point2D.Double();
          Point2D back1 = new Point2D.Double();
          Point2D back2 = new Point2D.Double();
  
          length = Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
  
          // Compute normalized line vector
          x = (x2 - x1) / length;
          y = (y2 - y1) / length;
          // Compute points for arrow head
          base.setLocation(x2 - x * length, y2 - y * length);
          back1.setLocation(base.getX() - width * y, base.getY() + width * x);
          back2.setLocation(base.getX() + length * y, base.getY() - width * x);
  
          Line2D.Double l1 = new Line2D.Double(start, end);
          Line2D.Double l2 = new Line2D.Double(end, back2);
          Line2D.Double l3 = new Line2D.Double(end, back1);
  
          GeneralPath c = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
          c.append(l1, true);
          c.append(l2, true);
          c.append(l3, true);
  
          return c;
      }
  
      private void drawArrow(int x1, int y1, int x2, int y2, Graphics2D g2d) {
  
          int x[] = { 0, 36, 0 };
          int y[] = { -10, 0, 10 };
  
          g2d.rotate(theta);
          g2d.drawLine(x1 - 20, y1, x1 + 20, y1);
          // will move the orgin
          g2d.translate(x1, y1);
          double angle = findLineAngle(x1 - 20, y1, x1 + 20, y1);
          System.out.println("angle is===&gt;" + angle);
          g2d.rotate(angle);
  
          g2d.fillPolygon(new Polygon(x, y, 3));
          // /will restore orgin
          g2d.translate(-x2, -y2);
          g2d.rotate(-angle);
      }
  
      private double findLineAngle(int x1, int y1, int x2, int y2) {
          if ((x2 - x1) == 0)
              return Math.PI / 2;
          return Math.atan((y2 - y1) / (x2 - x1));
      }
  
      private JSlider getSlider() {
          JSlider slider = new JSlider(-180, 180, 0);
          slider.addChangeListener(this);
          return slider;
      }
  
      public static void main(String[] args) {
          Arrow_Test test = new Arrow_Test();
          JFrame f = new JFrame();
          f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
          f.add(test);
          f.add(test.getSlider(), "Last");
          f.setSize(400, 400);
          f.setLocationRelativeTo(null);
          f.setVisible(true);
      }
  }
  </code></pre>