Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: Fregloin от Ноябрь 01, 2013, 14:12



Название: Вычисление координат в элементе после трансофрмации
Отправлено: Fregloin от Ноябрь 01, 2013, 14:12
Есть прямоугольный элемент. По сути это ресайзер - элемент, который позволяет с помощью маркеров изменять размер дочернего.
Перемещение и изменение размеров делаю вручную. Все работает до того, как не использовать поворот. После этого все координаты сбиваются.
Что то я не пойму, как после трансформации получить координаты в пространстве элемента?
Привожу код

Код:
void    CRailItemResizer::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    if(event->button()==Qt::LeftButton)
    {
        if(editableItem())
            foldItemPosition = editableItem()->pos();
        fdragOrigin = event->pos();
        fsizeOrigin = fsize;
        fcurrentAnchor = getCurrentAnchor(event->pos());
        if(fcurrentAnchor!=AnchorNone)
        {
            QRectF  anchorRect = fanchors.at(fcurrentAnchor);
            switch (fcurrentAnchor)
            {
            case AnchorLeft:
                foriginOffset.setX(fdragOrigin.x()-anchorRect.right());
                break;
            case AnchorTopLeft:
                foriginOffset.setX(fdragOrigin.x()-anchorRect.right());
                foriginOffset.setY(fdragOrigin.y()-anchorRect.bottom());
                break;
            case AnchorTop:
                foriginOffset.setY(fdragOrigin.y()-anchorRect.bottom());
                break;
            case AnchorTopRight:
                foriginOffset.setX(fdragOrigin.x()-anchorRect.left());
                foriginOffset.setY(fdragOrigin.y()-anchorRect.bottom());
                break;
            case AnchorRight:
                foriginOffset.setX(fdragOrigin.x()-anchorRect.left());
                break;
            case AnchorBottomRight:
                foriginOffset.setX(fdragOrigin.x()-anchorRect.left());
                foriginOffset.setY(fdragOrigin.y()-anchorRect.top());
                break;
            case AnchorBottom:
                foriginOffset.setY(fdragOrigin.y()-anchorRect.top());
                break;
            case AnchorBottomLeft:
                foriginOffset.setX(fdragOrigin.x()-anchorRect.right());
                foriginOffset.setY(fdragOrigin.y()-anchorRect.top());
                break;
            default:
                break;
            }
        }
        update(); //обновить картинку с выделеным анкером
    }
    else
    {
        QGraphicsObject::mousePressEvent(event);
    }
}

void    CRailItemResizer::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
    QSizeF  oldSize = fsize;
    switch(fcurrentAnchor)
    {
    case    AnchorNone:
        onDrag(event->scenePos()-fdragOrigin);
    return;

    case    AnchorTopLeft:
        oldSize.setHeight(oldSize.height()-(event->pos().y()-foriginOffset.y()));
        oldSize.setWidth(oldSize.width()-(event->pos().x()-foriginOffset.x()));
        onDrag(event->scenePos()-fdragOrigin);
    break;

    case    AnchorTop:
    {
        QPointF oldPos = pos();
        oldPos.setY(event->scenePos().y()-fdragOrigin.y());
        oldSize.setHeight(oldSize.height()-(event->pos().y()-foriginOffset.y()));
        onDrag(oldPos);
    }
    break;

    case    AnchorTopRight:
    {
        QPointF oldPos = pos();
        oldPos.setY(event->scenePos().y()-fdragOrigin.y());
        oldSize.setHeight(oldSize.height()-event->pos().y()+foriginOffset.y());
        oldSize.setWidth(event->pos().x()-foriginOffset.x());
        onDrag(oldPos);
    }
    break;

    case    AnchorRight:
        oldSize.setWidth(event->pos().x()-foriginOffset.x());
    break;

    case    AnchorBottomRight:
        oldSize.setHeight(event->pos().y()-foriginOffset.y());
        oldSize.setWidth(event->pos().x()-foriginOffset.x());
    break;

    case    AnchorBottom:
    {
        oldSize.setHeight(event->pos().y()-foriginOffset.y());
    }
    break;

    case    AnchorBottomLeft:
    {
        QPointF oldPos = pos();
        oldPos.setX(event->scenePos().x()-fdragOrigin.x());
        oldSize.setHeight(event->pos().y()-foriginOffset.y());
        oldSize.setWidth(oldSize.width()-(event->pos().x()-foriginOffset.x()));
        onDrag(oldPos);
    }
    break;

    case    AnchorLeft:
    {
        QPointF oldPos = pos();
        oldPos.setX(event->scenePos().x()-fdragOrigin.x());
        oldSize.setWidth(oldSize.width()-(event->pos().x()-foriginOffset.x()));
        onDrag(oldPos);
    }
    break;
    }
    fsize = oldSize;
    prepareGeometryChange();
    recalculate();
    onResize(fsize);   //вызываем
}

