Jump to content

Help? AffineTransform scale around a point


LoudPacks

Recommended Posts

I want to be able to zoom in using scaling but right now it scales relative to the top left corner and I want to be able to scale based on my mouse position. Does any one have any ideas on how I can make this happen?

 

51b8971846720785fc05d60a6ff7209d.gif

 

This is how it looks as of now, scaling into the top left corner.

 

Code:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class PictureFrame {
	
	private ImageCanvas canvas;
	
	public PictureFrame(String filePath) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				createFrame(filePath);
			}
		});
	}
	
	public PictureFrame(Image image) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				createFrame(image);
			}
		});
	}

	private void createFrame(String filePath) {
		JFrame frame = new JFrame("Picture Frame Test");
		frame.setSize(800, 600);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		canvas = new ImageCanvas(filePath, frame.getWidth(), frame.getHeight());

		frame.getContentPane().add(canvas);
		frame.setVisible(true);
	}
	
	private void createFrame(Image image) {
		JFrame frame = new JFrame("Picture Frame Test");
		frame.setSize(800, 600);
		frame.setResizable(false);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		canvas = new ImageCanvas(image, frame.getWidth(), frame.getHeight());

		frame.getContentPane().add(canvas);
		frame.setVisible(true);
	}

	private class ImageCanvas extends JComponent {

		private Image image;
		private AffineTransform transformer = new AffineTransform();

		ImageCanvas(String filePath, int width, int height) {
			try {
				image = ImageIO.read(new File(filePath));
				setSize(width, height);
				EventListener eventListener = new EventListener();
				addMouseListener(eventListener);
				addMouseWheelListener(eventListener);
				addMouseMotionListener(eventListener);
			} catch (IOException e) {
				System.out.println("Unable to read image file!");
			}

		}
		
		ImageCanvas(Image image, int width, int height) {
				this.image = image;
				setSize(width, height);
				EventListener eventListener = new EventListener();
				addMouseListener(eventListener);
				addMouseWheelListener(eventListener);
				addMouseMotionListener(eventListener);

		}
		
		public double getMinScale(){
			
			double limitX = (double) canvas.getWidth() / (double) canvas.getImage().getWidth(null);
			double limitY = (double) canvas.getHeight() / (double) canvas.getImage().getHeight(null);
			
			return (limitX > limitY) ? limitX : limitY;
		}
		
		public Image getImage(){
			return image;
		}
		
		public AffineTransform getTransformer(){
			return transformer;
		}

		@[member=Override]
		protected void paintComponent(Graphics g) {
			try {
				Graphics2D graphics = (Graphics2D) g;
				graphics.setTransform(transformer);
				Point mouse = MouseInfo.getPointerInfo().getLocation();
				SwingUtilities.convertPointFromScreen(mouse, this);
				graphics.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null), null);
				graphics.setColor(Color.BLACK);
				graphics.fillRect(0, 0, 90, 15);
				graphics.setColor(Color.WHITE);
				graphics.drawString(String.format("X: %.0f Y: %.0f", mouse.getX(), mouse.getY()), 10, 10);
				Thread.sleep(15);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private class EventListener implements MouseListener, MouseWheelListener, MouseMotionListener {
		
		private Point startPoint, endPoint;
		private double deltaX, deltaY;
		
		
		@[member=Override]
		public void mouseWheelMoved(MouseWheelEvent e) {
			AffineTransform transformer = canvas.getTransformer();
			
			if(e.getWheelRotation() < 0)
				transformer.setToScale(transformer.getScaleX() + .05, transformer.getScaleY() + .05);
			else
				transformer.setToScale(Math.max(canvas.getMinScale(), transformer.getScaleX() - .05), Math.max(canvas.getMinScale(), transformer.getScaleY() - .05));
			
			
			 transformer.translate(deltaX, deltaY);
			 canvas.repaint();
		}
		
		@[member=Override]
		public void mouseClicked(MouseEvent e) {
			
		}

		@[member=Override]
		public void mousePressed(MouseEvent e) {
			startPoint = e.getPoint();
		}

		@[member=Override]
		public void mouseReleased(MouseEvent e) {

		}

		@[member=Override]
		public void mouseEntered(MouseEvent e) {

		}

		@[member=Override]
		public void mouseExited(MouseEvent e) {

		}

		@[member=Override]
		public void mouseDragged(MouseEvent e) {
			AffineTransform transformer = canvas.getTransformer();
			 try {
		            endPoint = e.getPoint();
		            Point dragStart = transformPoint(startPoint);
		            Point dragEnd = transformPoint(endPoint);
		            /*
		            double dx = dragEnd.getX() - dragStart.getX();
		            double dy = dragEnd.getY() - dragStart.getY();
		            deltaX += dx;
		            deltaY += dy;
		            */
		             double deltaW = (double) canvas.getWidth() - (double) canvas.getImage().getWidth(null) * transformer.getScaleX();
					 double deltaH = (double) canvas.getHeight() - (double) canvas.getImage().getHeight(null) * transformer.getScaleY();
					 double px = Math.max(deltaW, Math.min(0, deltaX + (dragEnd.getX() - dragStart.getX())));
					 double dx = px - deltaX;
					 double py = Math.max(deltaH, Math.min(0, deltaY + (dragEnd.getY() - dragStart.getY())));
					 double dy = py - deltaY;
					 deltaX = px;
					 deltaY = py;
		            
		            transformer.translate(dx, dy);
		            startPoint = endPoint;
		            endPoint = null;
		        } catch (NoninvertibleTransformException ex) {
		            ex.printStackTrace();
		        }
			canvas.repaint();
		}

		@[member=Override]
		public void mouseMoved(MouseEvent e) {
			canvas.repaint();
		}
		
		private Point transformPoint(Point p1) throws NoninvertibleTransformException{
			AffineTransform transformer = canvas.getTransformer();
			AffineTransform inverse = transformer.createInverse();
	        Point p2 = new Point();
	        inverse.transform(p1, p2);
	        return p2;
		}

	}

}

