2
votes

How would one go about rotating the mouse coordinate system when a rotation is applied to a Canvas? When I rotate the Canvas, the mouse stays in the same position relative to the rotated components. I would like to have the mouse coordinates consider the rotation of the component, instead of the coordinates being the position relative to the window, with no consideration for rotation.

I've provided a picture to illustrate more of what I'm getting at. The black box represents a shape for reference, and the purple box lies on the mouse coordinates. Rotation example image

Leftmost picture - Unrotated Canvas Middle picture - Rotated Canvas as Java sees it Rightmost picture - Desired outcome

My example code simulates a Canvas that rotates by pressing the left or right arrow keys. This simulation shows how the mouse stays in a position relative to rotated components, rather than relative to my mouse on screen.

Is there a way to transform or calculate these new coordinates (shown in the rightmost image) so that they lock onto my mouse in the window, regardless of rotation?

 package rotation;

    import java.awt.Canvas;
    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.MouseInfo;
    import java.awt.Point;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.awt.geom.AffineTransform;
    import java.awt.image.BufferStrategy;

    import javax.swing.JFrame;

    @SuppressWarnings("serial")
    public class RotationExample extends Canvas implements Runnable{

        boolean isRunning = false;
        boolean left = false;
        boolean right = false;
        AffineTransform transform = new AffineTransform();
        double rotation = 0.0d;

        public RotationExample() {
            //Create jframe
            JFrame f = new JFrame();
            f.setSize(500, 500);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setResizable(false);
            f.setUndecorated(true);

            //Add key listener
            this.addKeyListener(new KeyAdapter() {
                public void keyPressed(KeyEvent e) {
                    int k = e.getKeyCode();
                    //Set left and right variables
                    if(k == KeyEvent.VK_LEFT) left = true;
                    if(k == KeyEvent.VK_RIGHT) right = true;
                }

                public void keyReleased(KeyEvent e) {
                    int k = e.getKeyCode();
                    if(k == KeyEvent.VK_LEFT) left = false;
                    if(k == KeyEvent.VK_RIGHT) right = false;
                }
            });

            f.add(this);
            f.setVisible(true);
            start();
        }

        public void render() {
            BufferStrategy bs = this.getBufferStrategy();
            if(bs == null){
                this.createBufferStrategy(3);
                return;
            }

            Graphics g = bs.getDrawGraphics();
            Graphics2D gt = (Graphics2D) g;

            gt.setTransform(transform);

            gt.clearRect(0, 0, 500, 500);

            //Increment rotation based on left or right variables
            if(left) rotation += 0.001;
            else if(right) rotation -= 0.001;

            //Rotate around middle of frame
            gt.rotate(rotation, 250, 250);

            //Draw black rectangle in middle
            gt.setColor(Color.BLACK);
            gt.fillRect(175, 175, 150, 150);

            //Draw red up arrow
            gt.setColor(Color.RED);
            gt.fillPolygon(new int[] {250, 300, 270, 270, 230, 230, 200}, new int[] {200, 250, 250, 300, 300, 250, 250}, 7);

            //Draw rectangle at mouse coordinates
            gt.setColor(Color.MAGENTA);
            Point m = MouseInfo.getPointerInfo().getLocation();
            gt.fillRect((int) m.getX() - 8, (int) m.getY() - 8, 16, 16);

            bs.show();
            gt.dispose();
        }

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

        public void start() {
            isRunning = true;
            new Thread(this).start();
        }

        public void run() {
            //Continuous rendering
            while(isRunning) {
                render();
            }

        }
    }
1
java.awt.Robot? Calculating the new position of the purple square is a simple geometric coordinate transform, then move the mouse to the new coordinates. The coordinate transform is a pure geometry question unrelated to programming, and reference info is available lots of places on the web.Jim Garrison
@JimGarrison I've tried implementing a basic robot but I ended up with the same results. Any idea how I could do this with a robot? I'm fairly new to this, apologiesBenjamin Mroz

1 Answers

4
votes

The mouse position is reported in absolute, but the box drawing is after transform. You need to do the inverse transform for the mouse position to bring it back to the pointer.

        //Draw rectangle at mouse coordinates
        gt.setColor(Color.MAGENTA);
        Point m = MouseInfo.getPointerInfo().getLocation();
        try {
            gt.getTransform().createInverse().transform(m, m);
            gt.fillRect((int) m.getX() - 8, (int) m.getY() - 8, 16, 16);
        } catch (java.awt.geom.NoninvertibleTransformException e) {
            System.err.println(e);
        }