Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: iroln от Август 07, 2011, 13:49



Название: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 07, 2011, 13:49
Здравствуйте!

Сначала кратко опишу, что я хочу сделать, а затем опишу проблему, с которой я столкнулся.

Итак. Я разрабатываю некоторый инструментарий для отображения и работы с изображением. Графическая сцена (QGraphicsScene) всегда имеет размер оригинального изображения, а графическое представление (QGraphicsView) кроме сцены отображает изображение с заданными параметрами масштаба и сдвига. Изображение рисуется специальным рисовальщиком не на background-слой сцены, а в viewport уже с заданными параметрами отображения (масштаб, сдвиг и т.д.). Масштабом отображения сцены и изображения управляет графическое представление с помощью своей матрицы преобразования.

Кроме отображения изображения, мне нужны инструменты для работы с изображением. Первый инструмент - это интерактивная рамка (ImageRectItem). Пользователь может перемещать эту рамку по изображению, изменять её размеры, таская мышкой за края рамки и специальные маркеры:
(http://lostpic.net/thumbs/9b9fafe60af16a625705a0ac37a61063.png) (http://lostpic.net/?view=9b9fafe60af16a625705a0ac37a61063)

При разработке такого инструмента я и столкнулся с проблемой.
Инструмент ImageRectItem реализован на базе класса QGraphicsRectItem, ручки-маркеры ImageRectMarkerItem реализованы тоже на базе QGraphicsRectItem и являются потомками ImageRectItem, они обеспечивают возможность изменения размера рамки (resize). Проблема вот в чём. Необходимо, чтобы размеры ручек-маркеров находились в системе координат области отображения и не зависели от текущего масштаба вида, то есть при масштабировании матрицы представления, размеры ручек маркеров не изменялись, чтобы не было вот такого:
(http://lostpic.net/thumbs/105c039686b7ce391c5da9bf7b078b50.png) (http://lostpic.net/?view=105c039686b7ce391c5da9bf7b078b50)

Я попытался решить эту проблему, выставив для ImageRectMarkerItem флаг ItemIgnoresTransformations в true, но проблему это не решило. Размеры теперь не изменяются, но теперь ручки-маркеры стали "жить" в системе координат области отображения и зависеть от scale области отображения:
(http://lostpic.net/thumbs/3959faeef7d83fdfb3f032a7479a430a.png) (http://lostpic.net/?view=3959faeef7d83fdfb3f032a7479a430a)
То есть локальные координаты рамок ручек-маркеров соответствуют системе координат сцены, поэтому неверно отображаются на виде.

Затем я попытался переопределить метод paint в классе ImageRectMarkerItem и рисовать ручки-маркеры как мне нужно, игнорируя scale, но появилась проблема с boundingRect и shape, так как эти функции ничего не знают о том, что я рисую в paint.

Подскажите, пожалуйста, как решить эту проблему, как заставить графические элементы жить в системе координат сцены, но чтобы их размеры оставались неизменны при масштабировании вида области отображения? Естественно, что с одной сценой могут работать несколько видов.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 07, 2011, 21:40
В общем на данный момент смог залепить такой костыль:

1. Для элементов класса ImageRectItem устанавливаю флаг ItemIgnoresTransformations в true
2. Для элементов класса ImageRectMarkerItem устанавливаю флаг ItemIgnoresTransformations в false и свойство transformOriginPoint в значение marker_rect.center(), позиция маркера обновляется всякий раз при обновлении родительской рамки (ImageRectItem)
3. В классе ImageRectItem переопределяю метод setScale() и в этом методе для всех потомков (ручек-маркеров) устанавливаю scale = 1 / parent_scale
4. В своём классе ImageView, который наследуется от QGraphicsView, в методе, который изменяет масштаб отображения, для всех элементов класса ImageRectItem обновляю scale, вызывая их метод setScale() и передавая в него текущий масштаб вида.

По такой схеме всё работает правильно, но мне не нравится то, что приходится в классе вида взаимодействовать с графическими элементами определённого типа, изменять их свойства. Проверка типа элементов и установка трансформаций занимает время и вообще, всё это как-то криво, как мне кажется. Хотя бы потому, что такая схема не работает с несколькими видами. Так как трансформации инструмента, сделанные в одном виде, делают неверным отображение этого же инструмента в другом виде, где может быть задан совсем другой масштаб.

Должен быть более красивый и верный способ сделать то, что я хочу. Гуру работы с графикой в Qt, подскажите путь, куда двигаться. С этими трансформациями можно мозги покалечить. :)



Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 08, 2011, 09:48
Проблему решил. Не совсем, конечно, так как хотелось в идеале, но дальше возиться с этим нет ни желания ни времени. Лень уже описывать как именно проблема была решена, но если кому-то вдруг будет интересно решение, или кто-то столкнётся с подобными трудностями, пишите в личку.

Понял одно, хвалёная гибкость и универсальность тулкитов вроде Qt может выйти боком и вообще ставится под сомнение, когда нужно сделать что-то не совсем стандартное.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: Igors от Август 08, 2011, 10:14
Понял одно, хвалёная гибкость и универсальность тулкитов вроде Qt может выйти боком и вообще ставится под сомнение, когда нужно сделать что-то не совсем стандартное.
Ну "нестандартным" то что Вы хотите никак не назовешь  :)
Я столкнулся с похожими трудностями: хотел рисовать одну модель в неск окнах (виды спереди, сбоку и.т.п). Логично было бы иметь один QGraphicsItem, одну QGraphicsScene и нужное кол-во QGraphicsView - но это не проходит из-за boundingRect  :'(

Иногда молчание объясняется не тем что, мол, никому неинтересно, а тем что хорошего ответа просто нет  :) 


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 08, 2011, 11:05
Я столкнулся с похожими трудностями: хотел рисовать одну модель в неск окнах (виды спереди, сбоку и.т.п). Логично было бы иметь один QGraphicsItem, одну QGraphicsScene и нужное кол-во QGraphicsView - но это не проходит из-за boundingRect
Мде, как говорится - "хотеть не вредно" :(
Тоже не раз приходило такое желание, но, видимо, MVC в случае с QGraphics не работает. Максимально, что удалось из этого выжать - это zoom-view.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 08, 2011, 15:02
Проблему решил. Не совсем, конечно, так как хотелось в идеале, но дальше возиться с этим нет ни желания ни времени. Лень уже описывать как именно проблема была решена, но если кому-то вдруг будет интересно решение, или кто-то столкнётся с подобными трудностями, пишите в личку.

Понял одно, хвалёная гибкость и универсальность тулкитов вроде Qt может выйти боком и вообще ставится под сомнение, когда нужно сделать что-то не совсем стандартное.
На самом деле, имхо, вы просто не разобрались до конца и делается это всё довольно-таки просто. Вот работающий пример:
Код
C++ (Qt)
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>
#include <QMouseEvent>
 
class RubberItem : public QGraphicsRectItem
{
public:
RubberItem( const QRectF& r, QGraphicsItem* parent = 0 )
: QGraphicsRectItem( r, parent )
{
QColor clr( Qt::blue );
setPen( clr );
clr.setAlphaF( .1 );
setBrush( clr );
}
virtual ~RubberItem() {}
QRectF boundingRect() const
{
qreal es = grip_size_ / 2;
return rect().adjusted( -es, -es, es, es );
}
void paint( QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = 0 )
{
QGraphicsRectItem::paint( painter, option, widget );
 
QMatrix m = painter->matrix();
QRectF irect( QRectF( QPointF( 0, 0 ), m.mapRect( rect() ).size() ) );
 
qreal gs = grip_size_;
QRectF r( -gs / 2, -gs / 2, gs, gs );
r.translate( m.map( QPointF( 0, 0 ) ) );
 
QColor clr( painter->brush().color() );
clr.setAlphaF( 1 );
painter->setBrush( clr );
 
painter->resetTransform();
 
painter->drawRect( r.translated( irect.topLeft() ) );
painter->drawRect( r.translated( QPointF( irect.width() / 2, 0 ) ) );
painter->drawRect( r.translated( irect.topRight() ) );
painter->drawRect( r.translated( QPointF( 0, irect.height() / 2 ) ) );
painter->drawRect( r.translated( irect.bottomLeft() ) );
painter->drawRect( r.translated( QPointF( irect.width(), irect.height() / 2 ) ) );
painter->drawRect( r.translated( irect.bottomRight() ) );
painter->drawRect( r.translated( QPointF( irect.width() / 2, irect.height() ) ) );
}
Qt::WindowFrameSection frameSectionAt( const QPointF& p ) const
{
QRectF irect( rect() );
 
qreal gs = grip_size_;
QRectF r( -gs / 2, -gs / 2, gs, gs );
r.translate( pos() );
 
Qt::WindowFrameSection section = Qt::NoSection;
if( r.translated( irect.topLeft() ).contains( p ) )
section = Qt::TopLeftSection;
else if( r.translated( QPointF( irect.width() / 2, 0 ) ).contains( p ) )
section = Qt::TopSection;
else if( r.translated( irect.topRight() ).contains( p ) )
section = Qt::TopRightSection;
else if( r.translated( QPointF( irect.width(), irect.height() / 2 ) ).contains( p ) )
section = Qt::RightSection;
else if( r.translated( irect.bottomRight() ).contains( p ) )
section = Qt::BottomRightSection;
else if( r.translated( QPointF( irect.width() / 2, irect.height() ) ).contains( p ) )
section = Qt::BottomSection;
else if( r.translated( irect.bottomLeft() ).contains( p ) )
section = Qt::BottomLeftSection;
else if( r.translated( QPointF( 0, irect.height() / 2 ) ).contains( p ) )
section = Qt::LeftSection;
return section;
}
 
static qreal gripSize() { return grip_size_; }
 
private:
static const qreal grip_size_ = 5;
};
 
class GraphicsView : public QGraphicsView
{
public:
GraphicsView( QWidget* p = 0 ) : QGraphicsView( p )
{
viewport()->setMouseTracking( true );
}
void resizeEvent( QResizeEvent* e )
{
fitInView( scene()->sceneRect() );
}
void mouseMoveEvent( QMouseEvent* e )
{
QGraphicsView::mouseMoveEvent( e );
QList< QGraphicsItem* > il = items(
e->pos().x(), e->pos().y(), 1, 1, Qt::IntersectsItemBoundingRect );
RubberItem* ri;
if( !il.isEmpty() &&
( ri = dynamic_cast< RubberItem* >( il.first() ) ) )
updateRubberItemCursor( ri, e->pos() );
else
viewport()->unsetCursor();
}
void updateRubberItemCursor( RubberItem* ri, const QPoint& cpos )
{
switch( ri->frameSectionAt( mapToScene( cpos ) ) )
{
case Qt::TopLeftSection:
case Qt::BottomRightSection:
viewport()->setCursor( Qt::SizeFDiagCursor );
break;
case Qt::TopRightSection:
case Qt::BottomLeftSection:
viewport()->setCursor( Qt::SizeBDiagCursor );
break;
case Qt::TopSection:
case Qt::BottomSection:
viewport()->setCursor( Qt::SizeVerCursor );
break;
case Qt::LeftSection:
case Qt::RightSection:
viewport()->setCursor( Qt::SizeHorCursor );
break;
default:
viewport()->unsetCursor();
break;
}
}
};
 
int main( int argc, char** argv )
{
QApplication app( argc, argv );
 
GraphicsView gv;
QGraphicsScene scene;
 
gv.setScene( &scene );
 
scene.setSceneRect( 0, 0, 300, 300 );
RubberItem item( QRectF( 0, 0, 200, 200 ) );
scene.addItem( &item );
item.setPos( 50, 50 );
 
gv.show();
 
return app.exec();
}
 

PS: исправил GraphicsView::mouseMoveEvent() чтобы при поиске элемента учитывался его boundingRect().


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 08, 2011, 16:56
GreatSnake, благодарю за пример!

Но у меня почему-то в этом примере не работает ресайз, пока не разбирался почему. Очень трудно попасть мышкой в grips, потому что нужно суметь прицелиться в точку вершины прямоугольника (e->pos()), так как grips по сути в этом примере виртуальные, они просто рисуются в методе paint.

В моём коде я сделал ручки-маркеры (grips) в виде графических объектов, это позволяет задавать им нужный boundingRect для лучшего попадания мышкой. Если бы ещё решить проблему с трансформациями, а именно, я хочу, чтобы событие ресайза активировалось не только когда курсор находится над ручкой-маркером, но и по всем границам рамки. Раньше у меня это было сделано как раз через boundingRect и shape ручек-маркеров, но после переделки кода, ручки маркеры стали игнорировать трансформации, поэтому так сделать уже не получается, так как родитель трансформации не игнорирует и без знания о масштабе вида не удастся вычислить правильные boundingRect.

Я могу убрать всё лишнее из моей реализации, выложить её сюда, чтобы стало более понятно, если это кому-то нужно. Ещё одна причина, по которой я стараюсь не переопределять кричные к скорости методы, такие как paint, boundingRect и т.д., это то, что я пишу приложение на PySide.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: Igors от Август 08, 2011, 21:23
На самом деле, имхо, вы просто не разобрались до конца и делается это всё довольно-таки просто. Вот работающий пример:
Не могу назвать такой пример простым и ясным :) Написали Вы чисто, хорошо, но капитальный пробой в архитектуре QGraphics от этого, пожалуй, еще более заметен. Мол, "если чего не достает, сделаем руками!" - так тут много чего придется делать. Вычисление ресайза уже не мед. А если родительский rect item перекрыт (полностью или частично)? Какие "ручки" бум рисовать а какие нет? Это только так, навскидку - а там "чем дальше в лес тем больше дров", попрет из всех щелей.

