java Affine转换正确的顺序

时间:2012-04-22 14:15:40

标签: java swing

我无法确定应用于应用中元素的正确转换顺序。 app具有父/子关系的元素,每个元素都有一个转换(每个元素都在局部空间中绘制然后转换)。

我要归档的是,如果我变换父项,它的所有子项也应该被变换(所以如果你旋转父项,子项应该围绕父项旋转)。

下面的代码就是这样,但问题是我旋转父级然后想要移动孩子。它向错误的方向移动(由于其父转换)。我已经尝试改变转换的顺序,但没有运气(我知道我应该首先翻译,然后转换,但然后孩子围绕自己的轴旋转 - 而不是父母)。

代码:

 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);
}

问题:   - 给出两个元素(另一个孩子)   - 父母旋转(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]

2 个答案:

答案 0 :(得分: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);
}

答案 1 :(得分: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);

这是你的意思吗?