Does QGraphicsItem::mapFromItem() account for transformations? - c++

I want to place an item (foreground) above another item (background) at a certain coordinate (x, y) of the background. The background is
transformed and foreground and background are in no parent-child relation.
I thus would do:
foreground->setPos(foreground->mapToParent(
foreground->mapFromScene(background->mapToScene(x, y))))
First determine where on the scene the background coordinate will be after transformation of the background, then map this coord from the scene to the foreground item's parent coordinate system for the setPos() call.
However this seems to be equivalent (at least in my case) to:
foreground->setPos(foreground->mapToParent(
foreground->mapFromItem(background, (x, y))))
Does mapFromItem(item) account for any transformation applied to item? Or is the equivalency just an artifact of my overall situation?

If you define that foreground is the parent of background, Qt will translate background automatically if the position of foreground changes.
background->setParent(foreground);
background->setPos(20,20); // cooridinate system origin is pos() of foreground.
foreground->setPos(10,10); // background moves also

Related

C++ How do I stop resizing Sf :: Text on screen resize ( but at the same position)

Im making map editor and i want to add resizing window but when i resize window my gui elements are resizing too how can i stop that,
i stop resizing map surface with set new size of map view but i cant do it with gui elements because it changes positions of gui elements
if(events.type == sf::Event::Resized)
{
m_defaultViewSize.x = events.size.width;
m_defaultViewSize.y = events.size.height;
m_mapView.setSize(m_defaultViewSize);
m_mapView.setSize(m_mapView.getSize() / m_zoomScale);// Apply the zoom level
m_stateData->window->setView(m_mapView);
}
sorry for my poor english
If you currently DO NOT have a GUI view your rendering code might look something like:
m_stateData->window->clear();
m_stateData->window->setView(m_mapView);
m_stateData->window->draw(m_map);
m_stateData->window->draw(m_gui);
m_stateData->window->display();
This is drawing the GUI on the same view as the map, so if the map view changes so does the GUI. This might be fine if the map does not change, but if you are planning on moving, scaling or rotating the map it would be best to create a GUI view.
Now rendering might look like this:
m_stateData->window->clear();
m_stateData->window->setView(m_mapView);
m_stateData->window->draw(m_map);
m_stateData->window->setView(m_guiView);
m_stateData->window->draw(m_gui);
m_stateData->window->display();
This is fine until we resize the window.
After resizing the window the view stays the same even though the viewport has changed size. If the window has been made larger twice horizontally but not vertically, the GUI is going to be stretched horizontally.
I personally do not like stretching, I do not think it looks nice. We should resize the view.
You could resize the view the same way you resized the map view.
m_guiView.setSize(m_defaultViewSize);
m_guiView.setSize(m_guiView.getSize() / m_zoomScale);
This will stop resizing the GUI elements, but their position will be the same as if we had not resized the window. You might want to reposition the GUI elements. One simple way of doing this is by storing the GUI elements position as a ratio along the screen horizontally and vertically. So, the top left might be (-0.5, -0.5) and the bottom right might be (0.5, 0.5).
This might look like (with a view centered on (0, 0)):
// get ratio position of gui element
sf::Vector2f ratio_position = {
(m_gui.getPosition().x) / m_guiView.getSize().x,
(m_gui.getPosition().y) / m_guiView.getSize().y
};
// resize view
m_guiView.setSize(m_defaultViewSize);
m_guiView.setSize(m_guiView.getSize() / m_zoomScale);
// set position of gui element
m_gui.setPosition(
(ratio_position.x)* m_guiView.getSize().x,
(ratio_position.y) * m_guiView.getSize().y
);
You could also have this be functionality of a class.
You can use things other than ratios as well.
You could make GUI elements relative to corners of the screen, or other ratios. So You could have Health bar, Stamina bar, Mana bar all relative to the top left of the view. This would just be calculating the top left position (view center - half of the view size) and then adding on some relative position (for example, (0, 0) for health bar, (0, 32) for stamina bar etc).
I suggest you look at how other Game Engines handle GUI. Unity uses Anchor Points. Godot uses containers. Try and recreate a system you like.

Ignore transformation of QGraphicsItem's shape

My reimplemented QGraphicsItem draws a circle. It has flag ItemIgnoresTransformations, so it has always the same size when scaling. Should I set transformations manually for item's shape function to be accurate or there exists easy way? I need shape function for processing mouse events for this circle in QGraphicsScene.

QGraphicsScene image pos pixmap