На мой взгляд лучше все вспомогательные ручки держать как item'ы. Да. приходится смириться с тем что для каждого QGraphicsView надо иметь свои QGraphicsItem'ы. Да, это у них сделано мудаковато, но в конце концов "nothing is perfect", нельзя надеяться что фреймворк удовлетворит все наши запросы/желания - к этому нужно спокойно относиться  :)


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 08, 2011, 22:17
На мой взгляд лучше все вспомогательные ручки держать как item'ы. Да. приходится смириться с тем что для каждого QGraphicsView надо иметь свои QGraphicsItem'ы. Да, это у них сделано мудаковато, но в конце концов "nothing is perfect", нельзя надеяться что фреймворк удовлетворит все наши запросы/желания - к этому нужно спокойно относиться  :)
А как это, для каждого QGraphicsView свои QGraphicsItem'ы? Ведь нельзя же вроде item'ы на одном виде скрыть, на другом показать. Это тогда надо и сцену для каждого представления свою собственную. Но тогда вся архитектура модель-представление в QGraphics летит к чертям. Честно говоря, на мой взгляд, QGraphics, конечно, лучше чем QCanvas, но что-то в архитектуре всё же не так, потому что шаг в сторону от колеи примеров из документации, обязательно вылазит какая-нибудь бяка.

