Java矩形绕中心旋转后内部点坐标计算结果异常排查
问题原因
坐标计算结果和预期不符,核心是三点错误:
- 直接套用数学坐标系的旋转公式后,仅加回原矩形的中心偏移,没有考虑90度旋转后矩形宽高互换、新画布尺寸变化带来的坐标偏移,和实际用Java2D渲染图像时的变换逻辑不匹配。
- 角度方向和图像坐标系规则未对齐:图像/屏幕坐标系默认Y轴向下为正,Java2D的
rotate方法传入正角度代表顺时针旋转,和数学坐标系Y轴向上、正角度逆时针的规则不同,传值错误直接导致结果偏差。 - 手动实现的点旋转逻辑,没有复刻
rotate渲染方法里的translate((neww-w)/2, (newh-h)/2)平移动作,变换步骤和渲染流程不一致。
正确计算逻辑
要得到和Photoshop、Java2D渲染完全一致的点坐标,必须严格对齐渲染时的变换顺序,步骤如下:
- 根据旋转角度计算旋转后新画布的宽高:
- 旋转90度、270度时,新宽=原高,新高=原宽
- 任意角度通用计算:
neww = 原宽 * |cosθ| + 原高 * |sinθ|,newh = 原高 * |cosθ| + 原宽 * |sinθ|
- 按和渲染逻辑一致的顺序变换点坐标:
- 第一步:将原坐标系下的点平移到以原图像中心为原点的相对坐标系
- 第二步:对相对坐标应用旋转变换
- 第三步:将旋转后的相对坐标平移回原图像坐标系
- 第四步:叠加新画布相对原图像的平移偏移,得到最终新画布下的点坐标
修正后的代码
public class CoordinateRotator { /** * 计算图像绕中心旋转后,原内部点在新画布中的坐标 * @param x 原图像内点的x坐标 * @param y 原图像内点的y坐标 * @param w 原图像宽度 * @param h 原图像高度 * @param degrees 顺时针旋转角度 * @return 旋转后新画布内的点坐标,x为数组[0]位,y为数组[1]位 */ public static int[] rotatePoint(int x, int y, int w, int h, double degrees) { double angle = Math.toRadians(degrees); double cos = Math.cos(angle); double sin = Math.sin(angle); // 计算新画布尺寸 int newW = (int) Math.floor(w * Math.abs(cos) + h * Math.abs(sin)); int newH = (int) Math.floor(h * Math.abs(cos) + w * Math.abs(sin)); // 原图像中心 int cx = w / 2; int cy = h / 2; // 第一步:转换为以原中心为原点的相对坐标 double x1 = x - cx; double y1 = y - cy; // 第二步:旋转变换 double x2 = x1 * cos - y1 * sin; double y2 = x1 * sin + y1 * cos; // 第三步:平移回原图像坐标系,叠加新画布的平移偏移 double tx = (newW - w) / 2.0; double ty = (newH - h) / 2.0; int rx = (int) Math.round(x2 + cx + tx); int ry = (int) Math.round(y2 + cy + ty); return new int[]{rx, ry}; } public static void main(String[] args) { // 测试案例:原宽50,高128,点(15,111),顺时针旋转90度 int[] res = rotatePoint(15, 111, 50, 128, 90); // 输出17,15,和Photoshop结果完全一致 System.out.println(res[0] + "," + res[1]); } }
注意事项
- 该方法逻辑和Java2D图像旋转方法完全对齐,计算结果和渲染后的像素位置无偏差,可直接用于碰撞盒角点坐标计算。
- 不要随意给角度加负号,Java2D中Y轴向下,传入正角度即为顺时针旋转,和Photoshop的旋转方向一致。
- 坐标取整用
Math.round做四舍五入,避免强制类型转换直接截断小数带来的1像素误差。
内容的提问来源于stack exchange,提问作者Zizzyzizzy
相关产品推荐
相关产品推荐

