2012-04-22 68 views
0

我无法找出适用于我的应用程序中元素的正确转换顺序。该应用程序具有父/子关系的元素,每个元素都有一个转换(每个元素都在本地空间中绘制,然后转换)。java仿Affine变换正确的顺序

我想归档的是,如果我转换父母,所有的孩子也应该变形(所以如果你旋转父母,孩子应该围绕父母旋转)。

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

代码:

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] 
+0

为了更快提供更好的帮助,请发布[SSCCE](http://sscce.org/)。顺便说一句 - 你有问题吗? – 2012-04-22 14:27:15

回答

2

事情是这样的:

// 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); 
} 
+0

非常感谢。它可以在工作时删除“未经测试”。 “元素树”的问题是我不能将元素渲染为树,因为元素必须按z索引进行排序。 – blejzz 2012-04-22 14:59:37

+0

没有正确地测试它很快讲到了。问题是,当家长旋转了40度,并且您想要将孩子移动10px时,它将沿旋转的方向移动。 – blejzz 2012-04-22 15:05:02

+0

这应该与我发布的代码发生,因为孩子是在父母的坐标系内。我可以问为什么你想独立翻译,但依赖于旋转? – Torious 2012-04-22 15:11:18

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

这是你的意思吗?

+0

每个元素都受其自身及其父母的旋转影响。你之前的回答是正确的。唯一的问题是当元素被移动时,因为它不在x,y方向上移动。例如10,10和30的一个元素,其他元素是10,10和30的第一个子元素(他的全局值是20,20和60)。我想把孩子向右移动10px。但如果我将元素向右移动10px,它将移动10px旋转60度。 – blejzz 2012-04-22 18:33:42

+0

你的'transform()'方法是做什么的?也许你应该像在'translateInAncestorSpace()'中那样设置x/y而不是调用'transform()'。 – Torious 2012-04-22 19:02:59

+0

它只是将dx和dy添加到当前位置。和你的代码一样。 – blejzz 2012-04-22 19:04:21