Вот как пример: Вся эта куча трансформаций и систем координат. В QPainter своя матрица трансформации, в QGraphicsView своя матрица трансформации, у QGraphicsItem тоже есть своя матрица трансформации, а толку? Я понимаю, что это сделано для гибкости, но при всей этой гибкости многие вещи всё равно сделать не получается. Вопросов у людей по поводу QGraphicsScene /QGraphicsView тоже куча, потому что использование этого инструмента нельзя назвать тривиальным и даже удобным. Архитектура QGraphicsScene/QGraphicsView появилась в Qt 4.2, но мне кажется, что инструментарий ещё сырой, даже API местами не согласовано и слишком перегружено.

Не отрицаю, что может быть я просто не разобрался до конца в инструменте, но в остальном Qt у меня не возникает столько трудностей, сколько возникает с этой графической архитектурой, хотя я пишу уже не первое приложение с её использованием.



Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: Igors от Август 09, 2011, 09:35
А как это, для каждого QGraphicsView свои QGraphicsItem'ы? Ведь нельзя же вроде item'ы на одном виде скрыть, на другом показать. Это тогда надо и сцену для каждого представления свою собственную.
Да, ну и что здесь такого уж плохого? У Вас уже есть необходимость в 2 и более видах одной сцены? Если пока нет, то решаете "немасштабируемость" компенсацией масштаба.и живете спокойно.

