You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

BufferedImage旋转后,如何同步旋转用于选择的边界框?

问题描述

我正在开发一个Java程序,需要先在BufferedImage上绘制对象,再将其绘制到JPanel上,这种方式方便管理同一JPanel上的多个可绘制、可旋转对象。

核心绘制与旋转代码如下:

public void draw(Graphics2D g2, JPanel p)
{
    BufferedImage bufferedImage = new BufferedImage(Width + 40, Height + 40, BufferedImage.TYPE_INT_ARGB); 
    Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();  // Graphics for the first object only
        
    AffineTransform old = g2.getTransform();
        
    g2d.setStroke(new BasicStroke(2));
    g2d.setColor(Color.blue);
        
    if(type.equals("cone"))
    {
            
    }
    else if(type.equals("cube"))
    {
        g2d.drawRect(20, 20, Width, Height);
    }
    else if(type.equals("circle"))
    {
        g2d.drawOval(20, 20, Width, Height);
    }
    else if(type.equals("line"))
    {
        g2d.drawRect(20, 20, Width, Height);
    }
        
    if(isselected)
        drawbounding(g2d, p);
        
    g2.rotate((double) rotate, X, Y);
    g2.drawImage(bufferedImage, X, Y, p);
        
    g2d.setTransform(old);
}

我用下面的代码判断点击是否在预设边界框内:

public boolean isSelected(int x, int y)
{
    if(x > X && x < X + 40 + Width)
    {
        if(y > Y && y < Y + 40 + Height)
        {
            isselected = true;
            return true;
        }
    }
        
    isselected = false;
    return false;
}

现在遇到的问题是:BufferedImage旋转后,边界框并没有跟着旋转。我知道原因是边界框用的是全局X、Y坐标,而BufferedImage用的是局部坐标,请问怎么让边界框和BufferedImage一起旋转?


解决方案

要解决这个问题,核心是让点击检测逻辑和图像的旋转变换保持一致,有两种直接可行的方案:

方案一:坐标逆变换

把点击的全局坐标转换到未旋转的局部坐标系中,再用原始边界框判断:

public boolean isSelected(int x, int y) {
    // 创建和绘制时一致的旋转变换(注意:如果rotate是角度,要转成弧度)
    AffineTransform transform = AffineTransform.getRotateInstance(Math.toRadians(rotate), X, Y);
    AffineTransform inverseTransform = null;
    try {
        // 获取逆变换,用于将全局坐标转成局部坐标
        inverseTransform = transform.createInverse();
    } catch (NoninvertibleTransformException e) {
        e.printStackTrace();
        return false;
    }
    
    // 转换点击坐标
    Point2D.Double globalPoint = new Point2D.Double(x, y);
    Point2D.Double localPoint = new Point2D.Double();
    inverseTransform.transform(globalPoint, localPoint);
    
    // 用局部坐标判断是否在原始边界框内
    boolean isIn = localPoint.getX() > X && localPoint.getX() < X + 40 + Width 
                && localPoint.getY() > Y && localPoint.getY() < Y + 40 + Height;
    
    isselected = isIn;
    return isIn;
}

方案二:旋转形状碰撞检测

直接创建旋转后的边界框形状,用Shape.contains()方法做检测:

public boolean isSelected(int x, int y) {
    // 创建原始的边界框矩形
    Rectangle2D originalRect = new Rectangle2D.Double(X, Y, Width + 40, Height + 40);
    // 创建旋转变换,和绘制时的参数完全一致
    AffineTransform transform = AffineTransform.getRotateInstance(Math.toRadians(rotate), X, Y);
    // 获取旋转后的形状
    Shape rotatedRect = transform.createTransformedShape(originalRect);
    
    // 判断点击点是否在旋转后的形状内
    boolean isIn = rotatedRect.contains(x, y);
    isselected = isIn;
    return isIn;
}

额外优化提示

  1. 你的draw方法存在一个小问题:g2d.setTransform(old);中的old是g2的原始变换,应该替换为g2d自身的初始变换,避免影响后续绘图:
// 替换原来的AffineTransform old = g2.getTransform();
AffineTransform oldG2d = g2d.getTransform();
// ... 绘制代码 ...
g2d.setTransform(oldG2d);
  1. 如果rotate变量存储的是角度值(如0-360),必须用Math.toRadians()转换为弧度,因为AffineTransform的旋转方法默认使用弧度作为单位。

内容的提问来源于stack exchange,提问作者Gizmo Dailys

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:57:39