void CRailItemResizer::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
    if(event->button()==Qt::LeftButton && editableItem())
    {
        if(foldItemPosition!=editableItem()->pos() || fsizeOrigin!=fsize)
            emit    changed(editableItem(),foldItemPosition,editableItem()->pos(),fsizeOrigin,fsize);
    }
}

Без поворта все работает отлично, как только поворот сделан, все, все плывет..
Поворт раньше делал через setRotation а теперь так
Код:
        QTransform  matrix;
        QRectF      boundRect = item->boundingRect();
        matrix.translate(boundRect.width()/2,boundRect.height()/2);
        matrix.rotate(angle);
        matrix.translate(-boundRect.width()/2,-boundRect.height()/2);
        //item->setRotation(angle);
        item->setTransform(matrix);


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: GreatSnake от Ноябрь 01, 2013, 14:17
Код
C++ (Qt)
QRectF QGraphicsItem::sceneBoundingRect () const


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Fregloin от Ноябрь 01, 2013, 15:20
и как мне это доолжно помочь?


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Igors от Ноябрь 02, 2013, 11:39
Что то я не пойму, как после трансформации получить координаты в пространстве элемента?
Не работал с QGraphics, но математика везде одинакова. Должно быть так. В пространстве элемента все остается неизменным. matrix переводит из пр-ва элемента в мир. После того как Вы сделали первый поворот нужно сохранить полученную матрицу и при следующем повороте домножать ее на новую. Как они множат -хз, ну вариантов всего 2, методом втыка попадете.


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Fregloin от Ноябрь 04, 2013, 18:40
Вобщем проблема так и не решена.

Задача - создать класс, который позволял бы "редактировать" элементы на сцене.
Под редактированием подразумевается:
Клик по объекту на сцене, над этим элементом создается редактор, задача которого отслеживать перемещение мыши и транслировать их в элемент под ним.
Например для изменения размера элемента или перемещения опортных точек полигона, из которого он состоит.
Все бы хорошо, все работает, но после поворта уже все не так работает как хотелось бы. Уже неделю бьюсь, ничего не могу понять. В инете все прошерстил. Эти трансформации...
Хоть убей не пойму.


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Old от Ноябрь 04, 2013, 19:01
Вобщем проблема так и не решена.
Почитайте в ассистенте тему "The Graphics View Coordinate System".
У вас есть методы mapFromXXX и mapToXXX, которые позволяют преобразовывать координаты из/в системы координат элемента, например, в систему координат сцены. Вам нужно взять координаты курсора мыши, преобразовать их в координатную систему элемента, тогда их можно сравнивать, или наоборот, преобразовать координаты всех узлов из системы координат элемента в систему координат сцены.
Вот вышеназванная тема как раз описывает все системы координат и их взаимодействия друг с другом.


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Fregloin от Ноябрь 04, 2013, 22:12
Вот сделал минимальный пример, вырезал все, оставил только все что касается перемещение и изменения размеров элемента на сцене. Посмотрите пожклуйста и подскажите где я ошибся. Уже несколько дней бьюсь, не могу понять в упор что не так.


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Igors от Ноябрь 05, 2013, 22:58
Пример: тянем правый верхний угол. Считаем что противоположный (левый нижний) остается на месте. Начало координат вйтема в левом верхнем углу