Я лично не вижу зачем иметь 2 и более вида "с теми же самыми айтемами". Гораздо более реален напр такой случай: в одном окне - все "объекты", а в другом - только один крупным планом. Так все равно с одной сценой не протолкнетесь.

Но тогда вся архитектура модель-представление в QGraphics летит к чертям.
То чего нет - не летает  :)


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 09, 2011, 09:53
Я лично не вижу зачем иметь 2 и более вида "с теми же самыми айтемами". Гораздо более реален напр такой случай: в одном окне - все "объекты", а в другом - только один крупным планом. Так все равно с одной сценой не протолкнетесь.
Ну почему, я думаю это вполне возможно. В первом окне отображаются все объекты, а для второго окна можно задать нужные параметры масштаба и sceneRect и отображать нужный кусок сцены. Проблема в том, что с одной сценой не получится настроить различную интерактивность отдельных элементов в каждом из видов и скрывать/показывать отдельные элементы, это и портит всю малину. :)

То чего нет - не летает  :)
Видимо так и есть. :)


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: Igors от Август 09, 2011, 10:02
Ну почему, я думаю это вполне возможно. В первом окне отображаются все объекты, а для второго окна можно задать нужные параметры масштаба и sceneRect и отображать нужный кусок сцены.
Да, здесь придется синхронизировать 2 или более сцен, но так ли уж это страшно? Ну дали каждому айтему указатель на "корневые" данные (общие для всех сцен), связали айтемы в разных сценах сигналами для их синхронного перемещения, выбора, удаления. Зато руки свободны, что хотите - то и делаете


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 09, 2011, 10:44
Igors, согласен с Вами. Мысли здравые. Похоже, так и буду делать. :)


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 09, 2011, 11:12
Но у меня почему-то в этом примере не работает ресайз, пока не разбирался почему.
Дык ресайз там просто не реализован)

Цитировать
Очень трудно попасть мышкой в grips, потому что нужно суметь прицелиться в точку вершины прямоугольника (e->pos()),
А кто мешает в frameSectionAt() увеличить границы.

