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

问题: - 给定两个元素(另一个元素的一个子元素) - 父元素旋转(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 回答