Код
C++ (Qt)
   case    AnchorTopRight:
   {
/*
       QPointF oldPos = pos();
       oldPos.setY(event->scenePos().y()-fdragOrigin.y());
       oldSize.setHeight(oldSize.height()-event->pos().y()+foriginOffset.y());
       oldSize.setWidth(event->pos().x()-foriginOffset.x());
       onDrag(oldPos);
*/

qreal x1 = 0, y1 = oldSize.height();   // opposite (left bottom) corner
qreal x2 = event->pos().x(),
y2 = event->pos().y();   // dragged (right top) corner
 
oldSize = QSizeF(qAbs(x1 - x2), qAbs(y1 - y2)); // recalc size
               // QPointF newPos = QPointF(0, y1 - oldSize.height()) + pos();  // неверно
QPointF newPos = editableItem()->mapToScene(QPointF(0, y2));
onDrag(newPos);
   }
   break;
 
Edit: ошибка (которую я тоже повторил  :)) была в том что pos() в координатах сцены, а event->pos() в координатах айтема. Складывая/вычитая их получаем ерунду


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Fregloin от Ноябрь 06, 2013, 10:40
Спасибо за ответ, но у меня он не заработал как надо. По сути ничего не изменилось, после поворота начинается расколбас.


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: GreatSnake от Ноябрь 06, 2013, 13:10
Очень всё усложнил.
Вот переделанный CRailItemResizer::mouseMoveEvent():
Код
C++ (Qt)
void    CRailItemResizer::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QPointF d = event->scenePos() - event->lastScenePos();
qreal dx1 = 0;
qreal dy1 = 0;
qreal dx2 = 0;
qreal dy2 = 0;
 
switch(fcurrentAnchor)
{
case AnchorNone:
onDrag( pos() + d );
return;
break;
 
case    AnchorTopLeft:
dy1 = d.y();
dx1 = d.x();
break;
 
case    AnchorTop:
dy1 = d.y();
break;
 
case    AnchorTopRight:
dx2 = d.x();
dy1 = d.y();
break;
 
case    AnchorRight:
dx2 = d.x();
break;
 
case    AnchorBottomRight:
dx2 = d.x();
dy2 = d.y();
break;
 
case    AnchorBottom:
dy2 = d.y();
break;
 
case    AnchorBottomLeft:
dx1 = d.x();
dy2 = d.y();
break;
 
case    AnchorLeft:
dx1 = d.x();
break;
}
 
QRectF r( pos(), size() );
r.adjust( dx1, dy1, dx2, dy2 );
onDrag( r.topLeft() );
 
fsize = r.size();
onResize( fsize );
 
prepareGeometryChange();
recalculate();
}
 
но всё равно остаются проблемы с логикой расчёта.
Может проще использовать QGraphicsPolygonItem с уже повёрнутым прямоугольником внутри?


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Igors от Ноябрь 06, 2013, 13:45
Спасибо за ответ, но у меня он не заработал как надо. По сути ничего не изменилось, после поворота начинается расколбас.
У меня все норм - конечно только для одного угла который после поворота справа


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Fregloin от Ноябрь 06, 2013, 18:10
мне тоже кажется что логика рассчета у меня не ахти, но как говорится маемо те що маемо.
спасибо за советы, попробую еще совет от GreatSnake.


Название: Re: Вычисление координат в элементе после трансофрмации
Отправлено: Maestro от Ноябрь 12, 2013, 01:45
Помнится, нечто похожее есть в Embedded Dialogs Example
http://qt-project.org/doc/qt-5.0/qtwidgets/graphicsview-embeddeddialogs.html (http://qt-project.org/doc/qt-5.0/qtwidgets/graphicsview-embeddeddialogs.html)