Russian Qt Forum
Октябрь 01, 2024, 12:33 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Вычисление координат в элементе после трансофрмации  (Прочитано 23862 раз)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« : Ноябрь 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);
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #1 : Ноябрь 01, 2013, 14:17 »

Код
C++ (Qt)
QRectF QGraphicsItem::sceneBoundingRect () const
Записан

Qt 5.11/4.8.7 (X11/Win)
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #2 : Ноябрь 01, 2013, 15:20 »

и как мне это доолжно помочь?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #3 : Ноябрь 02, 2013, 11:39 »

Что то я не пойму, как после трансформации получить координаты в пространстве элемента?
Не работал с QGraphics, но математика везде одинакова. Должно быть так. В пространстве элемента все остается неизменным. matrix переводит из пр-ва элемента в мир. После того как Вы сделали первый поворот нужно сохранить полученную матрицу и при следующем повороте домножать ее на новую. Как они множат -хз, ну вариантов всего 2, методом втыка попадете.
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #4 : Ноябрь 04, 2013, 18:40 »

Вобщем проблема так и не решена.

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

Сообщений: 4350



Просмотр профиля
« Ответ #5 : Ноябрь 04, 2013, 19:01 »

Вобщем проблема так и не решена.
Почитайте в ассистенте тему "The Graphics View Coordinate System".
У вас есть методы mapFromXXX и mapToXXX, которые позволяют преобразовывать координаты из/в системы координат элемента, например, в систему координат сцены. Вам нужно взять координаты курсора мыши, преобразовать их в координатную систему элемента, тогда их можно сравнивать, или наоборот, преобразовать координаты всех узлов из системы координат элемента в систему координат сцены.
Вот вышеназванная тема как раз описывает все системы координат и их взаимодействия друг с другом.
« Последнее редактирование: Ноябрь 04, 2013, 20:11 от Old » Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #6 : Ноябрь 04, 2013, 22:12 »

Вот сделал минимальный пример, вырезал все, оставил только все что касается перемещение и изменения размеров элемента на сцене. Посмотрите пожклуйста и подскажите где я ошибся. Уже несколько дней бьюсь, не могу понять в упор что не так.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #7 : Ноябрь 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() в координатах айтема. Складывая/вычитая их получаем ерунду
« Последнее редактирование: Ноябрь 06, 2013, 01:25 от Igors » Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #8 : Ноябрь 06, 2013, 10:40 »

Спасибо за ответ, но у меня он не заработал как надо. По сути ничего не изменилось, после поворота начинается расколбас.
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #9 : Ноябрь 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 с уже повёрнутым прямоугольником внутри?
Записан

Qt 5.11/4.8.7 (X11/Win)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #10 : Ноябрь 06, 2013, 13:45 »

Спасибо за ответ, но у меня он не заработал как надо. По сути ничего не изменилось, после поворота начинается расколбас.
У меня все норм - конечно только для одного угла который после поворота справа
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #11 : Ноябрь 06, 2013, 18:10 »

мне тоже кажется что логика рассчета у меня не ахти, но как говорится маемо те що маемо.
спасибо за советы, попробую еще совет от GreatSnake.
Записан
Maestro
Гость
« Ответ #12 : Ноябрь 12, 2013, 01:45 »

Помнится, нечто похожее есть в Embedded Dialogs Example
http://qt-project.org/doc/qt-5.0/qtwidgets/graphicsview-embeddeddialogs.html
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.194 секунд. Запросов: 23.