[Solved] make image point toward specific location in java


Okay, so two things jump out at me…

  1. If you take a Point from outside the context of the label, you will have to translate the point into the components coordinate context
  2. The calculateAngle seems wrong

So starting with…

private void calculateAngle(Point target) {
  // calculate the angle from the center of the image
  float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
  float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
  angle = (float) Math.atan2(deltaY, deltaX);
  if (angle < 0) {
     angle += (Math.PI * 2);
  }
}

angle = (float) Math.atan2(deltaY, deltaX); should be angle = (float) Math.atan2(deltaX, deltaY); (swap the deltas)

You will find that you need to adjust the result by 180 degrees in order to get the image to point in the right direction

angle = Math.toRadians(Math.toDegrees(angle) + 180.0);

Okay, I’m an idiot, but it works 😛

I’d also make use of a AffineTransform to translate and rotate the image – personally, I find it easier to deal with.

In the example, I’ve cheated a little. I set the translation of the AffineTransform to the centre of the component, I then rotate the context around the new origin point (0x0). I then paint the image offset by half it’s height/width, thus making it appear as the if the image is been rotated about it’s centre – It’s late, I’m tired, it works 😛

Point at me

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private ImageLabel label;

        public TestPane() {
            setLayout(new GridBagLayout());
            label = new ImageLabel();
            add(label);

            addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    label.pointImageToPoint(e.getPoint(), TestPane.this);
                }
            });
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

    }

    public final class ImageLabel extends JLabel {

        private double angle = 0;
        private Point imageLocation = new Point();
        private File imageFile = null;
        private Dimension imageSize = new Dimension(50, 50);
        private BufferedImage bi;

        public ImageLabel() {
            setBorder(new LineBorder(Color.BLUE));
            bi = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = bi.createGraphics();
            g2d.setColor(Color.RED);
            g2d.drawLine(25, 0, 25, 50);
            g2d.drawLine(25, 0, 0, 12);
            g2d.drawLine(25, 0, 50, 12);
            g2d.dispose();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(bi.getWidth(), bi.getHeight());
        }

        protected Point centerPoint() {
            return new Point(getWidth() / 2, getHeight() / 2);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (bi == null) {
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            AffineTransform at = g2d.getTransform();
            Point center = centerPoint();
            at.translate(center.x, center.y);
            at.rotate(angle, 0, 0);
            g2d.setTransform(at);
            g2d.drawImage(bi, -bi.getWidth() / 2, -bi.getHeight() / 2, this);
            g2d.dispose();
        }

        public void rotateImage(float angle) { // rotate the image to specific angle
            this.angle = (float) Math.toRadians(angle);
            repaint();
        }

        public void pointImageToPoint(Point target, JComponent fromContext) {
            calculateAngle(target, fromContext);
            repaint();
        }

        private void calculateAngle(Point target, JComponent fromContext) {
            // calculate the angle from the center of the image
            target = SwingUtilities.convertPoint(fromContext, target, this);
            Point center = centerPoint();
            float deltaY = target.y - center.y;
            float deltaX = target.x - center.x;
            angle = (float) -Math.atan2(deltaX, deltaY);
            angle = Math.toRadians(Math.toDegrees(angle) + 180.0);
            repaint();
        }
    }
}

I just want to add that using a JLabel for this purpose is overkill, a simple JPanel or JComponent would do the same job and carry a lot less overhead with it, just saying

0

solved make image point toward specific location in java