2012-04-22 3 views
0

У меня возникли проблемы с определением правильного порядка преобразований для применения к элементам в моем приложении. Приложение имеет элементы, которые имеют родительские/дочерние отношения, и каждый элемент имеет преобразование (каждый элемент рисуется в локальном пространстве, а затем преобразовывается).java Affine Transform правильный заказ

То, что я хочу архивировать, состоит в том, что если я преобразую родительский объект, все его дочерние элементы также должны быть преобразованы (поэтому, если вы вращаете родителя, ребенок должен вращаться вокруг родителя).

Код ниже делает именно это, но проблема заключается в том, что я поворачиваю родительский элемент, а затем хочу переместить его. Он движется в неправильном направлении (из-за его родительского преобразования). Я попытался изменить последовательность преобразований, но не повезло (я знаю, что должен сначала перевести, а затем преобразовать, но потом ребенок повернут вокруг своей оси - вместо родителей).

Код:

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 Как могу я конкатенатные преобразования, чтобы при перемещении ребенка он не двигался в повернутом направлении?

EDIT: Код, который 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/). Кстати. У вас есть вопрос? –

ответ

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

+0

говорил вскоре, не проверив его правильно. Проблема в том, что когда родитель поворачивается на 40 градусов, и вы хотите переместить ребенка на 10 пикселей, он будет двигаться в повернутом направлении. – blejzz

+0

Это должно произойти с кодом, который я опубликовал, так как ребенок находится внутри системы координат родителя. Могу ли я спросить, почему вы хотите переводить независимо, но вращаться зависимо? – Torious

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). И я хочу переместить ребенка вправо на 10 пикселей. Но если я перемещаю элемент на 10 пикселей вправо, он перемещается на 10 пикселей, поворачиваясь на 60 градусов. – blejzz

+0

Что делает ваш метод 'transform()'? Возможно, вам нужно просто установить x/y, как я сделал в 'translateInAncestorSpace()' вместо вызова 'transform()'. – Torious

+0

просто добавляет dx и dy в текущую позицию. То же, что и ваш код. – blejzz

Смежные вопросы