1

アプリの要素に適用する変換の正しい順序を理解するのに苦労しています。アプリには親子関係を持つ要素があり、各要素には変換があります (各要素はローカル空間に描画されてから変換されます)。

私がアーカイブしたいのは、親を変換すると、そのすべての子も変換される必要があることです(したがって、親を回転させると、子は親の周りを回転する必要があります)。

以下のコードはまさにそれを行いますが、問題は親を回転させてから子を移動したい場合です。間違った方向に移動します (親の変換のため)。変換のシーケンスを変更しようとしましたが、うまくいきませんでした (最初に変換してから変換する必要があることはわかっていますが、その後、子は親ではなく独自の軸を中心に回転します)。

コード:

 Element e;
 AffineTransform t = new AffineTransform();
 AffineTransform t3 = new AffineTransform();

 for (i = 0; i < el.size(); i++)
 {
    e = el.get(i);
    t3.setToIdentity();
    t.setToIdentity();
    tmp = e.getParent();
    while(tmp != null)
    {
         t.translate(tmp.getX(), tmp.getY());
         t3.rotate(Math.toRadians(tmp.getAngle()),tmp.getAnchorX(), tmp.getAnchorY());
         tmp = tmp.getParent();
    }

    t.concatenate(t3);
    t.translate(e.getX(), e.getY());

    t.rotate(Math.toRadians(e.getAngle()),e.getAnchorX(), e.getAnchorY());

    e.draw(g2d,t);
}

問題: - 2 つの要素 (他の 1 つの子) が与えられた場合 - 親が回転 (40 度) - 子が 10px 移動 子を移動したときに回転方向に移動しないように変換を連結するにはどうすればよいですか?

編集: Torious が投稿したコード (まだ動作していません):

public AffineTransform getTransformTo(Element ancestor) {
    AffineTransform t = (AffineTransform)getAffineTransform().clone();
    Element parent = getParent();
    while (parent != null && parent != ancestor) {
        t.preConcatenate(parent.getAffineTransform());
        parent = parent.getParent();
    }
    return t;
}


public void translateInAncestorSpace(Element ancestor, Point translation) {
    AffineTransform fromAncestor = getTransformTo(ancestor); // to ancestor space
    try
    {
        fromAncestor.invert();
    } catch(Exception e)
    {
       e.printStackTrace();   
    }
    translation = (Point)fromAncestor.transform(translation, new Point());

    Transform t1 = new Transform();
    t1.translate(translation.x,translation.y);
    transform(t1);
}

コードの出力:

 Moving by [x=1,y=1] old position [x=22,y=40]
 Moved by [x=-21,y=-39] new position [x=1,y=1]
 Moving by [x=2,y=2] old position [x=1,y=1]
 Moved by [x=1,y=1] new position [x=2,y=2]
 Moving by [x=4,y=3] old position [x=2,y=2]
 Moved by [x=2,y=1] new position [x=4,y=3]
4

2 に答える 2

3

このようなもの:

// get composite transform for 'e'
t.setToIdentity();
t.translate(e.getX(), e.getY());
t.rotate(...);

tmp = e.getParent();
while (tmp != null) {

    // get composite transform for parent
    t3.setToIdentity();
    t3.translate(tmp.getX(), tmp.getY());
    t3.rotate(...);
    tmp = tmp.getParent();

    t.preConcatenate(t3); // t3 is applied after t
}

e.draw(g2d, t);

編集:実際には別の要素の子である要素を「グローバル空間」で移動するには、目的の移動を要素空間に変換して、その翻訳に簡単に追加できるようにすることをお勧めします。

(未テストのコード)

// Element.getTransformTo: get transform to ancestor or root (null)
public AffineTransform getTransformTo(Element ancestor) {
    AffineTransform t = getCompositeTransform();
    Element parent = getParent();
    while (parent != null && parent != ancestor) {
        t.preConcatenate(parent.getCompositeTransform());
        parent = parent.getParent();
    }
}

// Element.translateInAncestorSpace
// ancestor may be null for root/global space
public void translateInAncestorSpace(Element ancestor, Point translation) {
    AffineTransform fromAncestor = getTransformTo(ancestor); // to ancestor space
    fromAncestor.invert(); // from ancestor space

    // [NEW] re-apply element rotation since translation occurs after rotation
    fromAncestor.rotate(Math.toRadians(angle), anchor.x, anchor.y);

    translation = fromAncestor.deltaTransform(translation, new Point());

    // translation is now in element space; add to existing translation
    element.setX(element.getX() + translation.x);
    element.setY(element.getY() + translation.y);
}

// example usage:
// (this should move the element 10px to the right, regardless
// of parent transforms)
element.translateInAncestorSpace(null, new Point(10, 0));

AffineTransform Element.getCompositeTransform()また、最終的にあなたの人生を楽にする方法を実装することを検討してください.

また、「要素ツリー」をルート ノードからリーフ ノードにレンダリングすることを検討すると、次のようになります。

public void render(Element node, AffineTransform transform) {

    AffineTransform nodeTransform = node.getCompositeTransform();
    nodeTransform.preConcatenate(transform);

    node.draw(g2d, nodeTransform);

    for (Element child : node.children())
        render(child, nodeTransform);
}
于 2012-04-22T14:28:33.527 に答える
1

わかりました、私はあなたが今何を望んでいるのか理解していると思います. 以下のコード、(テストされていない) 翻訳を連結する必要がありますが、回転は連結しません。各要素は、独自の回転によってのみ影響を受けます。

コードの意図が以前の回答のコードとは異なるため、これを新しい回答として投稿しました。

このコードでは、要素の x と y を設定して翻訳します。

// set e's translation
t.setToIdentity();
t.translate(e.getX(), e.getY());

// add ancestor translations (order is irrelevant)
Element parent = e.getParent();
while (parent != null) {
    t.translate(parent.getX(), parent.getY());
    parent = parent.getParent();
}

// append e's rotation (applied first)
t.rotate(...);

e.draw(g2d, t);

これはあなたが意味するものですか?

于 2012-04-22T18:13:21.833 に答える