I am using Qt Graphics Framework for displaying an image. I have opened a raw image in subclassed QGraphicsScene in QGraphicsView using addPixmap(). I have added zoom feature by using scale function and drag mode is set as scroll hand drag. Now, I need to get the pixel coordinates within the scene on mouse hover such that the x and y value show the pixel in the image (drawn by pixmap) the mouse is currently pointing to. I tried using pos() but it didn't work.
Here is the code from Widget.cpp:
img = openImage(dirPath2.toLocal8Bit().data(),
sizeX,sizeY,file_heade,scan_heade,bpp,sign);
QPixmap x = QPixmap(sizeX,sizeY);
x.convertFromImage(img,Qt::AutoColor);
scene->addPixmap(x);
ui->disp_img->setDragMode(QGraphicsView::ScrollHandDrag);
GraphicsScene.h:
class GraphicsScene : public QGraphicsScene {
public:
GraphicsScene(QWidget *parent) : QGraphicsScene(parent){}
};
(preferably the pixmap coordinates but even that doesn't happen and if the values change when zoomed I will use scale factor to get the original values)
I suggest you start by reading about Qt's Graphics Coordinate System.
There are various layers of coordinate systems and you need to think about those with which you dealing with. At the top layer is the screen (or view), which is where the mouse coordinates reside.
The next layer from the view is the graphics scene. Graphics items, such as the QGraphicsPixmapItem which you added with addPixmap, reside here. The graphics scene can be visualised as a world of items, each with there own position and orientation.
Moving to the last coordinate system is an item's local coordinate system. If, for example, we take a rectangle, it may have local coordinates of (-5, -5, 10, 10) for (x, y, w, h). This item is then placed in the scene at some position. If its position is the origin of the scene (0,0), then the item's local coordinates would read the same as its scene coordinates.
However, if we move the rectangle +5 units in x-axis, its local coordinates are the same, but its scene coordinates would now be (0, -5, 10, 10).
Likewise, the view (QGraphicsScene) is a window into the scene and can be looking at the whole scene, or just part of it. As the view's top left coordinate is (0,0), it may map onto (0,0) of the scene, or may not, depending on what area of the scene the view is looking at.
So, by getting a mouse position you're starting in the view's coordinates and need to convert to the scene's coordinate system. Fortunately, Qt provides lots of useful functions for this at every level.
To convert the mouse coordinates from the view to the scene, you can use the view's mapToScene function.
Using the scene coordinates you can then get an item and map that to the local coordinate's of the item with the item's mapFromScene.

Qt drawing outside the Painter device

I created a subclass of QToolBar to make a context tool bar associate with QGraphicsItem.
What I want to add is a small triangle point to where my toolbar popped up. I know that QPainter can't draw outside the QToolBar. But is there a way to draw from pic 1 to pic 2
Sorry. My pics are awful. But you could understand.
Maybe you should create a new widget (or a tiny frameless, borderless window), with only the small triangle and put it at the required position (ie: the x coordinate should be the mouseX - width_of_window/2 and the Y coordinate should be mouseX - height_of_window).
Make sure the widget (windows) is hidden when the scrollbar is not shown, and show it at the calculated global coordinates on a mouse action.

QGraphicsView and QGraphicsScene coordinate systems

in Qt 4.8 i have create a QGraphicsView and a DynamicRadarScene(derived from QGraphicsScene):
QGraphicsView* view = new QGraphicsView;
view->setMinimumSize(800, 600);
DynamicRadarScene* _scene = new DynamicRadarScene(mode, channel_types, this);
view->setScene(_scene);
What is the coordinate system of QGraphicsScene? (0,0) is from upper left corner?
How can i draw an item in the upper right corner of the scene (i have set it 800x600: view->setMinimumSize(800, 600);)?
If i resize the widget and so i resize the QGraphicsView, how can move the item i have drawn before to remain in the upper left corner?
Yes, the upper left corner is generally the coordinate of (0,0) in a graphics scene. What you need to consider is that a QGraphicsView is like a window looking into a world (the QGraphicsScene). You set the view to look at an area or the scene, which may be all or just part of the scene.
Once the scene and view are setup, you can then add QGraphicsItems / QGraphicsObjects or instances of classes derived from those by using functions such as QGraphicsScene::addItem. These items are positioned in the scene and draw themselves.
i (sic) resize the widget and so i resize the QGraphicsView
You can change the QGraphicsView position and dimensions, but then the items in the scene will remain in the same place within the scene. Usually you would set up the scene and view and then move / resize the graphics items / objects within the scene, often with the setPos function: QGraphicsItem::setPos(). This sets the position of the item, relative to its parent. If the item has no parent, it sets the position of the item in the scene.
QGraphicsScene has property sceneRect. If it is not set then it is auto adjusted depending on scene content. This can give a filling that origin of coordinating is in some strange place or even that it is mobile.
Set this property. See also this.