3

我正在寻找一种以这种方式组合仿射变换的方法,以便效果等同于使用每个变换来连续操纵形状。问题是如果我简单地连接变换,那么每个连续变换的效果都会在现有变换的坐标空间中解释。

例如,考虑原点周围的正方形(-50、-50、100,100)。我想旋转它,然后将它向下平移 100 像素。如果我进行变换并旋转然后平移,则平移将在旋转坐标中进行解释。相反,如果我变换形状本身以旋转它,然后再次变换该形状以翻译它,则两种翻译都在“正常”未翻译平面中解释,它给了我我想要的东西。

问题是,对于我正在做的事情,可能会发生许多变换,每个变换都需要在法线坐标平面中进行解释,但我不想存储一堆变换,也不能简单地继续操纵形状,因为我需要随时能够从原始起始形状创建最终的转换形状。

示例:左侧的普通连接,右侧的连续变换

我知道,对于这个简单的示例,如果我在旋转之前进行翻译,我会得到相同的结果,但这没有抓住重点。我正在处理一组任意的连续缩放、平移和旋转变换,因此简单地将它们按特定顺序放置并不会减少它。

我有一种暗示,应该有一种方法来连接变换,以便在连接之前修改新变换,纠正现有变换,以便效果是新变换似乎已被应用,就好像它参考未转换的坐标平面。例如,如果您在上面的示例中转换为 (70.7, 70.7) 而不是 (0,100),则结果将变得等价。我只是似乎无法弄清楚数学是什么,通常要弄清楚如何改变新的变换,使其正常工作。

感谢阅读 - 希望这是有道理的。下面是创建屏幕截图的示例的来源:

public class TransformExample extends JPanel {

@Override
protected void paintComponent(Graphics _g) {
    super.paintComponent(_g);
    Graphics2D g = (Graphics2D) _g;
    g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    g.translate(150, 100); // translate so we can see method 1 clearly
    paintConcatenate(g);
    g.translate(200, 0); // translate again so we can see method 2 to the right of method 1
    paintSuccessive(g);
}

private void paintConcatenate(Graphics2D g) {
    AffineTransform tx = new AffineTransform();
    Shape shape = new Rectangle(-50, -50, 100, 100);

    // Draw the 3 steps, altering the transform each time
    draw(g, shape, tx, Color.GRAY);
    tx.rotate(Math.PI / 4);
    draw(g, shape, tx, Color.GREEN);
    tx.translate(70.7, 70.7);
    draw(g, shape, tx, Color.PINK);
}

private void paintSuccessive(Graphics2D g) {
    Shape shape = new Rectangle(-50, -50, 100, 100);

    // Draw the 3 steps, altering the shape each time with a new transform
    draw(g, shape, null, Color.GRAY);
    shape = AffineTransform.getRotateInstance(Math.PI / 4).createTransformedShape(shape);
    draw(g, shape, null, Color.GREEN);
    shape = AffineTransform.getTranslateInstance(0, 100).createTransformedShape(shape);
    draw(g, shape, null, Color.PINK);
}

private void draw(Graphics2D g, Shape shape, AffineTransform tx, Color color) {
    if (tx != null) {
        shape = tx.createTransformedShape(shape);
    }
    g.setColor(color);
    g.fill(shape);
}

public static void main(String[] args) {
    JFrame f = new JFrame("Transform Example");
    f.setSize(500, 350);
    f.setContentPane(new TransformExample());
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setVisible(true);
}

}

(我正在使用 Java2D,尽管我认为语言或 2d 库在这里并不是那么相关。)

4

2 回答 2

1

我建议您跟踪一些绝对值,然后尽可能减少转换。

例如,存储平移矩阵和围绕原点的旋转角度。

int translate[2];
int rotate;

现在,假设您要围绕其中心旋转,然后将对象平移到某个位置,然后在其中心下方再次旋转它。因为使用仿射变换,旋转矩阵不是可交换的,所以如果你应用旋转、平移、旋转,你会得到错误的结果。

但是您可以简单地将第一次和第三次旋转的旋转角度相加,然后应用一次旋转然后平移。

希望清楚。

于 2011-04-28T18:51:42.260 回答
0

旋转对象时,通常会围绕特定点旋转。看起来您只是在 (0,0) 周围旋转,这通常不是您想要的。

要围绕特定点 (x,y) 旋转,

  • 将点转换为 0 (-x, -y),
  • 然后旋转,
  • 然后翻译回来(x,y)。

    公共静态AffineTransform getRotateInstance(双theta,双anchorx,双anchor)

于 2011-04-28T18:53:54.333 回答