Цитировать
так как grips по сути в этом примере виртуальные, они просто рисуются в методе paint.
А что если grips-ы будут самостоятельными айтемами что-то изменится ???

Igors, согласен с Вами. Мысли здравые. Похоже, так и буду делать. :)
Зачем так сложно ??? Чем не устраивает мой вариант?
Что вы выиграете от разбивки grips-ов на отдельные элементы? Да ещё создавая кучу сцен.
Не понимаю. Зачем из простой задачи устраивать такие сложности?



Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 09, 2011, 11:32
Не могу назвать такой пример простым и ясным :) Написали Вы чисто, хорошо, но капитальный пробой в архитектуре QGraphics от этого, пожалуй, еще более заметен. Мол, "если чего не достает, сделаем руками!" - так тут много чего придется делать. Вычисление ресайза уже не мед.
Абсолютно согласен. Только вот, имхо, на данный момент это самый простой вариант. Иначе одновременно рисовать с трансформациями и без не получится.

Цитировать
А если родительский rect item перекрыт (полностью или частично)? Какие "ручки" бум рисовать а какие нет? Это только так, навскидку - а там "чем дальше в лес тем больше дров", попрет из всех щелей.
Не понял насчёт "родительский rect item". Его ведь нет. Всё делается в рамках одного айтема. Изучая исходники Qt ни разу не видел обеспокоенности авторов об излишней отрисовке. Включите перед запуском любого приложения переменную среды QT_FLUSH_UPDATE и сами всё увидите) Тем более что при "глобальном" double-buffering это не так актуально. Но если уж очень хочется,  то никто нам не мешает получить от painter-a clipRegion() и проверять вхождение этих grips в "exposures".

Цитировать
На мой взгляд лучше все вспомогательные ручки держать как item'ы. Да. приходится смириться с тем что для каждого QGraphicsView надо иметь свои QGraphicsItem'ы.
А вот это, имхо, самое тупиковое решение. Айтем должен быть один. Если отрисовка вьюх должна отличаться по содержанию нужно такую отрисовку переность в QGraphicsView::drawForeground() или в перегруженных QGraphicsItem::paint() проверать в какой вьюхе делается отрисовка и делать return для ненужной.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 09, 2011, 11:35
Вот как пример: Вся эта куча трансформаций и систем координат. В QPainter своя матрица трансформации, в QGraphicsView своя матрица трансформации, у QGraphicsItem тоже есть своя матрица трансформации, а толку?
В QPainter матрица берётся от QGraphicsView и перемножается на матрицу QGraphicsItem, если оная у него имеется.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 09, 2011, 14:43
Цитировать
А кто мешает в frameSectionAt() увеличить границы.
Да это не поможет. Дело в другом. В вашем коде событие сработает только когда курсор мыши попадёт в активную область айтема, поэтому половина ручки игнорируется. Точность границы айтема можно задать через boundingRect() и shape(), у вас просто shape не переопределён, поэтому используется область по умолчанию. И ещё что-то с определением попадания не так, области ручек как будто бы сдвинуты внутрь айтема.

Я вообще не очень понимаю, почему Вы обрабатываете событие попадания в ручку айтема в классе вида, когда это можно делать непосредственно в классе айтема, например, в функции hoverEnterEvent(). При этом для айтема точно так же можно определить точность границ через функции boundingRect() и shape(), которые будут учитывать размеры ручек, что, кстати позволит сделать отслеживание области ресайза по всему периметру рамки, а не только внутри ручек.

Я сделаю вариант инстурмента по вашему примеру, сравню работоспособность и удобство использования, скорость и прочее. Выберу, что больше понравится и будет лучше работать. :)

Цитировать
Иначе одновременно рисовать с трансформациями и без не получится.
У меня получилось. Я рисую родительский айтем рамки с трансформациями пером нулевой толщины, а потомки-айтемы ручек рисую с игнорированием трнасформаций, просто задавая для них позицию, привязанную к координатам родительского айтема. Получается, что ручки всегда стоят на своих местах и не изменяют размер при любом масштабе.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 09, 2011, 16:09
Цитировать
А кто мешает в frameSectionAt() увеличить границы.
Да это не поможет. Дело в другом. В вашем коде событие сработает только когда курсор мыши попадёт в активную область айтема, поэтому половина ручки игнорируется. Точность границы айтема можно задать через boundingRect() и shape(), у вас просто shape не переопределён, поэтому используется область по умолчанию. И ещё что-то с определением попадания не так, области ручек как будто бы сдвинуты внутрь айтема.
Исправил. При поиске элемента использвался режим Qt::IntersectsItemShape, а нужен Qt::IntersectsItemBoundingRect.