Link to comment
Share on other sites

I reckon you should translate the transformed image according to your mouse.

				Graphics2D graphics = (Graphics2D) g;
				graphics.setTransform(transformer);
				Point mouse = MouseInfo.getPointerInfo().getLocation();
				SwingUtilities.convertPointFromScreen(mouse, this);
                                > graphics.translate(-mouse.getX() * graphics.getTransform().getScaleX(), -mouse.getY() * graphics.getTransform().getScaleY());
				graphics.drawImage(image, 0, 0, image.getWidth(null), image.getHeight(null), null);
                                > graphics.translate(mouse.getX() * graphics.getTransform().getScaleX(), mouse.getY() * graphics.getTransform().getScaleY());
				graphics.setColor(Color.BLACK);
				graphics.fillRect(0, 0, 90, 15);
				graphics.setColor(Color.WHITE);
				graphics.drawString(String.format("X: %.0f Y: %.0f", mouse.getX(), mouse.getY()), 10, 10);

Just a guess tho, haven't tried compiling your code

EDIT: remember to translate back :boge:

Edited by FrostBug
Link to comment
Share on other sites

try something like this

            AffineTransform transformer = canvas.getTransformer();
            Point p = e.getPoint();
            int mouseX = p.x;
            int mouseY = p.y;
            double zoom = e.getUnitsToScroll() < 0 ? 1.05 : 1 / 1.05;
            deltaX = (int) ((transformer.getTranslateX() * zoom) - ((mouseX * zoom) - mouseX));
            deltaY = (int) ((transformer.getTranslateY() * zoom) - ((mouseY * zoom) - mouseY));
            transformer.setToScale(transformer.getScaleX() * zoom, transformer.getScaleY() * zoom);
            transformer.translate(deltaX, deltaY);
            canvas.repaint();
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...