使用Affine Transformation旋转图像时超出可视边界的解决方法
问题描述
我正在使用Affine Transformation旋转图像实现摆锤来回摆动的效果,但图像向左旋转时会超出可视边界消失。怎么调整边界让图像始终可见?
摆动的图像:
旋转图像的代码:
public void paintComponent(Graphics g) { // if no image set, then just draw a rectangle if (sprite == null) { g.setColor(c); g.fillRect(0, 0, (int) getBounds().getWidth(), (int) getBounds().getHeight()); } else { try { AffineTransform at = new AffineTransform(); if (spriteAngle != 0) { at.rotate(spriteAngle, getWidth() / 2, getHeight() / 2); } at.scale(getWidth() * 1.0 / sprite.getWidth(), getHeight() * 1.0 / sprite.getHeight()); Graphics2D g2d = (Graphics2D) g; g2d.drawImage(sprite, at, null); } catch (Exception e) { g.drawImage(sprite, 0, 0, getWidth(), getHeight(), this); } } }
我试过用Rectangle类做临时变换移动边界、平移对象,也试过绕中心旋转、更换图像。把图像放在右下角能让它始终在边界内:
但这个方法不行,因为我需要随时间延长图像长度。
解决方案
要解决旋转时图像出界的问题,核心是让旋转后的图像始终落在组件可视区域内,从这几个方面调整:
1. 换旋转原点,对齐摆锤固定端
当前代码绕组件中心旋转,会导致图像两端超出边界。摆锤应该绕自身的固定端点(比如图像顶部中心)旋转,这样旋转时图像只会在固定点周围摆动,不会轻易出界。
修改代码步骤:
- 确定图像的旋转原点:比如图像的顶部中心
(sprite.getWidth()/2, 0)。 - 先平移图像,让这个旋转原点对齐到组件内的固定位置(比如组件顶部中心)。
- 再执行旋转操作,最后绘制图像。
修改后的代码示例:
public void paintComponent(Graphics g) { if (sprite == null) { g.setColor(c); g.fillRect(0, 0, getWidth(), getHeight()); } else { Graphics2D g2d = (Graphics2D) g; try { AffineTransform at = new AffineTransform(); // 等比例缩放,避免图像拉伸变形 double scale = Math.min((double) getWidth() / sprite.getWidth(), (double) getHeight() / sprite.getHeight()); at.scale(scale, scale); // 图像的旋转原点:顶部中心(摆锤固定端) int imgRotX = sprite.getWidth() / 2; int imgRotY = 0; // 平移图像,让旋转原点对齐到组件顶部中心 double compRotX = getWidth() / 2.0 / scale; // 转换到缩放后的坐标 at.translate(compRotX - imgRotX, 0 - imgRotY); // 绕图像顶部中心旋转 if (spriteAngle != 0) { at.rotate(spriteAngle, imgRotX, imgRotY); } g2d.drawImage(sprite, at, null); } catch (Exception e) { g.drawImage(sprite, 0, 0, getWidth(), getHeight(), this); } } }
2. 让组件尺寸适配旋转后的图像
旋转后的图像外接矩形会比原图像大,需要让组件尺寸能容纳这个外接矩形。重写getPreferredSize()方法,返回计算后的最小尺寸:
private Dimension getRotatedImageSize() { if (sprite == null) return new Dimension(100, 100); double angle = Math.abs(spriteAngle); int imgW = sprite.getWidth(); int imgH = sprite.getHeight(); // 计算旋转后外接矩形的宽高 double rotatedW = Math.abs(imgW * Math.cos(angle)) + Math.abs(imgH * Math.sin(angle)); double rotatedH = Math.abs(imgW * Math.sin(angle)) + Math.abs(imgH * Math.cos(angle)); // 应用缩放比例 double scale = Math.min((double) getWidth() / imgW, (double) getHeight() / imgH); return new Dimension((int)(rotatedW * scale), (int)(rotatedH * scale)); } @Override public Dimension getPreferredSize() { return getRotatedImageSize(); }
3. 保持图像等比例缩放
原代码直接按组件宽高缩放会导致图像拉伸,用等比例缩放既能保证图像不变形,也能更准确计算旋转后的边界。
内容的提问来源于stack exchange,提问作者341069300
相关产品推荐
相关产品推荐