Цитировать
Я вообще не очень понимаю, почему Вы обрабатываете событие попадания в ручку айтема в классе вида, когда это можно делать непосредственно в классе айтема, например, в функции hoverEnterEvent().
Дело в том, что я испульзую один айтем для отрисовки "ручек", поэтому hoverEnterEvent() мне ничего не даст. А вот помог бы QGraphicsItem::mouseMoveEvent(), но он отрабатывает только при нажатой кнопке - косяк Qt?

Цитировать
Цитировать
Иначе одновременно рисовать с трансформациями и без не получится.
У меня получилось. Я рисую родительский айтем рамки с трансформациями пером нулевой толщины, а потомки-айтемы ручек рисую с игнорированием трнасформаций, просто задавая для них позицию, привязанную к координатам родительского айтема. Получается, что ручки всегда стоят на своих местах и не изменяют размер при любом масштабе.
А вот это наверное самое правильное решение) Про sub-items изначально я и не подумал.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: Igors от Август 09, 2011, 17:45
У меня получилось. Я рисую родительский айтем рамки с трансформациями пером нулевой толщины, а потомки-айтемы ручек рисую с игнорированием трнасформаций, просто задавая для них позицию, привязанную к координатам родительского айтема. Получается, что ручки всегда стоят на своих местах и не изменяют размер при любом масштабе.
Что значит "просто рисую" - а как boundingRect ручек?

Зачем так сложно ??? Чем не устраивает мой вариант?
Что вы выиграете от разбивки grips-ов на отдельные элементы? Да ещё создавая кучу сцен.
Не понимаю. Зачем из простой задачи устраивать такие сложности?
Да все Вы прекрасно понимаете :) Каждая из ручек по сути "айтем" поскольку обладает всеми его свойствами "графической единицы" - может быть включена или скрыта, выбрана и.т.п. Сваливать всю эту ф-циональность на родителя не по уму. Предположим появился еще треугольник - у него 3 ручки (по углам) что будете делать? Создавать какой-то базовый класс (на том основании что оба "имеют ручки")? Нормальное решение - есть парент-айтем, у него чайлд-айтемы которые двигаются вместе с ним. Если же чайлд-айтем драгается - значит это ресайз парента. Попытки переломить эту естественность (через paintEvent парента и.т.п) будут автоматычно порождать одну проблему за другой - нет даже смысла терять время на их обсуждение.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 09, 2011, 18:02
Сваливать всю эту ф-циональность на родителя не по уму.
Я всё никак не могу понять про какого "родителя" идёт речь?

Цитировать
Предположим появился еще треугольник - у него 3 ручки (по углам) что будете делать? Создавать какой-то базовый класс (на том основании что оба "имеют ручки")? Нормальное решение - есть парент-айтем, у него чайлд-айтемы которые двигаются вместе с ним. Если же чайлд-айтем драгается - значит это ресайз парента.
Вот как раз в моём случае в одном универсальном классе это будет легко реализовать. Стоит только в качестве базы использовать QGraphicsPolygonItem и на вершины навесить ручки.

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

PS. Хм... похоже Вы не поняли идею, хотя я про неё и не говорил) Этот RubberItem является просто инструментом для растяжки существующих элементов сцены. При клике на элемент этот RubberItem просто помещается на выбранный элемент и уже управляет им. Обычно так в редакторах делается.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: Igors от Август 09, 2011, 18:33
Я всё никак не могу понять про какого "родителя" идёт речь?
То что у Вас QGraphicsRectItem - который нужно сайзить, на что навешаны ручки (handles)

Вот как раз в моём случае в одном универсальном классе это будет легко реализовать. Стоит только в качестве базы использовать QGraphicsPolygonItem и на вершины навесить ручки.
Сомнительная общность. Часто встречается круг - и даже полукруг который нужно сайзить интерактивно. Даже если полигон - он может иметь слишком много точек чтобы каждая была handle

А главное - handle явно класс, то уже парент решит сколько handles навесить и где. А как Вы сделаете его классом если у Вас все свалено в paintEvent, разборки курсора  и.т.п? Это конечно можно сделать но совсем непросто и получается какой-то EquippedGraphicsItem (который может иметь и управлять handles). Приходим опять к QGtapgicsItemGroup. Я люблю изобретать велосипед - но все же не настолько  :)


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 09, 2011, 19:14
2 Igors :
Судя по Вашей логике, каждый элемент сцены должен иметь набор "ручек" ???


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: Igors от Август 09, 2011, 19:45
2 Igors :
Судя по Вашей логике, каждый элемент сцены должен иметь набор "ручек" ???
В 3D сцене - да, и во многих вариантах (когда объект выбран)

- просто 3D объект (простейший случай). Вращать его интерактивно надо? И к бабке не ходи - надо. Двигать вдоль каждой из осей или free - стопудово. Ну и сайзить тоже бы неплохо.

