1

我正在实现一个 java swing 应用程序,它有一个用作绘图表面的 JPanel。表面呈现(活动)不同的元素。每个元素都有自己的形状和用于渲染和碰撞检测的仿射变换(每个元素都是用局部坐标绘制的,然后用仿射变换进行变换——比如 opengl)。

元素可以在表面上移动和旋转(这是通过变换完成的)。每次应用变换时,都会使用形状和变换创建一个 Area 对象(用于准确的碰撞检测)。

问题是当我旋转元素(45 度)然后将其移动 10 像素时。当我移动它时,元素会沿我不想要的旋转方向移动。

有什么简单的方法可以克服这个问题吗?
(如果我的描述不够,我会发布一些示例代码)。

编辑:

 class Element
 {
     private AffineTransform transform = new AffineTransform();
     private Shape shape = new Rectangle(0,0,100,100);       
     private Area boundingBox;       

     public void onMouseDrag(MouseEvent e)
     {
        translate(dx,dy); // dx,dy are calculated from event
     }

     public void onMouseMove(MouseEvent e)
     {
        rotate(Math.atan2(dx/dy); // dx,dy are calculated from event
     }

     public void translate(int dx,int dy)
     {
        transform.translate(dx,dy);
        boundingBox = new Area(shape);
        boundingBox.transform(transform);
     }

     public void rotate(double angle)
     {
         transform.rotate(Math.toRadians(angle));
         boundingBox = new Area(shape);
         boundingBox.transform(transform);
     }

     public void draw(Graphics2D g2d)
     {
         g2d.setTransform(transform); 

         g2d.draw(shape); 
        ...
      }

 } 
4

2 回答 2

2

颠倒您应用转换的顺序。或者取消旋转对象,移动它,然后重新旋转对象。我们真的需要查看您的代码(甚至是伪代码)才能为您提供比这更好的答案。

于 2012-04-18T22:44:39.420 回答
2

我已经通过提供Element positionorientation字段修改了您的代码,您可能希望通过 getter/setter 公开这些代码(可能Point在返回/设置之前防御性地复制实例)。只需根据的当前和updateTransform()重新构建。AffineTransformElementpositionorientation

public class Element {

    private Point position = new Point();
    private float orientation;

    private AffineTransform transform = new AffineTransform();
    private Shape shape = new Rectangle(0, 0, 100, 100);
    private Area boundingBox;

    public void onMouseDrag(MouseEvent e) {
        translate(dx, dy);
    }

    public void onMouseMove(MouseEvent e) {
        rotate(Math.atan2(dx / dy));
    }

    public void translate(int dx, int dy) {
        position.translate(dx, dy);
        updateTransform();
    }

    public void rotate(double angle) {
        orientation += Math.toRadians(angle);
        updateTransform();
    }

    private void updateTransform() {
        transform.setToIdentity();
        transform.translate(position.x, position.y);
        transform.rotate(orientation);
        // ... update bounding box here ...
    }

    public void draw(Graphics2D g2d) {
        g2d.setTransform(transform);
        g2d.draw(shape);
    }

}

另外,请考虑以下方法:

  • 更改draw(Graphics2D)draw(Graphics2D, AffineTransform transform)
  • 创建AffineTransform Element.getCompositeTransform()哪个构建当前AffineTransform并返回它(如updateTransform())。
  • 从 中删除该transform字段Element
  • 在您的渲染方法中,执行以下操作:

.

for (Element element : elements) {
    AffineTransform transform = element.getCompositeTransform();
    element.draw(graphics, transform);
}

为什么?这使您可以灵活地从Element外部控制 的绘图变换。如果您要构建一个节点图(例如当一个Element可以有Element孩子时)并且您将递归地渲染该图,连接变换,这将非常有用。顺便说一句,这种方法在 3D 编程中几乎是标准的。

于 2012-04-18T23:48:53.433 回答