3

各変換を使用して連続して形状を操作するのと同じ効果が得られるように、アフィン変換を組み合わせる方法を探しています。問題は、単純に変換を連結すると、連続する各変換の効果が既存の変換の座標空間で解釈されることです。

たとえば、原点 (-50、-50、100、100) の周りの正方形を考えてみましょう。回転させてから、100px下に翻訳します。変換して回転させてから平行移動すると、平行移動は回転された座標で解釈されます。代わりに、形状自体を変換して回転させ、その形状を再度変換して平行移動すると、両方の平行移動が「通常の」非平行平面で解釈され、必要なものが得られます。

問題は、私がやっていることのために多くの変換が行われる可能性があり、それぞれが通常の座標平面で解釈される必要があることですが、変換のスタックを保存したくないし、単純に形状を操作し続けることもできません、元の開始形状から最終的な変換された形状をいつでも作成できるようにする必要があるためです。

例: 左が通常の連結、右が連続変換

この単純な例では、回転の前に平行移動を行った場合に同じ結果が得られることは承知していますが、それは要点がありません。私は連続するスケール、移動、および回転変換の任意のセットを扱っているので、単純にそれらを特定の順序に並べるだけではうまくいきません。

変換を連結する前に新しい変換を変更し、既存の変換を修正して、新しい変換が適用されたかのように見えるような方法で変換を連結する方法があるはずだと私は考えています。変換されていない座標平面を参照していました。たとえば、上記の例で (0,100) の代わりに (70.7, 70.7) で変換すると、結果は同等になります。一般的に、新しい変換を変更して正しく機能させる方法を理解するための数学が何であるかを理解できないようです。

読んでくれてありがとう - これが理にかなっていることを願っています. スクリーンショットを作成した例のソースは次のとおりです。

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;

ここで、オブジェクトをその中心を中心に回転させてから、オブジェクトをどこかに移動させてから、その中心の下で再び回転させたいとします。アフィン変換では、回転行列は可換ではないため、回転、平行移動、回転を適用すると、間違った結果が得られます。

ただし、1 回目と 3 回目の回転の回転角度を単純に合計し、1 回の回転を適用してから平行移動を適用することができます。

明確になることを願っています。

于 2011-04-28T18:51:42.260 に答える