- 3D light - ну тут засада (dropoff, направление, размеры источника света - по всякому, радиус тумана, радиус flare и.т.п.) - там приходится иметь опции "какие handles показывать" - иначе ховайся

- остальные - еше хуже

Так что не дело все лить в paintEvent


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 09, 2011, 20:43
Что значит "просто рисую" - а как boundingRect ручек?
Прошу прощения, неверно выразился. Не рисую, а создаю айтемы. Каждая ручка - это айтем - потомок айтема рамки. boundingRect у каждой ручки соответственно свой, ну а дальше всё работает так как Вы описали: Ручки можно скрыть, показать, они связаны сигналами со своим родителем и если я их тащу, родитель изменяет размер, ну и т.д.
В такой реализации осталась одна проблема (на самом деле две, но первая проблема более неприятная). Я не могу задать для айтемов ручек такой boundingRect, который бы распространялся на все грани родительского айтема, чтобы ресайзить можно было за края айтема, а не толкьо за ручки, ну удобнее так просто-напросто. А так как родитель принимает трансформации, а ручки их игнорируют, то без знания масштаба внутри boundingRect ручки не вычислить размер грани родительского айтема, вернее вычислить то можно, а вот задать правильный boundingRect никак нельзя, так как он будет игнорировать трансформации и всегда будет фиксированного размера, а не изменяться вместе с родительским айтемом.

Вторая проблема - это как раз толщина линии (Pen) родительского айтема, я могу ставить её только равной нулю, иначе она будет иметь размер в пикселях изображения, ну то-есть сцены. Я вообще не пойму, почему такие простые вещи нельзя сделать, например задать толщину линии, не зависящую от масштаба (в координатах области отображения), но чтобы сама линия масштабировалась, это же просто жизненно необходимо!



Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 09, 2011, 21:19
Я вообще не пойму, почему такие простые вещи нельзя сделать, например задать толщину линии, не зависящую от масштаба (в координатах области отображения), но чтобы сама линия масштабировалась, это же просто жизненно необходимо!
Код
C++ (Qt)
void QPen::setCosmetic ( bool cosmetic )


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 09, 2011, 21:26
2 Igors :
Судя по Вашей логике, каждый элемент сцены должен иметь набор "ручек" ???
В 3D сцене - да, и во многих вариантах (когда объект выбран)
Опять с Вами не соглашусь)
Всё-таки здесь разговор идёт про 2D, а не про 3D.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: kamre от Август 09, 2011, 21:28
Вторая проблема - это как раз толщина линии (Pen) родительского айтема, я могу ставить её только равной нулю, иначе она будет иметь размер в пикселях изображения, ну то-есть сцены. Я вообще не пойму, почему такие простые вещи нельзя сделать, например задать толщину линии, не зависящую от масштаба (в координатах области отображения), но чтобы сама линия масштабировалась, это же просто жизненно необходимо!
Именно по этой причине я отказался от QGraphicsView Framework и начал писать свою реализацию под задачу. А причина более или менее понятна: bounding box в системе координат сцены у такого отрезка постоянной толщины будет постоянно меняться, а весь индекс для items  основан именно на этих bounding boxes.

При этом Nokia считает этот framework как Done (http://labs.qt.nokia.com/2011/05/12/qt-modules-maturity-level-the-list/) и развивать больше не собирается.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: kamre от Август 09, 2011, 21:35
Код
C++ (Qt)
void QPen::setCosmetic ( bool cosmetic )
А теперь внимательно читаем:  QGraphicsItem does not support use of cosmetic pens with a non-zero width. (http://doc.qt.nokia.com/latest/qgraphicsitem.html)


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 09, 2011, 22:36
Код
C++ (Qt)
void QPen::setCosmetic ( bool cosmetic )
А теперь внимательно читаем:  QGraphicsItem does not support use of cosmetic pens with a non-zero width. (http://doc.qt.nokia.com/latest/qgraphicsitem.html)
Я несколько раз перечитывал описание метода paint() (http://doc.qt.nokia.com/latest/qgraphicsitem.html#paint) но так до конца и не понял, что они хотели сказать в этом предложении (QGraphicsItem does not support use of cosmetic pens with a non-zero width) применительно к отрисовке айтема. Понятно, что надо рисовать в границах boundingRect, иначе артефакты будут вылезать, но как cosmetic на это влияет?

Да в принципе это работает. Перо не меняет толщину при трансформациях. Одной проблемой меньше, запишем в Evernote ещё одну заметку в Qt-блокнотик. Cosmetic... млин, как интуитивно просто связать это с неизменностью ширины линии. :)


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: kamre от Август 10, 2011, 00:14
Понятно, что надо рисовать в границах boundingRect, иначе артефакты будут вылезать, но как cosmetic на это влияет?

Представим, что сделали zoom out так, что все очень мелко стало. При этом bounding box в координатах сцены стал меньше толщины кисти, которая cosmetic и от zoom не зависит.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 10, 2011, 10:44
Код
C++ (Qt)
void QPen::setCosmetic ( bool cosmetic )
А теперь внимательно читаем:  QGraphicsItem does not support use of cosmetic pens with a non-zero width. (http://doc.qt.nokia.com/latest/qgraphicsitem.html)
И? Всё он прекрасно поддерживает. Да и как он может это не поддерживать коли я рисую через QPainter?


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: Igors от Август 10, 2011, 11:19
Я не могу задать для айтемов ручек такой boundingRect, который бы распространялся на все грани родительского айтема, чтобы ресайзить можно было за края айтема, а не толкьо за ручки, ну удобнее так просто-напросто.
Для прямоугольника - да, удобнее. А вот хотя бы круга или треугольника - какой курсор показывать на resize? Для чуть более сложной фигуры эта техника может вообще оказаться нереальной/невыполнимой. Зачем же обещать это пользователю?

Если говорить о haтdles, то обычно возникают др. проблемы. Напр: есть 10 (или больше айтемов каждый из которых может иметь handles). Пользователь выбрал все 10. - у всех показать handles или как?  :)
Др. ситуация: один из айтемов полностью перекрыт другими. Как пользователь сможет выбрать перекрытый? Должны ли показываться handles если айтем выбран но перекрыт?


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 10, 2011, 11:24
Для прямоугольника - да, удобнее. А вот хотя бы круга или треугольника - какой курсор показывать на resize? Для чуть более сложной фигуры эта техника может вообще оказаться нереальной/невыполнимой. Зачем же обещать это пользователю?
А с чего Вы взяли, что у ТС, да и у многих других, фигуры будут сложнее прямоугольника?

Цитировать
Др. ситуация: один из айтемов полностью перекрыт другими. Как пользователь сможет выбрать перекрытый? Должны ли показываться handles если айтем выбран но перекрыт?
Выбранный элемент всегда должен иметь z-ку больше других и таких вопросов не будет.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 10, 2011, 11:45
Для прямоугольника - да, удобнее. А вот хотя бы круга или треугольника - какой курсор показывать на resize? Для чуть более сложной фигуры эта техника может вообще оказаться нереальной/невыполнимой. Зачем же обещать это пользователю?

Если говорить о haтdles, то обычно возникают др. проблемы. Напр: есть 10 (или больше айтемов каждый из которых может иметь handles). Пользователь выбрал все 10. - у всех показать handles или как?  :)
Др. ситуация: один из айтемов полностью перекрыт другими. Как пользователь сможет выбрать перекрытый? Должны ли показываться handles если айтем выбран но перекрыт?

Когда фигура сложнее прямоугольника, там появляется много других проблем и функциональность "ручек" там не самая большая проблема. Многоугольник или свободную кривую вообще не понятно как редактировать с помощью ручек. Можно редактировать с использованием сплайнов для сглаживания, можно без, можно вообще использовать NURB-сплайны, тогда ручки вообще будут лежать вне граней и т.д. В данной задаче у меня ничего сложнее прямоугольника редактировать не требуется. Слишком обобщать, универсализировать и абстрагировать бывает наоборот вредно.

Сейчас у меня при выборе рамки ее zValue устанавливается больше, чем zValue всех остальных, поэтому он автоматом выходит на передний план. Но естественно, что если одна рамка полностью перекрыта другой рамкой, то перекрытую не получится вытащить, не отодвинув ту, которая перекрывает. При перекрытии "ручки" перекрытых рамок не скрываю, всё прозрачно, а зачем их скрывать? Вообще сейчас я ручки убираю только если isResizable == false.


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: GreatSnake от Август 10, 2011, 11:51
Но естественно, что если одна рамка полностью перекрыта другой рамкой, то перекрытую не получится вытащить, не отодвинув ту, которая перекрывает.
Для таких случаев нужно иметь список элементов при клике (дабл-клике?) на который элемент сцены поднимется выше других)


Название: Re: QGraphicsItem и трансформации систем координат
Отправлено: iroln от Август 10, 2011, 11:57
Для таких случаев нужно иметь список элементов при клике (дабл-клике?) на который элемент сцены поднимется выше других)
Ну это уже обеспечивается функциональностью приложения, в котором инструментарий используется. Это конечно же есть у меня в программе. Из-за специфики задачи этих рамок может быть до нескольких тысяч, естественно их список есть. :)